From f327a3f62a83ef7809ea9b8d7483420cacdb8e25 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 15 Aug 2022 17:13:40 +0200 Subject: [PATCH 001/415] Python: Remove strange-pointsto-interaction-investigation These tests are not relevant anymore :muscle: --- .../README.md | 96 ------------------- .../src/eval_no_problem.py | 43 --------- .../src/isfile_no_problem.py | 43 --------- .../src/simple_no_problem.py | 43 --------- .../src/urandom_no_if_no_problem.py | 43 --------- .../src/urandom_no_import_no_problem.py | 43 --------- .../src/urandom_problem.py | 43 --------- .../test-1-normal/NormalDataflowTest.expected | 2 - .../test-1-normal/NormalDataflowTest.ql | 2 - .../test-1-normal/Splitting.expected | 6 -- .../test-1-normal/Splitting.ql | 16 ---- .../test-1-normal/UnresolvedCalls.expected | 0 .../test-1-normal/UnresolvedCalls.ql | 2 - .../UnresolvedPointsToCalls.expected | 5 - .../test-1-normal/UnresolvedPointsToCalls.ql | 10 -- .../test-1-normal/options | 1 - .../NormalDataflowTest.expected | 3 - .../NormalDataflowTest.ql | 2 - .../Splitting.expected | 6 -- .../test-2-without-splitting/Splitting.ql | 16 ---- .../UnresolvedCalls.expected | 2 - .../UnresolvedCalls.ql | 2 - .../UnresolvedPointsToCalls.expected | 3 - .../UnresolvedPointsToCalls.ql | 10 -- .../test-2-without-splitting/options | 1 - .../NormalDataflowTest.expected | 3 - .../NormalDataflowTest.ql | 2 - .../Splitting.expected | 6 -- .../test-3-max-import-depth-0/Splitting.ql | 16 ---- .../UnresolvedCalls.expected | 2 - .../UnresolvedCalls.ql | 2 - .../UnresolvedPointsToCalls.expected | 2 - .../UnresolvedPointsToCalls.ql | 10 -- .../test-3-max-import-depth-0/options | 1 - .../NormalDataflowTest.expected | 3 - .../NormalDataflowTest.ql | 2 - .../Splitting.expected | 6 -- .../test-4-max-import-depth-100/Splitting.ql | 16 ---- .../UnresolvedCalls.expected | 5 - .../UnresolvedCalls.ql | 2 - .../UnresolvedPointsToCalls.expected | 1 - .../UnresolvedPointsToCalls.ql | 10 -- .../test-4-max-import-depth-100/options | 1 - .../NormalDataflowTest.expected | 3 - .../NormalDataflowTest.ql | 2 - .../Splitting.expected | 6 -- .../test-5-max-import-depth-3/Splitting.ql | 16 ---- .../UnresolvedCalls.expected | 5 - .../UnresolvedCalls.ql | 2 - .../UnresolvedPointsToCalls.expected | 1 - .../UnresolvedPointsToCalls.ql | 10 -- .../test-5-max-import-depth-3/options | 1 - .../NormalDataflowTest.expected | 5 - .../NormalDataflowTest.ql | 2 - .../Splitting.expected | 6 -- .../test-6-max-import-depth-2/Splitting.ql | 16 ---- .../UnresolvedCalls.expected | 6 -- .../UnresolvedCalls.ql | 2 - .../UnresolvedPointsToCalls.expected | 4 - .../UnresolvedPointsToCalls.ql | 10 -- .../test-6-max-import-depth-2/options | 1 - 61 files changed, 631 deletions(-) delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/README.md delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/eval_no_problem.py delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/isfile_no_problem.py delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/simple_no_problem.py delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_if_no_problem.py delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_import_no_problem.py delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_problem.py delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/options delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/options delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/options delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/options delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/options delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.expected delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.ql delete mode 100644 python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/options diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/README.md b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/README.md deleted file mode 100644 index 59e9087ee49..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/README.md +++ /dev/null @@ -1,96 +0,0 @@ -While working on the field-flow tests, I encountered some very strange behavior. By moving some tests into a new file, they suddenly started working :O - -This folder contains the artifacts from investigating this problem, so we can recall the facts (but besides that, don't have much value in itself). - -The test files can be found in `src/`, and I have set of a bunch of different tests with different extractor options in the `test-*` folders. - -The core of the problem is that in _some_ configuration of extractor options, after seeing the code below, points-to gives up trying to resolve calls :flushed: - -```py -import os -cond = os.urandom(1)[0] > 128 - -if cond: - pass - -if cond: - pass -``` - -This seems to have been caused by not allowing enough imports to be resolved. There is also some interaction with splitting, since turning that off also removes the problem. - -But allowing our test to see more imports is more representative of what happens when analyzing real code, so that's the better approach :+1: (and going above 3 does not seem to change anything in this case). - -I've thought about whether we can write a query to reliably cases such as this, but I don't see any solutions. However, we can easily try running all our tests with `--max-import-depth=100` and see if anything changes from this. - -# Seeing the solutions work - -Doing `diff -u -r test-1-normal/ test-5-max-import-depth-3/` shows that all the calls we should be able to resolve, are now resolved properly. and critically this line is added: - -```diff -+| ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | -``` - -
-full diff - -```diff -diff '--color=auto' -u -r test-1-normal/NormalDataflowTest.expected test-5-max-import-depth-3/NormalDataflowTest.expected ---- test-1-normal/NormalDataflowTest.expected 2022-02-27 10:33:00.603882599 +0100 -+++ test-5-max-import-depth-3/NormalDataflowTest.expected 2022-02-28 10:10:08.930743800 +0100 -@@ -1,2 +1,3 @@ - missingAnnotationOnSink - failures -+| ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | -diff '--color=auto' -u -r test-1-normal/options test-5-max-import-depth-3/options ---- test-1-normal/options 2022-02-27 10:36:51.124793909 +0100 -+++ test-5-max-import-depth-3/options 2022-02-27 11:01:43.908098372 +0100 -@@ -1 +1 @@ --semmle-extractor-options: --max-import-depth=1 -R ../src -+semmle-extractor-options: --max-import-depth=3 -R ../src -diff '--color=auto' -u -r test-1-normal/UnresolvedCalls.expected test-5-max-import-depth-3/UnresolvedCalls.expected ---- test-1-normal/UnresolvedCalls.expected 2022-02-28 10:09:19.213742437 +0100 -+++ test-5-max-import-depth-3/UnresolvedCalls.expected 2022-02-28 10:10:08.638737921 +0100 -@@ -0,0 +1,5 @@ -+| ../src/isfile_no_problem.py:34:33:34:70 | Comment # $ unresolved_call=os.path.isfile(..) | Missing result:unresolved_call=os.path.isfile(..) | -+| ../src/urandom_no_if_no_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -+| ../src/urandom_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -+| ../src/urandom_problem.py:42:18:42:47 | Comment # $ unresolved_call=give_src() | Missing result:unresolved_call=give_src() | -+| ../src/urandom_problem.py:43:11:43:75 | Comment # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-15 -> foo" | Missing result:unresolved_call=SINK(..) | -diff '--color=auto' -u -r test-1-normal/UnresolvedPointsToCalls.expected test-5-max-import-depth-3/UnresolvedPointsToCalls.expected ---- test-1-normal/UnresolvedPointsToCalls.expected 2022-02-28 10:09:19.033738812 +0100 -+++ test-5-max-import-depth-3/UnresolvedPointsToCalls.expected 2022-02-28 10:12:48.572752108 +0100 -@@ -1,5 +1 @@ --| ../src/urandom_no_if_no_problem.py:34:8:34:20 | ../src/urandom_no_if_no_problem.py:34 | os.urandom(..) | - | ../src/urandom_no_import_no_problem.py:34:8:34:20 | ../src/urandom_no_import_no_problem.py:34 | os.urandom(..) | --| ../src/urandom_problem.py:34:8:34:20 | ../src/urandom_problem.py:34 | os.urandom(..) | --| ../src/urandom_problem.py:42:7:42:16 | ../src/urandom_problem.py:42 | give_src() | --| ../src/urandom_problem.py:43:1:43:9 | ../src/urandom_problem.py:43 | SINK(..) | -``` - -
- -There are no benefit in increasing import depth above 3 for this test-example: - -```diff -$ diff -u -r test-4-max-import-depth-100/ test-5-max-import-depth-3/ ---- test-4-max-import-depth-100/options 2022-02-28 10:02:09.269071781 +0100 -+++ test-5-max-import-depth-3/options 2022-02-27 11:01:43.908098372 +0100 -@@ -1 +1 @@ --semmle-extractor-options: --max-import-depth=100 -R ../src -+semmle-extractor-options: --max-import-depth=3 -R ../src -``` - -Also notice that using import depth 2 actually makes things worse, as we no longer handle the `isfile_no_problem.py` file properly :facepalm: :sweat_smile: NOTE: This was only for Python 3, for Python 2 there was no change :flushed: - -```diff -diff '--color=auto' -u -r test-4-max-import-depth-100/NormalDataflowTest.expected test-6-max-import-depth-2/NormalDataflowTest.expected ---- test-4-max-import-depth-100/NormalDataflowTest.expected 2022-02-28 10:10:02.206608379 +0100 -+++ test-6-max-import-depth-2/NormalDataflowTest.expected 2022-02-28 10:10:13.882716665 +0100 -@@ -1,3 +1,5 @@ - missingAnnotationOnSink -+| ../src/isfile_no_problem.py:43:6:43:8 | ../src/isfile_no_problem.py:43 | ERROR, you should add `# $ MISSING: flow` annotation | foo | - failures -+| ../src/isfile_no_problem.py:43:11:43:41 | Comment # $ flow="SOURCE, l:-15 -> foo" | Missing result:flow="SOURCE, l:-15 -> foo" | - | ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | -``` diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/eval_no_problem.py b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/eval_no_problem.py deleted file mode 100644 index f64100c667b..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/eval_no_problem.py +++ /dev/null @@ -1,43 +0,0 @@ -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - -# ------------------------------------------------------------------------------ -# Actual tests -# ------------------------------------------------------------------------------ - -def give_src(): - return SOURCE - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-3 -> foo" - -import os -cond = eval("False") - -if cond: - pass - -if cond: - pass - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-15 -> foo" diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/isfile_no_problem.py b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/isfile_no_problem.py deleted file mode 100644 index 895763b7a88..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/isfile_no_problem.py +++ /dev/null @@ -1,43 +0,0 @@ -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - -# ------------------------------------------------------------------------------ -# Actual tests -# ------------------------------------------------------------------------------ - -def give_src(): - return SOURCE - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-3 -> foo" - -import os -cond = os.path.isfile(__file__) # $ unresolved_call=os.path.isfile(..) - -if cond: - pass - -if cond: - pass - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-15 -> foo" diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/simple_no_problem.py b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/simple_no_problem.py deleted file mode 100644 index 447d0258349..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/simple_no_problem.py +++ /dev/null @@ -1,43 +0,0 @@ -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - -# ------------------------------------------------------------------------------ -# Actual tests -# ------------------------------------------------------------------------------ - -def give_src(): - return SOURCE - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-3 -> foo" - -import os -cond = 1 + 1 == 2 - -if cond: - pass - -if cond: - pass - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-15 -> foo" diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_if_no_problem.py b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_if_no_problem.py deleted file mode 100644 index 5a2c71b1e47..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_if_no_problem.py +++ /dev/null @@ -1,43 +0,0 @@ -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - -# ------------------------------------------------------------------------------ -# Actual tests -# ------------------------------------------------------------------------------ - -def give_src(): - return SOURCE - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-3 -> foo" - -import os -cond = os.urandom(1)[0] > 128 # $ unresolved_call=os.urandom(..) - -# if cond: -# pass -# -# if cond: -# pass - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-15 -> foo" diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_import_no_problem.py b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_import_no_problem.py deleted file mode 100644 index 487170078ab..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_no_import_no_problem.py +++ /dev/null @@ -1,43 +0,0 @@ -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - -# ------------------------------------------------------------------------------ -# Actual tests -# ------------------------------------------------------------------------------ - -def give_src(): - return SOURCE - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-3 -> foo" - -# import os -cond = os.urandom(1)[0] > 128 # $ unresolved_call=os.urandom(..) - -# if cond: -# pass -# -# if cond: -# pass - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-15 -> foo" diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_problem.py b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_problem.py deleted file mode 100644 index d4a06529cf6..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/src/urandom_problem.py +++ /dev/null @@ -1,43 +0,0 @@ -# These are defined so that we can evaluate the test code. -NONSOURCE = "not a source" -SOURCE = "source" - - -def is_source(x): - return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j - - -def SINK(x): - if is_source(x): - print("OK") - else: - print("Unexpected flow", x) - - -def SINK_F(x): - if is_source(x): - print("Unexpected flow", x) - else: - print("OK") - -# ------------------------------------------------------------------------------ -# Actual tests -# ------------------------------------------------------------------------------ - -def give_src(): - return SOURCE - -foo = give_src() -SINK(foo) # $ flow="SOURCE, l:-3 -> foo" - -import os -cond = os.urandom(1)[0] > 128 # $ unresolved_call=os.urandom(..) - -if cond: - pass - -if cond: - pass - -foo = give_src() # $ unresolved_call=give_src() -SINK(foo) # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-15 -> foo" diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.expected deleted file mode 100644 index 3875da4e143..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.expected +++ /dev/null @@ -1,2 +0,0 @@ -missingAnnotationOnSink -failures diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.ql deleted file mode 100644 index 3ee344d0b87..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/NormalDataflowTest.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.expected deleted file mode 100644 index 6d281f5f299..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.expected +++ /dev/null @@ -1,6 +0,0 @@ -| ../src/eval_no_problem.py | has splitting | -| ../src/isfile_no_problem.py | has splitting | -| ../src/simple_no_problem.py | has splitting | -| ../src/urandom_no_if_no_problem.py | does not have splitting | -| ../src/urandom_no_import_no_problem.py | does not have splitting | -| ../src/urandom_problem.py | has splitting | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.ql deleted file mode 100644 index ce4cba33871..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/Splitting.ql +++ /dev/null @@ -1,16 +0,0 @@ -import python - -// this can be quick-eval to see which ones have splitting. But that's basically just -// anything from line 39 and further. -predicate exprWithSplitting(Expr e) { - exists(e.getLocation().getFile().getRelativePath()) and - 1 < count(ControlFlowNode cfn | cfn.getNode() = e) -} - -from File f, string msg -where - exists(f.getRelativePath()) and - if exists(Expr e | e.getLocation().getFile() = f and exprWithSplitting(e)) - then msg = "has splitting" - else msg = "does not have splitting" -select f.toString(), msg diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedCalls.expected deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedCalls.ql deleted file mode 100644 index c31dc161620..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedCalls.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.UnresolvedCalls diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.expected deleted file mode 100644 index 5c3279e5b65..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.expected +++ /dev/null @@ -1,5 +0,0 @@ -| ../src/urandom_no_if_no_problem.py:34:8:34:20 | ../src/urandom_no_if_no_problem.py:34 | os.urandom(..) | -| ../src/urandom_no_import_no_problem.py:34:8:34:20 | ../src/urandom_no_import_no_problem.py:34 | os.urandom(..) | -| ../src/urandom_problem.py:34:8:34:20 | ../src/urandom_problem.py:34 | os.urandom(..) | -| ../src/urandom_problem.py:42:7:42:16 | ../src/urandom_problem.py:42 | give_src() | -| ../src/urandom_problem.py:43:1:43:9 | ../src/urandom_problem.py:43 | SINK(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.ql deleted file mode 100644 index 212b840decc..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/UnresolvedPointsToCalls.ql +++ /dev/null @@ -1,10 +0,0 @@ -import python -private import semmle.python.dataflow.new.internal.PrintNode - -from CallNode call -where - exists(call.getLocation().getFile().getRelativePath()) and - not exists(Value value | call = value.getACall()) and - // somehow print is not resolved, but that is not the focus right now - not call.getFunction().(NameNode).getId() = "print" -select call.getLocation(), prettyExpr(call.getNode()) diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/options b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/options deleted file mode 100644 index 2b7a8c5c0dd..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-1-normal/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=1 -R ../src diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.expected deleted file mode 100644 index ceeb0ef30e0..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.expected +++ /dev/null @@ -1,3 +0,0 @@ -missingAnnotationOnSink -failures -| ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.ql deleted file mode 100644 index 3ee344d0b87..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/NormalDataflowTest.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.expected deleted file mode 100644 index 1669504bb58..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.expected +++ /dev/null @@ -1,6 +0,0 @@ -| ../src/eval_no_problem.py | does not have splitting | -| ../src/isfile_no_problem.py | does not have splitting | -| ../src/simple_no_problem.py | does not have splitting | -| ../src/urandom_no_if_no_problem.py | does not have splitting | -| ../src/urandom_no_import_no_problem.py | does not have splitting | -| ../src/urandom_problem.py | does not have splitting | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.ql deleted file mode 100644 index ce4cba33871..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/Splitting.ql +++ /dev/null @@ -1,16 +0,0 @@ -import python - -// this can be quick-eval to see which ones have splitting. But that's basically just -// anything from line 39 and further. -predicate exprWithSplitting(Expr e) { - exists(e.getLocation().getFile().getRelativePath()) and - 1 < count(ControlFlowNode cfn | cfn.getNode() = e) -} - -from File f, string msg -where - exists(f.getRelativePath()) and - if exists(Expr e | e.getLocation().getFile() = f and exprWithSplitting(e)) - then msg = "has splitting" - else msg = "does not have splitting" -select f.toString(), msg diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.expected deleted file mode 100644 index 8078da5b640..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.expected +++ /dev/null @@ -1,2 +0,0 @@ -| ../src/urandom_problem.py:42:18:42:47 | Comment # $ unresolved_call=give_src() | Missing result:unresolved_call=give_src() | -| ../src/urandom_problem.py:43:11:43:75 | Comment # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-15 -> foo" | Missing result:unresolved_call=SINK(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.ql deleted file mode 100644 index c31dc161620..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedCalls.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.UnresolvedCalls diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.expected deleted file mode 100644 index f145962da0d..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.expected +++ /dev/null @@ -1,3 +0,0 @@ -| ../src/urandom_no_if_no_problem.py:34:8:34:20 | ../src/urandom_no_if_no_problem.py:34 | os.urandom(..) | -| ../src/urandom_no_import_no_problem.py:34:8:34:20 | ../src/urandom_no_import_no_problem.py:34 | os.urandom(..) | -| ../src/urandom_problem.py:34:8:34:20 | ../src/urandom_problem.py:34 | os.urandom(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.ql deleted file mode 100644 index 212b840decc..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/UnresolvedPointsToCalls.ql +++ /dev/null @@ -1,10 +0,0 @@ -import python -private import semmle.python.dataflow.new.internal.PrintNode - -from CallNode call -where - exists(call.getLocation().getFile().getRelativePath()) and - not exists(Value value | call = value.getACall()) and - // somehow print is not resolved, but that is not the focus right now - not call.getFunction().(NameNode).getId() = "print" -select call.getLocation(), prettyExpr(call.getNode()) diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/options b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/options deleted file mode 100644 index acbba69f1d5..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-2-without-splitting/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --dont-split-graph --max-import-depth=1 -R ../src diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.expected deleted file mode 100644 index ceeb0ef30e0..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.expected +++ /dev/null @@ -1,3 +0,0 @@ -missingAnnotationOnSink -failures -| ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.ql deleted file mode 100644 index 3ee344d0b87..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/NormalDataflowTest.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.expected deleted file mode 100644 index 6d281f5f299..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.expected +++ /dev/null @@ -1,6 +0,0 @@ -| ../src/eval_no_problem.py | has splitting | -| ../src/isfile_no_problem.py | has splitting | -| ../src/simple_no_problem.py | has splitting | -| ../src/urandom_no_if_no_problem.py | does not have splitting | -| ../src/urandom_no_import_no_problem.py | does not have splitting | -| ../src/urandom_problem.py | has splitting | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.ql deleted file mode 100644 index ce4cba33871..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/Splitting.ql +++ /dev/null @@ -1,16 +0,0 @@ -import python - -// this can be quick-eval to see which ones have splitting. But that's basically just -// anything from line 39 and further. -predicate exprWithSplitting(Expr e) { - exists(e.getLocation().getFile().getRelativePath()) and - 1 < count(ControlFlowNode cfn | cfn.getNode() = e) -} - -from File f, string msg -where - exists(f.getRelativePath()) and - if exists(Expr e | e.getLocation().getFile() = f and exprWithSplitting(e)) - then msg = "has splitting" - else msg = "does not have splitting" -select f.toString(), msg diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.expected deleted file mode 100644 index 8078da5b640..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.expected +++ /dev/null @@ -1,2 +0,0 @@ -| ../src/urandom_problem.py:42:18:42:47 | Comment # $ unresolved_call=give_src() | Missing result:unresolved_call=give_src() | -| ../src/urandom_problem.py:43:11:43:75 | Comment # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-15 -> foo" | Missing result:unresolved_call=SINK(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.ql deleted file mode 100644 index c31dc161620..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedCalls.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.UnresolvedCalls diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.expected deleted file mode 100644 index b9a1652ce68..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.expected +++ /dev/null @@ -1,2 +0,0 @@ -| ../src/isfile_no_problem.py:34:8:34:31 | ../src/isfile_no_problem.py:34 | os.path.isfile(..) | -| ../src/urandom_no_import_no_problem.py:34:8:34:20 | ../src/urandom_no_import_no_problem.py:34 | os.urandom(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.ql deleted file mode 100644 index 212b840decc..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/UnresolvedPointsToCalls.ql +++ /dev/null @@ -1,10 +0,0 @@ -import python -private import semmle.python.dataflow.new.internal.PrintNode - -from CallNode call -where - exists(call.getLocation().getFile().getRelativePath()) and - not exists(Value value | call = value.getACall()) and - // somehow print is not resolved, but that is not the focus right now - not call.getFunction().(NameNode).getId() = "print" -select call.getLocation(), prettyExpr(call.getNode()) diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/options b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/options deleted file mode 100644 index 762f1f95d9a..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-3-max-import-depth-0/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=0 -R ../src diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.expected deleted file mode 100644 index ceeb0ef30e0..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.expected +++ /dev/null @@ -1,3 +0,0 @@ -missingAnnotationOnSink -failures -| ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.ql deleted file mode 100644 index 3ee344d0b87..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/NormalDataflowTest.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.expected deleted file mode 100644 index 6d281f5f299..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.expected +++ /dev/null @@ -1,6 +0,0 @@ -| ../src/eval_no_problem.py | has splitting | -| ../src/isfile_no_problem.py | has splitting | -| ../src/simple_no_problem.py | has splitting | -| ../src/urandom_no_if_no_problem.py | does not have splitting | -| ../src/urandom_no_import_no_problem.py | does not have splitting | -| ../src/urandom_problem.py | has splitting | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.ql deleted file mode 100644 index ce4cba33871..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/Splitting.ql +++ /dev/null @@ -1,16 +0,0 @@ -import python - -// this can be quick-eval to see which ones have splitting. But that's basically just -// anything from line 39 and further. -predicate exprWithSplitting(Expr e) { - exists(e.getLocation().getFile().getRelativePath()) and - 1 < count(ControlFlowNode cfn | cfn.getNode() = e) -} - -from File f, string msg -where - exists(f.getRelativePath()) and - if exists(Expr e | e.getLocation().getFile() = f and exprWithSplitting(e)) - then msg = "has splitting" - else msg = "does not have splitting" -select f.toString(), msg diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.expected deleted file mode 100644 index d215a40ab29..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.expected +++ /dev/null @@ -1,5 +0,0 @@ -| ../src/isfile_no_problem.py:34:33:34:70 | Comment # $ unresolved_call=os.path.isfile(..) | Missing result:unresolved_call=os.path.isfile(..) | -| ../src/urandom_no_if_no_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -| ../src/urandom_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -| ../src/urandom_problem.py:42:18:42:47 | Comment # $ unresolved_call=give_src() | Missing result:unresolved_call=give_src() | -| ../src/urandom_problem.py:43:11:43:75 | Comment # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-15 -> foo" | Missing result:unresolved_call=SINK(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.ql deleted file mode 100644 index c31dc161620..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedCalls.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.UnresolvedCalls diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.expected deleted file mode 100644 index ce3d7597c36..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.expected +++ /dev/null @@ -1 +0,0 @@ -| ../src/urandom_no_import_no_problem.py:34:8:34:20 | ../src/urandom_no_import_no_problem.py:34 | os.urandom(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.ql deleted file mode 100644 index 212b840decc..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/UnresolvedPointsToCalls.ql +++ /dev/null @@ -1,10 +0,0 @@ -import python -private import semmle.python.dataflow.new.internal.PrintNode - -from CallNode call -where - exists(call.getLocation().getFile().getRelativePath()) and - not exists(Value value | call = value.getACall()) and - // somehow print is not resolved, but that is not the focus right now - not call.getFunction().(NameNode).getId() = "print" -select call.getLocation(), prettyExpr(call.getNode()) diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/options b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/options deleted file mode 100644 index 82f44bce3c0..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-4-max-import-depth-100/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=100 -R ../src diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.expected deleted file mode 100644 index ceeb0ef30e0..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.expected +++ /dev/null @@ -1,3 +0,0 @@ -missingAnnotationOnSink -failures -| ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.ql deleted file mode 100644 index 3ee344d0b87..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/NormalDataflowTest.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.expected deleted file mode 100644 index 6d281f5f299..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.expected +++ /dev/null @@ -1,6 +0,0 @@ -| ../src/eval_no_problem.py | has splitting | -| ../src/isfile_no_problem.py | has splitting | -| ../src/simple_no_problem.py | has splitting | -| ../src/urandom_no_if_no_problem.py | does not have splitting | -| ../src/urandom_no_import_no_problem.py | does not have splitting | -| ../src/urandom_problem.py | has splitting | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.ql deleted file mode 100644 index ce4cba33871..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/Splitting.ql +++ /dev/null @@ -1,16 +0,0 @@ -import python - -// this can be quick-eval to see which ones have splitting. But that's basically just -// anything from line 39 and further. -predicate exprWithSplitting(Expr e) { - exists(e.getLocation().getFile().getRelativePath()) and - 1 < count(ControlFlowNode cfn | cfn.getNode() = e) -} - -from File f, string msg -where - exists(f.getRelativePath()) and - if exists(Expr e | e.getLocation().getFile() = f and exprWithSplitting(e)) - then msg = "has splitting" - else msg = "does not have splitting" -select f.toString(), msg diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.expected deleted file mode 100644 index d215a40ab29..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.expected +++ /dev/null @@ -1,5 +0,0 @@ -| ../src/isfile_no_problem.py:34:33:34:70 | Comment # $ unresolved_call=os.path.isfile(..) | Missing result:unresolved_call=os.path.isfile(..) | -| ../src/urandom_no_if_no_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -| ../src/urandom_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -| ../src/urandom_problem.py:42:18:42:47 | Comment # $ unresolved_call=give_src() | Missing result:unresolved_call=give_src() | -| ../src/urandom_problem.py:43:11:43:75 | Comment # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-15 -> foo" | Missing result:unresolved_call=SINK(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.ql deleted file mode 100644 index c31dc161620..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedCalls.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.UnresolvedCalls diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.expected deleted file mode 100644 index ce3d7597c36..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.expected +++ /dev/null @@ -1 +0,0 @@ -| ../src/urandom_no_import_no_problem.py:34:8:34:20 | ../src/urandom_no_import_no_problem.py:34 | os.urandom(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.ql deleted file mode 100644 index 212b840decc..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/UnresolvedPointsToCalls.ql +++ /dev/null @@ -1,10 +0,0 @@ -import python -private import semmle.python.dataflow.new.internal.PrintNode - -from CallNode call -where - exists(call.getLocation().getFile().getRelativePath()) and - not exists(Value value | call = value.getACall()) and - // somehow print is not resolved, but that is not the focus right now - not call.getFunction().(NameNode).getId() = "print" -select call.getLocation(), prettyExpr(call.getNode()) diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/options b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/options deleted file mode 100644 index fd080c5b1e1..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-5-max-import-depth-3/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=3 -R ../src diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.expected deleted file mode 100644 index 7b5784017f3..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.expected +++ /dev/null @@ -1,5 +0,0 @@ -missingAnnotationOnSink -| ../src/isfile_no_problem.py:43:6:43:8 | ../src/isfile_no_problem.py:43 | ERROR, you should add `# $ MISSING: flow` annotation | foo | -failures -| ../src/isfile_no_problem.py:43:11:43:41 | Comment # $ flow="SOURCE, l:-15 -> foo" | Missing result:flow="SOURCE, l:-15 -> foo" | -| ../src/urandom_problem.py:43:6:43:8 | ControlFlowNode for foo | Fixed missing result:flow="SOURCE, l:-15 -> foo" | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.ql deleted file mode 100644 index 3ee344d0b87..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/NormalDataflowTest.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.expected deleted file mode 100644 index 6d281f5f299..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.expected +++ /dev/null @@ -1,6 +0,0 @@ -| ../src/eval_no_problem.py | has splitting | -| ../src/isfile_no_problem.py | has splitting | -| ../src/simple_no_problem.py | has splitting | -| ../src/urandom_no_if_no_problem.py | does not have splitting | -| ../src/urandom_no_import_no_problem.py | does not have splitting | -| ../src/urandom_problem.py | has splitting | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.ql deleted file mode 100644 index ce4cba33871..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/Splitting.ql +++ /dev/null @@ -1,16 +0,0 @@ -import python - -// this can be quick-eval to see which ones have splitting. But that's basically just -// anything from line 39 and further. -predicate exprWithSplitting(Expr e) { - exists(e.getLocation().getFile().getRelativePath()) and - 1 < count(ControlFlowNode cfn | cfn.getNode() = e) -} - -from File f, string msg -where - exists(f.getRelativePath()) and - if exists(Expr e | e.getLocation().getFile() = f and exprWithSplitting(e)) - then msg = "has splitting" - else msg = "does not have splitting" -select f.toString(), msg diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.expected deleted file mode 100644 index 7a80091654c..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.expected +++ /dev/null @@ -1,6 +0,0 @@ -| ../src/isfile_no_problem.py:42:7:42:16 | ControlFlowNode for give_src() | Unexpected result: unresolved_call=give_src() | -| ../src/isfile_no_problem.py:43:1:43:9 | ControlFlowNode for SINK() | Unexpected result: unresolved_call=SINK(..) | -| ../src/urandom_no_if_no_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -| ../src/urandom_problem.py:34:31:34:64 | Comment # $ unresolved_call=os.urandom(..) | Missing result:unresolved_call=os.urandom(..) | -| ../src/urandom_problem.py:42:18:42:47 | Comment # $ unresolved_call=give_src() | Missing result:unresolved_call=give_src() | -| ../src/urandom_problem.py:43:11:43:75 | Comment # $ unresolved_call=SINK(..) MISSING: flow="SOURCE, l:-15 -> foo" | Missing result:unresolved_call=SINK(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.ql deleted file mode 100644 index c31dc161620..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedCalls.ql +++ /dev/null @@ -1,2 +0,0 @@ -import python -import experimental.dataflow.TestUtil.UnresolvedCalls diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.expected b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.expected deleted file mode 100644 index c8ec76401e0..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.expected +++ /dev/null @@ -1,4 +0,0 @@ -| ../src/isfile_no_problem.py:34:8:34:31 | ../src/isfile_no_problem.py:34 | os.path.isfile(..) | -| ../src/isfile_no_problem.py:42:7:42:16 | ../src/isfile_no_problem.py:42 | give_src() | -| ../src/isfile_no_problem.py:43:1:43:9 | ../src/isfile_no_problem.py:43 | SINK(..) | -| ../src/urandom_no_import_no_problem.py:34:8:34:20 | ../src/urandom_no_import_no_problem.py:34 | os.urandom(..) | diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.ql b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.ql deleted file mode 100644 index 212b840decc..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/UnresolvedPointsToCalls.ql +++ /dev/null @@ -1,10 +0,0 @@ -import python -private import semmle.python.dataflow.new.internal.PrintNode - -from CallNode call -where - exists(call.getLocation().getFile().getRelativePath()) and - not exists(Value value | call = value.getACall()) and - // somehow print is not resolved, but that is not the focus right now - not call.getFunction().(NameNode).getId() = "print" -select call.getLocation(), prettyExpr(call.getNode()) diff --git a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/options b/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/options deleted file mode 100644 index d902599b806..00000000000 --- a/python/ql/test/experimental/dataflow/strange-pointsto-interaction-investigation/test-6-max-import-depth-2/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=2 -R ../src From 6f5007b810960b735796d6dc7cf002ca2fdbadc1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 31 May 2022 01:18:20 +0200 Subject: [PATCH 002/415] Python: Rename -> DataFlowDispatch So diff can make more sense when introducing blank state for type-tracking based call-graph --- .../{DataFlowDispatchPointsTo.qll => DataFlowDispatch.qll} | 0 .../lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename python/ql/lib/semmle/python/dataflow/new/internal/{DataFlowDispatchPointsTo.qll => DataFlowDispatch.qll} (100%) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll similarity index 100% rename from python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatchPointsTo.qll rename to python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 6f1396518aa..e120ddbedad 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -16,7 +16,7 @@ private import semmle.python.Frameworks // make it more digestible. import MatchUnpacking import IterableUnpacking -import DataFlowDispatchPointsTo +import DataFlowDispatch /** Gets the callable in which this node occurs. */ DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() } From 716576b1d6faf7d3febb57e8d87102af3e2eb73b Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 28 Oct 2022 14:03:22 +0200 Subject: [PATCH 003/415] Python: Minimal type-tracking call-graph That does absolutely nothing so far, but compiles --- .../new/internal/DataFlowDispatch.qll | 596 +++--------------- .../dataflow/new/internal/DataFlowPrivate.qll | 133 +--- .../dataflow/new/internal/DataFlowPublic.qll | 111 +--- .../new/internal/FlowSummaryImplSpecific.qll | 28 +- .../new/internal/TypeTrackerSpecific.qll | 42 +- 5 files changed, 158 insertions(+), 752 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 0efae6ae45c..90c8010739d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1,280 +1,39 @@ /** * INTERNAL: Do not use. * - * Points-to based call-graph. + * TypeTracker based call-graph. + * + * A goal of this library is to support modeling calls that happens by third-party + * libraries. For example `call_later(func, arg0, arg1, foo=val)`, and the fact that the + * library might inject it's own arguments, for example a context that will always be + * passed as the actual first argument to the function. Currently the aim is to provide + * enough predicates for such `call_later` function to be modeled by providing + * additional data-flow steps for the arguments/parameters. This means we cannot have + * any special logic that requires an AST call to be made before we care to figure out + * what callable this call might end up targeting. */ private import python private import DataFlowPublic -private import semmle.python.SpecialMethods private import FlowSummaryImpl as FlowSummaryImpl -/** A parameter position represented by an integer. */ -class ParameterPosition extends int { - ParameterPosition() { exists(any(DataFlowCallable c).getParameter(this)) } - - /** Holds if this position represents a positional parameter at position `pos`. */ - predicate isPositional(int pos) { this = pos } // with the current representation, all parameters are positional +/** A parameter position. */ +class ParameterPosition extends Unit { + // TODO(call-graph): implement this! } -/** An argument position represented by an integer. */ -class ArgumentPosition extends int { - ArgumentPosition() { this in [-2, -1] or exists(any(Call c).getArg(this)) } - - /** Holds if this position represents a positional argument at position `pos`. */ - predicate isPositional(int pos) { this = pos } // with the current representation, all arguments are positional +/** An argument position. */ +abstract class ArgumentPosition extends Unit { + // TODO(call-graph): implement this! } /** Holds if arguments at position `apos` match parameters at position `ppos`. */ pragma[inline] -predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos } - -/** - * Computes routing of arguments to parameters - * - * When a call contains more positional arguments than there are positional parameters, - * the extra positional arguments are passed as a tuple to a starred parameter. This is - * achieved by synthesizing a node `TPosOverflowNode(call, callable)` - * that represents the tuple of extra positional arguments. There is a store step from each - * extra positional argument to this node. - * - * CURRENTLY NOT SUPPORTED: - * When a call contains an iterable unpacking argument, such as `func(*args)`, it is expanded into positional arguments. - * - * CURRENTLY NOT SUPPORTED: - * If a call contains an iterable unpacking argument, such as `func(*args)`, and the callee contains a starred argument, any extra - * positional arguments are passed to the starred argument. - * - * When a call contains keyword arguments that do not correspond to keyword parameters, these - * extra keyword arguments are passed as a dictionary to a doubly starred parameter. This is - * achieved by synthesizing a node `TKwOverflowNode(call, callable)` - * that represents the dictionary of extra keyword arguments. There is a store step from each - * extra keyword argument to this node. - * - * When a call contains a dictionary unpacking argument, such as `func(**kwargs)`, with entries corresponding to a keyword parameter, - * the value at such a key is unpacked and passed to the parameter. This is achieved - * by synthesizing an argument node `TKwUnpacked(call, callable, name)` representing the unpacked - * value. This node is used as the argument passed to the matching keyword parameter. There is a read - * step from the dictionary argument to the synthesized argument node. - * - * When a call contains a dictionary unpacking argument, such as `func(**kwargs)`, and the callee contains a doubly starred parameter, - * entries which are not unpacked are passed to the doubly starred parameter. This is achieved by - * adding a dataflow step from the dictionary argument to `TKwOverflowNode(call, callable)` and a - * step to clear content of that node at any unpacked keys. - * - * ## Examples: - * Assume that we have the callable - * ```python - * def f(x, y, *t, **d): - * pass - * ``` - * Then the call - * ```python - * f(0, 1, 2, a=3) - * ``` - * will be modeled as - * ```python - * f(0, 1, [*t], [**d]) - * ``` - * where `[` and `]` denotes synthesized nodes, so `[*t]` is the synthesized tuple argument - * `TPosOverflowNode` and `[**d]` is the synthesized dictionary argument `TKwOverflowNode`. - * There will be a store step from `2` to `[*t]` at pos `0` and one from `3` to `[**d]` at key - * `a`. - * - * For the call - * ```python - * f(0, **{"y": 1, "a": 3}) - * ``` - * no tuple argument is synthesized. It is modeled as - * ```python - * f(0, [y=1], [**d]) - * ``` - * where `[y=1]` is the synthesized unpacked argument `TKwUnpacked` (with `name` = `y`). There is - * a read step from `**{"y": 1, "a": 3}` to `[y=1]` at key `y` to get the value passed to the parameter - * `y`. There is a dataflow step from `**{"y": 1, "a": 3}` to `[**d]` to transfer the content and - * a clearing of content at key `y` for node `[**d]`, since that value has been unpacked. - */ -module ArgumentPassing { - /** - * Holds if `call` represents a `DataFlowCall` to a `DataFlowCallable` represented by `callable`. - * - * It _may not_ be the case that `call = callable.getACall()`, i.e. if `call` represents a `ClassCall`. - * - * Used to limit the size of predicates. - */ - predicate connects(CallNode call, CallableValue callable) { - exists(NormalCall c | - call = c.getNode() and - callable = c.getCallable().getCallableValue() - ) - } - - /** - * Gets the `n`th parameter of `callable`. - * If the callable has a starred parameter, say `*tuple`, that is matched with `n=-1`. - * If the callable has a doubly starred parameter, say `**dict`, that is matched with `n=-2`. - * Note that, unlike other languages, we do _not_ use -1 for the position of `self` in Python, - * as it is an explicit parameter at position 0. - */ - NameNode getParameter(CallableValue callable, int n) { - // positional parameter - result = callable.getParameter(n) - or - // starred parameter, `*tuple` - exists(Function f | - f = callable.getScope() and - n = -1 and - result = f.getVararg().getAFlowNode() - ) - or - // doubly starred parameter, `**dict` - exists(Function f | - f = callable.getScope() and - n = -2 and - result = f.getKwarg().getAFlowNode() - ) - } - - /** - * A type representing a mapping from argument indices to parameter indices. - * We currently use two mappings: NoShift, the identity, used for ordinary - * function calls, and ShiftOneUp which is used for calls where an extra argument - * is inserted. These include method calls, constructor calls and class calls. - * In these calls, the argument at index `n` is mapped to the parameter at position `n+1`. - */ - newtype TArgParamMapping = - TNoShift() or - TShiftOneUp() - - /** A mapping used for parameter passing. */ - abstract class ArgParamMapping extends TArgParamMapping { - /** Gets the index of the parameter that corresponds to the argument at index `argN`. */ - bindingset[argN] - abstract int getParamN(int argN); - - /** Gets a textual representation of this element. */ - abstract string toString(); - } - - /** A mapping that passes argument `n` to parameter `n`. */ - class NoShift extends ArgParamMapping, TNoShift { - NoShift() { this = TNoShift() } - - override string toString() { result = "NoShift [n -> n]" } - - bindingset[argN] - override int getParamN(int argN) { result = argN } - } - - /** A mapping that passes argument `n` to parameter `n+1`. */ - class ShiftOneUp extends ArgParamMapping, TShiftOneUp { - ShiftOneUp() { this = TShiftOneUp() } - - override string toString() { result = "ShiftOneUp [n -> n+1]" } - - bindingset[argN] - override int getParamN(int argN) { result = argN + 1 } - } - - /** - * Gets the node representing the argument to `call` that is passed to the parameter at - * (zero-based) index `paramN` in `callable`. If this is a positional argument, it must appear - * at an index, `argN`, in `call` which satisfies `paramN = mapping.getParamN(argN)`. - * - * `mapping` will be the identity for function calls, but not for method- or constructor calls, - * where the first parameter is `self` and the first positional argument is passed to the second positional parameter. - * Similarly for classmethod calls, where the first parameter is `cls`. - * - * NOT SUPPORTED: Keyword-only parameters. - */ - Node getArg(CallNode call, ArgParamMapping mapping, CallableValue callable, int paramN) { - connects(call, callable) and - ( - // positional argument - exists(int argN | - paramN = mapping.getParamN(argN) and - result = TCfgNode(call.getArg(argN)) - ) - or - // keyword argument - // TODO: Since `getArgName` have no results for keyword-only parameters, - // these are currently not supported. - exists(Function f, string argName | - f = callable.getScope() and - f.getArgName(paramN) = argName and - result = TCfgNode(call.getArgByName(unbind_string(argName))) - ) - or - // a synthesized argument passed to the starred parameter (at position -1) - callable.getScope().hasVarArg() and - paramN = -1 and - result = TPosOverflowNode(call, callable) - or - // a synthesized argument passed to the doubly starred parameter (at position -2) - callable.getScope().hasKwArg() and - paramN = -2 and - result = TKwOverflowNode(call, callable) - or - // argument unpacked from dict - exists(string name | - call_unpacks(call, mapping, callable, name, paramN) and - result = TKwUnpackedNode(call, callable, name) - ) - ) - } - - /** Currently required in `getArg` in order to prevent a bad join. */ - bindingset[result, s] - private string unbind_string(string s) { result <= s and s <= result } - - /** Gets the control flow node that is passed as the `n`th overflow positional argument. */ - ControlFlowNode getPositionalOverflowArg(CallNode call, CallableValue callable, int n) { - connects(call, callable) and - exists(Function f, int posCount, int argNr | - f = callable.getScope() and - f.hasVarArg() and - posCount = f.getPositionalParameterCount() and - result = call.getArg(argNr) and - argNr >= posCount and - argNr = posCount + n - ) - } - - /** Gets the control flow node that is passed as the overflow keyword argument with key `key`. */ - ControlFlowNode getKeywordOverflowArg(CallNode call, CallableValue callable, string key) { - connects(call, callable) and - exists(Function f | - f = callable.getScope() and - f.hasKwArg() and - not exists(f.getArgByName(key)) and - result = call.getArgByName(key) - ) - } - - /** - * Holds if `call` unpacks a dictionary argument in order to pass it via `name`. - * It will then be passed to the parameter of `callable` at index `paramN`. - */ - predicate call_unpacks( - CallNode call, ArgParamMapping mapping, CallableValue callable, string name, int paramN - ) { - connects(call, callable) and - exists(Function f | - f = callable.getScope() and - not exists(int argN | paramN = mapping.getParamN(argN) | exists(call.getArg(argN))) and // no positional argument available - name = f.getArgName(paramN) and - // not exists(call.getArgByName(name)) and // only matches keyword arguments not preceded by ** - // TODO: make the below logic respect control flow splitting (by not going to the AST). - not call.getNode().getANamedArg().(Keyword).getArg() = name and // no keyword argument available - paramN >= 0 and - paramN < f.getPositionalParameterCount() + f.getKeywordOnlyParameterCount() and - exists(call.getNode().getKwargs()) // dict argument available - ) - } +predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { + // TODO(call-graph): implement this! + none() } -import ArgumentPassing - /** A callable defined in library code, identified by a unique string. */ abstract class LibraryCallable extends string { bindingset[this] @@ -287,92 +46,34 @@ abstract class LibraryCallable extends string { abstract ArgumentNode getACallback(); } -/** - * IPA type for DataFlowCallable. - * - * A callable is either a function value, a class value, or a module (for enclosing `ModuleVariableNode`s). - * A module has no calls. - */ newtype TDataFlowCallable = - TCallableValue(CallableValue callable) { - callable instanceof FunctionValue and - not callable.(FunctionValue).isLambda() - or - callable instanceof ClassValue - } or - TLambda(Function lambda) { lambda.isLambda() } or + // TODO(call-graph): implement this! + /** For enclosing `ModuleVariableNode`s -- don't actually have calls. */ TModule(Module m) or TLibraryCallable(LibraryCallable callable) /** A callable. */ -class DataFlowCallable extends TDataFlowCallable { +abstract class DataFlowCallable extends TDataFlowCallable { /** Gets a textual representation of this element. */ - string toString() { result = "DataFlowCallable" } - - /** Gets a call to this callable. */ - CallNode getACall() { none() } + abstract string toString(); /** Gets the scope of this callable */ - Scope getScope() { none() } + abstract Scope getScope(); - /** Gets the specified parameter of this callable */ - NameNode getParameter(int n) { none() } - - /** Gets the name of this callable. */ - string getName() { none() } - - /** Gets a callable value for this callable, if any. */ - CallableValue getCallableValue() { none() } + /** Gets the parameter at position `ppos`, if any. */ + abstract ParameterNode getParameter(ParameterPosition ppos); /** Gets the underlying library callable, if any. */ LibraryCallable asLibraryCallable() { this = TLibraryCallable(result) } - Location getLocation() { none() } + /** Gets the location of this dataflow callable. */ + abstract Location getLocation(); } -/** A class representing a callable value. */ -class DataFlowCallableValue extends DataFlowCallable, TCallableValue { - CallableValue callable; - - DataFlowCallableValue() { this = TCallableValue(callable) } - - override string toString() { result = callable.toString() } - - override CallNode getACall() { result = callable.getACall() } - - override Scope getScope() { result = callable.getScope() } - - override NameNode getParameter(int n) { result = getParameter(callable, n) } - - override string getName() { result = callable.getName() } - - override CallableValue getCallableValue() { result = callable } -} - -/** A class representing a callable lambda. */ -class DataFlowLambda extends DataFlowCallable, TLambda { - Function lambda; - - DataFlowLambda() { this = TLambda(lambda) } - - override string toString() { result = lambda.toString() } - - override CallNode getACall() { result = this.getCallableValue().getACall() } - - override Scope getScope() { result = lambda.getEvaluatingScope() } - - override NameNode getParameter(int n) { result = getParameter(this.getCallableValue(), n) } - - override string getName() { result = "Lambda callable" } - - override FunctionValue getCallableValue() { - result.getOrigin().getNode() = lambda.getDefinition() - } - - Expr getDefinition() { result = lambda.getDefinition() } -} - -/** A class representing the scope in which a `ModuleVariableNode` appears. */ +/** + * A module. This is not actually a callable, but we need this so a + * `ModuleVariableNode` have an enclosing callable. + */ class DataFlowModuleScope extends DataFlowCallable, TModule { Module mod; @@ -380,15 +81,11 @@ class DataFlowModuleScope extends DataFlowCallable, TModule { override string toString() { result = mod.toString() } - override CallNode getACall() { none() } + override Module getScope() { result = mod } - override Scope getScope() { result = mod } + override Location getLocation() { result = mod.getLocation() } - override NameNode getParameter(int n) { none() } - - override string getName() { result = mod.getName() } - - override CallableValue getCallableValue() { none() } + override ParameterNode getParameter(ParameterPosition ppos) { none() } } class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { @@ -398,66 +95,36 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { override string toString() { result = callable.toString() } - override CallNode getACall() { result = callable.getACall().getNode() } - /** Gets a data-flow node, where this library callable is used as a call-back. */ ArgumentNode getACallback() { result = callable.getACallback() } override Scope getScope() { none() } - override NameNode getParameter(int n) { none() } - - override string getName() { result = callable } + override ParameterNode getParameter(ParameterPosition ppos) { none() } override LibraryCallable asLibraryCallable() { result = callable } + + override Location getLocation() { none() } } -/** - * IPA type for DataFlowCall. - * - * Calls corresponding to `CallNode`s are either to callable values or to classes. - * The latter is directed to the callable corresponding to the `__init__` method of the class. - * - * An `__init__` method can also be called directly, so that the callable can be targeted by - * different types of calls. In that case, the parameter mappings will be different, - * as the class call will synthesize an argument node to be mapped to the `self` parameter. - * - * A call corresponding to a special method call is handled by the corresponding `SpecialMethodCallNode`. - * - * TODO: Add `TClassMethodCall` mapping `cls` appropriately. - */ newtype TDataFlowCall = - /** - * Includes function calls, method calls, class calls and library calls. - * All these will be associated with a `CallNode`. - */ - TNormalCall(CallNode call) or - /** - * Includes calls to special methods. - * These will be associated with a `SpecialMethodCallNode`. - */ - TSpecialCall(SpecialMethodCallNode special) or + // TODO(call-graph): implement this! + MkDataFlowCall() or /** A synthesized call inside a summarized callable */ TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) { FlowSummaryImpl::Private::summaryCallbackRange(c, receiver) } -/** A call found in the program source (as opposed to a synthesised summary call). */ -class TExtractedDataFlowCall = TSpecialCall or TNormalCall; - /** A call that is taken into account by the global data flow computation. */ abstract class DataFlowCall extends TDataFlowCall { /** Gets a textual representation of this element. */ abstract string toString(); - /** Get the callable to which this call goes, if such exists. */ + /** Get the callable to which this call goes. */ abstract DataFlowCallable getCallable(); - /** - * Gets the argument to this call that will be sent - * to the `n`th parameter of the callable, if any. - */ - abstract Node getArg(int n); + /** Gets the argument at position `apos`, if any. */ + abstract ArgumentNode getArgument(ArgumentPosition apos); /** Get the control flow node representing this call, if any. */ abstract ControlFlowNode getNode(); @@ -483,130 +150,10 @@ abstract class DataFlowCall extends TDataFlowCall { } /** A call found in the program source (as opposed to a synthesised call). */ -abstract class ExtractedDataFlowCall extends DataFlowCall, TExtractedDataFlowCall { - final override Location getLocation() { result = this.getNode().getLocation() } +abstract class ExtractedDataFlowCall extends DataFlowCall { + ExtractedDataFlowCall() { exists(this.getNode()) } - abstract override DataFlowCallable getCallable(); - - abstract override Node getArg(int n); - - abstract override ControlFlowNode getNode(); -} - -/** A call associated with a `CallNode`. */ -class NormalCall extends ExtractedDataFlowCall, TNormalCall { - CallNode call; - - NormalCall() { this = TNormalCall(call) } - - override string toString() { result = call.toString() } - - abstract override Node getArg(int n); - - override CallNode getNode() { result = call } - - abstract override DataFlowCallable getCallable(); - - override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() } -} - -/** - * A call to a function. - * This excludes calls to bound methods, classes, and special methods. - * Bound method calls and class calls insert an argument for the explicit - * `self` parameter, and special method calls have special argument passing. - */ -class FunctionCall extends NormalCall { - DataFlowCallableValue callable; - - FunctionCall() { - call = any(FunctionValue f).getAFunctionCall() and - call = callable.getACall() - } - - override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) } - - override DataFlowCallable getCallable() { result = callable } -} - -/** A call to a lambda. */ -class LambdaCall extends NormalCall { - DataFlowLambda callable; - - LambdaCall() { - call = callable.getACall() and - callable = TLambda(any(Function f)) - } - - override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) } - - override DataFlowCallable getCallable() { result = callable } -} - -/** - * Represents a call to a bound method call. - * The node representing the instance is inserted as argument to the `self` parameter. - */ -class MethodCall extends NormalCall { - FunctionValue bm; - - MethodCall() { call = bm.getAMethodCall() } - - private CallableValue getCallableValue() { result = bm } - - override Node getArg(int n) { - n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n) - or - n = 0 and result = TCfgNode(call.getFunction().(AttrNode).getObject()) - } - - override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) } -} - -/** - * Represents a call to a class. - * The pre-update node for the call is inserted as argument to the `self` parameter. - * That makes the call node be the post-update node holding the value of the object - * after the constructor has run. - */ -class ClassCall extends NormalCall { - ClassValue c; - - ClassCall() { - not c.isAbsent() and - call = c.getACall() - } - - private CallableValue getCallableValue() { c.getScope().getInitMethod() = result.getScope() } - - override Node getArg(int n) { - n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n) - or - n = 0 and result = TSyntheticPreUpdateNode(TCfgNode(call)) - } - - override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) } -} - -/** A call to a special method. */ -class SpecialCall extends ExtractedDataFlowCall, TSpecialCall { - SpecialMethodCallNode special; - - SpecialCall() { this = TSpecialCall(special) } - - override string toString() { result = special.toString() } - - override Node getArg(int n) { result = TCfgNode(special.(SpecialMethod::Potential).getArg(n)) } - - override ControlFlowNode getNode() { result = special } - - override DataFlowCallable getCallable() { - result = TCallableValue(special.getResolvedSpecialMethod()) - } - - override DataFlowCallable getEnclosingCallable() { - result.getScope() = special.getNode().getScope() - } + override Location getLocation() { result = this.getNode().getLocation() } } /** @@ -617,27 +164,42 @@ class SpecialCall extends ExtractedDataFlowCall, TSpecialCall { * We hope to lift this restriction in the future and include all potential calls to summaries * in this class. */ -class LibraryCall extends NormalCall { +class LibraryCall extends DataFlowCall { LibraryCall() { - // TODO: share this with `resolvedCall` - not ( - call = any(DataFlowCallableValue cv).getACall() - or - call = any(DataFlowLambda l).getACall() - or - // TODO: this should be covered by `DataFlowCallableValue`, but a `ClassValue` is not a `CallableValue`. - call = any(ClassValue c).getACall() - ) + // TODO(call-graph): implement this! + none() } - // TODO: Implement Python calling convention? - override Node getArg(int n) { result = TCfgNode(call.getArg(n)) } + override string toString() { + // TODO(call-graph): implement this! + none() + } // We cannot refer to a `LibraryCallable` here, // as that could in turn refer to type tracking. // This call will be tied to a `LibraryCallable` via // `getViableCallabe` when the global data flow is assembled. override DataFlowCallable getCallable() { none() } + + override ArgumentNode getArgument(ArgumentPosition apos) { + // TODO(call-graph): implement this! + none() + } + + override ControlFlowNode getNode() { + // TODO(call-graph): implement this! + none() + } + + override DataFlowCallable getEnclosingCallable() { + // TODO(call-graph): implement this! + none() + } + + override Location getLocation() { + // TODO(call-graph): implement this! + none() + } } /** @@ -663,7 +225,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall { override DataFlowCallable getCallable() { none() } - override Node getArg(int n) { none() } + override ArgumentNode getArgument(ArgumentPosition apos) { none() } override ControlFlowNode getNode() { none() } @@ -681,22 +243,22 @@ abstract class ParameterNodeImpl extends Node { /** * Holds if this node is the parameter of callable `c` at the - * (zero-based) index `i`. + * position `ppos`. */ - abstract predicate isParameterOf(DataFlowCallable c, int i); + abstract predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos); } /** A parameter for a library callable with a flow summary. */ class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode { private FlowSummaryImpl::Public::SummarizedCallable sc; - private int pos; + private ParameterPosition pos; SummaryParameterNode() { this = TSummaryParameterNode(sc, pos) } override Parameter getParameter() { none() } - override predicate isParameterOf(DataFlowCallable c, int i) { - sc = c.asLibraryCallable() and i = pos + override predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos) { + sc = c.asLibraryCallable() and ppos = pos } override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = sc } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index e120ddbedad..33a5558d232 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -78,7 +78,11 @@ module SyntheticPreUpdateNode { * that is mapped to the `self` parameter. That way, constructor calls represent the value of the * object after the constructor (currently only `__init__`) has run. */ - CfgNode objectCreationNode() { result.getNode() = any(ClassCall c).getNode() } + CfgNode objectCreationNode() { + // TODO(call-graph): implement this! + none() + // result.getNode().(CallNode) = any(ClassCall c).getNode() + } } import SyntheticPreUpdateNode @@ -88,8 +92,6 @@ deprecated module syntheticPostUpdateNode = SyntheticPostUpdateNode; /** A module collecting the different reasons for synthesising a post-update node. */ module SyntheticPostUpdateNode { - private import semmle.python.SpecialMethods - /** A post-update node is synthesized for all nodes which satisfy `NeedsSyntheticPostUpdateNode`. */ class SyntheticPostUpdateNode extends PostUpdateNode, TSyntheticPostUpdateNode { NeedsSyntheticPostUpdateNode pre; @@ -137,29 +139,22 @@ module SyntheticPostUpdateNode { * and should not have an extra node synthesised. */ Node argumentPreUpdateNode() { - result = any(FunctionCall c).getArg(_) - or - result = any(LambdaCall c).getArg(_) - or - // Avoid argument 0 of method calls as those have read post-update nodes. - exists(MethodCall c, int n | n > 0 | result = c.getArg(n)) - or - result = any(SpecialCall c).getArg(_) - or - // Avoid argument 0 of class calls as those have non-synthetic post-update nodes. - exists(ClassCall c, int n | n > 0 | result = c.getArg(n)) - or - // any argument of any call that we have not been able to resolve - exists(CallNode call | not resolvedCall(call) | - result.(CfgNode).getNode() in [call.getArg(_), call.getArgByName(_)] - ) - } - - /** Holds if `call` can be resolved as a normal call */ - private predicate resolvedCall(CallNode call) { - call = any(DataFlowCallableValue cv).getACall() - or - call = any(DataFlowLambda l).getACall() + // TODO(call-graph): implement this! + none() + // result = any(FunctionCall c).getArg(_) + // or + // // Avoid argument 0 of method calls as those have read post-update nodes. + // exists(MethodCall c, int n | n > 0 | result = c.getArg(n)) + // or + // result = any(SpecialCall c).getArg(_) + // or + // // Avoid argument 0 of class calls as those have non-synthetic post-update nodes. + // exists(ClassCall c, int n | n > 0 | result = c.getArg(n)) + // or + // // any argument of any call that we have not been able to resolve + // exists(CallNode call | not call = any(DataFlowCall c).getNode() | + // result.(CfgNode).getNode() in [call.getArg(_), call.getArgByName(_)] + // ) } /** Gets the pre-update node associated with a store. This is used for when an object might have its value changed after a store. */ @@ -274,13 +269,6 @@ module EssaFlow { iterableUnpackingFlowStep(nodeFrom, nodeTo) or matchFlowStep(nodeFrom, nodeTo) - or - // Overflow keyword argument - exists(CallNode call, CallableValue callable | - call = callable.getACall() and - nodeTo = TKwOverflowNode(call, callable) and - nodeFrom.asCfgNode() = call.getNode().getKwargs().getAFlowNode() - ) } predicate useToNextUse(NameNode nodeFrom, NameNode nodeTo) { @@ -521,10 +509,6 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) { or attributeStoreStep(nodeFrom, c, nodeTo) or - posOverflowStoreStep(nodeFrom, c, nodeTo) - or - kwOverflowStoreStep(nodeFrom, c, nodeTo) - or matchStoreStep(nodeFrom, c, nodeTo) or any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo) @@ -669,30 +653,6 @@ predicate attributeStoreStep(Node nodeFrom, AttributeContent c, PostUpdateNode n ) } -/** - * Holds if `nodeFrom` flows into the synthesized positional overflow argument (`nodeTo`) - * at the position indicated by `c`. - */ -predicate posOverflowStoreStep(CfgNode nodeFrom, TupleElementContent c, Node nodeTo) { - exists(CallNode call, CallableValue callable, int n | - nodeFrom.asCfgNode() = getPositionalOverflowArg(call, callable, n) and - nodeTo = TPosOverflowNode(call, callable) and - c.getIndex() = n - ) -} - -/** - * Holds if `nodeFrom` flows into the synthesized keyword overflow argument (`nodeTo`) - * at the key indicated by `c`. - */ -predicate kwOverflowStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeTo) { - exists(CallNode call, CallableValue callable, string key | - nodeFrom.asCfgNode() = getKeywordOverflowArg(call, callable, key) and - nodeTo = TKwOverflowNode(call, callable) and - c.getKey() = key - ) -} - predicate defaultValueFlowStep(CfgNode nodeFrom, CfgNode nodeTo) { exists(Function f, Parameter p, ParameterDefinition def | // `getArgByName` supports, unlike `getAnArg`, keyword-only parameters @@ -722,8 +682,6 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) { or attributeReadStep(nodeFrom, c, nodeTo) or - kwUnpackReadStep(nodeFrom, c, nodeTo) - or FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom, c, nodeTo) } @@ -814,38 +772,12 @@ predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo) nodeTo.accesses(nodeFrom, c.getAttribute()) } -/** - * Holds if `nodeFrom` is a dictionary argument being unpacked and `nodeTo` is the - * synthesized unpacked argument with the name indicated by `c`. - */ -predicate kwUnpackReadStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeTo) { - exists(CallNode call, CallableValue callable, string name | - nodeFrom.asCfgNode() = call.getNode().getKwargs().getAFlowNode() and - nodeTo = TKwUnpackedNode(call, callable, name) and - name = c.getKey() - ) -} - -/** - * Clear content at key `name` of the synthesized dictionary `TKwOverflowNode(call, callable)`, - * whenever `call` unpacks `name`. - */ -predicate kwOverflowClearStep(Node n, Content c) { - exists(CallNode call, CallableValue callable, string name | - call_unpacks(call, _, callable, name, _) and - n = TKwOverflowNode(call, callable) and - c.(DictionaryElementContent).getKey() = name - ) -} - /** * Holds if values stored inside content `c` are cleared at node `n`. For example, * any value stored inside `f` is cleared at the pre-update node associated with `x` * in `x.f = newValue`. */ predicate clearsContent(Node n, Content c) { - kwOverflowClearStep(n, c) - or matchClearStep(n, c) or attributeClearStep(n, c) @@ -912,17 +844,20 @@ class LambdaCallKind = Unit; /** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { - // lambda - kind = kind and - creation.asExpr() = c.(DataFlowLambda).getDefinition() - or - // normal function - exists(FunctionDef def | - def.defines(creation.asVar().getSourceVariable()) and - def.getDefinedFunction() = c.(DataFlowCallableValue).getCallableValue().getScope() - ) - or + // TODO(call-graph): implement this! + // + // // lambda + // kind = kind and + // creation.asExpr() = c.(DataFlowLambda).getDefinition() + // or + // // normal function + // exists(FunctionDef def | + // def.defines(creation.asVar().getSourceVariable()) and + // def.getDefinedFunction() = c.(DataFlowCallableValue).getCallableValue().getScope() + // ) + // or // summarized function + exists(kind) and // avoid warning on unused 'kind' exists(Call call | creation.asExpr() = call.getAnArg() and creation = c.(LibraryCallableValue).getACallback() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 4a00d0aafc3..5eaff0815af 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -45,37 +45,6 @@ newtype TNode = ImportStar::globalNameDefinedInModule(v.getId(), m) ) } or - /** - * A node representing the overflow positional arguments to a call. - * That is, `call` contains more positional arguments than there are - * positional parameters in `callable`. The extra ones are passed as - * a tuple to a starred parameter; this synthetic node represents that tuple. - */ - TPosOverflowNode(CallNode call, CallableValue callable) { - exists(getPositionalOverflowArg(call, callable, _)) - } or - /** - * A node representing the overflow keyword arguments to a call. - * That is, `call` contains keyword arguments for keys that do not have - * keyword parameters in `callable`. These extra ones are passed as - * a dictionary to a doubly starred parameter; this synthetic node - * represents that dictionary. - */ - TKwOverflowNode(CallNode call, CallableValue callable) { - exists(getKeywordOverflowArg(call, callable, _)) - or - ArgumentPassing::connects(call, callable) and - exists(call.getNode().getKwargs()) and - callable.getScope().hasKwArg() - } or - /** - * A node representing an unpacked element of a dictionary argument. - * That is, `call` contains argument `**{"foo": bar}` which is passed - * to parameter `foo` of `callable`. - */ - TKwUnpackedNode(CallNode call, CallableValue callable, string name) { - call_unpacks(call, _, callable, name, _) - } or /** * A synthetic node representing that an iterable sequence flows to consumer. */ @@ -298,14 +267,12 @@ class ExtractedParameterNode extends ParameterNodeImpl, CfgNode { //, LocalSourceNode { ParameterDefinition def; - ExtractedParameterNode() { - node = def.getDefiningNode() and - // Disregard parameters that we cannot resolve - // TODO: Make this unnecessary - exists(DataFlowCallable c | node = c.getParameter(_)) - } + ExtractedParameterNode() { node = def.getDefiningNode() } - override predicate isParameterOf(DataFlowCallable c, int i) { node = c.getParameter(i) } + override predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos) { + // TODO(call-graph): implement this! + none() + } override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) } @@ -329,14 +296,14 @@ abstract class ArgumentNode extends Node { /** A data flow node that represents a call argument found in the source code. */ class ExtractedArgumentNode extends ArgumentNode { - ExtractedArgumentNode() { this = any(ExtractedDataFlowCall c).getArg(_) } + ExtractedArgumentNode() { this = any(ExtractedDataFlowCall c).getArgument(_) } final override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { this.extractedArgumentOf(call, pos) } predicate extractedArgumentOf(ExtractedDataFlowCall call, ArgumentPosition pos) { - this = call.getArg(pos) + this = call.getArgument(pos) } } @@ -448,70 +415,6 @@ private predicate resolved_import_star_module(Module m, string name, Node n) { ) } -/** - * The node holding the extra positional arguments to a call. This node is passed as a tuple - * to the starred parameter of the callable. - */ -class PosOverflowNode extends Node, TPosOverflowNode { - CallNode call; - - PosOverflowNode() { this = TPosOverflowNode(call, _) } - - override string toString() { result = "PosOverflowNode for " + call.getNode().toString() } - - override DataFlowCallable getEnclosingCallable() { - exists(Node node | - node = TCfgNode(call) and - result = node.getEnclosingCallable() - ) - } - - override Location getLocation() { result = call.getLocation() } -} - -/** - * The node holding the extra keyword arguments to a call. This node is passed as a dictionary - * to the doubly starred parameter of the callable. - */ -class KwOverflowNode extends Node, TKwOverflowNode { - CallNode call; - - KwOverflowNode() { this = TKwOverflowNode(call, _) } - - override string toString() { result = "KwOverflowNode for " + call.getNode().toString() } - - override DataFlowCallable getEnclosingCallable() { - exists(Node node | - node = TCfgNode(call) and - result = node.getEnclosingCallable() - ) - } - - override Location getLocation() { result = call.getLocation() } -} - -/** - * The node representing the synthetic argument of a call that is unpacked from a dictionary - * argument. - */ -class KwUnpackedNode extends Node, TKwUnpackedNode { - CallNode call; - string name; - - KwUnpackedNode() { this = TKwUnpackedNode(call, _, name) } - - override string toString() { result = "KwUnpacked " + name } - - override DataFlowCallable getEnclosingCallable() { - exists(Node node | - node = TCfgNode(call) and - result = node.getEnclosingCallable() - ) - } - - override Location getLocation() { result = call.getLocation() } -} - /** * A synthetic node representing an iterable sequence. Used for changing content type * for instance from a `ListElement` to a `TupleElement`, especially if the content is 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 056ed02a874..5d950247369 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll @@ -61,11 +61,11 @@ bindingset[c, rk] DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { any() } /** - * Gets the type of the `i`th parameter in a synthesized call that targets a - * callback of type `t`. + * Gets the type of the parameter matching arguments at position `pos` in a + * synthesized call that targets a callback of type `t`. */ -bindingset[t, i] -DataFlowType getCallbackParameterType(DataFlowType t, int i) { any() } +bindingset[t, pos] +DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) { any() } /** * Gets the return type of kind `rk` in a synthesized call that targets a @@ -213,16 +213,20 @@ module ParsePositions { /** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */ ArgumentPosition parseParamBody(string s) { - exists(int i | - ParsePositions::isParsedParameterPosition(s, i) and - result.isPositional(i) - ) + none() + // TODO(call-graph): implement this! + // exists(int i | + // ParsePositions::isParsedParameterPosition(s, i) and + // result.isPositional(i) + // ) } /** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */ ParameterPosition parseArgBody(string s) { - exists(int i | - ParsePositions::isParsedArgumentPosition(s, i) and - result.isPositional(i) - ) + none() + // TODO(call-graph): implement this! + // exists(int i | + // ParsePositions::isParsedArgumentPosition(s, i) and + // result.isPositional(i) + // ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index 690216089e9..e9c97d86e8c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -60,21 +60,21 @@ string getPossibleContentName() { result = any(DataFlowPublic::AttrRef a).getAttributeName() } -/** - * Gets a callable for the call where `nodeFrom` is used as the `i`'th argument. - * - * Helper predicate to avoid bad join order experienced in `callStep`. - * This happened when `isParameterOf` was joined _before_ `getCallable`. - */ -pragma[nomagic] -private DataFlowPrivate::DataFlowCallable getCallableForArgument( - DataFlowPublic::ExtractedArgumentNode nodeFrom, int i -) { - exists(DataFlowPrivate::ExtractedDataFlowCall call | - nodeFrom.extractedArgumentOf(call, i) and - result = call.getCallable() - ) -} +// /** +// * Gets a callable for the call where `nodeFrom` is used as the `i`'th argument. +// * +// * Helper predicate to avoid bad join order experienced in `callStep`. +// * This happened when `isParameterOf` was joined _before_ `getCallable`. +// */ +// pragma[nomagic] +// private DataFlowPrivate::DataFlowCallable getCallableForArgument( +// DataFlowPublic::ExtractedArgumentNode nodeFrom, int i +// ) { +// exists(DataFlowPrivate::ExtractedDataFlowCall call | +// nodeFrom.extractedArgumentOf(call, i) and +// result = call.getCallable() +// ) +// } /** * Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. @@ -84,11 +84,13 @@ private DataFlowPrivate::DataFlowCallable getCallableForArgument( * methods is done using API graphs (which uses type tracking). */ predicate callStep(DataFlowPublic::ArgumentNode nodeFrom, DataFlowPrivate::ParameterNodeImpl nodeTo) { - // TODO: Support special methods? - exists(DataFlowPrivate::DataFlowCallable callable, int i | - callable = getCallableForArgument(nodeFrom, i) and - nodeTo.isParameterOf(callable, i) - ) + // TODO(call-graph): implement this! + none() + // // TODO: Support special methods? + // exists(DataFlowPrivate::DataFlowCallable callable, int i | + // callable = getCallableForArgument(nodeFrom, i) and + // nodeTo.isParameterOf(callable, i) + // ) } /** Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */ From a98554b6edf531cb538e5b6a54d041c2344436b8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 31 Oct 2022 14:14:05 +0100 Subject: [PATCH 004/415] Python: Accept tmp changes to flow summaries After solving merge conflict --- .../NormalTaintTrackingTest.expected | 12 ++++ .../dataflow/summaries/summaries.expected | 69 ++++--------------- 2 files changed, 26 insertions(+), 55 deletions(-) diff --git a/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected index 3875da4e143..8e04ba142cb 100644 --- a/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected +++ b/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected @@ -1,2 +1,14 @@ missingAnnotationOnSink +| summaries.py:33:6:33:12 | summaries.py:33 | ERROR, you should add `# $ MISSING: flow` annotation | tainted | +| summaries.py:37:6:37:19 | summaries.py:37 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_lambda | +| summaries.py:52:6:52:22 | summaries.py:52 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_mapped[0] | +| summaries.py:58:6:58:31 | summaries.py:58 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_mapped_explicit[0] | +| summaries.py:61:6:61:30 | summaries.py:61 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_mapped_summary[0] | +| summaries.py:64:6:64:20 | summaries.py:64 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_list[0] | failures +| summaries.py:33:16:33:49 | Comment # $ flow="SOURCE, l:-1 -> tainted" | Missing result:flow="SOURCE, l:-1 -> tainted" | +| summaries.py:37:23:37:63 | Comment # $ flow="SOURCE, l:-1 -> tainted_lambda" | Missing result:flow="SOURCE, l:-1 -> tainted_lambda" | +| summaries.py:52:26:52:69 | Comment # $ flow="SOURCE, l:-1 -> tainted_mapped[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_mapped[0]" | +| summaries.py:58:35:58:87 | Comment # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" | +| summaries.py:61:34:61:85 | Comment # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" | +| summaries.py:64:24:64:65 | Comment # $ flow="SOURCE, l:-1 -> tainted_list[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_list[0]" | diff --git a/python/ql/test/experimental/dataflow/summaries/summaries.expected b/python/ql/test/experimental/dataflow/summaries/summaries.expected index 2d1190eb69c..8f5366ed6c2 100644 --- a/python/ql/test/experimental/dataflow/summaries/summaries.expected +++ b/python/ql/test/experimental/dataflow/summaries/summaries.expected @@ -1,70 +1,29 @@ edges -| summaries.py:32:11:32:26 | ControlFlowNode for identity() | summaries.py:33:6:33:12 | ControlFlowNode for tainted | -| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:32:11:32:26 | ControlFlowNode for identity() | -| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | -| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | | summaries.py:44:25:44:32 | ControlFlowNode for List | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:44:25:44:32 | ControlFlowNode for List | -| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | -| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | -| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | -| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | summaries.py:52:6:52:22 | ControlFlowNode for Subscript | -| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | -| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | -| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | -| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | summaries.py:58:6:58:31 | ControlFlowNode for Subscript | -| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | -| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | -| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | -| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | summaries.py:61:6:61:30 | ControlFlowNode for Subscript | -| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | -| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | -| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | summaries.py:64:6:64:20 | ControlFlowNode for Subscript | -| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | -| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | -| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | nodes -| summaries.py:32:11:32:26 | ControlFlowNode for identity() | semmle.label | ControlFlowNode for identity() | -| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:33:6:33:12 | ControlFlowNode for tainted | semmle.label | ControlFlowNode for tainted | -| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | semmle.label | ControlFlowNode for apply_lambda() | -| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | semmle.label | ControlFlowNode for tainted_lambda | | summaries.py:44:25:44:32 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | -| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | semmle.label | ControlFlowNode for tainted_mapped [List element] | -| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | -| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | semmle.label | ControlFlowNode for tainted_mapped_explicit [List element] | -| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | -| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | -| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | semmle.label | ControlFlowNode for tainted_mapped_summary [List element] | -| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | semmle.label | ControlFlowNode for append_to_list() [List element] | -| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | -| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | semmle.label | ControlFlowNode for json_loads() [List element] | | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | semmle.label | ControlFlowNode for tainted_resultlist [List element] | | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | subpaths invalidSpecComponent +| append_to_list | Argument[0] | Argument[0] | +| append_to_list | Argument[1] | Argument[1] | +| apply_lambda | Argument[0].Parameter[0] | Argument[0] | +| apply_lambda | Argument[0].Parameter[0] | Parameter[0] | +| apply_lambda | Argument[0].ReturnValue | Argument[0] | +| apply_lambda | Argument[1] | Argument[1] | +| builtins.reversed | Argument[0].ListElement | Argument[0] | +| identity | Argument[0] | Argument[0] | +| json.loads | Argument[0] | Argument[0] | +| list_map | Argument[0].Parameter[0] | Argument[0] | +| list_map | Argument[0].Parameter[0] | Parameter[0] | +| list_map | Argument[0].ReturnValue | Argument[0] | +| list_map | Argument[1].ListElement | Argument[1] | +| reversed | Argument[0].ListElement | Argument[0] | #select -| summaries.py:33:6:33:12 | ControlFlowNode for tainted | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:33:6:33:12 | ControlFlowNode for tainted | $@ | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | $@ | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | $@ | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:52:6:52:22 | ControlFlowNode for Subscript | $@ | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:58:6:58:31 | ControlFlowNode for Subscript | $@ | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:61:6:61:30 | ControlFlowNode for Subscript | $@ | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | -| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:64:6:64:20 | ControlFlowNode for Subscript | $@ | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | $@ | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | From c85ccb20038f38022f9b56271e9e97219370b7ea Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 30 May 2022 15:49:29 +0200 Subject: [PATCH 005/415] Python: Add call-graph compare meta-queries Also changed the definition of a relevant call-target, so it's only what is in the actual source code, which is what we want in the future! (so what we're designing type-tracking to handle) I also changed terminology from `callee` to `target`. It felt more natural this way in my opinion. --- .../analysis-quality/CallGraphQuality.qll | 131 ++++++++++++++---- .../PointsToResolvableCallsRelevantTarget.ql | 2 +- .../src/meta/analysis-quality/TTCallGraph.ql | 17 +++ .../analysis-quality/TTCallGraphMissing.ql | 18 +++ .../meta/analysis-quality/TTCallGraphNew.ql | 18 +++ .../analysis-quality/TTCallGraphOverview.ql | 35 +++++ .../analysis-quality/TTCallGraphShared.ql | 18 +++ 7 files changed, 211 insertions(+), 28 deletions(-) create mode 100644 python/ql/src/meta/analysis-quality/TTCallGraph.ql create mode 100644 python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql create mode 100644 python/ql/src/meta/analysis-quality/TTCallGraphNew.ql create mode 100644 python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql create mode 100644 python/ql/src/meta/analysis-quality/TTCallGraphShared.ql diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index 46f384b89ad..a5d03063f54 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -1,16 +1,55 @@ /** * Provides predicates for measuring the quality of the call graph, that is, - * the number of calls that could be resolved to a callee. + * the number of calls that could be resolved to a target. */ import python import meta.MetaMetrics +newtype TTarget = + TFunction(Function func) or + TClass(Class cls) + +class Target extends TTarget { + /** Gets a textual representation of this element. */ + abstract string toString(); + + /** Gets the location of this dataflow call. */ + abstract Location getLocation(); + + /** Whether this target is relevant. */ + predicate isRelevant() { exists(this.getLocation().getFile().getRelativePath()) } +} + +class TargetFunction extends Target, TFunction { + Function func; + + TargetFunction() { this = TFunction(func) } + + override string toString() { result = func.toString() } + + override Location getLocation() { result = func.getLocation() } + + Function getFunction() { result = func } +} + +class TargetClass extends Target, TClass { + Class cls; + + TargetClass() { this = TClass(cls) } + + override string toString() { result = cls.toString() } + + override Location getLocation() { result = cls.getLocation() } + + Class getClass() { result = cls } +} + /** * A call that is (possibly) relevant for analysis quality. * See `IgnoredFile` for details on what is excluded. */ -class RelevantCall extends Call { +class RelevantCall extends CallNode { RelevantCall() { not this.getLocation().getFile() instanceof IgnoredFile } } @@ -18,12 +57,16 @@ class RelevantCall extends Call { module PointsToBasedCallGraph { /** A call that can be resolved by points-to. */ class ResolvableCall extends RelevantCall { - Value callee; + Value targetValue; - ResolvableCall() { callee.getACall() = this.getAFlowNode() } + ResolvableCall() { targetValue.getACall() = this } - /** Gets a resolved callee of this call. */ - Value getCallee() { result = callee } + /** Gets a resolved target of this call. */ + Target getTarget() { + result.(TargetFunction).getFunction() = targetValue.(CallableValue).getScope() + or + result.(TargetClass).getClass() = targetValue.(ClassValue).getScope() + } } /** A call that cannot be resolved by points-to. */ @@ -32,34 +75,68 @@ module PointsToBasedCallGraph { } /** - * A call that can be resolved by points-to, where the resolved callee is relevant. - * Relevant callees include: - * - builtins - * - standard library + * A call that can be resolved by points-to, where the resolved target is relevant. + * Relevant targets include: * - source code of the project */ - class ResolvableCallRelevantCallee extends ResolvableCall { - ResolvableCallRelevantCallee() { - callee.isBuiltin() - or - exists(File file | - file = callee.(CallableValue).getScope().getLocation().getFile() - or - file = callee.(ClassValue).getScope().getLocation().getFile() - | - file.inStdlib() - or - // part of the source code of the project - exists(file.getRelativePath()) + class ResolvableCallRelevantTarget extends ResolvableCall { + ResolvableCallRelevantTarget() { + exists(Target target | target = getTarget() | + exists(target.getLocation().getFile().getRelativePath()) ) } } /** - * A call that can be resolved by points-to, where the resolved callee is not considered relevant. - * See `ResolvableCallRelevantCallee` for the definition of relevance. + * A call that can be resolved by points-to, where the resolved target is not considered relevant. + * See `ResolvableCallRelevantTarget` for the definition of relevance. */ - class ResolvableCallIrrelevantCallee extends ResolvableCall { - ResolvableCallIrrelevantCallee() { not this instanceof ResolvableCallRelevantCallee } + class ResolvableCallIrrelevantTarget extends ResolvableCall { + ResolvableCallIrrelevantTarget() { not this instanceof ResolvableCallRelevantTarget } + } +} + +/** Provides classes for call-graph resolution by using type-tracking. */ +module TypeTrackingBasedCallGraph { + private import semmle.python.dataflow.new.internal.DataFlowDispatch as TT + + /** A call that can be resolved by type-tracking. */ + class ResolvableCall extends RelevantCall { + TT::DataFlowCallable dataflowTarget; + + ResolvableCall() { dataflowTarget = TT::viableCallable(TT::TNormalCall(this)) } + + /** Gets a resolved target of this call. */ + Target getTarget() { + result.(TargetFunction).getFunction() = dataflowTarget.(TT::DataFlowFunction).getScope() + // TODO: class calls + // result.(TargetClass).getClass() + } + } + + /** A call that cannot be resolved by type-tracking. */ + class UnresolvableCall extends RelevantCall { + UnresolvableCall() { not this instanceof ResolvableCall } + } + + /** + * A call that can be resolved by type-tracking, where the resolved callee is relevant. + * Relevant targets include: + * - source code of the project + */ + class ResolvableCallRelevantTarget extends ResolvableCall { + ResolvableCallRelevantTarget() { + exists(Target target | target = getTarget() | + exists(target.getLocation().getFile().getRelativePath()) + ) + } + } + + /** + * A call that can be resolved by type-tracking, where the resolved target is not considered relevant. + * See `ResolvableCallRelevantTarget` for the definition of relevance. + */ + class ResolvableCallIrrelevantTarget extends ResolvableCall { + ResolvableCallIrrelevantTarget() { not this instanceof ResolvableCallRelevantTarget } } } diff --git a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql index 0e9c47023c3..580d2d6b8a1 100644 --- a/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql +++ b/python/ql/src/meta/analysis-quality/PointsToResolvableCallsRelevantTarget.ql @@ -11,4 +11,4 @@ import python import CallGraphQuality -select projectRoot(), count(PointsToBasedCallGraph::ResolvableCallRelevantCallee call) +select projectRoot(), count(PointsToBasedCallGraph::ResolvableCallRelevantTarget call) diff --git a/python/ql/src/meta/analysis-quality/TTCallGraph.ql b/python/ql/src/meta/analysis-quality/TTCallGraph.ql new file mode 100644 index 00000000000..67faca55893 --- /dev/null +++ b/python/ql/src/meta/analysis-quality/TTCallGraph.ql @@ -0,0 +1,17 @@ +/** + * @name New call graph edge from using type-tracking instead of points-to + * @kind problem + * @problem.severity recommendation + * @id py/meta/call-graph-new + * @tags meta + * @precision very-low + */ + +import python +import CallGraphQuality + +from CallNode call, Target target +where + target.isRelevant() and + call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target +select call, "$@ to $@", call, "Call", target, target.toString() diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql b/python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql new file mode 100644 index 00000000000..bbf5b3553ef --- /dev/null +++ b/python/ql/src/meta/analysis-quality/TTCallGraphMissing.ql @@ -0,0 +1,18 @@ +/** + * @name Missing call graph edge from using type-tracking instead of points-to + * @kind problem + * @problem.severity recommendation + * @id py/meta/call-graph-missing + * @tags meta + * @precision very-low + */ + +import python +import CallGraphQuality + +from CallNode call, Target target +where + target.isRelevant() and + call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and + not call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target +select call, "MISSING: $@ to $@", call, "Call", target, target.toString() diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphNew.ql b/python/ql/src/meta/analysis-quality/TTCallGraphNew.ql new file mode 100644 index 00000000000..82a830265c6 --- /dev/null +++ b/python/ql/src/meta/analysis-quality/TTCallGraphNew.ql @@ -0,0 +1,18 @@ +/** + * @name New call graph edge from using type-tracking instead of points-to + * @kind problem + * @problem.severity recommendation + * @id py/meta/call-graph-new + * @tags meta + * @precision very-low + */ + +import python +import CallGraphQuality + +from CallNode call, Target target +where + target.isRelevant() and + not call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and + call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target +select call, "NEW: $@ to $@", call, "Call", target, target.toString() diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql b/python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql new file mode 100644 index 00000000000..5a789d1be90 --- /dev/null +++ b/python/ql/src/meta/analysis-quality/TTCallGraphOverview.ql @@ -0,0 +1,35 @@ +/** + * @name Call graph edge overview from using type-tracking instead of points-to + * @id py/meta/call-graph-overview + * @precision very-low + */ + +import python +import CallGraphQuality + +from string tag, int c +where + tag = "SHARED" and + c = + count(CallNode call, Target target | + target.isRelevant() and + call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and + call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target + ) + or + tag = "NEW" and + c = + count(CallNode call, Target target | + target.isRelevant() and + not call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and + call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target + ) + or + tag = "MISSING" and + c = + count(CallNode call, Target target | + target.isRelevant() and + call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and + not call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target + ) +select tag, c diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphShared.ql b/python/ql/src/meta/analysis-quality/TTCallGraphShared.ql new file mode 100644 index 00000000000..7a3bd794839 --- /dev/null +++ b/python/ql/src/meta/analysis-quality/TTCallGraphShared.ql @@ -0,0 +1,18 @@ +/** + * @name Shared call graph edge from using type-tracking instead of points-to + * @kind problem + * @problem.severity recommendation + * @id py/meta/call-graph-shared + * @tags meta + * @precision very-low + */ + +import python +import CallGraphQuality + +from CallNode call, Target target +where + target.isRelevant() and + call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and + call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target +select call, "SHARED: $@ to $@", call, "Call", target, target.toString() From aa78a434070fed4bd9dfec8910c2a64abaf3a1a4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 31 May 2022 01:33:58 +0200 Subject: [PATCH 006/415] Python: Enable type-tracking in call-graph test --- .../library-tests/CallGraph/InlineCallGraphTest.ql | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql index 50ad10bd191..cba9bc6e1d8 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql @@ -1,5 +1,6 @@ import python import TestUtilities.InlineExpectationsTest +private import semmle.python.dataflow.new.internal.DataFlowDispatch as TT /** Holds when `call` is resolved to `callable` using points-to based call-graph. */ predicate pointsToCallEdge(CallNode call, Function callable) { @@ -10,7 +11,13 @@ predicate pointsToCallEdge(CallNode call, Function callable) { } /** Holds when `call` is resolved to `callable` using type-tracking based call-graph. */ -predicate typeTrackerCallEdge(CallNode call, Function callable) { none() } +predicate typeTrackerCallEdge(CallNode call, Function callable) { + exists(TT::DataFlowCallable dfCallable, TT::DataFlowCall dfCall | + dfCallable.getScope() = callable and + dfCall.getNode() = call and + dfCallable = TT::viableCallable(dfCall) + ) +} class CallGraphTest extends InlineExpectationsTest { CallGraphTest() { this = "CallGraphTest" } From 9c275c177a5821df31da30cec0071fcaef843897 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 31 May 2022 01:41:23 +0200 Subject: [PATCH 007/415] Python: Implement call-graph with type-trackers This commit is a squash of 80 other commits. While developing, things changed majorly 2-3 times, and it just wasn't feasible to go back and write a really nice commit history. My apologies for this HUGE commit. Also, later on this is where I solved merge conflicts after flow-summaries PR was merged. For your amusement, I've included the original commit messages below. Python: Add proper argument/parameter positions Python: Handle normal function calls Python: Reduce dataflow-consistency warnings Previously there was a lot of failures for `uniqueEnclosingCallable` and `argHasPostUpdate` Removing the override of `getEnclosingCallable` in ParameterNode is probably the most controversial... although from my point of view it's a change for the better, since we're able to provide data-flow ParameterNodes for more of the AST parameter nodes. Python: Adjust `dataflow/calls` test Python: Implement `isParameterOf`/`argumentOf`/`OutNode` This makes the tests under `dataflow/basic` work as well :+1: (initially I had these as separate commits, but it felt like it was too much noise) Python: Accept fix for `dataflow/consistency` Python: Changes to `coverage/argumentRoutingTest.ql` Notice we gain a few new resolved arguments. We loose out on stuff due to: 1. not handling `*` or `**` in either arguments/parameters (yet) 2. not handling special calls (yet) Python: Small fix for `TestUtil/RoutingTest.qll` Since the helper predicates do not depend on this, moved outside class. Python: Accept changes to `dataflow/coverage/NormalDataflowTest.ql` Most of this is due to: - not handling any kinds of methods yet - not handling `*` or `**` Python: Small investigation of `test_deep_callgraph` Python: Accept changes to `coverage/localFlow.ql` I don't fully understand why the .expected file changed. Since we still have the desired flow, I'm not going to worry too much about it. with this commit, the `dataflow/coverage` tests passes :+1: Python: Minor doc update Python: Add staticmethod/classmethod to `dataflow/calls` Python: Handle method calls on class instances without trying to deal with any class inheritance, or staticmethod/classmethod at all. Notice that with this change, we only have a DataFlowCall for the calls that we can actually resolve. I'm not 100% sure if we need to add a `UnresolvedCall` subclass of `DataFlowCall` for MaD in the future, but it should be easy to do. I'm still unsure about the value of `classesCallGraph`, but have just accepted the changes. Python: Handle direct method calls `C.foo(C, arg0)` Python: Handle `@staticmethod` Python: Handle class method calls... but the code is shit WIP todo Rewrite method calls to be better also fixed a problem with `self` being an argument to the `x.staticmethod()` call :| Python: Add subclass tests Python: Split `class_advanced` test Python: Rewrite call-graph tests to be inline expectation (1/2) This adds inline expectations, next commit will remove old annotations code... but I thought it would be easier to review like this. Minor fixup Python: Add simple subclass support Python: more precise subclass lookup Still not 100% precise.. but it's better New ambiguous Python: Add test for `self.m()` and `cls.m()` calls Python: Handle `self.m()` and `cls.m()` calls Python: Add tests for `__init__` and `__new__` Python: Handle class calls Python: Fix `self` argument passing for class calls Now field-flow tests also pass :muscle: (although the crosstalk fieldflow test changes were due to this specific commit) I also copied much of the setup for pre/post update nodes from Ruby, specifically having the abstract `PostUpdateNodeImpl` in DataFlowPrivate seemed like a nice change. Same for the setup with `TNode` definition having the specification directly in the body, instead of a `NeedsSyntheticPostUpdateNode` class. Python: Add new crosstalk test WIP Maybe needs a bit of refactoring, and to see how it all behaves with points-to Python: Add `super()` call-graph tests Python: Refactor MethodCall char-pred In anticipation of supporting `super(MyClass, self).foo()`, where the `self` argument doesn't come from an AttrNode, but from the second argument to super. Without `pragma[inline]` the optimizer found a terrible join-order -- this won't guarantee a good join-order for the future, but for now it was just so simple and could let me move on with life. Python: Add basic `super()` support I debated a little (with myself) whether I should really do `superTracker`, but I thought "why not" and just rolled with it. I did not confirm whether it was actually needed anywhere, that is if anyone does `ref = super; ref().foo()` -- although I certainly doubt it's very wide-spread. Python: InlineCallGraphTest: Allow non-unique callable name in different files Python: more MRO tests Python: Add MRO approximation for `super()` Although it's not 100% accurate, it seems to be on level with the one in points-to. Python: Remove some spurious targets for direct calls removal of TODO from refactoring remove TODOs class call support Python: Add contrived subclass call example Python: Remove more spurious call targets NOTE: I initially forgot to use `findFunctionAccordingToMroKnownStartingClass` instead of `findFunctionAccordingToMro` for __init__ and __new__, and since I did make that mistake myself, I wanted to add something to the test to highlight this fact, and make it viewable by PR reviewer... this will be fixed in the next commit. Python: Proper fix for spurious __init__ targets Python: Add call-graph example of class decorator Python: Support decorated classes in new call-graph Python: Add call-graph tests for `type(obj).meth()` Python: support `type(obj).meth()` Python: Add test for callable defined in function Python: Add test for callable as argument Current'y we don't find these with type-tracking, which is super mysterious. I did check that we have proper flow from the arguments to the parameters. Python: Found problem for callable as argument :| MAJOR WIP WIP commit IT WORKS AGAIN (but terrible performance) remove pragma[inline] remove oops Fix performance problem I tried to optimize it even further, but I didn't end up achieving anything :| Fix call-graph comparison add comparison version with easy lookup incomplete missing call-graph tests unhandled tests trying to replicate missing call-edge due to missing imports ... but it's hard also seems to be problems with the inline-expectation-value that I used, seems like it has both missing/unexpected results with same value Python: Add import-problem test Python: Add shadowing problem some cleanup of rewrite fix a little more cleanup Add consistency queries to call-graph tests Python: Add post-update nodes for `self` in implicit `super()` uses But we do need to discuss whether this is the right approach :O Fix for field-flow tests This came from more precise argument passing Fixed results in type-tracking Comes from better argument passing with super() and handling of functions with decorators fix of inline call graph tests Fixup call annotation test Many minor cleanups/fixes NewNormalCall -> NormalCall Python: Major restructuring + qldoc writing Python: Accept changes from pre/post update node .toString changes Python: Reduce `super` complexity !! WIP !! Python: Only pass self-reference if in same enclosing-callable Python: Add call-graph test with nested class This was inspired by the ImpliesDataflow test that showed missing flow for q_super, but at least for the call-graph, I'm not able to reproduce this missing result :| Python: Restrict `super()` to function defined directly on class Python: Accept fixes to ImpliesDataflow Python: Expand field-flow crosstalk tests --- .../new/internal/DataFlowDispatch.qll | 915 +++++++++++++++++- .../dataflow/new/internal/DataFlowPrivate.qll | 174 +--- .../dataflow/new/internal/DataFlowPublic.qll | 70 +- .../new/internal/TypeTrackerSpecific.qll | 35 +- .../analysis-quality/CallGraphQuality.qll | 23 +- .../TTCallGraphNewAmbiguous.ql | 19 + .../dataflow/TestUtil/RoutingTest.qll | 41 +- .../dataflow/basic/callGraphSinks.expected | 1 - .../dataflow/basic/callGraphSources.expected | 1 - .../dataflow/basic/global.expected | 1 - .../dataflow/basic/globalStep.expected | 1 - .../dataflow/basic/local.expected | 8 +- .../dataflow/basic/localStep.expected | 1 - .../dataflow/basic/sinks.expected | 7 +- .../dataflow/basic/sources.expected | 7 +- .../callgraph_crosstalk/Arguments.expected | 13 + .../dataflow/callgraph_crosstalk/Arguments.ql | 9 + .../dataflow-consistency.expected | 19 + .../dataflow-consistency.ql | 1 + .../dataflow/callgraph_crosstalk/options | 1 + .../dataflow/callgraph_crosstalk/test.py | 70 ++ .../dataflow/calls/DataFlowCallTest.ql | 18 +- .../test/experimental/dataflow/calls/test.py | 56 +- .../consistency/modeling-consistency.expected | 1 - .../dataflow/coverage/argumentPassing.py | 16 +- .../experimental/dataflow/coverage/classes.py | 64 +- .../dataflow/coverage/datamodel.py | 47 +- .../dataflow/coverage/localFlow.expected | 6 - .../dataflow/coverage/localFlow.ql | 2 +- .../experimental/dataflow/coverage/test.py | 64 +- .../experimental/dataflow/fieldflow/test.py | 49 +- .../dataflow/typetracking/test.py | 10 +- .../InlineCallGraphTest.expected | 1 - .../CallGraph-implicit-init/example.py | 2 +- .../InlineCallGraphTest.expected | 5 + .../InlineCallGraphTest.qlref | 1 + .../library-tests/CallGraph-imports/README.md | 5 + .../library-tests/CallGraph-imports/options | 1 + .../CallGraph-imports/pkg/__init__.py | 0 .../pkg/alias_only_direct.py | 1 + .../CallGraph-imports/pkg/alias_problem.py | 2 + .../pkg/alias_problem_fixed.py | 3 + .../CallGraph-imports/pkg/alias_star.py | 2 + .../CallGraph-imports/pkg/func_def.py | 2 + .../CallGraph-imports/pkg/other.py | 2 + .../CallGraph-imports/pkg/use.py | 33 + .../CallGraph/InlineCallGraphTest.expected | 53 +- .../CallGraph/InlineCallGraphTest.ql | 45 +- .../CallGraph/code/aliased_import.py | 1 + .../CallGraph/code/bound_method_arg.py | 16 + .../CallGraph/code/callable_as_argument.py | 55 ++ .../CallGraph/code/class_advanced.py | 40 - .../CallGraph/code/class_attr_assign.py | 30 + .../CallGraph/code/class_construction.py | 66 ++ .../CallGraph/code/class_decorator.py | 34 + .../CallGraph/code/class_more_mro.py | 35 + .../CallGraph/code/class_more_mro2.py | 22 + .../CallGraph/code/class_properties.py | 43 + .../CallGraph/code/class_simple.py | 29 - .../CallGraph/code/class_special_methods.py | 29 + .../CallGraph/code/class_subclass.py | 178 ++++ .../CallGraph/code/class_subclass2.py | 38 + .../CallGraph/code/class_super.py | 108 +++ .../CallGraph/code/conditional_in_argument.py | 36 + .../CallGraph/code/def_in_function.py | 24 + .../code/func_defined_outside_class.py | 43 + .../CallGraph/code/nested_class.py | 87 ++ .../CallGraph/code/relative_import.py | 7 + .../CallGraph/code/runtime_decision.py | 4 +- .../library-tests/CallGraph/code/shadowing.py | 22 + .../library-tests/CallGraph/code/simple.py | 8 +- .../CallGraph/code/through_content.py | 6 + .../code/type_tracking_limitation.py | 8 + .../code/underscore_prefix_func_name.py | 8 +- .../CallGraph/dataflow-consistency.expected | 19 + .../CallGraph/dataflow-consistency.ql | 1 + .../PointsTo/new/ImpliesDataflow.expected | 5 - .../django-orm/ReflectedXss.expected | 12 +- python/ql/test/library-tests/fuck/options | 1 + python/ql/test/library-tests/fuck/test.py | 17 + .../ql/test/library-tests/fuck/wat.expected | 1 + 81 files changed, 2494 insertions(+), 447 deletions(-) create mode 100644 python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql create mode 100644 python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.expected create mode 100644 python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.ql create mode 100644 python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected create mode 100644 python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql create mode 100644 python/ql/test/experimental/dataflow/callgraph_crosstalk/options create mode 100644 python/ql/test/experimental/dataflow/callgraph_crosstalk/test.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.qlref create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/README.md create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/options create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/__init__.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_only_direct.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem_fixed.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_star.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/func_def.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/other.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/aliased_import.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/bound_method_arg.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/callable_as_argument.py delete mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_attr_assign.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_decorator.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro2.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py delete mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_subclass.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_subclass2.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/class_super.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/def_in_function.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/func_defined_outside_class.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/nested_class.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/relative_import.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/through_content.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/type_tracking_limitation.py create mode 100644 python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected create mode 100644 python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql create mode 100644 python/ql/test/library-tests/fuck/options create mode 100644 python/ql/test/library-tests/fuck/test.py create mode 100644 python/ql/test/library-tests/fuck/wat.expected diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 90c8010739d..37841765030 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -3,6 +3,18 @@ * * TypeTracker based call-graph. * + * The overall scheme for resolving calls, is to notice that Python has different kinds + * of callables, and resolve those with different strategies. Currently we handle these + * completely separately: + * 1. plain functions (and lambdas) + * 2. methods on classes + * 3. class instantiation + * + * So we have type-trackers for each of the 3 categories above, with some considerable + * effort to handle different kinds of methods on classes (staticmethod, classmethod, + * normal), and resolving methods correctly in regards to MRO. + * + * * A goal of this library is to support modeling calls that happens by third-party * libraries. For example `call_later(func, arg0, arg1, foo=val)`, and the fact that the * library might inject it's own arguments, for example a context that will always be @@ -11,29 +23,104 @@ * additional data-flow steps for the arguments/parameters. This means we cannot have * any special logic that requires an AST call to be made before we care to figure out * what callable this call might end up targeting. + * + * Specifically this means that we cannot use type-backtrackes from the function of a + * `CallNode`, since there is no `CallNode` to backtrack from for `func` in the example + * above. + * + * Note: This hasn't been 100% realized yet, so we don't currently expose a predicate to + * ask what targets any data-flow node has. But it's still the plan to do this! */ private import python private import DataFlowPublic +private import DataFlowPrivate private import FlowSummaryImpl as FlowSummaryImpl +newtype TParameterPosition = + /** Used for `self` in methods, and `cls` in classmethods. */ + TSelfParameterPosition() or + TPositionalParameterPosition(int pos) { pos = any(Parameter p).getPosition() } or + TKeywordParameterPosition(string name) { name = any(Parameter p).getName() } + /** A parameter position. */ -class ParameterPosition extends Unit { - // TODO(call-graph): implement this! +class ParameterPosition extends TParameterPosition { + /** Holds if this position represents a `self`/`cls` parameter. */ + predicate isSelf() { this = TSelfParameterPosition() } + + /** Holds if this position represents a positional parameter at (0-based) `index`. */ + predicate isPositional(int index) { this = TPositionalParameterPosition(index) } + + /** Holds if this position represents a keyword parameter named `name`. */ + predicate isKeyword(string name) { this = TKeywordParameterPosition(name) } + + /** Gets a textual representation of this element. */ + string toString() { + this.isSelf() and result = "self" + or + exists(int index | this.isPositional(index) and result = "position " + index) + or + exists(string name | this.isKeyword(name) and result = "keyword " + name) + } } +newtype TArgumentPosition = + /** Used for `self` in methods, and `cls` in classmethods. */ + TSelfArgumentPosition() or + TPositionalArgumentPosition(int pos) { exists(any(CallNode c).getArg(pos)) } or + TKeywordArgumentPosition(string name) { exists(any(CallNode c).getArgByName(name)) } + /** An argument position. */ -abstract class ArgumentPosition extends Unit { - // TODO(call-graph): implement this! +class ArgumentPosition extends TArgumentPosition { + /** Holds if this position represents a `self`/`cls` argument. */ + predicate isSelf() { this = TSelfArgumentPosition() } + + /** Holds if this position represents a positional argument at (0-based) `index`. */ + predicate isPositional(int index) { this = TPositionalArgumentPosition(index) } + + /** Holds if this position represents a keyword argument named `name`. */ + predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) } + + /** Gets a textual representation of this element. */ + string toString() { + this.isSelf() and result = "self" + or + exists(int pos | this.isPositional(pos) and result = "position " + pos) + or + exists(string name | this.isKeyword(name) and result = "keyword " + name) + } } /** Holds if arguments at position `apos` match parameters at position `ppos`. */ pragma[inline] predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { - // TODO(call-graph): implement this! - none() + ppos.isSelf() and apos.isSelf() + or + exists(int index | ppos.isPositional(index) and apos.isPositional(index)) + or + exists(string name | ppos.isKeyword(name) and apos.isKeyword(name)) } +// ============================================================================= +// Helper predicates +// ============================================================================= +/** Holds if the function has a `staticmethod` decorator. */ +predicate hasStaticmethodDecorator(Function func) { + exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() | + func.getADecorator() = id.getNode() + ) +} + +/** Holds if the function has a `classmethod` decorator. */ +predicate hasClassmethodDecorator(Function func) { + exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() | + func.getADecorator() = id.getNode() + ) +} + +// ============================================================================= +// Callables +// ============================================================================= /** A callable defined in library code, identified by a unique string. */ abstract class LibraryCallable extends string { bindingset[this] @@ -47,8 +134,8 @@ abstract class LibraryCallable extends string { } newtype TDataFlowCallable = - // TODO(call-graph): implement this! - /** For enclosing `ModuleVariableNode`s -- don't actually have calls. */ + TFunction(Function func) or + /** see QLDoc for `DataFlowModuleScope` for why we need this. */ TModule(Module m) or TLibraryCallable(LibraryCallable callable) @@ -57,6 +144,9 @@ abstract class DataFlowCallable extends TDataFlowCallable { /** Gets a textual representation of this element. */ abstract string toString(); + /** Gets qualified name for this callable, if any. */ + abstract string getQualifiedName(); + /** Gets the scope of this callable */ abstract Scope getScope(); @@ -70,6 +160,71 @@ abstract class DataFlowCallable extends TDataFlowCallable { abstract Location getLocation(); } +/** A callable function. */ +abstract class DataFlowFunction extends DataFlowCallable, TFunction { + Function func; + + DataFlowFunction() { this = TFunction(func) } + + override string toString() { result = func.toString() } + + override string getQualifiedName() { result = func.getQualifiedName() } + + override Function getScope() { result = func } + + override Location getLocation() { result = func.getLocation() } + + /** Gets the positional parameter offset, to take into account self/cls parameters. */ + int positionalOffset() { result = 0 } + + override ParameterNode getParameter(ParameterPosition ppos) { + exists(int index | ppos.isPositional(index) | + result.getParameter() = func.getArg(index + this.positionalOffset()) + ) + or + exists(string name | ppos.isKeyword(name) | result.getParameter() = func.getArgByName(name)) + } +} + +/** A plain (non-method) function. */ +class DataFlowPlainFunction extends DataFlowFunction { + DataFlowPlainFunction() { not this instanceof DataFlowMethod } +} + +/** A method, except staticmethods. */ +class DataFlowMethod extends DataFlowFunction { + Class cls; + + DataFlowMethod() { cls.getAMethod() = func } + + /** Gets the class this function is a method of. */ + Class getClass() { result = cls } + + override int positionalOffset() { result = 1 } + + override ParameterNode getParameter(ParameterPosition ppos) { + ppos.isSelf() and result.getParameter() = func.getArg(0) + or + result = super.getParameter(ppos) + } +} + +/** A classmethod. */ +class DataFlowClassmethod extends DataFlowMethod { + DataFlowClassmethod() { hasClassmethodDecorator(func) } +} + +/** A staticmethod. */ +class DataFlowStaticmethod extends DataFlowMethod, DataFlowFunction { + DataFlowStaticmethod() { hasStaticmethodDecorator(func) } + + override int positionalOffset() { result = 0 } + + override ParameterNode getParameter(ParameterPosition ppos) { + result = DataFlowFunction.super.getParameter(ppos) + } +} + /** * A module. This is not actually a callable, but we need this so a * `ModuleVariableNode` have an enclosing callable. @@ -81,6 +236,8 @@ class DataFlowModuleScope extends DataFlowCallable, TModule { override string toString() { result = mod.toString() } + override string getQualifiedName() { result = mod.getName() } + override Module getScope() { result = mod } override Location getLocation() { result = mod.getLocation() } @@ -95,6 +252,8 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { override string toString() { result = callable.toString() } + override string getQualifiedName() { result = callable.toString() } + /** Gets a data-flow node, where this library callable is used as a call-back. */ ArgumentNode getACallback() { result = callable.getACallback() } @@ -107,9 +266,702 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { override Location getLocation() { none() } } +// ============================================================================= +// Type trackers used to resolve calls. +// ============================================================================= +/** Gets a call to `type`. */ +private CallCfgNode getTypeCall() { + exists(NameNode id | id.getId() = "type" and id.isGlobal() | + result.getFunction().asCfgNode() = id + ) +} + +/** Gets a call to `super`. */ +private CallCfgNode getSuperCall() { + // While it is possible to reference super and call it later, it's almost never done in + // practice. From looking at top 1000 projects, there were a few uses around mocking (see + // link below), but otherwise only 2 edgecases. Overall it seems ok to ignore this complexity. + // + // https://github.com/python/cpython/blob/18b1782192f85bd26db89f5bc850f8bee4247c1a/Lib/unittest/mock.py#L48-L50 + exists(NameNode id | id.getId() = "super" and id.isGlobal() | + result.getFunction().asCfgNode() = id + ) +} + +/** + * Gets a reference to the function `func`. + */ +private TypeTrackingNode functionTracker(TypeTracker t, Function func) { + t.start() and + ( + result.asExpr() = func.getDefinition() + or + // when a function is decorated, it's the result of the (last) decorator call that + // is used + result.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall() + ) + or + exists(TypeTracker t2 | result = functionTracker(t2, func).track(t2, t)) +} + +/** + * Gets a reference to the function `func`. + */ +Node functionTracker(Function func) { functionTracker(TypeTracker::end(), func).flowsTo(result) } + +/** + * Gets a reference to the class `cls`. + */ +private TypeTrackingNode classTracker(TypeTracker t, Class cls) { + t.start() and + ( + result.asExpr() = cls.getParent() + or + // when a class is decorated, it's the result of the (last) decorator call that + // is used + result.asExpr() = cls.getParent().(ClassExpr).getADecoratorCall() + or + // `type(obj)`, where obj is an instance of this class + result = getTypeCall() and + result.(CallCfgNode).getArg(0) = classInstanceTracker(cls) + ) + or + exists(TypeTracker t2 | result = classTracker(t2, cls).track(t2, t)) +} + +/** + * Gets a reference to the class `cls`. + */ +Node classTracker(Class cls) { classTracker(TypeTracker::end(), cls).flowsTo(result) } + +/** + * Gets a reference to an instance of the class `cls`. + */ +private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) { + t.start() and + result.(CallCfgNode).getFunction() = classTracker(cls) + or + exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) +} + +/** + * Gets a reference to an instance of the class `cls`. + */ +Node classInstanceTracker(Class cls) { + classInstanceTracker(TypeTracker::end(), cls).flowsTo(result) +} + +/** + * Gets a reference to the `self` argument of a method on class `classWithMethod`. + * The method cannot be a `staticmethod` or `classmethod`. + */ +private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) { + t.start() and + exists(Function func | + func = classWithMethod.getAMethod() and + not hasStaticmethodDecorator(func) and + not hasClassmethodDecorator(func) + | + result.asExpr() = func.getArg(0) + ) + or + exists(TypeTracker t2 | result = selfTracker(t2, classWithMethod).track(t2, t)) +} + +/** + * Gets a reference to the `self` argument of a method on class `classWithMethod`. + * The method cannot be a `staticmethod` or `classmethod`. + */ +Node selfTracker(Class classWithMethod) { + selfTracker(TypeTracker::end(), classWithMethod).flowsTo(result) +} + +/** + * Gets a reference to the `cls` argument of a classmethod on class `classWithMethod`. + */ +private TypeTrackingNode clsTracker(TypeTracker t, Class classWithMethod) { + t.start() and + ( + exists(Function func | + func = classWithMethod.getAMethod() and + hasClassmethodDecorator(func) + | + result.asExpr() = func.getArg(0) + ) + or + // type(self) + result = getTypeCall() and + result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) + ) + or + exists(TypeTracker t2 | result = clsTracker(t2, classWithMethod).track(t2, t)) +} + +/** + * Gets a reference to the `cls` argument of a classmethod on class `classWithMethod`. + */ +Node clsTracker(Class classWithMethod) { + clsTracker(TypeTracker::end(), classWithMethod).flowsTo(result) +} + +/** + * Gets a reference to the result of calling `super` without any argument, where the + * call happened in the method `func` (either a method or a classmethod). + */ +private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func) { + not hasStaticmethodDecorator(func) and + t.start() and + exists(CallCfgNode call | result = call | + call = getSuperCall() and + not exists(call.getArg(_)) and + call.getScope() = func + ) + or + exists(TypeTracker t2 | result = superCallNoArgumentTracker(t2, func).track(t2, t)) +} + +/** + * Gets a reference to the result of calling `super` without any argument, where the + * call happened in the method `func` (either a method or a classmethod). + */ +Node superCallNoArgumentTracker(Function func) { + superCallNoArgumentTracker(TypeTracker::end(), func).flowsTo(result) +} + +/** + * Gets a reference to the result of calling `super` with 2 arguments, where the + * first is a reference to the class `cls`, and the second argument is `obj`. + */ +private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, Node obj) { + t.start() and + exists(CallCfgNode call | result = call | + call = getSuperCall() and + call.getArg(0) = classTracker(cls) and + call.getArg(1) = obj + ) + or + exists(TypeTracker t2 | result = superCallTwoArgumentTracker(t2, cls, obj).track(t2, t)) +} + +/** + * Gets a reference to the result of calling `super` with 2 arguments, where the + * first is a reference to the class `cls`, and the second argument is `obj`. + */ +Node superCallTwoArgumentTracker(Class cls, Node obj) { + superCallTwoArgumentTracker(TypeTracker::end(), cls, obj).flowsTo(result) +} + +// ============================================================================= +// MRO +// ============================================================================= +/** + * Gets a direct superclass of the argument `cls`, if any. + * + * For `A` with the class definition `class A(B, C)` it will have results `B` and `C`. + */ +Class getADirectSuperclass(Class cls) { cls.getABase() = classTracker(result).asExpr() } + +/** + * Gets a direct subclass of the argument `cls`, if any. + * + *For `B` with the class definition `class A(B)` it will have result `A`. + */ +Class getADirectSubclass(Class cls) { cls = getADirectSuperclass(result) } + +/** + * Gets a class that, from an approximated MRO calculation, might be the next class used + * for member-lookup when `super().attr` is used inside the class `cls`. + * + * In the example below, with `cls=B`, this predicate will have `A` and `C` as results. + * ```py + * class A: pass + * class B(A): pass + * class C(A): pass + * class D(B, C): pass + * ``` + * + * NOTE: This approximation does not handle all cases correctly, and in the example + * below, with `cls=A` will not have any results, although it should include `Y`. + * + * ```py + * class A: pass + * class B(A): pass + * class X: pass + * class Y(X): pass + * class Ex(B, Y): pass + * ``` + * + * NOTE for debugging the results of this predicate: Since a class can be part of + * multiple MROs, results from this predicate might only be valid in some, but not all, + * inheritance chains (such as the result `C` for `cls=B` in the first example -- this + * might make it difficult to see if the definition of `D` is located in an other file) + * + * For more info on the C3 MRO used in Python see: + * - https://docs.python.org/3/glossary.html#term-method-resolution-order + * - https://www.python.org/download/releases/2.3/mro/ + */ +private Class getNextClassInMro(Class cls) { + // class A(B, ...): + // `B` must be the next class after `A` in the MRO for A. + cls.getBase(0) = classTracker(result).asExpr() + or + // class A(B, C, D): + // - `C` could be the next class after `B` in MRO. + // - `D` could be the next class after `C` in MRO. + exists(Class sub, int i | + sub.getBase(i) = classTracker(cls).asExpr() and + sub.getBase(i + 1) = classTracker(result).asExpr() and + not result = cls + ) + // There are two important properties for MRO computed with C3 in Python: + // + // 1) monotonicity: if C1 precedes C2 in the MRO of C, then C1 precedes C2 in the MRO + // of any subclass of C. + // 2) local precedence ordering: if C1 precedes C2 in the list of superclasses for C, + // they will keep the same order in the MRO for C (and due to monotonicity, any + // subclass). +} + +/** + * Gets a potential definition of the function `name` according to our approximation of + * MRO for the class `cls` (see `getNextClassInMro` for more information). + */ +Function findFunctionAccordingToMro(Class cls, string name) { + result = cls.getAMethod() and + result.getName() = name + or + not exists(Function f | f.getName() = name and f = cls.getAMethod()) and + result = findFunctionAccordingToMro(getNextClassInMro(cls), name) +} + +/** + * Gets a class that, from an approximated MRO calculation, might be the next class + * after `cls` in the MRO for `startingClass`. + * + * Note: this is almost the same as `getNextClassInMro`, except we know the + * `startingClass`, which can give slightly more precise results. + * + * See QLDoc for `getNextClassInMro`. + */ +Class getNextClassInMroKnownStartingClass(Class cls, Class startingClass) { + cls.getBase(0) = classTracker(result).asExpr() and + cls = getADirectSuperclass*(startingClass) + or + exists(Class sub, int i | sub = getADirectSuperclass*(startingClass) | + sub.getBase(i) = classTracker(cls).asExpr() and + sub.getBase(i + 1) = classTracker(result).asExpr() and + not result = cls + ) +} + +private Function findFunctionAccordingToMroKnownStartingClass( + Class cls, Class startingClass, string name +) { + result = cls.getAMethod() and + result.getName() = name and + cls = getADirectSuperclass*(startingClass) + or + not exists(Function f | f.getName() = name and f = cls.getAMethod()) and + result = + findFunctionAccordingToMroKnownStartingClass(getNextClassInMroKnownStartingClass(cls, + startingClass), startingClass, name) +} + +/** + * Gets a potential definition of the function `name` according to our approximation of + * MRO for the class `cls` (see `getNextClassInMroKnownStartingClass` for more information). + * + * Note: this is almost the same as `findFunctionAccordingToMro`, except we know the + * `startingClass`, which can give slightly more precise results. + */ +pragma[inline] +Function findFunctionAccordingToMroKnownStartingClass(Class startingClass, string name) { + result = findFunctionAccordingToMroKnownStartingClass(startingClass, startingClass, name) +} + +// ============================================================================= +// attribute trackers +// ============================================================================= +/** Gets a reference to the attribute read `attr` */ +private TypeTrackingNode attrReadTracker(TypeTracker t, AttrRead attr) { + t.start() and + result = attr + or + exists(TypeTracker t2 | result = attrReadTracker(t2, attr).track(t2, t)) +} + +/** Gets a reference to the attribute read `attr` */ +Node attrReadTracker(AttrRead attr) { attrReadTracker(TypeTracker::end(), attr).flowsTo(result) } + +// ============================================================================= +// call and argument resolution +// ============================================================================= +newtype TCallType = + /** A call to a function that is not part of a class. */ + CallTypePlainFunction() or + /** + * A call to an "normal" method on a class instance. + * Does not include staticmethods or classmethods. + */ + CallTypeNormalMethod() or + /** A call to a staticmethod. */ + CallTypeStaticMethod() or + /** A call to a classmethod. */ + CallTypeClassMethod() or + /** + * A call to method on a class, not going through an instance method, such as + * + * ```py + * class Foo: + * def method(self, arg): + * pass + * + * foo = Foo() + * Foo.method(foo, 42) + * ``` + */ + CallTypeMethodAsPlainFunction() or + /** A call to a class. */ + CallTypeClass() + +/** A type of call. */ +class CallType extends TCallType { + string toString() { + this instanceof CallTypePlainFunction and + result = "CallTypePlainFunction" + or + this instanceof CallTypeNormalMethod and + result = "CallTypeNormalMethod" + or + this instanceof CallTypeStaticMethod and + result = "CallTypeStaticMethod" + or + this instanceof CallTypeClassMethod and + result = "CallTypeClassMethod" + or + this instanceof CallTypeMethodAsPlainFunction and + result = "CallTypeMethodAsPlainFunction" + or + this instanceof CallTypeClass and + result = "CallTypeClass" + } +} + +// ------------------------------------- +// method call resolution +// ------------------------------------- +private module MethodCalls { + /** + * Holds if `call` is a call to a method `target` on an instance or class, where the + * instance or class is not derived from an implicit `self`/`cls` argument to a method + * -- for that, see `callWithinMethodImplicitSelfOrCls`. + * + * It is found by making an attribute read `attr` with the name `functionName` on a + * reference to the class `cls`, or to an instance of the class `cls`. The reference the + * attribute-read is made on is `self`. + */ + pragma[noinline] + private predicate directCall( + CallNode call, Function target, string functionName, Class cls, AttrRead attr, Node self + ) { + target = findFunctionAccordingToMroKnownStartingClass(cls, cls, functionName) and + directCall_join(call, functionName, cls, attr, self) + } + + /** Extracted to give good join order */ + pragma[noinline] + private predicate directCall_join( + CallNode call, string functionName, Class cls, AttrRead attr, Node self + ) { + ( + call.getFunction() = attrReadTracker(attr).asCfgNode() and + attr.accesses(classTracker(cls), functionName) + or + call.getFunction() = attrReadTracker(attr).asCfgNode() and + attr.accesses(classInstanceTracker(cls), functionName) + ) and + attr.accesses(self, functionName) + } + + /** + * Holds if `call` is a call to a method `target` derived from an implicit `self`/`cls` + * argument to a method within the class `classWithMethod`. + * + * It is found by making an attribute read `attr` with the name `functionName` on a + * reference to an implicit `self`/`cls` argument. The reference the attribute-read is + * made on is `self`. + */ + pragma[noinline] + private predicate callWithinMethodImplicitSelfOrCls( + CallNode call, Function target, string functionName, Class classWithMethod, AttrRead attr, + Node self + ) { + target = findFunctionAccordingToMro(getADirectSubclass*(classWithMethod), functionName) and + callWithinMethodImplicitSelfOrCls_join(call, functionName, classWithMethod, attr, self) + } + + /** Extracted to give good join order */ + pragma[noinline] + private predicate callWithinMethodImplicitSelfOrCls_join( + CallNode call, string functionName, Class classWithMethod, AttrRead attr, Node self + ) { + ( + call.getFunction() = attrReadTracker(attr).asCfgNode() and + attr.accesses(clsTracker(classWithMethod), functionName) + or + call.getFunction() = attrReadTracker(attr).asCfgNode() and + attr.accesses(selfTracker(classWithMethod), functionName) + ) and + attr.accesses(self, functionName) + } + + /** + * Holds if `call` is a call to a method `target`, derived from a use of `super`, either + * as: + * + * (1) `super(SomeClass, obj)`, where the first argument is a reference to the class + * `classUsedInSuper`, and the second argument is `self`. + * + * (2) `super()`. This implicit version can only happen within a method in a class. + * The implicit first argument is the class the call happens within `classUsedInSuper`. + * The implicit second argument is the `self`/`cls` parameter of the method this happens + * within. + * + * The method call is found by making an attribute read `attr` with the name + * `functionName` on the return value from the `super` call. + */ + pragma[noinline] + predicate fromSuper( + CallNode call, Function target, string functionName, Class classUsedInSuper, AttrRead attr, + Node self + ) { + target = findFunctionAccordingToMro(getNextClassInMro(classUsedInSuper), functionName) and + fromSuper_join(call, functionName, classUsedInSuper, attr, self) + } + + /** Extracted to give good join order */ + pragma[noinline] + private predicate fromSuper_join( + CallNode call, string functionName, Class classUsedInSuper, AttrRead attr, Node self + ) { + call.getFunction() = attrReadTracker(attr).asCfgNode() and + ( + exists(Function func | + attr.accesses(superCallNoArgumentTracker(func), functionName) and + // Requiring enclosing scope of function to be a class is a little too + // restrictive, since it is possible to use `super()` in a function defined inside + // the method, where the first argument to the nested-function will be used as + // implicit self argument. In practice I don't expect this to be a problem, and we + // did not support this with points-to either. + func.getEnclosingScope() = classUsedInSuper and + self.(ParameterNode).getParameter() = func.getArg(0) + ) + or + attr.accesses(superCallTwoArgumentTracker(classUsedInSuper, self), functionName) + ) + } + + predicate resolveMethodCall(ControlFlowNode call, Function target, CallType type, Node self) { + ( + directCall(call, target, _, _, _, self) + or + callWithinMethodImplicitSelfOrCls(call, target, _, _, _, self) + or + fromSuper(call, target, _, _, _, self) + ) and + ( + // normal method call + type instanceof CallTypeNormalMethod and + ( + self = classInstanceTracker(_) + or + self = selfTracker(_) + ) and + not hasStaticmethodDecorator(target) and + not hasClassmethodDecorator(target) + or + // method as plain function call + type instanceof CallTypeMethodAsPlainFunction and + self = classTracker(_) and + not hasStaticmethodDecorator(target) and + not hasClassmethodDecorator(target) + or + // staticmethod call + type instanceof CallTypeStaticMethod and + hasStaticmethodDecorator(target) + or + // classmethod call + type instanceof CallTypeClassMethod and + hasClassmethodDecorator(target) + ) + } +} + +import MethodCalls + +// ------------------------------------- +// class call resolution +// ------------------------------------- +/** + * Holds when `call` is a call to the class `cls`. + * + * NOTE: We have this predicate mostly to be able to compare with old point-to + * call-graph resolution. So it could be removed in the future. + */ +predicate resolveClassCall(CallNode call, Class cls) { + call.getFunction() = classTracker(cls).asCfgNode() +} + +/** + * Gets a function (`__init__`/`__new__`) that will be invoked when `cls` is + * constructed -- where the function lookup is based on our MRO calculation. + */ +Function invokedFunctionFromClassConstruction(Class cls) { + result = findFunctionAccordingToMroKnownStartingClass(cls, "__new__") + or + // as described in https://docs.python.org/3/reference/datamodel.html#object.__new__ + // __init__ will only be called when __new__ returns an instance of the class (which + // is not a requirement). However, for simplicity, we assume that __init__ will always + // be called. + result = findFunctionAccordingToMroKnownStartingClass(cls, "__init__") +} + +// ------------------------------------- +// overall call resolution +// ------------------------------------- +/** + * Holds if `call` is a call to the `target`, with call-type `type`. + */ +predicate resolveCall(ControlFlowNode call, Function target, CallType type) { + type instanceof CallTypePlainFunction and + call.(CallNode).getFunction() = functionTracker(target).asCfgNode() and + not exists(Class cls | cls.getAMethod() = target) + or + resolveMethodCall(call, target, type, _) + or + type instanceof CallTypeClass and + exists(Class cls | + resolveClassCall(call, cls) and + target = invokedFunctionFromClassConstruction(cls) + ) +} + +// ============================================================================= +// Argument resolution +// ============================================================================= +/** + * Holds if the argument of `call` at position `apos` is `arg`. This is just a helper + * predicate that maps ArgumentPositions to the arguments of the underlying `CallNode`. + */ +private predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { + exists(int index | + apos.isPositional(index) and + arg.asCfgNode() = call.getArg(index) + ) + or + exists(string name | + apos.isKeyword(name) and + arg.asCfgNode() = call.getArgByName(name) + ) +} + +/** + * Gets the argument of `call` at position `apos`, if any, where we can resolve `call` + * to `target` with CallType `type`. + * + * It might seem like it's enough to know the CallType to resolve arguments. The reason + * we also need the `target`, is to avoid cross-talk. In the example below, assuming + * that `Foo` and `Bar` define their own `meth` methods, we might end up passing _both_ + * `foo` and `bar` to both `Foo.meth` and `Bar.meth`, which is wrong. Since the + * attribute access uses the same name, we need to also distinguish on the resolved + * target, to know which of the two objects to pass as the self argument. + * + * + * ```py + * foo = Foo() + * bar = Bar() + * if cond: + * func = foo.meth + * else: + * func = bar.meth + * func(42) + * ``` + * + * Note: If `Bar.meth` and `Foo.meth` resolves to the same function, we will end up + * sending both `self` arguments to that function, which is by definition the right thing to do. + */ +predicate getCallArg( + ControlFlowNode call, Function target, CallType type, Node arg, ArgumentPosition apos +) { + // normal calls with a real call node + resolveCall(call, target, type) and + call instanceof CallNode and + ( + type instanceof CallTypePlainFunction and + normalCallArg(call, arg, apos) + or + // self argument for normal method calls + type instanceof CallTypeNormalMethod and + apos.isSelf() and + resolveMethodCall(call, target, type, arg) and + // dataflow lib has requirement that arguments and calls are in same enclosing callable. + exists(CfgNode cfgNode | cfgNode.getNode() = call | + cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() + ) + or + // cls argument for classmethod calls + type instanceof CallTypeClassMethod and + apos.isSelf() and + resolveMethodCall(call, target, type, arg) and + arg = classTracker(_) and + // dataflow lib has requirement that arguments and calls are in same enclosing callable. + exists(CfgNode cfgNode | cfgNode.getNode() = call | + cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() + ) + or + // normal arguments for method calls + ( + type instanceof CallTypeNormalMethod or + type instanceof CallTypeStaticMethod or + type instanceof CallTypeClassMethod + ) and + normalCallArg(call, arg, apos) + or + // method as plain function call. + // + // argument index 0 of call has position self (and MUST be given as positional + // argument in call). This also means that call-arguments are shifted by 1, such + // that argument index 1 of call has argument position 0 + type instanceof CallTypeMethodAsPlainFunction and + ( + apos.isSelf() and arg.asCfgNode() = call.(CallNode).getArg(0) + or + not apos.isPositional(_) and normalCallArg(call, arg, apos) + or + exists(ArgumentPosition normalPos, int index | + apos.isPositional(index - 1) and + normalPos.isPositional(index) and + normalCallArg(call, arg, normalPos) + ) + ) + or + // class call + type instanceof CallTypeClass and + ( + apos.isSelf() and + arg = TSyntheticPreUpdateNode(call) + or + normalCallArg(call, arg, apos) + ) + ) +} + +// ============================================================================= +// DataFlowCall +// ============================================================================= newtype TDataFlowCall = - // TODO(call-graph): implement this! - MkDataFlowCall() or + TNormalCall(CallNode call, Function target, CallType type) { resolveCall(call, target, type) } + or /** A synthesized call inside a summarized callable */ TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) { FlowSummaryImpl::Private::summaryCallbackRange(c, receiver) @@ -151,11 +1003,44 @@ abstract class DataFlowCall extends TDataFlowCall { /** A call found in the program source (as opposed to a synthesised call). */ abstract class ExtractedDataFlowCall extends DataFlowCall { - ExtractedDataFlowCall() { exists(this.getNode()) } - override Location getLocation() { result = this.getNode().getLocation() } } +/** + * A resolved call in source code with an underlying `CallNode`. + * + * This is considered normal, compared with special calls such as `obj[0]` calling the + * `__getitem__` method on the object. + */ +class NormalCall extends ExtractedDataFlowCall, TNormalCall { + CallNode call; + Function target; + CallType type; + + NormalCall() { this = TNormalCall(call, target, type) } + + override string toString() { + // note: if we used toString directly on the CallNode we would get + // `ControlFlowNode for func()` + // but the `ControlFlowNode` part is just clutter, so we go directly to the AST node + // instead. + result = call.getNode().toString() + } + + override ControlFlowNode getNode() { result = call } + + override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getScope() } + + override DataFlowCallable getCallable() { result.(DataFlowFunction).getScope() = target } + + override ArgumentNode getArgument(ArgumentPosition apos) { + getCallArg(call, target, type, result, apos) + } + + /** Gets the `CallType` of this call. */ + CallType getCallType() { result = type } +} + /** * A call to a summarized callable, a `LibraryCallable`. * @@ -239,6 +1124,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall { * flow graph. */ abstract class ParameterNodeImpl extends Node { + /** Gets the `Parameter` this `ParameterNode` represents. */ abstract Parameter getParameter(); /** @@ -316,7 +1202,7 @@ private class SummaryArgumentNode extends SummaryNode, ArgumentNode { } } -private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode { +private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNodeImpl { private Node pre; SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) } @@ -338,6 +1224,9 @@ DataFlowCallable viableCallable(ExtractedDataFlowCall call) { ) } +// ============================================================================= +// Remaining required data-flow things +// ============================================================================= private newtype TReturnKind = TNormalReturnKind() /** diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 33a5558d232..8c4c807d3a8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -39,157 +39,47 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) //-------- predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr } -/** DEPRECATED: Alias for `SyntheticPreUpdateNode` */ -deprecated module syntheticPreUpdateNode = SyntheticPreUpdateNode; +class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { + CallNode node; -/** A module collecting the different reasons for synthesising a pre-update node. */ -module SyntheticPreUpdateNode { - class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { - NeedsSyntheticPreUpdateNode post; + SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(node) } - SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(post) } + /** Gets the node for which this is a synthetic pre-update node. */ + CfgNode getPostUpdateNode() { result.getNode() = node } - /** Gets the node for which this is a synthetic pre-update node. */ - Node getPostUpdateNode() { result = post } + override string toString() { result = "[pre] " + node.toString() } - override string toString() { result = "[pre " + post.label() + "] " + post.toString() } + override Scope getScope() { result = node.getScope() } - override Scope getScope() { result = post.getScope() } - - override Location getLocation() { result = post.getLocation() } - } - - /** A data flow node for which we should synthesise an associated pre-update node. */ - class NeedsSyntheticPreUpdateNode extends PostUpdateNode { - NeedsSyntheticPreUpdateNode() { this = objectCreationNode() } - - override Node getPreUpdateNode() { result.(SyntheticPreUpdateNode).getPostUpdateNode() = this } - - /** - * Gets the label for this kind of node. This will figure in the textual representation of the synthesized pre-update node. - * - * There is currently only one reason for needing a pre-update node, so we always use that as the label. - */ - string label() { result = "objCreate" } - } - - /** - * Calls to constructors are treated as post-update nodes for the synthesized argument - * that is mapped to the `self` parameter. That way, constructor calls represent the value of the - * object after the constructor (currently only `__init__`) has run. - */ - CfgNode objectCreationNode() { - // TODO(call-graph): implement this! - none() - // result.getNode().(CallNode) = any(ClassCall c).getNode() - } + override Location getLocation() { result = node.getLocation() } } -import SyntheticPreUpdateNode - -/** DEPRECATED: Alias for `SyntheticPostUpdateNode` */ -deprecated module syntheticPostUpdateNode = SyntheticPostUpdateNode; - -/** A module collecting the different reasons for synthesising a post-update node. */ -module SyntheticPostUpdateNode { - /** A post-update node is synthesized for all nodes which satisfy `NeedsSyntheticPostUpdateNode`. */ - class SyntheticPostUpdateNode extends PostUpdateNode, TSyntheticPostUpdateNode { - NeedsSyntheticPostUpdateNode pre; - - SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(pre) } - - override Node getPreUpdateNode() { result = pre } - - override string toString() { result = "[post " + pre.label() + "] " + pre.toString() } - - override Scope getScope() { result = pre.getScope() } - - override Location getLocation() { result = pre.getLocation() } - } - - /** A data flow node for which we should synthesise an associated post-update node. */ - class NeedsSyntheticPostUpdateNode extends Node { - NeedsSyntheticPostUpdateNode() { - this = argumentPreUpdateNode() - or - this = storePreUpdateNode() - or - this = readPreUpdateNode() - } - - /** - * Gets the label for this kind of node. This will figure in the textual representation of the synthesized post-update node. - * We favour being an arguments as the reason for the post-update node in case multiple reasons apply. - */ - string label() { - if this = argumentPreUpdateNode() - then result = "arg" - else - if this = storePreUpdateNode() - then result = "store" - else result = "read" - } - } - - /** - * Gets the pre-update node for this node. - * - * An argument might have its value changed as a result of a call. - * Certain arguments, such as implicit self arguments are already post-update nodes - * and should not have an extra node synthesised. - */ - Node argumentPreUpdateNode() { - // TODO(call-graph): implement this! - none() - // result = any(FunctionCall c).getArg(_) - // or - // // Avoid argument 0 of method calls as those have read post-update nodes. - // exists(MethodCall c, int n | n > 0 | result = c.getArg(n)) - // or - // result = any(SpecialCall c).getArg(_) - // or - // // Avoid argument 0 of class calls as those have non-synthetic post-update nodes. - // exists(ClassCall c, int n | n > 0 | result = c.getArg(n)) - // or - // // any argument of any call that we have not been able to resolve - // exists(CallNode call | not call = any(DataFlowCall c).getNode() | - // result.(CfgNode).getNode() in [call.getArg(_), call.getArgByName(_)] - // ) - } - - /** Gets the pre-update node associated with a store. This is used for when an object might have its value changed after a store. */ - CfgNode storePreUpdateNode() { - exists(Attribute a | - result.getNode() = a.getObject().getAFlowNode() and - a.getCtx() instanceof Store - ) - } - - /** - * Gets a node marking the state change of an object after a read. - * - * A reverse read happens when the result of a read is modified, e.g. in - * ```python - * l = [ mutable ] - * l[0].mutate() - * ``` - * we may now have changed the content of `l`. To track this, there must be - * a postupdate node for `l`. - */ - CfgNode readPreUpdateNode() { - exists(Attribute a | - result.getNode() = a.getObject().getAFlowNode() and - a.getCtx() instanceof Load - ) - or - result.getNode() = any(SubscriptNode s).getObject() - or - // The dictionary argument is read from if the callable has parameters matching the keys. - result.getNode().getNode() = any(Call call).getKwargs() - } +abstract class PostUpdateNodeImpl extends Node { + /** Gets the node before the state update. */ + abstract Node getPreUpdateNode(); } -import SyntheticPostUpdateNode +class SyntheticPostUpdateNode extends PostUpdateNodeImpl, TSyntheticPostUpdateNode { + ControlFlowNode node; + + SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(node) } + + override Node getPreUpdateNode() { result.(CfgNode).getNode() = node } + + override string toString() { result = "[post] " + node.toString() } + + override Scope getScope() { result = node.getScope() } + + override Location getLocation() { result = node.getLocation() } +} + +class NonSyntheticPostUpdateNode extends PostUpdateNodeImpl, CfgNode { + SyntheticPreUpdateNode pre; + + NonSyntheticPostUpdateNode() { this = pre.getPostUpdateNode() } + + override Node getPreUpdateNode() { result = pre } +} class DataFlowExpr = Expr; diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 5eaff0815af..aa48df91c0c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -31,10 +31,41 @@ newtype TNode = or node.getNode() instanceof Pattern } or - /** A synthetic node representing the value of an object before a state change */ - TSyntheticPreUpdateNode(NeedsSyntheticPreUpdateNode post) or - /** A synthetic node representing the value of an object after a state change. */ - TSyntheticPostUpdateNode(NeedsSyntheticPostUpdateNode pre) or + /** + * A synthetic node representing the value of an object before a state change. + * + * For class calls we pass a synthetic self argument, so attribute writes in + * `__init__` is reflected on the resulting object (we need special logic for this + * since there is no `return` in `__init__`) + */ + // NOTE: since we can't rely on the call graph, but we want to have synthetic + // pre-update nodes for class calls, we end up getting synthetic pre-update nodes for + // ALL calls :| + TSyntheticPreUpdateNode(CallNode call) or + /** + * A synthetic node representing the value of an object after a state change. + * See QLDoc for `PostUpdateNode`. + */ + TSyntheticPostUpdateNode(ControlFlowNode node) { + exists(CallNode call | + node = call.getArg(_) + or + node = call.getArgByName(_) + ) + or + node = any(AttrNode a).getObject() + or + node = any(SubscriptNode s).getObject() + or + // self parameter when used implicitly in `super()` + exists(Class cls, Function func, ParameterDefinition def | + func = cls.getAMethod() and + not hasStaticmethodDecorator(func) and + // this matches what we do in ParameterNode + def.getDefiningNode() = node and + def.getParameter() = func.getArg(0) + ) + } or /** A node representing a global (module-level) variable in a specific module. */ TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m and @@ -270,13 +301,9 @@ class ExtractedParameterNode extends ParameterNodeImpl, CfgNode { ExtractedParameterNode() { node = def.getDefiningNode() } override predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos) { - // TODO(call-graph): implement this! - none() + this = c.getParameter(ppos) } - override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) } - - /** Gets the `Parameter` this `ParameterNode` represents. */ override Parameter getParameter() { result = def.getParameter() } } @@ -294,16 +321,16 @@ abstract class ArgumentNode extends Node { final ExtractedDataFlowCall getCall() { this.argumentOf(result, _) } } -/** A data flow node that represents a call argument found in the source code. */ +/** + * A data flow node that represents a call argument found in the source code, + * where the call can be resolved. + */ class ExtractedArgumentNode extends ArgumentNode { - ExtractedArgumentNode() { this = any(ExtractedDataFlowCall c).getArgument(_) } + ExtractedArgumentNode() { getCallArg(_, _, _, this, _) } final override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { - this.extractedArgumentOf(call, pos) - } - - predicate extractedArgumentOf(ExtractedDataFlowCall call, ArgumentPosition pos) { - this = call.getArgument(pos) + this = call.getArgument(pos) and + call instanceof ExtractedDataFlowCall } } @@ -312,16 +339,17 @@ class ExtractedArgumentNode extends ArgumentNode { * changed its state. * * This can be either the argument to a callable after the callable returns - * (which might have mutated the argument), or the qualifier of a field after - * an update to the field. + * (which might have mutated the argument), the qualifier of a field after + * an update to the field, or a container such as a list/dictionary after an element + * update. * * Nodes corresponding to AST elements, for example `ExprNode`s, usually refer - * to the value before the update with the exception of `ObjectCreationNode`s, + * to the value before the update with the exception of class calls, * which represents the value _after_ the constructor has run. */ -abstract class PostUpdateNode extends Node { +class PostUpdateNode extends Node instanceof PostUpdateNodeImpl { /** Gets the node before the state update. */ - abstract Node getPreUpdateNode(); + Node getPreUpdateNode() { result = super.getPreUpdateNode() } } /** diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index e9c97d86e8c..e00303d750b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -60,22 +60,6 @@ string getPossibleContentName() { result = any(DataFlowPublic::AttrRef a).getAttributeName() } -// /** -// * Gets a callable for the call where `nodeFrom` is used as the `i`'th argument. -// * -// * Helper predicate to avoid bad join order experienced in `callStep`. -// * This happened when `isParameterOf` was joined _before_ `getCallable`. -// */ -// pragma[nomagic] -// private DataFlowPrivate::DataFlowCallable getCallableForArgument( -// DataFlowPublic::ExtractedArgumentNode nodeFrom, int i -// ) { -// exists(DataFlowPrivate::ExtractedDataFlowCall call | -// nodeFrom.extractedArgumentOf(call, i) and -// result = call.getCallable() -// ) -// } - /** * Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. * @@ -83,14 +67,17 @@ string getPossibleContentName() { * recursion (or, at best, terrible performance), since identifying calls to library * methods is done using API graphs (which uses type tracking). */ -predicate callStep(DataFlowPublic::ArgumentNode nodeFrom, DataFlowPrivate::ParameterNodeImpl nodeTo) { - // TODO(call-graph): implement this! - none() - // // TODO: Support special methods? - // exists(DataFlowPrivate::DataFlowCallable callable, int i | - // callable = getCallableForArgument(nodeFrom, i) and - // nodeTo.isParameterOf(callable, i) - // ) +predicate callStep(DataFlowPublic::ArgumentNode nodeFrom, DataFlowPublic::ParameterNode nodeTo) { + // TODO: Fix performance problem with pandas + exists( + DataFlowPrivate::DataFlowCall call, DataFlowPrivate::DataFlowCallable callable, + DataFlowPrivate::ArgumentPosition apos, DataFlowPrivate::ParameterPosition ppos + | + nodeFrom = call.getArgument(apos) and + nodeTo = callable.getParameter(ppos) and + DataFlowPrivate::parameterMatch(ppos, apos) and + callable = call.getCallable() + ) } /** Holds if `nodeFrom` steps to `nodeTo` by being returned from a call. */ diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index a5d03063f54..cdb143017db 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -102,15 +102,26 @@ module TypeTrackingBasedCallGraph { /** A call that can be resolved by type-tracking. */ class ResolvableCall extends RelevantCall { - TT::DataFlowCallable dataflowTarget; - - ResolvableCall() { dataflowTarget = TT::viableCallable(TT::TNormalCall(this)) } + ResolvableCall() { + exists(TT::TNormalCall(this, _, _)) + or + TT::resolveClassCall(this, _) + } /** Gets a resolved target of this call. */ Target getTarget() { - result.(TargetFunction).getFunction() = dataflowTarget.(TT::DataFlowFunction).getScope() - // TODO: class calls - // result.(TargetClass).getClass() + exists(TT::DataFlowCall call, TT::CallType ct, Function targetFunc | + call = TT::TNormalCall(this, targetFunc, ct) and + not ct instanceof TT::CallTypeClass and + targetFunc = result.(TargetFunction).getFunction() + ) + or + // a TT::TNormalCall only exists when the call can be resolved to a function. + // Since points-to just says the call goes directly to the class itself, and + // type-tracking based wants to resolve this to the constructor, which might not + // exist. So to do a proper comparison, we don't require the call to be resolve to + // a specific function. + TT::resolveClassCall(this, result.(TargetClass).getClass()) } } diff --git a/python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql b/python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql new file mode 100644 index 00000000000..dc27dcf262c --- /dev/null +++ b/python/ql/src/meta/analysis-quality/TTCallGraphNewAmbiguous.ql @@ -0,0 +1,19 @@ +/** + * @name New call graph edge from using type-tracking instead of points-to, that is ambiguous + * @kind problem + * @problem.severity recommendation + * @id py/meta/call-graph-new-ambiguous + * @tags meta + * @precision very-low + */ + +import python +import CallGraphQuality + +from CallNode call, Target target +where + target.isRelevant() and + not call.(PointsToBasedCallGraph::ResolvableCall).getTarget() = target and + call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget() = target and + 1 < count(call.(TypeTrackingBasedCallGraph::ResolvableCall).getTarget()) +select call, "NEW: $@ to $@", call, "Call", target, target.toString() diff --git a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll index e96922bc25e..36b603baa78 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/RoutingTest.qll @@ -26,29 +26,30 @@ abstract class RoutingTest extends InlineExpectationsTest { element = fromNode.toString() and ( tag = this.flowTag() and - if "\"" + tag + "\"" = this.fromValue(fromNode) - then value = "" - else value = this.fromValue(fromNode) + if "\"" + tag + "\"" = fromValue(fromNode) then value = "" else value = fromValue(fromNode) or + // only have result for `func` tag if the function where `arg` is used, is + // different from the function name of the call where `arg` was specified as + // an argument tag = "func" and - value = this.toFunc(toNode) and - not value = this.fromFunc(fromNode) + value = toFunc(toNode) and + not value = fromFunc(fromNode) ) ) } - - pragma[inline] - private string fromValue(DataFlow::Node fromNode) { - result = "\"" + prettyNode(fromNode).replaceAll("\"", "'") + "\"" - } - - pragma[inline] - private string fromFunc(DataFlow::ArgumentNode fromNode) { - result = fromNode.getCall().getNode().(CallNode).getFunction().getNode().(Name).getId() - } - - pragma[inline] - private string toFunc(DataFlow::Node toNode) { - result = toNode.getEnclosingCallable().getCallableValue().getScope().getQualifiedName() // TODO: More robust pretty printing? - } +} + +pragma[inline] +private string fromValue(DataFlow::Node fromNode) { + result = "\"" + prettyNode(fromNode).replaceAll("\"", "'") + "\"" +} + +pragma[inline] +private string fromFunc(DataFlow::ArgumentNode fromNode) { + result = fromNode.getCall().getNode().(CallNode).getFunction().getNode().(Name).getId() +} + +pragma[inline] +private string toFunc(DataFlow::Node toNode) { + result = toNode.getEnclosingCallable().getQualifiedName() } diff --git a/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected b/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected index 01ae02a1ad0..17f3028ae23 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected +++ b/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected @@ -1,3 +1,2 @@ -| file://:0:0:0:0 | parameter 0 of builtins.reversed | | test.py:1:19:1:19 | ControlFlowNode for x | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/basic/callGraphSources.expected b/python/ql/test/experimental/dataflow/basic/callGraphSources.expected index 0b4613c42de..4023ba8f3ea 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphSources.expected +++ b/python/ql/test/experimental/dataflow/basic/callGraphSources.expected @@ -1,3 +1,2 @@ -| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:7:19:7:19 | ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/basic/global.expected b/python/ql/test/experimental/dataflow/basic/global.expected index 885d61309d4..8894bcc190a 100644 --- a/python/ql/test/experimental/dataflow/basic/global.expected +++ b/python/ql/test/experimental/dataflow/basic/global.expected @@ -1,4 +1,3 @@ -| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | diff --git a/python/ql/test/experimental/dataflow/basic/globalStep.expected b/python/ql/test/experimental/dataflow/basic/globalStep.expected index 38611776824..9f228998b9c 100644 --- a/python/ql/test/experimental/dataflow/basic/globalStep.expected +++ b/python/ql/test/experimental/dataflow/basic/globalStep.expected @@ -1,4 +1,3 @@ -| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 33636a8e81d..74263f31a52 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -1,8 +1,3 @@ -| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | -| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | -| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | -| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | -| file://:0:0:0:0 | parameter 0 of builtins.reversed | file://:0:0:0:0 | parameter 0 of builtins.reversed | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | @@ -55,5 +50,6 @@ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | +| test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:19:7:19 | [post arg] ControlFlowNode for a | test.py:7:19:7:19 | [post arg] ControlFlowNode for a | +| test.py:7:19:7:19 | [post] ControlFlowNode for a | test.py:7:19:7:19 | [post] ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/basic/localStep.expected b/python/ql/test/experimental/dataflow/basic/localStep.expected index 900e4ac3900..e147bb9f4fc 100644 --- a/python/ql/test/experimental/dataflow/basic/localStep.expected +++ b/python/ql/test/experimental/dataflow/basic/localStep.expected @@ -1,4 +1,3 @@ -| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index 3aa3245c465..97d7e313dac 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -1,7 +1,3 @@ -| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | -| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | -| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | -| file://:0:0:0:0 | parameter 0 of builtins.reversed | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | @@ -26,5 +22,6 @@ | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | +| test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:19:7:19 | [post arg] ControlFlowNode for a | +| test.py:7:19:7:19 | [post] ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index 3aa3245c465..97d7e313dac 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -1,7 +1,3 @@ -| file://:0:0:0:0 | [summary] read: argument 0.List element in builtins.reversed | -| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | -| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | -| file://:0:0:0:0 | parameter 0 of builtins.reversed | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | @@ -26,5 +22,6 @@ | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | +| test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:19:7:19 | [post arg] ControlFlowNode for a | +| test.py:7:19:7:19 | [post] ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.expected b/python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.expected new file mode 100644 index 00000000000..99c2d987d16 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.expected @@ -0,0 +1,13 @@ +| test.py:32:8:32:23 | CrosstalkTestX() | test.py:9:5:9:23 | Function __init__ | test.py:32:8:32:23 | [pre] ControlFlowNode for CrosstalkTestX() | self | +| test.py:33:8:33:23 | CrosstalkTestY() | test.py:21:5:21:23 | Function __init__ | test.py:33:8:33:23 | [pre] ControlFlowNode for CrosstalkTestY() | self | +| test.py:43:1:43:8 | func() | test.py:13:5:13:26 | Function setx | test.py:36:12:36:15 | ControlFlowNode for objx | self | +| test.py:43:1:43:8 | func() | test.py:13:5:13:26 | Function setx | test.py:43:6:43:7 | ControlFlowNode for IntegerLiteral | position 0 | +| test.py:43:1:43:8 | func() | test.py:25:5:25:26 | Function sety | test.py:38:12:38:15 | ControlFlowNode for objy | self | +| test.py:43:1:43:8 | func() | test.py:25:5:25:26 | Function sety | test.py:43:6:43:7 | ControlFlowNode for IntegerLiteral | position 0 | +| test.py:51:1:51:8 | func() | test.py:16:5:16:30 | Function setvalue | test.py:47:12:47:15 | ControlFlowNode for objx | self | +| test.py:51:1:51:8 | func() | test.py:16:5:16:30 | Function setvalue | test.py:51:6:51:7 | ControlFlowNode for IntegerLiteral | position 0 | +| test.py:51:1:51:8 | func() | test.py:28:5:28:30 | Function setvalue | test.py:49:12:49:15 | ControlFlowNode for objy | self | +| test.py:51:1:51:8 | func() | test.py:28:5:28:30 | Function setvalue | test.py:51:6:51:7 | ControlFlowNode for IntegerLiteral | position 0 | +| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:63:12:63:12 | ControlFlowNode for a | self | +| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:70:6:70:7 | ControlFlowNode for IntegerLiteral | position 0 | +| test.py:70:1:70:8 | func() | test.py:58:5:58:33 | Function foo | test.py:70:6:70:7 | ControlFlowNode for IntegerLiteral | self | diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.ql b/python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.ql new file mode 100644 index 00000000000..28699b1f9a7 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/Arguments.ql @@ -0,0 +1,9 @@ +private import python +private import semmle.python.dataflow.new.internal.DataFlowPrivate +private import semmle.python.dataflow.new.internal.DataFlowPublic + +from DataFlowCall call, DataFlowCallable callable, ArgumentNode arg, ArgumentPosition apos +where + callable = call.getCallable() and + arg = call.getArgument(apos) +select call, callable, arg, apos diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected new file mode 100644 index 00000000000..9fedaf9f663 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected @@ -0,0 +1,19 @@ +uniqueEnclosingCallable +uniqueType +uniqueNodeLocation +missingLocation +uniqueNodeToString +missingToString +parameterCallable +localFlowIsLocal +compatibleTypesReflexive +unreachableNodeCCtx +localCallNodes +postIsNotPre +postHasUniquePre +uniquePostUpdate +postIsInSameCallable +reverseRead +argHasPostUpdate +postWithInFlow +viableImplInCallContextTooLarge diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql new file mode 100644 index 00000000000..6743fa10d27 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql @@ -0,0 +1 @@ +import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/options b/python/ql/test/experimental/dataflow/callgraph_crosstalk/options new file mode 100644 index 00000000000..efa237f03c4 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=0 diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/test.py b/python/ql/test/experimental/dataflow/callgraph_crosstalk/test.py new file mode 100644 index 00000000000..1b676d30b89 --- /dev/null +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/test.py @@ -0,0 +1,70 @@ +import random +cond = random.randint(0,1) == 1 + +# ------------------------------------------------------------------------------ +# Calling different bound-methods based on conditional +# ------------------------------------------------------------------------------ + +class CrosstalkTestX: + def __init__(self): + self.x = None + self.y = None + + def setx(self, value): + self.x = value + + def setvalue(self, value): + self.x = value + + +class CrosstalkTestY: + def __init__(self): + self.x = None + self.y = None + + def sety(self ,value): + self.y = value + + def setvalue(self, value): + self.y = value + + +objx = CrosstalkTestX() +objy = CrosstalkTestY() + +if cond: + func = objx.setx +else: + func = objy.sety + +# What we're testing for is whether both objects are passed as self to both methods, +# which is wrong. + +func(42) + + +if cond: + func = objx.setvalue +else: + func = objy.setvalue + +func(43) + +# ------------------------------------------------------------------------------ +# Calling methods in different ways +# ------------------------------------------------------------------------------ + +class A(object): + def foo(self, arg="Default"): + print("A.foo", self, arg) + +a = A() +if cond: + func = a.foo # `44` is passed as arg +else: + func = A.foo # `44` is passed as self + +# What we're testing for is whether a single call ends up having both `a` and `44` is +# passed as self to `A.foo`, which is wrong. + +func(44) diff --git a/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql b/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql index 4536e8f40ad..b71e92db337 100644 --- a/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql +++ b/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql @@ -1,6 +1,6 @@ import python import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.internal.DataFlowPrivate +import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch import TestUtilities.InlineExpectationsTest private import semmle.python.dataflow.new.internal.PrintNode @@ -8,26 +8,28 @@ class DataFlowCallTest extends InlineExpectationsTest { DataFlowCallTest() { this = "DataFlowCallTest" } override string getARelevantTag() { - result in ["call", "qlclass"] + result in ["call", "callType"] or - result = "arg_" + [0 .. 10] + result = "arg[" + any(DataFlowDispatch::ArgumentPosition pos).toString() + "]" } override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and - exists(DataFlowCall call | + exists(DataFlowDispatch::DataFlowCall call | location = call.getLocation() and element = call.toString() | value = prettyExpr(call.getNode().getNode()) and tag = "call" or - value = call.getAQlClass() and - tag = "qlclass" + value = call.(DataFlowDispatch::NormalCall).getCallType().toString() and + tag = "callType" or - exists(int n, DataFlow::Node arg | arg = call.getArg(n) | + exists(DataFlowDispatch::ArgumentPosition pos, DataFlow::Node arg | + arg = call.getArgument(pos) + | value = prettyNodeForInlineTest(arg) and - tag = "arg_" + n + tag = "arg[" + pos + "]" ) ) } diff --git a/python/ql/test/experimental/dataflow/calls/test.py b/python/ql/test/experimental/dataflow/calls/test.py index 144a6a79fe1..3332d2caa9e 100644 --- a/python/ql/test/experimental/dataflow/calls/test.py +++ b/python/ql/test/experimental/dataflow/calls/test.py @@ -14,24 +14,60 @@ class MyClass(object): def my_method(self, arg): pass + @staticmethod + def staticmethod(arg): + pass + + @classmethod + def classmethod(cls, arg): + pass + def __getitem__(self, key): pass +func(0) # $ call=func(..) arg[position 0]=0 callType=CallTypePlainFunction -func("foo") # $ call=func(..) qlclass=FunctionCall arg_0="foo" -x = MyClass(1) # $ call=MyClass(..) qlclass=ClassCall arg_0=[pre]MyClass(..) arg_1=1 -x.my_method(2) # $ call=x.my_method(..) qlclass=MethodCall arg_0=x arg_1=2 +x = MyClass(1) # $ call=MyClass(..) arg[self]=[pre]MyClass(..) arg[position 0]=1 callType=CallTypeClass + +x.my_method(2) # $ call=x.my_method(..) arg[self]=x arg[position 0]=2 callType=CallTypeNormalMethod mm = x.my_method -mm(2) # $ call=mm(..) qlclass=MethodCall arg_1=2 MISSING: arg_0=x -x[3] # $ call=x[3] qlclass=SpecialCall arg_0=x arg_1=3 +mm(2) # $ call=mm(..) arg[self]=x arg[position 0]=2 callType=CallTypeNormalMethod +MyClass.my_method(x, 2) # $ call=MyClass.my_method(..) arg[position 0]=2 arg[self]=x callType=CallTypeMethodAsPlainFunction + +x.staticmethod(3) # $ call=x.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod +MyClass.staticmethod(3) # $ call=MyClass.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod + +x.classmethod(4) # $ call=x.classmethod(..) arg[position 0]=4 callType=CallTypeClassMethod +MyClass.classmethod(4) # $ call=MyClass.classmethod(..) arg[position 0]=4 arg[self]=MyClass callType=CallTypeClassMethod + +x[5] # $ MISSING: call=x[5] arg[self]=x arg[position 0]=5 + + +class Subclass(MyClass): + pass + +y = Subclass(1) # $ call=Subclass(..) arg[self]=[pre]Subclass(..) arg[position 0]=1 callType=CallTypeClass + +y.my_method(2) # $ call=y.my_method(..) arg[self]=y arg[position 0]=2 callType=CallTypeNormalMethod +mm = y.my_method +mm(2) # $ call=mm(..) arg[self]=y arg[position 0]=2 callType=CallTypeNormalMethod +Subclass.my_method(y, 2) # $ call=Subclass.my_method(..) arg[self]=y arg[position 0]=2 callType=CallTypeMethodAsPlainFunction + +y.staticmethod(3) # $ call=y.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod +Subclass.staticmethod(3) # $ call=Subclass.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod + +y.classmethod(4) # $ call=y.classmethod(..) arg[position 0]=4 callType=CallTypeClassMethod +Subclass.classmethod(4) # $ call=Subclass.classmethod(..) arg[self]=Subclass arg[position 0]=4 callType=CallTypeClassMethod + +y[5] # $ MISSING: call=y[5] arg[self]=y arg[position 0]=5 try: - # These are included to show how we handle absent things with points-to where - # `mypkg.foo` is a `missing module variable`, but `mypkg.subpkg.bar` is compeltely - # ignored. + # These are included to show whether we have a DataFlowCall for things we can't + # resolve. Both are interesting since with points-to we used to have a DataFlowCall + # for _one_ but not the other import mypkg - mypkg.foo(42) # $ call=mypkg.foo(..) qlclass=NormalCall - mypkg.subpkg.bar(43) # $ call=mypkg.subpkg.bar(..) qlclass=LibraryCall arg_0=43 + mypkg.foo(42) + mypkg.subpkg.bar(43) except: pass diff --git a/python/ql/test/experimental/dataflow/consistency/modeling-consistency.expected b/python/ql/test/experimental/dataflow/consistency/modeling-consistency.expected index 2cbecf5ba66..e69de29bb2d 100644 --- a/python/ql/test/experimental/dataflow/consistency/modeling-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/modeling-consistency.expected @@ -1 +0,0 @@ -| test.py:239:27:239:27 | Parameter | There is no `ParameterNode` associated with this parameter. | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 92b466cd25a..7129cded015 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -64,12 +64,12 @@ def argument_passing( @expects(7) def test_argument_passing1(): - argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg7 func=argument_passing MISSING: arg2 arg3="arg3 arg4 arg5 arg6 + argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 MISSING: arg2 arg3 arg4 arg6 arg7 @expects(7) def test_argument_passing2(): - argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1 arg2 arg3 + argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1 arg2 arg3 arg6 def with_pos_only(a, /, b): @@ -94,8 +94,8 @@ def with_multiple_kw_args(a, b, c): def test_multiple_kw_args(): with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1 arg2 arg3 with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1 MISSING: arg2 arg3 - with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1 arg2 arg3 func=with_multiple_kw_args MISSING: - with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1 arg2 arg3 func=with_multiple_kw_args + with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1 arg2 MISSING: arg3 + with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ MISSING: arg1 arg2 arg3 def with_default_arguments(a=arg1, b=arg2, c=arg3): #$ arg1 arg2 arg3 func=with_default_arguments @@ -109,7 +109,7 @@ def test_default_arguments(): with_default_arguments() with_default_arguments(arg1) #$ arg1 with_default_arguments(b=arg2) #$ arg2 - with_default_arguments(**{"c": arg3}) #$ arg3 func=with_default_arguments + with_default_arguments(**{"c": arg3}) #$ MISSING: arg3 # Nested constructor pattern @@ -135,7 +135,7 @@ def grab_baz(baz): @expects(4) def test_grab(): - grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1 arg2 arg3 func=grab_bar_baz func=grab_baz + grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1 MISSING: arg2 func=grab_bar_baz arg3 func=grab_baz # All combinations @@ -158,7 +158,7 @@ def test_pos_star(): if len(a) > 0: SINK1(a[0]) - with_star(arg1) #$ arg1 func=test_pos_star.with_star + with_star(arg1) #$ MISSING: arg1 func=test_pos_star.with_star def test_pos_kw(): @@ -186,4 +186,4 @@ def test_kw_doublestar(): def with_doublestar(**a): SINK1(a["a"]) - with_doublestar(a=arg1) #$ arg1 func=test_kw_doublestar.with_doublestar + with_doublestar(a=arg1) #$ MISSING: arg1 func=test_kw_doublestar.with_doublestar diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 0636eafcd7b..af8d19354e7 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -560,9 +560,9 @@ class With_getitem: def test_getitem(): - with_getitem = With_getitem() #$ arg1="SSA variable with_getitem" func=With_getitem.__getitem__ + with_getitem = With_getitem() #$ MISSING: arg1="SSA variable with_getitem" func=With_getitem.__getitem__ arg2 = 0 - with_getitem[arg2] #$ arg2 func=With_getitem.__getitem__ + with_getitem[arg2] #$ MISSING: arg2 func=With_getitem.__getitem__ # object.__setitem__(self, key, value) @@ -575,10 +575,10 @@ class With_setitem: def test_setitem(): - with_setitem = With_setitem() #$ arg1="SSA variable with_setitem" func=With_setitem.__setitem__ + with_setitem = With_setitem() #$ MISSING: arg1="SSA variable with_setitem" func=With_setitem.__setitem__ arg2 = 0 arg3 = "" - with_setitem[arg2] = arg3 #$ arg2 arg3 func=With_setitem.__setitem__ + with_setitem[arg2] = arg3 #$ MISSING: arg2 arg3 func=With_setitem.__setitem__ # object.__delitem__(self, key) @@ -590,9 +590,9 @@ class With_delitem: def test_delitem(): - with_delitem = With_delitem() #$ arg1="SSA variable with_delitem" func=With_delitem.__delitem__ + with_delitem = With_delitem() #$ MISSING: arg1="SSA variable with_delitem" func=With_delitem.__delitem__ arg2 = 0 - del with_delitem[arg2] #$ arg2 func=With_delitem.__delitem__ + del with_delitem[arg2] #$ MISSING: arg2 func=With_delitem.__delitem__ # object.__missing__(self, key) @@ -662,9 +662,9 @@ class With_add: def test_add(): - with_add = With_add() #$ arg1="SSA variable with_add" func=With_add.__add__ + with_add = With_add() #$ MISSING: arg1="SSA variable with_add" func=With_add.__add__ arg2 = with_add - with_add + arg2 #$ arg2 func=With_add.__add__ + with_add + arg2 #$ MISSING: arg2 func=With_add.__add__ # object.__sub__(self, other) @@ -677,9 +677,9 @@ class With_sub: def test_sub(): - with_sub = With_sub() #$ arg1="SSA variable with_sub" func=With_sub.__sub__ + with_sub = With_sub() #$ MISSING: arg1="SSA variable with_sub" func=With_sub.__sub__ arg2 = with_sub - with_sub - arg2 #$ arg2 func=With_sub.__sub__ + with_sub - arg2 #$ MISSING: arg2 func=With_sub.__sub__ # object.__mul__(self, other) @@ -692,9 +692,9 @@ class With_mul: def test_mul(): - with_mul = With_mul() #$ arg1="SSA variable with_mul" func=With_mul.__mul__ + with_mul = With_mul() #$ MISSING: arg1="SSA variable with_mul" func=With_mul.__mul__ arg2 = with_mul - with_mul * arg2 #$ arg2 func=With_mul.__mul__ + with_mul * arg2 #$ MISSING: arg2 func=With_mul.__mul__ # object.__matmul__(self, other) @@ -707,9 +707,9 @@ class With_matmul: def test_matmul(): - with_matmul = With_matmul() #$ arg1="SSA variable with_matmul" func=With_matmul.__matmul__ + with_matmul = With_matmul() #$ MISSING: arg1="SSA variable with_matmul" func=With_matmul.__matmul__ arg2 = with_matmul - with_matmul @ arg2 #$ arg2 func=With_matmul.__matmul__ + with_matmul @ arg2 #$ MISSING: arg2 func=With_matmul.__matmul__ # object.__truediv__(self, other) @@ -722,9 +722,9 @@ class With_truediv: def test_truediv(): - with_truediv = With_truediv() #$ arg1="SSA variable with_truediv" func=With_truediv.__truediv__ + with_truediv = With_truediv() #$ MISSING: arg1="SSA variable with_truediv" func=With_truediv.__truediv__ arg2 = with_truediv - with_truediv / arg2 #$ arg2 func=With_truediv.__truediv__ + with_truediv / arg2 #$ MISSING: arg2 func=With_truediv.__truediv__ # object.__floordiv__(self, other) @@ -737,9 +737,9 @@ class With_floordiv: def test_floordiv(): - with_floordiv = With_floordiv() #$ arg1="SSA variable with_floordiv" func=With_floordiv.__floordiv__ + with_floordiv = With_floordiv() #$ MISSING: arg1="SSA variable with_floordiv" func=With_floordiv.__floordiv__ arg2 = with_floordiv - with_floordiv // arg2 #$ arg2 func=With_floordiv.__floordiv__ + with_floordiv // arg2 #$ MISSING: arg2 func=With_floordiv.__floordiv__ # object.__mod__(self, other) @@ -752,9 +752,9 @@ class With_mod: def test_mod(): - with_mod = With_mod() #$ arg1="SSA variable with_mod" func=With_mod.__mod__ + with_mod = With_mod() #$ MISSING: arg1="SSA variable with_mod" func=With_mod.__mod__ arg2 = with_mod - with_mod % arg2 #$ arg2 func=With_mod.__mod__ + with_mod % arg2 #$ MISSING: arg2 func=With_mod.__mod__ # object.__divmod__(self, other) @@ -788,9 +788,9 @@ def test_pow(): def test_pow_op(): - with_pow = With_pow() #$ arg1="SSA variable with_pow" func=With_pow.__pow__ + with_pow = With_pow() #$ MISSING: arg1="SSA variable with_pow" func=With_pow.__pow__ arg2 = with_pow - with_pow ** arg2 #$ arg2 func=With_pow.__pow__ + with_pow ** arg2 #$ MISSING: arg2 func=With_pow.__pow__ # object.__lshift__(self, other) @@ -803,9 +803,9 @@ class With_lshift: def test_lshift(): - with_lshift = With_lshift() #$ arg1="SSA variable with_lshift" func=With_lshift.__lshift__ + with_lshift = With_lshift() #$ MISSING: arg1="SSA variable with_lshift" func=With_lshift.__lshift__ arg2 = with_lshift - with_lshift << arg2 #$ arg2 func=With_lshift.__lshift__ + with_lshift << arg2 #$ MISSING: arg2 func=With_lshift.__lshift__ # object.__rshift__(self, other) @@ -818,9 +818,9 @@ class With_rshift: def test_rshift(): - with_rshift = With_rshift() #$ arg1="SSA variable with_rshift" func=With_rshift.__rshift__ + with_rshift = With_rshift() #$ MISSING: arg1="SSA variable with_rshift" func=With_rshift.__rshift__ arg2 = with_rshift - with_rshift >> arg2 #$ arg2 func=With_rshift.__rshift__ + with_rshift >> arg2 #$ MISSING: arg2 func=With_rshift.__rshift__ # object.__and__(self, other) @@ -833,9 +833,9 @@ class With_and: def test_and(): - with_and = With_and() #$ arg1="SSA variable with_and" func=With_and.__and__ + with_and = With_and() #$ MISSING: arg1="SSA variable with_and" func=With_and.__and__ arg2 = with_and - with_and & arg2 #$ arg2 func=With_and.__and__ + with_and & arg2 #$ MISSING: arg2 func=With_and.__and__ # object.__xor__(self, other) @@ -848,9 +848,9 @@ class With_xor: def test_xor(): - with_xor = With_xor() #$ arg1="SSA variable with_xor" func=With_xor.__xor__ + with_xor = With_xor() #$ MISSING: arg1="SSA variable with_xor" func=With_xor.__xor__ arg2 = with_xor - with_xor ^ arg2 #$ arg2 func=With_xor.__xor__ + with_xor ^ arg2 #$ MISSING: arg2 func=With_xor.__xor__ # object.__or__(self, other) @@ -863,9 +863,9 @@ class With_or: def test_or(): - with_or = With_or() #$ arg1="SSA variable with_or" func=With_or.__or__ + with_or = With_or() #$ MISSING: arg1="SSA variable with_or" func=With_or.__or__ arg2 = with_or - with_or | arg2 #$ arg2 func=With_or.__or__ + with_or | arg2 #$ MISSING: arg2 func=With_or.__or__ # object.__radd__(self, other) diff --git a/python/ql/test/experimental/dataflow/coverage/datamodel.py b/python/ql/test/experimental/dataflow/coverage/datamodel.py index 364dbb299d7..e30ffea164a 100644 --- a/python/ql/test/experimental/dataflow/coverage/datamodel.py +++ b/python/ql/test/experimental/dataflow/coverage/datamodel.py @@ -124,6 +124,40 @@ def test_staticmethod_call(): C.staticmethod(arg1, arg2) # $ func=C.staticmethod arg1 arg2 +# subclass +class SC(C): + pass +sc = SC() + +@expects(6) +def test_subclass_method_call(): + func_obj = sc.method.__func__ + + sc.method(arg1, arg2) # $ func=C.method arg1 arg2 + SC.method(sc, arg1, arg2) # $ func=C.method arg1 arg2 + func_obj(sc, arg1, arg2) # $ MISSING: func=C.method arg1 arg2 + + +@expects(6) +def test_subclass_classmethod_call(): + c_func_obj = SC.classmethod.__func__ + + sc.classmethod(arg1, arg2) # $ func=C.classmethod arg1 arg2 + SC.classmethod(arg1, arg2) # $ func=C.classmethod arg1 arg2 + c_func_obj(SC, arg1, arg2) # $ MISSING: func=C.classmethod arg1 arg2 + + +@expects(5) +def test_subclass_staticmethod_call(): + try: + SC.staticmethod.__func__ + except AttributeError: + print("OK") + + sc.staticmethod(arg1, arg2) # $ func=C.staticmethod arg1 arg2 + SC.staticmethod(arg1, arg2) # $ func=C.staticmethod arg1 arg2 + + # Generator functions # A function or method which uses the yield statement (see section The yield statement) is called a generator function. Such a function, when called, always returns an iterator object which can be used to execute the body of the function: calling the iterator’s iterator.__next__() method will cause the function to execute until it provides a value using the yield statement. When the function executes a return statement or falls off the end, a StopIteration exception is raised and the iterator will have reached the end of the set of values to be returned. def gen(x, count): @@ -198,5 +232,16 @@ class Customized: customized = Customized() SINK(Customized.a) #$ MISSING:flow="SOURCE, l:-8 -> customized.a" SINK_F(Customized.b) -SINK(customized.a) #$ MISSING:flow="SOURCE, l:-10 -> customized.a" +SINK(customized.a) #$ flow="SOURCE, l:-10 -> customized.a" SINK(customized.b) #$ flow="SOURCE, l:-7 -> customized.b" + + +class Test2: + + def __init__(self, arg): + self.x = SOURCE + self.y = arg + +t = Test2(SOURCE) +SINK(t.x) # $ flow="SOURCE, l:-4 -> t.x" +SINK(t.y) # $ flow="SOURCE, l:-2 -> t.y" diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.expected b/python/ql/test/experimental/dataflow/coverage/localFlow.expected index 30b25979df3..7ca11daba51 100644 --- a/python/ql/test/experimental/dataflow/coverage/localFlow.expected +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.expected @@ -8,10 +8,4 @@ | test.py:187:1:187:53 | GSSA Variable SINK | test.py:189:5:189:8 | ControlFlowNode for SINK | | test.py:187:1:187:53 | GSSA Variable SOURCE | test.py:188:25:188:30 | ControlFlowNode for SOURCE | | test.py:188:5:188:5 | SSA variable x | test.py:189:10:189:10 | ControlFlowNode for x | -| test.py:188:9:188:68 | ControlFlowNode for .0 | test.py:188:9:188:68 | SSA variable .0 | | test.py:188:9:188:68 | ControlFlowNode for ListComp | test.py:188:5:188:5 | SSA variable x | -| test.py:188:9:188:68 | SSA variable .0 | test.py:188:9:188:68 | ControlFlowNode for .0 | -| test.py:188:16:188:16 | SSA variable v | test.py:188:45:188:45 | ControlFlowNode for v | -| test.py:188:40:188:40 | SSA variable u | test.py:188:56:188:56 | ControlFlowNode for u | -| test.py:188:51:188:51 | SSA variable z | test.py:188:67:188:67 | ControlFlowNode for z | -| test.py:188:62:188:62 | SSA variable y | test.py:188:10:188:10 | ControlFlowNode for y | diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.ql b/python/ql/test/experimental/dataflow/coverage/localFlow.ql index 6522dcf5c68..8fcbf74c64f 100644 --- a/python/ql/test/experimental/dataflow/coverage/localFlow.ql +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.ql @@ -4,5 +4,5 @@ import semmle.python.dataflow.new.DataFlow from DataFlow::Node nodeFrom, DataFlow::Node nodeTo where DataFlow::localFlowStep(nodeFrom, nodeTo) and - nodeFrom.getEnclosingCallable().getName().matches("%\\_with\\_local\\_flow") + nodeFrom.getEnclosingCallable().getQualifiedName().matches("%\\_with\\_local\\_flow") select nodeFrom, nodeTo diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index b09b2aa9984..0e06a828700 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -393,7 +393,7 @@ def test_call_unpack_iterable(): def test_call_unpack_mapping(): - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ MISSING: flow="SOURCE -> second(..)" def f_extra_pos(a, *b): @@ -401,7 +401,7 @@ def f_extra_pos(a, *b): def test_call_extra_pos(): - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_pos(..)" def f_extra_keyword(a, **b): @@ -409,7 +409,7 @@ def f_extra_keyword(a, **b): def test_call_extra_keyword(): - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_keyword(..)" # return the name of the first extra keyword argument @@ -509,17 +509,17 @@ def test_lambda_unpack_mapping(): def second(a, b): return b - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ MISSING: flow="SOURCE -> second(..)" def test_lambda_extra_pos(): f_extra_pos = lambda a, *b: b[0] - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_pos(..)" def test_lambda_extra_keyword(): f_extra_keyword = lambda a, **b: b["b"] - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_keyword(..)" # call the function with our source as the name of the keyword argument @@ -689,7 +689,7 @@ def test_iterable_star_unpacking_in_for_2(): def iterate_star_args(first, second, *args): for arg in args: - SINK(arg) #$ flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg" + SINK(arg) #$ MISSING: flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg" # FP reported here: https://github.com/github/codeql-python-team/issues/49 @expects(2) @@ -697,9 +697,16 @@ def test_overflow_iteration(): s = SOURCE iterate_star_args(NONSOURCE, NONSOURCE, SOURCE, s) +@expects(6) def test_deep_callgraph(): # port of python/ql/test/library-tests/taint/general/deep.py + # based on the fact that `test_deep_callgraph_defined_in_module` works the problem + # seems to be that we're defining these functions inside another function and that + # the flow of these function definitions DOESN'T flow into the body of the `f` + # functions (they DO flow into the body of `test_deep_callgraph`, otherwise the + # `f1` call wouldn't work). + def f1(arg): return arg @@ -720,8 +727,51 @@ def test_deep_callgraph(): x = f6(SOURCE) SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" + x = f5(SOURCE) + SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" + x = f4(SOURCE) + SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" + x = f3(SOURCE) + SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" + x = f2(SOURCE) + SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x" + x = f1(SOURCE) + SINK(x) #$ flow="SOURCE, l:-1 -> x" +def wat_f1(arg): + return arg + +def wat_f2(arg): + return wat_f1(arg) + +def wat_f3(arg): + return wat_f2(arg) + +def wat_f4(arg): + return wat_f3(arg) + +def wat_f5(arg): + return wat_f4(arg) + +def wat_f6(arg): + return wat_f5(arg) + +@expects(6) +def test_deep_callgraph_defined_in_module(): + x = wat_f6(SOURCE) + SINK(x) #$ flow="SOURCE, l:-1 -> x" + x = wat_f5(SOURCE) + SINK(x) #$ flow="SOURCE, l:-1 -> x" + x = wat_f4(SOURCE) + SINK(x) #$ flow="SOURCE, l:-1 -> x" + x = wat_f3(SOURCE) + SINK(x) #$ flow="SOURCE, l:-1 -> x" + x = wat_f2(SOURCE) + SINK(x) #$ flow="SOURCE, l:-1 -> x" + x = wat_f1(SOURCE) + SINK(x) #$ flow="SOURCE, l:-1 -> x" + @expects(2) def test_dynamic_tuple_creation_1(): tup = tuple() diff --git a/python/ql/test/experimental/dataflow/fieldflow/test.py b/python/ql/test/experimental/dataflow/fieldflow/test.py index 100ab6aac70..68bb71bd278 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/test.py +++ b/python/ql/test/experimental/dataflow/fieldflow/test.py @@ -84,10 +84,10 @@ def test_indirect_assign_bound_method(): sf = myobj.setFoo sf(SOURCE) - SINK(myobj.foo) # $ MISSING: flow="SOURCE, l:-1 -> myobj.foo" + SINK(myobj.foo) # $ flow="SOURCE, l:-1 -> myobj.foo" sf(NONSOURCE) - SINK_F(myobj.foo) + SINK_F(myobj.foo) # $ SPURIOUS: flow="SOURCE, l:-4 -> myobj.foo" @expects(3) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..) @@ -167,6 +167,17 @@ def fields_with_local_flow(x): def test_fields(): SINK(fields_with_local_flow(SOURCE)) # $ flow="SOURCE -> fields_with_local_flow(..)" + +def call_with_source(func): + func(SOURCE) + + +def test_bound_method_passed_as_arg(): + myobj = MyObj(NONSOURCE) + call_with_source(myobj.setFoo) + SINK(myobj.foo) # $ MISSING: flow="SOURCE, l:-5 -> foo.x" + + # ------------------------------------------------------------------------------ # Nested Object # ------------------------------------------------------------------------------ @@ -244,6 +255,9 @@ class CrosstalkTestX: def setvalue(self, value): self.x = value + def do_nothing(self, value): + pass + class CrosstalkTestY: def __init__(self): @@ -295,10 +309,10 @@ def test_potential_crosstalk_different_name(cond=True): func(SOURCE) - SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x" + SINK(objx.x) # $ flow="SOURCE, l:-2 -> objx.x" SINK_F(objx.y) SINK_F(objy.x) - SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y" + SINK(objy.y, not_present_at_runtime=True) # $ flow="SOURCE, l:-5 -> objy.y" @expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..) @@ -318,10 +332,10 @@ def test_potential_crosstalk_same_name(cond=True): func(SOURCE) - SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x" + SINK(objx.x) # $ flow="SOURCE, l:-2 -> objx.x" SINK_F(objx.y) SINK_F(objy.x) - SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y" + SINK(objy.y, not_present_at_runtime=True) # $ flow="SOURCE, l:-5 -> objy.y" @expects(10) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..) @@ -350,6 +364,27 @@ def test_potential_crosstalk_same_name_object_reference(cond=True): SINK(obj.y, not_present_at_runtime=True) # $ flow="SOURCE, l:-8 -> obj.y" +@expects(4) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..) +def test_potential_crosstalk_same_class(cond=True): + objx1 = CrosstalkTestX() + SINK_F(objx1.x) + + objx2 = CrosstalkTestX() + SINK_F(objx2.x) + + if cond: + func = objx1.setvalue + else: + func = objx2.do_nothing + + # We want to ensure that objx2.x does not end up getting tainted, since that would + # be cross-talk between the self arguments are their functions. + func(SOURCE) + + SINK(objx1.x) # $ flow="SOURCE, l:-2 -> objx1.x" + SINK_F(objx2.x) + + # ------------------------------------------------------------------------------ # Global scope # ------------------------------------------------------------------------------ @@ -400,7 +435,7 @@ SINK(obj2.foo) # $ flow="SOURCE, l:-1 -> obj2.foo" # apparently these if statements below makes a difference :O # but one is not enough -cond = os.urandom(1)[0] > 128 +cond = os.urandom(1)[0] > 128 # $ unresolved_call=os.urandom(..) if cond: pass diff --git a/python/ql/test/experimental/dataflow/typetracking/test.py b/python/ql/test/experimental/dataflow/typetracking/test.py index 5277450c151..8de0a3ded92 100644 --- a/python/ql/test/experimental/dataflow/typetracking/test.py +++ b/python/ql/test/experimental/dataflow/typetracking/test.py @@ -91,7 +91,7 @@ def unrelated_func(): return "foo" def use_funcs_with_decorators(): - x = get_tracked2() # $ MISSING: tracked + x = get_tracked2() # $ tracked y = unrelated_func() # ------------------------------------------------------------------------------ @@ -117,11 +117,11 @@ class Foo(object): def meth1(self): do_stuff(self) - def meth2(self): # $ MISSING: tracked_self - do_stuff(self) # $ MISSING: tracked_self + def meth2(self): # $ tracked_self + do_stuff(self) # $ tracked_self - def meth3(self): # $ MISSING: tracked_self - do_stuff(self) # $ MISSING: tracked_self + def meth3(self): # $ tracked_self + do_stuff(self) # $ tracked_self class Bar(Foo): diff --git a/python/ql/test/experimental/library-tests/CallGraph-implicit-init/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph-implicit-init/InlineCallGraphTest.expected index c847f9a8aa2..d5ed453c51a 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-implicit-init/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph-implicit-init/InlineCallGraphTest.expected @@ -1,5 +1,4 @@ failures debug_callableNotUnique pointsTo_found_typeTracker_notFound -| example.py:22:1:22:16 | ControlFlowNode for explicit_afunc() | explicit_afunc | typeTracker_found_pointsTo_notFound diff --git a/python/ql/test/experimental/library-tests/CallGraph-implicit-init/example.py b/python/ql/test/experimental/library-tests/CallGraph-implicit-init/example.py index 75ad8a9db11..f14669948bc 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-implicit-init/example.py +++ b/python/ql/test/experimental/library-tests/CallGraph-implicit-init/example.py @@ -19,4 +19,4 @@ from foo_explicit.bar.a import explicit_afunc afunc() # $ MISSING: pt,tt=afunc -explicit_afunc() # $ pt=explicit_afunc MISSING: tt=explicit_afunc +explicit_afunc() # $ pt,tt="foo_explicit/bar/a.py:explicit_afunc" diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected new file mode 100644 index 00000000000..2836800d300 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected @@ -0,0 +1,5 @@ +failures +debug_callableNotUnique +pointsTo_found_typeTracker_notFound +| pkg/use.py:10:5:10:10 | ControlFlowNode for func() | func | +typeTracker_found_pointsTo_notFound diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.qlref b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.qlref new file mode 100644 index 00000000000..25117a4582b --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.qlref @@ -0,0 +1 @@ +../CallGraph/InlineCallGraphTest.ql diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/README.md b/python/ql/test/experimental/library-tests/CallGraph-imports/README.md new file mode 100644 index 00000000000..4063a2851f9 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/README.md @@ -0,0 +1,5 @@ +A testcase observed in real code, where mixing `from .this import that` with `from .other import *` (in that order) causes import resolution to not work properly. + +This needs to be in a separate folder, since using relative imports requires a valid top-level package. We emulate real extractor behavior using `-R` extractor option. + +From this directory, you can run the code with `python -m pkg.use`. diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/options b/python/ql/test/experimental/library-tests/CallGraph-imports/options new file mode 100644 index 00000000000..1bbc489d153 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=1 -R ./pkg/ diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/__init__.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_only_direct.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_only_direct.py new file mode 100644 index 00000000000..dc687a4344e --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_only_direct.py @@ -0,0 +1 @@ +from .func_def import func diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem.py new file mode 100644 index 00000000000..dd9f6a8f215 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem.py @@ -0,0 +1,2 @@ +from .func_def import func +from .other import * diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem_fixed.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem_fixed.py new file mode 100644 index 00000000000..5c57e676d44 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_problem_fixed.py @@ -0,0 +1,3 @@ +# this ordering makes the problem go away +from .other import * +from .func_def import func diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_star.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_star.py new file mode 100644 index 00000000000..c34c7f1df7e --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/alias_star.py @@ -0,0 +1,2 @@ +from .func_def import * +from .other import * diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/func_def.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/func_def.py new file mode 100644 index 00000000000..531031c0358 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/func_def.py @@ -0,0 +1,2 @@ +def func(): + print("func") diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/other.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/other.py new file mode 100644 index 00000000000..c652349c911 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/other.py @@ -0,0 +1,2 @@ +def something(): + pass diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py new file mode 100644 index 00000000000..861359b5d91 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py @@ -0,0 +1,33 @@ +def test_direct_import(): + from .func_def import func + func() # $ pt,tt="pkg/func_def.py:func" + +test_direct_import() # $ pt,tt=test_direct_import + + +def test_alias_problem(): + from .alias_problem import func + func() # $ pt="pkg/func_def.py:func" MISSING: tt="pkg/func_def.py:func" + +test_alias_problem() # $ pt,tt=test_alias_problem + + +def test_alias_problem_fixed(): + from .alias_problem_fixed import func + func() # $ pt,tt="pkg/func_def.py:func" + +test_alias_problem_fixed() # $ pt,tt=test_alias_problem_fixed + + +def test_alias_star(): + from .alias_star import func + func() # $ pt,tt="pkg/func_def.py:func" + +test_alias_star() # $ pt,tt=test_alias_star + + +def test_alias_only_direct(): + from .alias_only_direct import func + func() # $ pt,tt="pkg/func_def.py:func" + +test_alias_only_direct() # $ pt,tt=test_alias_only_direct diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 02d08ac4c81..10031cecde5 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -1,22 +1,39 @@ failures debug_callableNotUnique -| code/class_advanced.py:18:5:18:18 | Function arg | Qualified function name 'B.arg' is not unique. Please fix. | -| code/class_advanced.py:23:5:23:25 | Function arg | Qualified function name 'B.arg' is not unique. Please fix. | +| code/class_properties.py:7:5:7:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | +| code/class_properties.py:12:5:12:25 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | +| code/class_properties.py:17:5:17:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | pointsTo_found_typeTracker_notFound -| code/class_simple.py:24:1:24:15 | ControlFlowNode for Attribute() | A.some_method | -| code/class_simple.py:25:1:25:21 | ControlFlowNode for Attribute() | A.some_staticmethod | -| code/class_simple.py:26:1:26:20 | ControlFlowNode for Attribute() | A.some_classmethod | -| code/class_simple.py:28:1:28:21 | ControlFlowNode for Attribute() | A.some_staticmethod | -| code/class_simple.py:29:1:29:20 | ControlFlowNode for Attribute() | A.some_classmethod | -| code/runtime_decision.py:18:1:18:6 | ControlFlowNode for func() | rd_bar | -| code/runtime_decision.py:18:1:18:6 | ControlFlowNode for func() | rd_foo | -| code/runtime_decision.py:26:1:26:7 | ControlFlowNode for func2() | rd_bar | -| code/runtime_decision.py:26:1:26:7 | ControlFlowNode for func2() | rd_foo | -| code/simple.py:15:1:15:5 | ControlFlowNode for foo() | foo | -| code/simple.py:16:1:16:14 | ControlFlowNode for indirect_foo() | foo | -| code/simple.py:17:1:17:5 | ControlFlowNode for bar() | bar | -| code/simple.py:18:1:18:5 | ControlFlowNode for lam() | lambda[simple.py:12:7] | -| code/underscore_prefix_func_name.py:18:5:18:19 | ControlFlowNode for some_function() | some_function | -| code/underscore_prefix_func_name.py:21:5:21:19 | ControlFlowNode for some_function() | some_function | -| code/underscore_prefix_func_name.py:24:1:24:21 | ControlFlowNode for _works_since_called() | _works_since_called | +| code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func | +| code/class_attr_assign.py:11:9:11:25 | ControlFlowNode for Attribute() | my_func | +| code/class_attr_assign.py:26:9:26:25 | ControlFlowNode for Attribute() | DummyObject.method | +| code/class_super.py:50:1:50:6 | ControlFlowNode for Attribute() | outside_def | +| code/conditional_in_argument.py:18:5:18:11 | ControlFlowNode for Attribute() | X.bar | +| code/func_defined_outside_class.py:21:1:21:11 | ControlFlowNode for Attribute() | A.foo | +| code/func_defined_outside_class.py:22:1:22:15 | ControlFlowNode for Attribute() | outside | +| code/func_defined_outside_class.py:24:1:24:14 | ControlFlowNode for Attribute() | outside_sm | +| code/func_defined_outside_class.py:25:1:25:14 | ControlFlowNode for Attribute() | outside_cm | +| code/func_defined_outside_class.py:38:11:38:21 | ControlFlowNode for _gen() | B._gen | +| code/func_defined_outside_class.py:39:11:39:21 | ControlFlowNode for _gen() | B._gen | +| code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func | +| code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func | +| code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func | typeTracker_found_pointsTo_notFound +| code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm | +| code/class_more_mro2.py:18:9:18:21 | ControlFlowNode for Attribute() | A.foo | +| code/class_more_mro2.py:21:1:21:8 | ControlFlowNode for Attribute() | A.foo | +| code/class_more_mro.py:24:9:24:21 | ControlFlowNode for Attribute() | A.foo | +| code/class_more_mro.py:34:1:34:16 | ControlFlowNode for Attribute() | A.foo | +| code/class_super.py:43:9:43:21 | ControlFlowNode for Attribute() | A.bar | +| code/class_super.py:44:9:44:27 | ControlFlowNode for Attribute() | A.bar | +| code/class_super.py:63:1:63:18 | ControlFlowNode for Attribute() | A.foo | +| code/class_super.py:78:9:78:28 | ControlFlowNode for Attribute() | A.foo | +| code/class_super.py:81:1:81:12 | ControlFlowNode for Attribute() | C.foo_on_A | +| code/class_super.py:92:9:92:21 | ControlFlowNode for Attribute() | X.foo | +| code/class_super.py:97:9:97:21 | ControlFlowNode for Attribute() | X.foo | +| code/class_super.py:97:9:97:21 | ControlFlowNode for Attribute() | Y.foo | +| code/class_super.py:101:1:101:7 | ControlFlowNode for Attribute() | Z.foo | +| code/class_super.py:108:1:108:8 | ControlFlowNode for Attribute() | Z.foo | +| code/def_in_function.py:22:5:22:11 | ControlFlowNode for Attribute() | test.A.foo | +| code/nested_class.py:83:9:83:16 | ControlFlowNode for Attribute() | X.class_def_in_func.Y.meth | +| code/underscore_prefix_func_name.py:14:5:14:19 | ControlFlowNode for some_function() | some_function | diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql index cba9bc6e1d8..d00d0ae1301 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql @@ -4,6 +4,8 @@ private import semmle.python.dataflow.new.internal.DataFlowDispatch as TT /** Holds when `call` is resolved to `callable` using points-to based call-graph. */ predicate pointsToCallEdge(CallNode call, Function callable) { + exists(call.getLocation().getFile().getRelativePath()) and + exists(callable.getLocation().getFile().getRelativePath()) and exists(PythonFunctionValue funcValue | funcValue.getScope() = callable and call = funcValue.getACall() @@ -12,6 +14,8 @@ predicate pointsToCallEdge(CallNode call, Function callable) { /** Holds when `call` is resolved to `callable` using type-tracking based call-graph. */ predicate typeTrackerCallEdge(CallNode call, Function callable) { + exists(call.getLocation().getFile().getRelativePath()) and + exists(callable.getLocation().getFile().getRelativePath()) and exists(TT::DataFlowCallable dfCallable, TT::DataFlowCall dfCall | dfCallable.getScope() = callable and dfCall.getNode() = call and @@ -19,6 +23,16 @@ predicate typeTrackerCallEdge(CallNode call, Function callable) { ) } +/** Holds if the call edge is from a class call. */ +predicate typeTrackerClassCall(CallNode call, Function callable) { + exists(call.getLocation().getFile().getRelativePath()) and + exists(callable.getLocation().getFile().getRelativePath()) and + exists(TT::NormalCall cc | + cc = TT::TNormalCall(call, _, any(TT::TCallType t | t instanceof TT::CallTypeClass)) and + TT::TFunction(callable) = TT::viableCallable(cc) + ) +} + class CallGraphTest extends InlineExpectationsTest { CallGraphTest() { this = "CallGraphTest" } @@ -35,7 +49,20 @@ class CallGraphTest extends InlineExpectationsTest { | location = call.getLocation() and element = call.toString() and - value = betterQualName(target) + if call.getLocation().getFile() = target.getLocation().getFile() + then value = betterQualName(target) + else + exists(string fixedRelativePath | + fixedRelativePath = + target + .getLocation() + .getFile() + .getRelativePath() + .regexpCapture(".*/CallGraph[^/]*/(.*)", 1) + | + // the value needs to be enclosed in quotes to allow special characters + value = "\"" + fixedRelativePath + ":" + betterQualName(target) + "\"" + ) ) } } @@ -53,9 +80,15 @@ string betterQualName(Function func) { } query predicate debug_callableNotUnique(Function callable, string message) { - exists(Function f | f != callable and f.getQualifiedName() = callable.getQualifiedName()) and + exists(callable.getLocation().getFile().getRelativePath()) and + exists(Function f | + f != callable and + f.getQualifiedName() = callable.getQualifiedName() and + f.getLocation().getFile() = callable.getLocation().getFile() + ) and message = - "Qualified function name '" + callable.getQualifiedName() + "' is not unique. Please fix." + "Qualified function name '" + callable.getQualifiedName() + + "' is not unique within its file. Please fix." } query predicate pointsTo_found_typeTracker_notFound(CallNode call, string qualname) { @@ -70,6 +103,10 @@ query predicate typeTracker_found_pointsTo_notFound(CallNode call, string qualna exists(Function target | not pointsToCallEdge(call, target) and typeTrackerCallEdge(call, target) and - qualname = betterQualName(target) + qualname = betterQualName(target) and + // We filter out result differences for points-to and type-tracking for class calls, + // since otherwise it gives too much noise (these are just handled differently + // between the two). + not typeTrackerClassCall(call, target) ) } diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/aliased_import.py b/python/ql/test/experimental/library-tests/CallGraph/code/aliased_import.py new file mode 100644 index 00000000000..ac0c7184881 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/aliased_import.py @@ -0,0 +1 @@ +from .simple import foo diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/bound_method_arg.py b/python/ql/test/experimental/library-tests/CallGraph/code/bound_method_arg.py new file mode 100644 index 00000000000..a59510ec681 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/bound_method_arg.py @@ -0,0 +1,16 @@ +class Foo(object): + def meth(self, arg): + print("Foo.meth", arg) + + @classmethod + def cm(cls, arg): + print("Foo.cm", arg) + + +def call_func(func): + func(42) # $ pt,tt=Foo.meth pt,tt=Foo.cm + + +foo = Foo() +call_func(foo.meth) # $ pt,tt=call_func +call_func(Foo.cm) # $ pt,tt=call_func diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/callable_as_argument.py b/python/ql/test/experimental/library-tests/CallGraph/code/callable_as_argument.py new file mode 100644 index 00000000000..ab8e0cf6ba9 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/callable_as_argument.py @@ -0,0 +1,55 @@ +# ============================================================================== +# function +# ============================================================================== + +def call_func(f): + f() # $ pt,tt=my_func pt,tt=test_func.inside_test_func + + +def my_func(): + print("my_func") + +call_func(my_func) # $ pt,tt=call_func + + +def test_func(): + def inside_test_func(): + print("inside_test_func") + + call_func(inside_test_func) # $ pt,tt=call_func + +test_func() # $ pt,tt=test_func + + +# ============================================================================== +# class +# ============================================================================== + +def class_func(cls): + cls.sm() # $ pt,tt=MyClass.sm tt=test_class.InsideTestFunc.sm + cls(42) # $ tt=MyClass.__init__ tt=test_class.InsideTestFunc.__init__ + + +class MyClass(object): + def __init__(self, arg): + print(self, arg) + + @staticmethod + def sm(): + print("MyClass.staticmethod") + +class_func(MyClass) # $ pt,tt=class_func + + +def test_class(): + class InsideTestFunc(object): + def __init__(self, arg): + print(self, arg) + + @staticmethod + def sm(): + print("InsideTestFunc.staticmethod") + + class_func(InsideTestFunc) # $ pt,tt=class_func + +test_class() # $ pt,tt=test_class diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py deleted file mode 100644 index 94667621f34..00000000000 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_advanced.py +++ /dev/null @@ -1,40 +0,0 @@ -class B(object): - - def __init__(self, arg): - print('B.__init__', arg) - self._arg = arg - - def __str__(self): - print('B.__str__') - return 'B (arg={})'.format(self.arg) - - def __add__(self, other): - print('B.__add__') - if isinstance(other, B): - return B(self.arg + other.arg) - return B(self.arg + other) - - @property - def arg(self): - print('B.arg getter') - return self._arg - - @arg.setter - def arg(self, value): - print('B.arg setter') - self._arg = value - - -b1 = B(1) -b2 = B(2) -b3 = b1 + b2 - -print('value printing:', str(b1)) -print('value printing:', str(b2)) -print('value printing:', str(b3)) - -b3.arg = 42 -b4 = b3 + 100 - -# this calls `str(b4)` inside -print('value printing:', b4) diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_attr_assign.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_attr_assign.py new file mode 100644 index 00000000000..605375925f7 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_attr_assign.py @@ -0,0 +1,30 @@ +def my_func(): + print("my_func") + +class Foo(object): + def __init__(self, func): + self.indirect_ref = func + self.direct_ref = my_func + + def later(self): + self.indirect_ref() # $ pt=my_func MISSING: tt=my_func + self.direct_ref() # $ pt=my_func MISSING: tt=my_func + +foo = Foo(my_func) # $ tt=Foo.__init__ +foo.later() # $ pt,tt=Foo.later + + +class DummyObject(object): + def method(self): + print("DummyObject.method") + +class Bar(object): + def __init__(self): + self.obj = DummyObject() + + def later(self): + self.obj.method() # $ pt=DummyObject.method MISSING: tt=DummyObject.method + + +bar = Bar(my_func) # $ tt=Bar.__init__ +bar.later() # $ pt,tt=Bar.later diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py new file mode 100644 index 00000000000..ce348fee15f --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py @@ -0,0 +1,66 @@ +class X(object): + def __init__(self, arg): + print("X.__init__", arg) + +X(42) # $ tt=X.__init__ +print() + + +class Y(X): + def __init__(self, arg): + print("Y.__init__", arg) + super().__init__(-arg) # $ pt,tt=X.__init__ + +Y(43) # $ tt=Y.__init__ +print() + +# --- + +class WithNew(object): + def __new__(cls, arg): + print("WithNew.__new__", arg) + inst = super().__new__(cls) + assert isinstance(inst, cls) + inst.some_method() # $ MISSING: pt,tt=WithNew.some_method + return inst + + def __init__(self, arg): + print("WithNew.__init__", arg) + + def some_method(self): + print("WithNew.__init__") + +WithNew(44) # $ tt=WithNew.__new__ tt=WithNew.__init__ +print() + + +class ExtraCallToInit(object): + def __new__(cls, arg): + print("ExtraCallToInit.__new__", arg) + inst = super().__new__(cls) + assert isinstance(inst, cls) + # you're not supposed to do this, since it will cause the __init__ method will be run twice. + inst.__init__(1001) # $ MISSING: pt,tt=ExtraCallToInit.__init__ + return inst + + def __init__(self, arg): + print("ExtraCallToInit.__init__", arg, self) + +ExtraCallToInit(1000) # $ tt=ExtraCallToInit.__new__ tt=ExtraCallToInit.__init__ +print() + + +class InitNotCalled(object): + """as described in https://docs.python.org/3/reference/datamodel.html#object.__new__ + __init__ will only be called when the returned object from __new__ is an instance of + the `cls` parameter... + """ + def __new__(cls, arg): + print("InitNotCalled.__new__", arg) + return False + + def __init__(self, arg): + print("InitNotCalled.__init__", arg) + +InitNotCalled(2000) # $ tt=InitNotCalled.__new__ SPURIOUS: tt=InitNotCalled.__init__ +print() diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_decorator.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_decorator.py new file mode 100644 index 00000000000..910e24d2519 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_decorator.py @@ -0,0 +1,34 @@ +# decorated class + +def my_class_decorator(cls): + print("dummy decorator") + return cls + +@my_class_decorator # $ pt=my_class_decorator tt=my_class_decorator +class A(object): + def foo(self): + pass + +a = A() +a.foo() # $ pt,tt=A.foo + +class B(A): + def bar(self): + self.foo() # $ pt,tt=A.foo + + +# decorated class, unknown decorator + +from some_unknown_module import unknown_class_decorator + +@unknown_class_decorator +class X(object): + def foo(self): + pass + +x = X() +x.foo() # $ pt,tt=X.foo + +class Y(X): + def bar(self): + self.foo() # $ pt,tt=X.foo diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro.py new file mode 100644 index 00000000000..d8eae002cb4 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro.py @@ -0,0 +1,35 @@ +class Base(object): + def foo(self): + print("Base.foo") + + +class A(Base): + def foo(self): + print("A.foo") + super().foo() # $ pt,tt=Base.foo + +class ASub(A): + pass + +class B(Base): + def foo(self): + print("B.foo") + # NOTE: If this missing result is fixed, please update the QLDoc for + # `getNextClassInMro` as well + super().foo() # $ pt,tt=Base.foo MISSING: pt,tt=A.foo + +class BSub(B): + def bar(self): + print("BSub.bar") + super().foo() # $ pt,tt=B.foo SPURIOUS: tt=A.foo + +bs = BSub() +bs.foo() # $ pt,tt=B.foo +bs.bar() # $ pt,tt=BSub.bar + +print("! Indirect") +class Indirect(BSub, ASub): + pass + +Indirect().foo() # $ pt,tt=B.foo SPURIOUS: tt=A.foo +Indirect().bar() # $ pt,tt=BSub.bar diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro2.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro2.py new file mode 100644 index 00000000000..6a64f905412 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_more_mro2.py @@ -0,0 +1,22 @@ +class A(object): + def foo(self): + print("A.foo") + +class B(A): + pass + +b = B() +b.foo() # $ pt,tt=A.foo + +class C(A): + def foo(self): + print("C.foo") + +class BC(B, C): + def bar(self): + print("BC.bar") + super().foo() # $ pt,tt=C.foo SPURIOUS: tt=A.foo + +bc = BC() +bc.foo() # $ pt,tt=C.foo SPURIOUS: tt=A.foo +bc.bar() # $ pt,tt=BC.bar diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py new file mode 100644 index 00000000000..06e4f3f3bd2 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py @@ -0,0 +1,43 @@ +class Prop(object): + def __init__(self, arg): + self._arg = arg + self._arg2 = arg + + @property + def arg(self): + print('Prop.arg getter') + return self._arg + + @arg.setter + def arg(self, value): + print('Prop.arg setter') + self._arg = value + + @arg.deleter + def arg(self): + print('Prop.arg deleter') + # haha, you cannot delete me! + + def _arg2_getter(self): + print('Prop.arg2 getter') + return self._arg2 + + def _arg2_setter(self, value): + print('Prop.arg2 setter') + self._arg2 = value + + def _arg2_deleter(self): + print('Prop.arg2 deleter') + # haha, you cannot delete me! + + arg2 = property(_arg2_getter, _arg2_setter, _arg2_deleter) + +prop = Prop(42) # $ tt=Prop.__init__ + +prop.arg +prop.arg = 43 +del prop.arg + +prop.arg2 +prop.arg2 = 43 +del prop.arg2 diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py deleted file mode 100644 index f201e648e3a..00000000000 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_simple.py +++ /dev/null @@ -1,29 +0,0 @@ -class A(object): - - def __init__(self, arg): - print('A.__init__', arg) - self.arg = arg - - def some_method(self): - print('A.some_method', self) - - @staticmethod - def some_staticmethod(): - print('A.some_staticmethod') - - @classmethod - def some_classmethod(cls): - print('A.some_classmethod', cls) - - -# TODO: Figure out how to annotate class instantiation (and add one here). -# Current points-to says it's a call to the class (instead of __init__/__new__/metaclass-something). -# However, current test setup uses "callable" for naming, and expects things to be Function. -a = A(42) - -a.some_method() # $ pt=A.some_method -a.some_staticmethod() # $ pt=A.some_staticmethod -a.some_classmethod() # $ pt=A.some_classmethod - -A.some_staticmethod() # $ pt=A.some_staticmethod -A.some_classmethod() # $ pt=A.some_classmethod diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py new file mode 100644 index 00000000000..7b8df9c4139 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py @@ -0,0 +1,29 @@ +class B(object): + + def __init__(self, arg): + print('B.__init__', arg) + self.arg = arg + + def __str__(self): + print('B.__str__') + return 'B (arg={})'.format(self.arg) + + def __add__(self, other): + print('B.__add__') + if isinstance(other, B): + return B(self.arg + other.arg) # $ tt=B.__init__ + return B(self.arg + other) # $ tt=B.__init__ + +b = B(1) # $ tt=B.__init__ + +print(str(b)) +# this calls `str(b)` inside +print(b) + + + +b2 = B(2) # $ tt=B.__init__ + +# __add__ is called +b + b2 +b + 100 diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_subclass.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_subclass.py new file mode 100644 index 00000000000..cd2ee42fa03 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_subclass.py @@ -0,0 +1,178 @@ +class A(object): + + def __init__(self, arg): + print('A.__init__', arg) + self.arg = arg + + def some_method(self): + print('A.some_method', self) + + @staticmethod + def some_staticmethod(): + print('A.some_staticmethod') + + @classmethod + def some_classmethod(cls): + print('A.some_classmethod', cls) + + +a = A(42) # $ tt=A.__init__ + +a.some_method() # $ pt,tt=A.some_method +a.some_staticmethod() # $ pt,tt=A.some_staticmethod +a.some_classmethod() # $ pt,tt=A.some_classmethod + +A.some_method(a) # $ pt,tt=A.some_method +A.some_staticmethod() # $ pt,tt=A.some_staticmethod +A.some_classmethod() # $ pt,tt=A.some_classmethod + +print("- type()") +type(a).some_method(a) # $ pt,tt=A.some_method +type(a).some_staticmethod() # $ pt,tt=A.some_staticmethod +type(a).some_classmethod() # $ pt,tt=A.some_classmethod + +# Subclass test +print("\n! B") +class B(A): + pass + +b = B(42) # $ tt=A.__init__ + +b.some_method() # $ pt,tt=A.some_method +b.some_staticmethod() # $ pt,tt=A.some_staticmethod +b.some_classmethod() # $ pt,tt=A.some_classmethod + +B.some_method(b) # $ pt,tt=A.some_method +B.some_staticmethod() # $ pt,tt=A.some_staticmethod +B.some_classmethod() # $ pt,tt=A.some_classmethod + +print("- type()") +type(b).some_method(b) # $ pt,tt=A.some_method +type(b).some_staticmethod() # $ pt,tt=A.some_staticmethod +type(b).some_classmethod() # $ pt,tt=A.some_classmethod + +# Subclass with method override +print("\n! Subclass with method override") +class C(A): + def some_method(self): + print('C.some_method', self) + +c = C(42) # $ tt=A.__init__ +c.some_method() # $ pt,tt=C.some_method + + +class D(object): + def some_method(self): + print('D.some_method', self) + +class E(C, D): + pass + +e = E(42) # $ tt=A.__init__ +e.some_method() # $ pt,tt=C.some_method + +class F(D, C): + pass + +f = F(42) # $ tt=A.__init__ +f.some_method() # $ pt,tt=D.some_method + +# ------------------------------------------------------------------------------ +# self/cls in methods +# ------------------------------------------------------------------------------ + +class Base(object): + def foo(self): + print('Base.foo') + + def bar(self): + print('Base.bar') + + def call_stuff(self): + self.foo() # $ pt,tt=Base.foo pt,tt=Sub.foo pt,tt=Mixin.foo + self.bar() # $ pt,tt=Base.bar + + self.sm() # $ pt,tt=Base.sm + self.cm() # $ pt,tt=Base.cm + + self.sm2() # $ pt,tt=Base.sm2 pt,tt=Sub.sm2 + self.cm2() # $ pt,tt=Base.cm2 pt,tt=Sub.cm2 + + type(self).sm2() # $ pt,tt=Base.sm2 pt,tt=Sub.sm2 + type(self).cm2() # $ pt,tt=Base.cm2 pt,tt=Sub.cm2 + + @staticmethod + def sm(): + print("Base.sm") + + @classmethod + def cm(cls): + print("Base.cm") + + @staticmethod + def sm2(): + print("Base.sm2") + + @classmethod + def cm2(cls): + print("Base.cm2") + + @classmethod + def call_from_cm(cls): + cls.sm() # $ pt,tt=Base.sm + cls.cm() # $ pt,tt=Base.cm + + cls.sm2() # $ pt,tt=Base.sm2 pt,tt=Sub.sm2 + cls.cm2() # $ pt,tt=Base.cm2 pt,tt=Sub.cm2 + +base = Base() +print("! base.call_stuff()") +base.call_stuff() # $ pt,tt=Base.call_stuff +print("! Base.call_from_cm()") +Base.call_from_cm() # $ pt,tt=Base.call_from_cm + +class Sub(Base): + def foo(self): + print("Sub.foo") + + def foo_on_super(self): + sup = super() + sup.foo() # $ pt,tt=Base.foo + + def also_call_stuff(self): + self.sm() # $ pt,tt=Base.sm + self.cm() # $ pt,tt=Base.cm + + self.sm2() # $ pt,tt=Sub.sm2 + self.cm2() # $ pt,tt=Sub.cm2 + + @staticmethod + def sm2(): + print("Sub.sm2") + + @classmethod + def cm2(cls): + print("Sub.cm2") + +sub = Sub() +print("! sub.foo_on_super()") +sub.foo_on_super() # $ pt,tt=Sub.foo_on_super +print("! sub.call_stuff()") +sub.call_stuff() # $ pt,tt=Base.call_stuff +print("! sub.also_call_stuff()") +sub.also_call_stuff() # $ pt,tt=Sub.also_call_stuff +print("! Sub.call_from_cm()") +Sub.call_from_cm() # $ pt,tt=Base.call_from_cm + + +class Mixin(object): + def foo(self): + print("Mixin.foo") + +class SubWithMixin(Mixin, Base): + # the ordering here means that in Base.call_stuff, the call to self.foo will go to Mixin.foo + pass + +swm = SubWithMixin() +print("! swm.call_stuff()") +swm.call_stuff() # $ pt,tt=Base.call_stuff diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_subclass2.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_subclass2.py new file mode 100644 index 00000000000..43f5c2d81f8 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_subclass2.py @@ -0,0 +1,38 @@ +class Base(object): + def foo(self): + print("Base.foo") + + def call_stuff(self): + print("Base.call_stuff") + self.foo() # $ pt,tt=Base.foo pt,tt=X.foo + +class X(object): + def __init__(self): + print("X.__init__") + + def foo(self): + print("X.foo") + +class Y(object): + def __init__(self): + print("Y.__init__") + + def foo(self): + print("Y.foo") + +class Contrived(X, Y, Base): + pass + +contrived = Contrived() # $ tt=X.__init__ +contrived.foo() # $ pt,tt=X.foo +contrived.call_stuff() # $ pt,tt=Base.call_stuff + +# Ensure that we don't mix up __init__ resolution for Contrived() due to MRO +# approximation + +class HasInit(object): + def __init__(self): + pass + +class TryingToTrickYou(Contrived, HasInit): + pass diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_super.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_super.py new file mode 100644 index 00000000000..dc3a58fb36c --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_super.py @@ -0,0 +1,108 @@ +def outside_def(self): + print("outside_def") + try: + super().foo() + except RuntimeError: + pass + + +class A(object): + def foo(self): + print("A.foo") + + @classmethod + def bar(cls): + print("A.bar") + +class B(A): + def foo(self): + print("B.foo") + + def foo_on_super(self): + print("B.foo_on_super") + super().foo() # $ pt,tt=A.foo + super(B, self).foo() # $ pt,tt=A.foo + + od = outside_def + + @staticmethod + def sm(): + try: + super().foo() + except RuntimeError: + print("B.sm") + pass + + @classmethod + def bar(cls): + print("B.bar") + + @classmethod + def bar_on_super(cls): + print("B.bar_on_super") + super().bar() # $ tt=A.bar + super(B, cls).bar() # $ tt=A.bar + + +b = B() +b.foo() # $ pt,tt=B.foo +b.foo_on_super() # $ pt,tt=B.foo_on_super +b.od() # $ pt=outside_def +b.sm() # $ pt,tt=B.sm + +print("="*10, "static method") +B.bar() # $ pt,tt=B.bar +B.bar_on_super() # $ pt,tt=B.bar_on_super + + +print("="*10, "Manual calls to super") + +super(B, b).foo() # $ pt,tt=A.foo + +assert A.foo == super(B, B).foo +super(B, B).foo(b) # $ tt=A.foo + +try: + super(B, 42).foo() +except TypeError: + pass + +# For some reason, points-to isn't able to resolve any calls from here on. I've tried to +# comment out both try-except blocks, but that did not solve the problem :| + +print("="*10, "C") + +class C(B): + def foo_on_A(self): + print('C.foo_on_A') + super(B, self).foo() # $ tt=A.foo + +c = C() +c.foo_on_A() # $ tt=C.foo_on_A + +print("="*10, "Diamon hierachy") + +class X(object): + def foo(self): + print('X.foo') + +class Y(X): + def foo(self): + print('Y.foo') + super().foo() # $ tt=X.foo + +class Z(X): + def foo(self): + print('Z.foo') + super().foo() # $ tt=X.foo tt=Y.foo + +print("! z.foo()") +z = Z() +z.foo() # $ tt=Z.foo + +class ZY(Z, Y): + pass + +print("! zy.foo()") +zy = ZY() +zy.foo() # $ tt=Z.foo diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py b/python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py new file mode 100644 index 00000000000..885393fae90 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/conditional_in_argument.py @@ -0,0 +1,36 @@ +class X(object): + def foo(self, *args): + print("X.foo", args) + + def bar(self, *args): + print("X.bar", args) + + +def func(cond=True): + x = X() + + # ok + x.foo() # $ pt,tt=X.foo + x.bar() # $ pt,tt=X.bar + + # the conditional in the argument makes us stop tracking the class instance :| + x.foo(1 if cond else 0) # $ pt,tt=X.foo + x.bar() # $ pt=X.bar MISSING: tt=X.bar + + +func() # $ pt,tt=func + +def func2(cond=True): + y = X() + + # ok + y.foo() # $ pt,tt=X.foo + y.bar() # $ pt,tt=X.bar + + if cond: + arg = 1 + else: + arg = 0 + + y.foo(arg) # $ pt,tt=X.foo + y.bar() # $ pt,tt=X.bar diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/def_in_function.py b/python/ql/test/experimental/library-tests/CallGraph/code/def_in_function.py new file mode 100644 index 00000000000..8b7e0dcfb89 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/def_in_function.py @@ -0,0 +1,24 @@ +def test(): + def foo(): + print("foo") + + foo() # $ pt,tt=test.foo + + def bar(): + print("bar") + def baz(): + print("baz") + baz() # $ pt,tt=test.bar.baz + return baz + + baz_ref = bar() # $ pt,tt=test.bar + baz_ref() # $ pt,tt=test.bar.baz + + class A(object): + def foo(self): + print("A.foo") + + a = A() + a.foo() # $ tt=test.A.foo + +test() # $ pt,tt=test diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/func_defined_outside_class.py b/python/ql/test/experimental/library-tests/CallGraph/code/func_defined_outside_class.py new file mode 100644 index 00000000000..c0ff09d4987 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/func_defined_outside_class.py @@ -0,0 +1,43 @@ +def outside(self): + print("outside", self) + +def outside_sm(): + print("outside_sm") + +def outside_cm(cls): + print("outside_cm", cls) + +class A(object): + def foo(self): + print("A.foo") + + foo_ref = foo + + outside_ref = outside + outside_sm = staticmethod(outside_sm) + outside_cm = classmethod(outside_cm) + +a = A() +a.foo_ref() # $ pt=A.foo +a.outside_ref() # $ pt=outside + +a.outside_sm() # $ pt=outside_sm +a.outside_cm() # $ pt=outside_cm + +# === + +print("\n! B") + +# this pattern was seen in django +class B(object): + def _gen(value): + def func(self): + print("B._gen.func", value) + return func + + foo = _gen("foo") # $ pt=B._gen + bar = _gen("bar") # $ pt=B._gen + +b = B() +b.foo() # $ pt=B._gen.func +b.bar() # $ pt=B._gen.func diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/nested_class.py b/python/ql/test/experimental/library-tests/CallGraph/code/nested_class.py new file mode 100644 index 00000000000..1248dbdb426 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/nested_class.py @@ -0,0 +1,87 @@ +class A(object): + class B(object): + @staticmethod + def foo(): + print("A.B.foo") + + @staticmethod + def bar(): + print("A.B.bar") + A.B.foo() # $ pt,tt=A.B.foo + + +A.B.bar() # $ pt,tt=A.B.bar + + +ab = A.B() +ab.bar() # $ pt,tt=A.B.bar + +# ============================================================================== + +class OuterBase(object): + def foo(self): + print("OuterBase.foo") + +class InnerBase(object): + def foo(self): + print("InnerBase.foo") + +class Outer(OuterBase): + def foo(self): + print("Outer.foo") + super().foo() # $ pt,tt=OuterBase.foo + + class Inner(InnerBase): + def foo(self): + print("Inner.foo") + super().foo() # $ pt,tt=InnerBase.foo + +outer = Outer() +outer.foo() # $ pt,tt=Outer.foo + +inner = Outer.Inner() +inner.foo() # $ pt,tt=Outer.Inner.foo + +# ============================================================================== + +class Base(object): + def foo(self): + print("Base.foo") + +class Base2(object): + def foo(self): + print("Base2.foo") + +class X(Base): + def meth(self): + print("X.meth") + super().foo() # $ pt,tt=Base.foo + + def inner_func(): + print("inner_func") + try: + super().foo() + except RuntimeError: + print("RuntimeError, as expected") + + inner_func() # $ pt,tt=X.meth.inner_func + + def inner_func2(this_works): + print("inner_func2") + super().foo() # $ MISSING: tt=Base.foo + + inner_func2(self) # $ pt,tt=X.meth.inner_func2 + + def class_def_in_func(self): + print("X.class_def_in_func") + class Y(Base2): + def meth(self): + print("Y.meth") + super().foo() # $ pt,tt=Base2.foo + + y = Y() + y.meth() # $ tt=X.class_def_in_func.Y.meth + +x = X() +x.meth() # $ pt,tt=X.meth +x.class_def_in_func() # $ pt=X.class_def_in_func tt=X.class_def_in_func diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/relative_import.py b/python/ql/test/experimental/library-tests/CallGraph/code/relative_import.py new file mode 100644 index 00000000000..06191fed7e9 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/relative_import.py @@ -0,0 +1,7 @@ +def test_relative_import(): + from .simple import foo + foo() # $ pt,tt="code/simple.py:foo" + +def test_aliased_relative_import(): + from .aliased_import import foo + foo() # $ pt,tt="code/simple.py:foo" diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py index 3c4ebbb73e1..3901a770188 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py @@ -15,7 +15,7 @@ if len(sys.argv) >= 2 and not sys.argv[1] in ['0', 'False', 'false']: else: func = rd_bar -func() # $ pt=rd_foo pt=rd_bar +func() # $ pt,tt=rd_foo pt,tt=rd_bar # Random doesn't work with points-to :O if random.random() < 0.5: @@ -23,4 +23,4 @@ if random.random() < 0.5: else: func2 = rd_bar -func2() # $ pt=rd_foo pt=rd_bar +func2() # $ pt,tt=rd_foo pt,tt=rd_bar diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py b/python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py new file mode 100644 index 00000000000..fdbf554084e --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py @@ -0,0 +1,22 @@ +def foo(n=0): + print("foo", n) + if n > 0: + foo(n-1) # $ pt,tt=foo + +foo(1) # $ pt,tt=foo + + +def test(): + def foo(): + print("test.foo") + + foo() # $ pt,tt=test.foo + + +class A(object): + def foo(self): + print("A.foo") + foo() # $ pt=foo MISSING: tt=foo + +a = A() +a.foo() # $ pt,tt=A.foo diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/simple.py b/python/ql/test/experimental/library-tests/CallGraph/code/simple.py index ac07ace93b2..7d7d4865049 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/simple.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/simple.py @@ -12,9 +12,9 @@ def bar(): lam = lambda: print("lambda called") -foo() # $ pt=foo -indirect_foo() # $ pt=foo -bar() # $ pt=bar -lam() # $ pt=lambda[simple.py:12:7] +foo() # $ pt,tt=foo +indirect_foo() # $ pt,tt=foo +bar() # $ pt,tt=bar +lam() # $ pt,tt=lambda[simple.py:12:7] # python -m trace --trackcalls simple.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/through_content.py b/python/ql/test/experimental/library-tests/CallGraph/code/through_content.py new file mode 100644 index 00000000000..f449c4bd6da --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/through_content.py @@ -0,0 +1,6 @@ +def my_func(): + print("my_func") + +funcs = [my_func] +for f in funcs: + f() # $ MISSING: tt=my_func diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/type_tracking_limitation.py b/python/ql/test/experimental/library-tests/CallGraph/code/type_tracking_limitation.py new file mode 100644 index 00000000000..4831cf74291 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/type_tracking_limitation.py @@ -0,0 +1,8 @@ +def return_arg(arg): + return arg + +def my_func(): + print("my_func") + +x = return_arg(my_func) # $ pt,tt=return_arg +x() # $ pt=my_func MISSING: tt=my_func diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py b/python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py index fb3f5fc45a8..0331dbb30c4 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/underscore_prefix_func_name.py @@ -11,14 +11,14 @@ def some_function(): def _ignored(): print('_ignored') - some_function() + some_function() # $ tt=some_function def _works_since_called(): print('_works_since_called') - some_function() # $ pt=some_function + some_function() # $ pt,tt=some_function def works_even_though_not_called(): - some_function() # $ pt=some_function + some_function() # $ pt,tt=some_function globals()['_ignored']() -_works_since_called() # $ pt=_works_since_called +_works_since_called() # $ pt,tt=_works_since_called diff --git a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected new file mode 100644 index 00000000000..9fedaf9f663 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected @@ -0,0 +1,19 @@ +uniqueEnclosingCallable +uniqueType +uniqueNodeLocation +missingLocation +uniqueNodeToString +missingToString +parameterCallable +localFlowIsLocal +compatibleTypesReflexive +unreachableNodeCCtx +localCallNodes +postIsNotPre +postHasUniquePre +uniquePostUpdate +postIsInSameCallable +reverseRead +argHasPostUpdate +postWithInFlow +viableImplInCallContextTooLarge diff --git a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql new file mode 100644 index 00000000000..6743fa10d27 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql @@ -0,0 +1 @@ +import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency diff --git a/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected b/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected index 5dcf739c068..0c2bd1b4ce0 100644 --- a/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected +++ b/python/ql/test/library-tests/PointsTo/new/ImpliesDataflow.expected @@ -5,11 +5,6 @@ | code/l_calls.py:12:1:12:20 | ControlFlowNode for ClassExpr | code/l_calls.py:25:16:25:16 | ControlFlowNode for a | | code/l_calls.py:33:5:33:23 | ControlFlowNode for FunctionExpr | code/l_calls.py:39:1:39:3 | ControlFlowNode for Attribute | | code/l_calls.py:48:5:48:30 | ControlFlowNode for FunctionExpr | code/l_calls.py:53:1:53:3 | ControlFlowNode for Attribute | -| code/q_super.py:10:18:10:21 | ControlFlowNode for self | code/q_super.py:4:22:4:25 | ControlFlowNode for self | -| code/q_super.py:26:14:26:17 | ControlFlowNode for self | code/q_super.py:22:32:22:35 | ControlFlowNode for self | -| code/q_super.py:31:14:31:17 | ControlFlowNode for self | code/q_super.py:22:32:22:35 | ControlFlowNode for self | -| code/q_super.py:37:14:37:17 | ControlFlowNode for self | code/q_super.py:22:32:22:35 | ControlFlowNode for self | -| code/q_super.py:37:14:37:17 | ControlFlowNode for self | code/q_super.py:27:32:27:35 | ControlFlowNode for self | | code/q_super.py:48:5:48:17 | ControlFlowNode for ClassExpr | code/q_super.py:51:25:51:29 | ControlFlowNode for Attribute | | code/q_super.py:63:5:63:17 | ControlFlowNode for ClassExpr | code/q_super.py:66:19:66:23 | ControlFlowNode for Attribute | | code/t_type.py:3:1:3:16 | ControlFlowNode for ClassExpr | code/t_type.py:6:1:6:9 | ControlFlowNode for type() | diff --git a/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected b/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected index dc055e4a08f..c56e9c8a3f6 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected +++ b/python/ql/test/library-tests/frameworks/django-orm/ReflectedXss.expected @@ -5,13 +5,13 @@ edges | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | testapp/orm_security_tests.py:47:14:47:53 | ControlFlowNode for Attribute() [Attribute name] | | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | testapp/orm_security_tests.py:22:23:22:34 | ControlFlowNode for Attribute | | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | testapp/orm_security_tests.py:23:22:23:33 | ControlFlowNode for Attribute | -| testapp/orm_security_tests.py:22:9:22:14 | [post store] ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:23:9:23:14 | ControlFlowNode for person [Attribute name] | +| testapp/orm_security_tests.py:22:9:22:14 | [post] ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:23:9:23:14 | ControlFlowNode for person [Attribute name] | | testapp/orm_security_tests.py:22:23:22:34 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:22:23:22:42 | ControlFlowNode for Subscript | -| testapp/orm_security_tests.py:22:23:22:42 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:22:9:22:14 | [post store] ControlFlowNode for person [Attribute name] | +| testapp/orm_security_tests.py:22:23:22:42 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:22:9:22:14 | [post] ControlFlowNode for person [Attribute name] | | testapp/orm_security_tests.py:23:9:23:14 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:23:9:23:14 | [post store] ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute age] | +| testapp/orm_security_tests.py:23:9:23:14 | [post] ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute age] | | testapp/orm_security_tests.py:23:22:23:33 | ControlFlowNode for Attribute | testapp/orm_security_tests.py:23:22:23:40 | ControlFlowNode for Subscript | -| testapp/orm_security_tests.py:23:22:23:40 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:23:9:23:14 | [post store] ControlFlowNode for person [Attribute age] | +| testapp/orm_security_tests.py:23:22:23:40 | ControlFlowNode for Subscript | testapp/orm_security_tests.py:23:9:23:14 | [post] ControlFlowNode for person [Attribute age] | | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute age] | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute name] | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | | testapp/orm_security_tests.py:42:13:42:18 | SSA variable person [Attribute age] | testapp/orm_security_tests.py:43:62:43:67 | ControlFlowNode for person [Attribute age] | @@ -48,11 +48,11 @@ nodes | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute age] | semmle.label | [orm-model] Class Person [Attribute age] | | testapp/orm_security_tests.py:15:1:15:27 | [orm-model] Class Person [Attribute name] | semmle.label | [orm-model] Class Person [Attribute name] | | testapp/orm_security_tests.py:19:12:19:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| testapp/orm_security_tests.py:22:9:22:14 | [post store] ControlFlowNode for person [Attribute name] | semmle.label | [post store] ControlFlowNode for person [Attribute name] | +| testapp/orm_security_tests.py:22:9:22:14 | [post] ControlFlowNode for person [Attribute name] | semmle.label | [post] ControlFlowNode for person [Attribute name] | | testapp/orm_security_tests.py:22:23:22:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | testapp/orm_security_tests.py:22:23:22:42 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | testapp/orm_security_tests.py:23:9:23:14 | ControlFlowNode for person [Attribute name] | semmle.label | ControlFlowNode for person [Attribute name] | -| testapp/orm_security_tests.py:23:9:23:14 | [post store] ControlFlowNode for person [Attribute age] | semmle.label | [post store] ControlFlowNode for person [Attribute age] | +| testapp/orm_security_tests.py:23:9:23:14 | [post] ControlFlowNode for person [Attribute age] | semmle.label | [post] ControlFlowNode for person [Attribute age] | | testapp/orm_security_tests.py:23:22:23:33 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | testapp/orm_security_tests.py:23:22:23:40 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | testapp/orm_security_tests.py:28:9:28:14 | ControlFlowNode for person [Attribute age] | semmle.label | ControlFlowNode for person [Attribute age] | diff --git a/python/ql/test/library-tests/fuck/options b/python/ql/test/library-tests/fuck/options new file mode 100644 index 00000000000..efa237f03c4 --- /dev/null +++ b/python/ql/test/library-tests/fuck/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=0 diff --git a/python/ql/test/library-tests/fuck/test.py b/python/ql/test/library-tests/fuck/test.py new file mode 100644 index 00000000000..3029c8be234 --- /dev/null +++ b/python/ql/test/library-tests/fuck/test.py @@ -0,0 +1,17 @@ +def my_func(arg): + print("my_func", arg) + +class Foo: + def foo(self, arg=42): + print("Foo.foo", self, arg) + + +my_func(43) + +import random +if random.choice([True, False]): + func = my_func +else: + func = Foo.foo + +func(44) diff --git a/python/ql/test/library-tests/fuck/wat.expected b/python/ql/test/library-tests/fuck/wat.expected new file mode 100644 index 00000000000..2a4f078a25f --- /dev/null +++ b/python/ql/test/library-tests/fuck/wat.expected @@ -0,0 +1 @@ +| 1 | From ed70e118a967701a9ecc9a15214e8a10b2219b78 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Aug 2022 09:02:42 +0200 Subject: [PATCH 008/415] Python: Make test/Filter query more robust Since if you had tornado installed, we would follow imports and have results from those files as well :| --- python/ql/test/library-tests/filters/tests/Filter.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/test/library-tests/filters/tests/Filter.ql b/python/ql/test/library-tests/filters/tests/Filter.ql index 0528a318f77..967ed8d12f7 100644 --- a/python/ql/test/library-tests/filters/tests/Filter.ql +++ b/python/ql/test/library-tests/filters/tests/Filter.ql @@ -2,4 +2,5 @@ import python import semmle.python.filters.Tests from TestScope t +where exists(t.getLocation().getFile().getRelativePath()) select t From 2e2cee06c36e7c689ece97d47562889f9efd9638 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Aug 2022 09:12:21 +0200 Subject: [PATCH 009/415] Python: Adjust InsecureRandomnessCustomizations.qll --- .../python/security/InsecureRandomnessCustomizations.qll | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python/ql/src/experimental/semmle/python/security/InsecureRandomnessCustomizations.qll b/python/ql/src/experimental/semmle/python/security/InsecureRandomnessCustomizations.qll index 29230af4634..cc99b286f8a 100644 --- a/python/ql/src/experimental/semmle/python/security/InsecureRandomnessCustomizations.qll +++ b/python/ql/src/experimental/semmle/python/security/InsecureRandomnessCustomizations.qll @@ -59,12 +59,11 @@ module InsecureRandomness { */ class RandomFnSink extends Sink { RandomFnSink() { - exists(DataFlowCallable randomFn | - randomFn - .getName() + exists(Function func | + func.getName() .regexpMatch("(?i).*(gen(erate)?|make|mk|create).*(nonce|salt|pepper|Password).*") | - this.getEnclosingCallable() = randomFn + this.asExpr().getScope() = func ) } } From 7648462f989b17d5b437e9daddf7970ee468f095 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Aug 2022 14:56:19 +0200 Subject: [PATCH 010/415] Python: Fix ExternalAPIs queries The output might end up being slightly more noisy since we don't collapse positional and keyword arguments when the external target function is included in the database, but this aligns with our long-term goal of not doing that anymore, so I think it's fine. --- .../CWE-020-ExternalAPIs/ExternalAPIs.qll | 263 +++++++++--------- ...ExternalAPIsUsedWithUntrustedData.expected | 5 +- .../UntrustedDataToExternalAPI.expected | 24 +- .../Security/CWE-020-ExternalAPIs/test.py | 8 +- 4 files changed, 159 insertions(+), 141 deletions(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index fc2e64fc786..94494f3ca9b 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -1,48 +1,36 @@ /** * Definitions for reasoning about untrusted data used in APIs defined outside the - * database. + * user-written code. */ -import python +private import python import semmle.python.dataflow.new.DataFlow -import semmle.python.dataflow.new.TaintTracking -import semmle.python.Concepts -import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.dataflow.new.TaintTracking +private import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.ApiGraphs private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate private import semmle.python.dataflow.new.internal.TaintTrackingPrivate as TaintTrackingPrivate -private import semmle.python.types.Builtins -private import semmle.python.objects.ObjectInternal -// IMPLEMENTATION NOTES: -// -// This query uses *both* the new data-flow library, and points-to. Why? To get this -// finished quickly, so it can provide value for our field team and ourselves. -// -// In the long run, it should not need to use points-to for anything. Possibly this can -// even be helpful in figuring out what we need from TypeTrackers and the new data-flow -// library to be fully operational. -// -// At least it will allow us to provide a baseline comparison against a solution that -// doesn't use points-to at all -// -// There is a few dirty things we do here: -// 1. DataFlowPrivate: since `DataFlowCall` and `DataFlowCallable` are not exposed -// publicly, but we really want access to them. -// 2. points-to: we kinda need to do this since this is what powers `DataFlowCall` and -// `DataFlowCallable` -// 3. ObjectInternal: to provide better names for built-in functions and methods. If we -// really wanted to polish our points-to implementation, we could move this -// functionality into `BuiltinFunctionValue` and `BuiltinMethodValue`, but will -// probably require some more work: for this query, it's totally ok to use -// `builtins.open` for the code `open(f)`, but well, it requires a bit of thinking to -// figure out if that is desirable in general. I simply skipped a corner here! -// 4. TaintTrackingPrivate: Nothing else gives us access to `defaultAdditionalTaintStep` :( /** - * A callable that is considered a "safe" external API from a security perspective. + * An external API that is considered a "safe" from a security perspective. */ class SafeExternalApi extends Unit { - /** Gets a callable that is considered a "safe" external API from a security perspective. */ - abstract DataFlowPrivate::DataFlowCallable getSafeCallable(); + /** + * Gets a call that is considered "safe" from a security perspective. You can use API + * graphs to find calls to functions you know are safe. + * + * Which works even when the external library isn't extracted. + */ + abstract DataFlow::CallCfgNode getSafeCall(); + + /** + * Gets a callable that is considered a "safe" external API from a security + * perspective. + * + * You probably want to define this as `none()` and use `getSafeCall` instead, since + * that can handle the external library not being extracted. + */ + DataFlowPrivate::DataFlowCallable getSafeCallable() { none() } } /** DEPRECATED: Alias for SafeExternalApi */ @@ -50,57 +38,112 @@ deprecated class SafeExternalAPI = SafeExternalApi; /** The default set of "safe" external APIs. */ private class DefaultSafeExternalApi extends SafeExternalApi { - override DataFlowPrivate::DataFlowCallable getSafeCallable() { - exists(CallableValue cv | cv = result.getCallableValue() | - cv = Value::named(["len", "isinstance", "getattr", "hasattr"]) - or - exists(ClassValue cls, string attr | - cls = Value::named("dict") and attr in ["__getitem__", "__setitem__"] - | - cls.lookup(attr) = cv - ) + override DataFlow::CallCfgNode getSafeCall() { + result = API::builtin(["len", "isinstance", "getattr", "hasattr"]).getACall() + } +} + +/** Gets a human readable representation of `node`. */ +string apiNodeToStringRepr(API::Node node) { + node = API::builtin(result) + or + node = API::moduleImport(result) + or + exists(API::Node base, string basename | + base.getDepth() < node.getDepth() and + basename = apiNodeToStringRepr(base) + | + exists(string m | node = base.getMember(m) | result = basename + "." + m) + or + node = base.getReturn() and + result = basename + "()" + or + node = base.getAwaited() and + result = basename + ) +} + +newtype TInterestingExternalApiCall = + TUnresolvedCall(DataFlow::CallCfgNode call) { + exists(call.getLocation().getFile().getRelativePath()) and + not exists(DataFlowPrivate::DataFlowCall dfCall | dfCall.getNode() = call.getNode()) and + not call = any(SafeExternalApi safe).getSafeCall() + } or + TResolvedCall(DataFlowPrivate::DataFlowCall call) { + exists(call.getLocation().getFile().getRelativePath()) and + not call.getCallable() = any(SafeExternalApi safe).getSafeCallable() and + not exists(call.getCallable().getLocation().getFile().getRelativePath()) + } + +abstract class InterestingExternalApiCall extends TInterestingExternalApiCall { + /** Gets the argument at position `apos`, if any */ + abstract DataFlow::Node getArgument(DataFlowPrivate::ArgumentPosition apos); + + /** Gets a textual representation of this element. */ + abstract string toString(); + + /** + * Gets a human-readable name for the external API. + */ + abstract string getApiName(); +} + +class ResolvedCall extends InterestingExternalApiCall, TResolvedCall { + DataFlowPrivate::DataFlowCall dfCall; + + ResolvedCall() { this = TResolvedCall(dfCall) } + + override DataFlow::Node getArgument(DataFlowPrivate::ArgumentPosition apos) { + result = dfCall.getArgument(apos) + } + + override string toString() { result = "ExternalAPI:ResolvedCall" } + + override string getApiName() { + exists(DataFlow::CallCfgNode call, API::Node apiNode | dfCall.getNode() = call.getNode() | + result = apiNodeToStringRepr(apiNode) and + apiNode.getACall() = call + ) + } +} + +class UnresolvedCall extends InterestingExternalApiCall, TUnresolvedCall { + DataFlow::CallCfgNode call; + + UnresolvedCall() { this = TUnresolvedCall(call) } + + override DataFlow::Node getArgument(DataFlowPrivate::ArgumentPosition apos) { + exists(int i | apos.isPositional(i) | result = call.getArg(i)) + or + exists(string name | apos.isKeyword(name) | result = call.getArgByName(name)) + } + + override string toString() { result = "ExternalAPI:UnresolvedCall" } + + override string getApiName() { + exists(API::Node apiNode | + result = apiNodeToStringRepr(apiNode) and + apiNode.getACall() = call ) } } /** A node representing data being passed to an external API through a call. */ class ExternalApiDataNode extends DataFlow::Node { - DataFlowPrivate::DataFlowCallable callable; - int i; + InterestingExternalApiCall call; + DataFlowPrivate::ArgumentPosition apos; ExternalApiDataNode() { - exists(DataFlowPrivate::DataFlowCall call | - exists(call.getLocation().getFile().getRelativePath()) - | - callable = call.getCallable() and - // TODO: this ignores some complexity of keyword arguments (especially keyword-only args) - this = call.getArg(i) - ) and - not any(SafeExternalApi safe).getSafeCallable() = callable and - exists(Value cv | cv = callable.getCallableValue() | - cv.isAbsent() - or - cv.isBuiltin() - or - cv.(CallableValue).getScope().getLocation().getFile().inStdlib() - or - not exists(cv.(CallableValue).getScope().getLocation().getFile().getRelativePath()) - ) and + this = call.getArgument(apos) and // Not already modeled as a taint step not exists(DataFlow::Node next | TaintTrackingPrivate::defaultAdditionalTaintStep(this, next)) and // for `list.append(x)`, we have a additional taint step from x -> [post] list. // Since we have modeled this explicitly, I don't see any cases where we would want to report this. - not exists(DataFlow::Node prev, DataFlow::PostUpdateNode post | + not exists(DataFlow::PostUpdateNode post | post.getPreUpdateNode() = this and - TaintTrackingPrivate::defaultAdditionalTaintStep(prev, post) + TaintTrackingPrivate::defaultAdditionalTaintStep(_, post) ) } - - /** Gets the index for the parameter that will receive this untrusted data */ - int getIndex() { result = i } - - /** Gets the callable to which this argument is passed. */ - DataFlowPrivate::DataFlowCallable getCallable() { result = callable } } /** DEPRECATED: Alias for ExternalApiDataNode */ @@ -133,19 +176,26 @@ deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode; /** An external API which is used with untrusted data. */ private newtype TExternalApi = - /** An untrusted API method `m` where untrusted data is passed at `index`. */ - TExternalApiParameter(DataFlowPrivate::DataFlowCallable callable, int index) { - exists(UntrustedExternalApiDataNode n | - callable = n.getCallable() and - index = n.getIndex() + MkExternalApi(string repr, DataFlowPrivate::ArgumentPosition apos) { + exists(UntrustedExternalApiDataNode ex, InterestingExternalApiCall call | + ex = call.getArgument(apos) and + repr = call.getApiName() ) } -/** An external API which is used with untrusted data. */ -class ExternalApiUsedWithUntrustedData extends TExternalApi { +/** A argument of an external API which is used with untrusted data. */ +class ExternalApiUsedWithUntrustedData extends MkExternalApi { + string repr; + DataFlowPrivate::ArgumentPosition apos; + + ExternalApiUsedWithUntrustedData() { this = MkExternalApi(repr, apos) } + /** Gets a possibly untrusted use of this external API. */ UntrustedExternalApiDataNode getUntrustedDataNode() { - this = TExternalApiParameter(result.getCallable(), result.getIndex()) + exists(InterestingExternalApiCall call | + result = call.getArgument(apos) and + call.getApiName() = repr + ) } /** Gets the number of untrusted sources used with this external API. */ @@ -154,63 +204,8 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi { } /** Gets a textual representation of this element. */ - string toString() { - exists( - DataFlowPrivate::DataFlowCallable callable, int index, string callableString, - string indexString - | - this = TExternalApiParameter(callable, index) and - indexString = "param " + index and - exists(CallableValue cv | cv = callable.getCallableValue() | - callableString = - cv.getScope().getEnclosingModule().getName() + "." + cv.getScope().getQualifiedName() - or - not exists(cv.getScope()) and - ( - cv instanceof BuiltinFunctionValue and - callableString = pretty_builtin_function_value(cv) - or - cv instanceof BuiltinMethodValue and - callableString = pretty_builtin_method_value(cv) - or - not cv instanceof BuiltinFunctionValue and - not cv instanceof BuiltinMethodValue and - callableString = cv.toString() - ) - ) and - result = callableString + " [" + indexString + "]" - ) - } + string toString() { result = repr + " [" + apos + "]" } } /** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */ deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData; - -/** Gets the fully qualified name for the `BuiltinFunctionValue` bfv. */ -private string pretty_builtin_function_value(BuiltinFunctionValue bfv) { - exists(Builtin b | b = bfv.(BuiltinFunctionObjectInternal).getBuiltin() | - result = prefix_with_module_if_found(b) - ) -} - -/** Gets the fully qualified name for the `BuiltinMethodValue` bmv. */ -private string pretty_builtin_method_value(BuiltinMethodValue bmv) { - exists(Builtin b | b = bmv.(BuiltinMethodObjectInternal).getBuiltin() | - exists(Builtin cls | cls.isClass() and cls.getMember(b.getName()) = b | - result = prefix_with_module_if_found(cls) + "." + b.getName() - ) - or - not exists(Builtin cls | cls.isClass() and cls.getMember(b.getName()) = b) and - result = b.getName() - ) -} - -/** Helper predicate that tries to adds module qualifier to `b`. Will succeed even if module not found. */ -private string prefix_with_module_if_found(Builtin b) { - exists(Builtin mod | mod.isModule() and mod.getMember(b.getName()) = b | - result = mod.getName() + "." + b.getName() - ) - or - not exists(Builtin mod | mod.isModule() and mod.getMember(b.getName()) = b) and - result = b.getName() -} diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected index 7438c415858..a346aef9d22 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected @@ -1 +1,4 @@ -| hmac.new [param 1] | 2 | 1 | +| hmac.new [keyword msg] | 1 | 1 | +| hmac.new [position 1] | 1 | 1 | +| unknown.lib.func [keyword kw] | 2 | 1 | +| unknown.lib.func [position 0] | 2 | 1 | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected index e024ef20cba..ead0ff7b093 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected @@ -1,12 +1,20 @@ edges | test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:13:16:13:22 | ControlFlowNode for request | | test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:23:16:23:22 | ControlFlowNode for request | +| test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:34:12:34:18 | ControlFlowNode for request | +| test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:42:12:42:18 | ControlFlowNode for request | | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:5:26:5:32 | GSSA Variable request | | test.py:5:26:5:32 | GSSA Variable request | test.py:0:0:0:0 | ModuleVariableNode for test.request | | test.py:13:16:13:22 | ControlFlowNode for request | test.py:13:16:13:27 | ControlFlowNode for Attribute | | test.py:13:16:13:27 | ControlFlowNode for Attribute | test.py:15:36:15:39 | ControlFlowNode for data | | test.py:23:16:23:22 | ControlFlowNode for request | test.py:23:16:23:27 | ControlFlowNode for Attribute | | test.py:23:16:23:27 | ControlFlowNode for Attribute | test.py:25:44:25:47 | ControlFlowNode for data | +| test.py:34:12:34:18 | ControlFlowNode for request | test.py:34:12:34:23 | ControlFlowNode for Attribute | +| test.py:34:12:34:23 | ControlFlowNode for Attribute | test.py:35:10:35:13 | ControlFlowNode for data | +| test.py:34:12:34:23 | ControlFlowNode for Attribute | test.py:36:13:36:16 | ControlFlowNode for data | +| test.py:42:12:42:18 | ControlFlowNode for request | test.py:42:12:42:23 | ControlFlowNode for Attribute | +| test.py:42:12:42:23 | ControlFlowNode for Attribute | test.py:43:22:43:25 | ControlFlowNode for data | +| test.py:42:12:42:23 | ControlFlowNode for Attribute | test.py:44:25:44:28 | ControlFlowNode for data | nodes | test.py:0:0:0:0 | ModuleVariableNode for test.request | semmle.label | ModuleVariableNode for test.request | | test.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | @@ -17,7 +25,19 @@ nodes | test.py:23:16:23:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | test.py:23:16:23:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:25:44:25:47 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| test.py:34:12:34:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| test.py:34:12:34:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:35:10:35:13 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| test.py:36:13:36:16 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| test.py:42:12:42:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| test.py:42:12:42:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:43:22:43:25 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| test.py:44:25:44:28 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | subpaths #select -| test.py:15:36:15:39 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [param 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:25:44:25:47 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:44:25:47 | ControlFlowNode for data | Call to hmac.new [param 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:15:36:15:39 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [position 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:25:44:25:47 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:25:44:25:47 | ControlFlowNode for data | Call to hmac.new [keyword msg] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:35:10:35:13 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:35:10:35:13 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:36:13:36:16 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:36:13:36:16 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:43:22:43:25 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:43:22:43:25 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:44:25:44:28 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:44:25:44:28 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py index ca4191ded85..dd4edcbcf64 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py @@ -32,16 +32,16 @@ def hmac_example2(): def unknown_lib_1(): from unknown.lib import func data = request.args.get("data") - func(data) # TODO: currently not recognized - func(kw=data) # TODO: currently not recognized + func(data) + func(kw=data) @app.route("/unknown-lib-2") def unknown_lib_2(): import unknown.lib data = request.args.get("data") - unknown.lib.func(data) # TODO: currently not recognized - unknown.lib.func(kw=data) # TODO: currently not recognized + unknown.lib.func(data) + unknown.lib.func(kw=data) if __name__ == "__main__": From 0bdc808a7a3e34c1551df10c2a961c18cd13f109 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Aug 2022 15:13:15 +0200 Subject: [PATCH 011/415] Python: Add ExternalAPI test `None.json.dumps` --- .../ExternalAPIsUsedWithUntrustedData.expected | 2 ++ .../UntrustedDataToExternalAPI.expected | 12 ++++++++++++ .../Security/CWE-020-ExternalAPIs/test.py | 10 ++++++++++ 3 files changed, 24 insertions(+) diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected index a346aef9d22..30220ea651d 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected @@ -1,3 +1,5 @@ +| None.json.dumps [position 0] | 1 | 1 | +| builtins.None.json.dumps [position 0] | 1 | 1 | | hmac.new [keyword msg] | 1 | 1 | | hmac.new [position 1] | 1 | 1 | | unknown.lib.func [keyword kw] | 2 | 1 | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected index ead0ff7b093..708054a8dab 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected @@ -3,6 +3,7 @@ edges | test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:23:16:23:22 | ControlFlowNode for request | | test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:34:12:34:18 | ControlFlowNode for request | | test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:42:12:42:18 | ControlFlowNode for request | +| test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:54:12:54:18 | ControlFlowNode for request | | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:5:26:5:32 | GSSA Variable request | | test.py:5:26:5:32 | GSSA Variable request | test.py:0:0:0:0 | ModuleVariableNode for test.request | | test.py:13:16:13:22 | ControlFlowNode for request | test.py:13:16:13:27 | ControlFlowNode for Attribute | @@ -15,6 +16,10 @@ edges | test.py:42:12:42:18 | ControlFlowNode for request | test.py:42:12:42:23 | ControlFlowNode for Attribute | | test.py:42:12:42:23 | ControlFlowNode for Attribute | test.py:43:22:43:25 | ControlFlowNode for data | | test.py:42:12:42:23 | ControlFlowNode for Attribute | test.py:44:25:44:28 | ControlFlowNode for data | +| test.py:47:17:47:19 | ControlFlowNode for arg | test.py:50:32:50:34 | ControlFlowNode for arg | +| test.py:54:12:54:18 | ControlFlowNode for request | test.py:54:12:54:23 | ControlFlowNode for Attribute | +| test.py:54:12:54:23 | ControlFlowNode for Attribute | test.py:55:17:55:20 | ControlFlowNode for data | +| test.py:55:17:55:20 | ControlFlowNode for data | test.py:47:17:47:19 | ControlFlowNode for arg | nodes | test.py:0:0:0:0 | ModuleVariableNode for test.request | semmle.label | ModuleVariableNode for test.request | | test.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | @@ -33,6 +38,11 @@ nodes | test.py:42:12:42:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:43:22:43:25 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:44:25:44:28 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| test.py:47:17:47:19 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | +| test.py:50:32:50:34 | ControlFlowNode for arg | semmle.label | ControlFlowNode for arg | +| test.py:54:12:54:18 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| test.py:54:12:54:23 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:55:17:55:20 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | subpaths #select | test.py:15:36:15:39 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:15:36:15:39 | ControlFlowNode for data | Call to hmac.new [position 1] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | @@ -41,3 +51,5 @@ subpaths | test.py:36:13:36:16 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:36:13:36:16 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:43:22:43:25 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:43:22:43:25 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:44:25:44:28 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:44:25:44:28 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:50:32:50:34 | ControlFlowNode for arg | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:50:32:50:34 | ControlFlowNode for arg | Call to None.json.dumps [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | +| test.py:50:32:50:34 | ControlFlowNode for arg | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:50:32:50:34 | ControlFlowNode for arg | Call to builtins.None.json.dumps [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py index dd4edcbcf64..18b46298d8a 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py @@ -44,6 +44,16 @@ def unknown_lib_2(): unknown.lib.func(kw=data) +def handle_this(arg, application = None): + if application: + # since application could be None, we could end up reporting `None.json.dumps` + application.json.dumps(arg) + +@app.route("/optional-arg") +def optional_arg(): + data = request.args.get("data") + handle_this(data) + if __name__ == "__main__": # http://127.0.0.1:5000/hmac-example?data=aGVsbG8gd29ybGQh app.run(debug=True) From 70cc986d5f794e433e94faa2173d252cefbf2d7d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Aug 2022 15:16:59 +0200 Subject: [PATCH 012/415] Python: Suppress `None.json.dumps` from ExternalAPI queries --- .../src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll | 10 ++++++++-- .../ExternalAPIsUsedWithUntrustedData.expected | 2 -- .../UntrustedDataToExternalAPI.expected | 2 -- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index 94494f3ca9b..ae2c9c273f5 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -43,7 +43,12 @@ private class DefaultSafeExternalApi extends SafeExternalApi { } } -/** Gets a human readable representation of `node`. */ +/** + * Gets a human readable representation of `node`. + * + * Note that this is only defined for API nodes that are allowed as external APIs, + * so `None.json.dumps` will for example not be allowed. + */ string apiNodeToStringRepr(API::Node node) { node = API::builtin(result) or @@ -51,7 +56,8 @@ string apiNodeToStringRepr(API::Node node) { or exists(API::Node base, string basename | base.getDepth() < node.getDepth() and - basename = apiNodeToStringRepr(base) + basename = apiNodeToStringRepr(base) and + not base = API::builtin("None") | exists(string m | node = base.getMember(m) | result = basename + "." + m) or diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected index 30220ea651d..a346aef9d22 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected @@ -1,5 +1,3 @@ -| None.json.dumps [position 0] | 1 | 1 | -| builtins.None.json.dumps [position 0] | 1 | 1 | | hmac.new [keyword msg] | 1 | 1 | | hmac.new [position 1] | 1 | 1 | | unknown.lib.func [keyword kw] | 2 | 1 | diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected index 708054a8dab..bb6ffaab366 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected @@ -51,5 +51,3 @@ subpaths | test.py:36:13:36:16 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:36:13:36:16 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:43:22:43:25 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:43:22:43:25 | ControlFlowNode for data | Call to unknown.lib.func [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | | test.py:44:25:44:28 | ControlFlowNode for data | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:44:25:44:28 | ControlFlowNode for data | Call to unknown.lib.func [keyword kw] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:50:32:50:34 | ControlFlowNode for arg | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:50:32:50:34 | ControlFlowNode for arg | Call to None.json.dumps [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | -| test.py:50:32:50:34 | ControlFlowNode for arg | test.py:5:26:5:32 | ControlFlowNode for ImportMember | test.py:50:32:50:34 | ControlFlowNode for arg | Call to builtins.None.json.dumps [position 0] with untrusted data from $@. | test.py:5:26:5:32 | ControlFlowNode for ImportMember | ControlFlowNode for ImportMember | From af9be6ad7ea6699d3b3c7709d57339664ab20ba6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Aug 2022 15:45:02 +0200 Subject: [PATCH 013/415] Python: Suppress more spurious alerts from ExternalAPI queries --- .../CWE-020-ExternalAPIs/ExternalAPIs.qll | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index ae2c9c273f5..76aa68c5162 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -39,7 +39,11 @@ deprecated class SafeExternalAPI = SafeExternalApi; /** The default set of "safe" external APIs. */ private class DefaultSafeExternalApi extends SafeExternalApi { override DataFlow::CallCfgNode getSafeCall() { - result = API::builtin(["len", "isinstance", "getattr", "hasattr"]).getACall() + result = + API::builtin([ + "len", "enumerate", "isinstance", "getattr", "hasattr", "bool", "float", "int", "repr", + "str", "type" + ]).getACall() } } @@ -57,28 +61,40 @@ string apiNodeToStringRepr(API::Node node) { exists(API::Node base, string basename | base.getDepth() < node.getDepth() and basename = apiNodeToStringRepr(base) and - not base = API::builtin("None") + not base = API::builtin(["None", "True", "False"]) | exists(string m | node = base.getMember(m) | result = basename + "." + m) or node = base.getReturn() and - result = basename + "()" + result = basename + "()" and + not base.getACall() = any(SafeExternalApi safe).getSafeCall() or node = base.getAwaited() and result = basename ) } +predicate resolvedCall(CallNode call) { + DataFlowPrivate::resolveCall(call, _, _) or + DataFlowPrivate::resolveClassCall(call, _) +} + newtype TInterestingExternalApiCall = TUnresolvedCall(DataFlow::CallCfgNode call) { exists(call.getLocation().getFile().getRelativePath()) and - not exists(DataFlowPrivate::DataFlowCall dfCall | dfCall.getNode() = call.getNode()) and + not resolvedCall(call.getNode()) and not call = any(SafeExternalApi safe).getSafeCall() } or TResolvedCall(DataFlowPrivate::DataFlowCall call) { exists(call.getLocation().getFile().getRelativePath()) and not call.getCallable() = any(SafeExternalApi safe).getSafeCallable() and - not exists(call.getCallable().getLocation().getFile().getRelativePath()) + // ignore calls inside codebase, and ignore calls that are marked as safe. This is + // only needed as long as we extract dependencies. When we stop doing that, all + // targets of resolved calls will be from user-written code. + not exists(call.getCallable().getLocation().getFile().getRelativePath()) and + not exists(DataFlow::CallCfgNode callCfgNode | callCfgNode.getNode() = call.getNode() | + any(SafeExternalApi safe).getSafeCall() = callCfgNode + ) } abstract class InterestingExternalApiCall extends TInterestingExternalApiCall { @@ -103,7 +119,9 @@ class ResolvedCall extends InterestingExternalApiCall, TResolvedCall { result = dfCall.getArgument(apos) } - override string toString() { result = "ExternalAPI:ResolvedCall" } + override string toString() { + result = "ExternalAPI:ResolvedCall: " + dfCall.getNode().getNode().toString() + } override string getApiName() { exists(DataFlow::CallCfgNode call, API::Node apiNode | dfCall.getNode() = call.getNode() | @@ -124,7 +142,9 @@ class UnresolvedCall extends InterestingExternalApiCall, TUnresolvedCall { exists(string name | apos.isKeyword(name) | result = call.getArgByName(name)) } - override string toString() { result = "ExternalAPI:UnresolvedCall" } + override string toString() { + result = "ExternalAPI:UnresolvedCall: " + call.getNode().getNode().toString() + } override string getApiName() { exists(API::Node apiNode | From 7c1320ed4bc13e41d91f4019767bd4c72c21ec37 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Aug 2022 15:49:51 +0200 Subject: [PATCH 014/415] Python: Adjust ExternalAPI qhelp files --- .../ExternalAPIsUsedWithUntrustedData.qhelp | 10 +++------- .../UntrustedDataToExternalAPI.qhelp | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp index 0627615ca64..e0692ffeae0 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp @@ -11,11 +11,9 @@ relevant for security analysis of this application.

An external API is defined as a call to a method that is not defined in the source code, and is not modeled as a taint step in the default taint library. External APIs may -be from the Python standard library or dependencies. The query will report the fully qualified name, -along with [param x], where x indicates the position of -the parameter receiving the untrusted data. Note that for methods and -classmethods, parameter 0 represents the class instance or class itself -respectively.

+be from the Python standard library or dependencies. The query will report the fully +qualified name, along with [position index] or [keyword name], +to indicate the argument passing the untrusted data.

Note that an excepted sink might not be included in the results, if it also defines a taint step. This is the case for pickle.loads which is a sink for the @@ -24,8 +22,6 @@ Unsafe Deserialization query, but is also a taint step for other queries.

Note: Compared to the Java version of this query, we currently do not give special care to methods that are overridden in the source code.

-

Note: Currently this query will only report results for external packages that are extracted.

- diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp b/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp index fc7f1a18da9..2b8c31d37b7 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp @@ -11,11 +11,9 @@ be modeled as either taint steps, or sinks for specific problems.

An external API is defined as a call to a method that is not defined in the source code, and is not modeled as a taint step in the default taint library. External APIs may -be from the Python standard library or dependencies. The query will report the fully qualified name, -along with [param x], where x indicates the position of -the parameter receiving the untrusted data. Note that for methods and -classmethods, parameter 0 represents the class instance or class itself -respectively.

+be from the Python standard library or dependencies. The query will report the fully +qualified name, along with [position index] or [keyword name], +to indicate the argument passing the untrusted data.

Note that an excepted sink might not be included in the results, if it also defines a taint step. This is the case for pickle.loads which is a sink for the @@ -24,8 +22,6 @@ Unsafe Deserialization query, but is also a taint step for other queries.

Note: Compared to the Java version of this query, we currently do not give special care to methods that are overridden in the source code.

-

Note: Currently this query will only report results for external packages that are extracted.

- From f2e92bf96322562e879c31392862f30471ed14b1 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 24 Aug 2022 10:45:08 +0200 Subject: [PATCH 015/415] Python: Port `py/meta/call-graph` --- python/ql/src/meta/analysis-quality/CallGraph.ql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/ql/src/meta/analysis-quality/CallGraph.ql b/python/ql/src/meta/analysis-quality/CallGraph.ql index d23ee43014c..71ca77e87f8 100644 --- a/python/ql/src/meta/analysis-quality/CallGraph.ql +++ b/python/ql/src/meta/analysis-quality/CallGraph.ql @@ -1,9 +1,9 @@ /** * @name Call graph - * @description An edge in the points-to call graph. + * @description An edge in the call graph. * @kind problem * @problem.severity recommendation - * @id py/meta/points-to-call-graph + * @id py/meta/call-graph * @tags meta * @precision very-low */ @@ -11,6 +11,6 @@ import python import semmle.python.dataflow.new.internal.DataFlowPrivate -from DataFlowCall c, DataFlowCallableValue f -where c.getCallable() = f -select c, "Call to $@", f.getScope(), f.toString() +from DataFlowCall call, DataFlowCallable target +where target = viableCallable(call) +select call, "Call to $@", target.getScope(), target.toString() From f3ac81a013d90479624c8ffba67c2d64829ccb73 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 6 Sep 2022 13:54:17 +0200 Subject: [PATCH 016/415] Python: Expand tests for special method calls --- .../CallGraph/code/class_special_methods.py | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py index 7b8df9c4139..454eb5207a1 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py @@ -1,29 +1,66 @@ -class B(object): +class Base(object): def __init__(self, arg): - print('B.__init__', arg) + print("Base.__init__", arg) self.arg = arg def __str__(self): - print('B.__str__') - return 'B (arg={})'.format(self.arg) + print("Base.__str__") + return 'Base STR (arg={})'.format(self.arg) def __add__(self, other): - print('B.__add__') - if isinstance(other, B): - return B(self.arg + other.arg) # $ tt=B.__init__ - return B(self.arg + other) # $ tt=B.__init__ + print("Base.__add__") + if isinstance(other, Base): + return Base(self.arg + other.arg) # $ tt=Base.__init__ + return Base(self.arg + other) # $ tt=Base.__init__ -b = B(1) # $ tt=B.__init__ + def __call__(self, val): + print("Base.__call__", val) + + def wat(self): + print("Base.wat") + self(43) # $ MISSING: tt=Base.__call__ tt=Sub.__call__ + + +b = Base(1) # $ tt=Base.__init__ print(str(b)) # this calls `str(b)` inside print(b) +print("\n! calls") +b(42) # $ MISSING: tt=Base.__call__ +b.wat() # $ pt,tt=Base.wat -b2 = B(2) # $ tt=B.__init__ +b.__call__(44) # $ pt,tt=Base.__call__ + +print("\n! b2") +b2 = Base(2) # $ tt=Base.__init__ # __add__ is called b + b2 b + 100 + + +# ======== +print("\n! Sub") + +class Sub(Base): + def __add__(self, other): + print("Sub.__add__") + + def __call__(self, arg): + print("Sub.__call__", arg) + +sub = Sub(10) # $ tt=Base.__init__ +sub + 42 + +sub(55) # $ MISSING: tt=Sub.__call__ +sub.wat() # $ pt,tt=Base.wat + +# not possible to indirectly access addition of subclass +try: + super(Sub, sub) + 143 +except TypeError: + print("TypeError as expected") From b5e8bf7882b0599c69f4b73eeca001b18ba01ef7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 6 Sep 2022 14:24:30 +0200 Subject: [PATCH 017/415] Python: Add note about trying `DataFlowDispatchPointsTo` for `InlineCallGraphTest` Since I was very confused about no results for __call__, I tried to see whether I had cheated by making the comparison too unfair. But it didn't seem to be the case. --- .../library-tests/CallGraph/InlineCallGraphTest.ql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql index d00d0ae1301..327621fb7f2 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql @@ -6,6 +6,10 @@ private import semmle.python.dataflow.new.internal.DataFlowDispatch as TT predicate pointsToCallEdge(CallNode call, Function callable) { exists(call.getLocation().getFile().getRelativePath()) and exists(callable.getLocation().getFile().getRelativePath()) and + // I did try using viableCallable from `DataFlowDispatchPointsTo` (from temporary copy + // of `dataflow.new.internal` that still uses points-to) instead of direct + // `getACall()` on a Value, but it only added results for `__init__` methods, not for + // anything else. exists(PythonFunctionValue funcValue | funcValue.getScope() = callable and call = funcValue.getACall() From a5c3e850f115c07d5a7b43870af464aa2f887aad Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 6 Sep 2022 14:34:30 +0200 Subject: [PATCH 018/415] Python: Handle `__call__` --- .../new/internal/DataFlowDispatch.qll | 42 +++++++++++++++++-- .../dataflow/new/internal/DataFlowPublic.qll | 3 ++ .../dataflow/basic/local.expected | 1 + .../dataflow/basic/sinks.expected | 1 + .../dataflow/basic/sources.expected | 1 + .../CallGraph/InlineCallGraphTest.expected | 4 ++ .../CallGraph/code/class_special_methods.py | 6 +-- 7 files changed, 52 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 37841765030..3a6b431de6e 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -622,7 +622,9 @@ newtype TCallType = */ CallTypeMethodAsPlainFunction() or /** A call to a class. */ - CallTypeClass() + CallTypeClass() or + /** A call on a class instance, that goes to the `__call__` method of the class */ + CallTypeClassInstanceCall() /** A type of call. */ class CallType extends TCallType { @@ -644,6 +646,9 @@ class CallType extends TCallType { or this instanceof CallTypeClass and result = "CallTypeClass" + or + this instanceof CallTypeClassInstanceCall and + result = "CallTypeClassInstanceCall" } } @@ -664,7 +669,7 @@ private module MethodCalls { private predicate directCall( CallNode call, Function target, string functionName, Class cls, AttrRead attr, Node self ) { - target = findFunctionAccordingToMroKnownStartingClass(cls, cls, functionName) and + target = findFunctionAccordingToMroKnownStartingClass(cls, functionName) and directCall_join(call, functionName, cls, attr, self) } @@ -826,6 +831,24 @@ Function invokedFunctionFromClassConstruction(Class cls) { result = findFunctionAccordingToMroKnownStartingClass(cls, "__init__") } +/** + * Holds when `call` is a call on a class instance, that goes to the `__call__` method + * of the class. + * + * See https://docs.python.org/3/reference/datamodel.html#object.__call__ + */ +predicate resolveClassInstanceCall(CallNode call, Function target, Node self) { + exists(Class cls | + call.getFunction() = classInstanceTracker(cls).asCfgNode() and + target = findFunctionAccordingToMroKnownStartingClass(cls, "__call__") + or + call.getFunction() = selfTracker(cls).asCfgNode() and + target = findFunctionAccordingToMro(getADirectSubclass*(cls), "__call__") + | + self.asCfgNode() = call.getFunction() + ) +} + // ------------------------------------- // overall call resolution // ------------------------------------- @@ -844,6 +867,9 @@ predicate resolveCall(ControlFlowNode call, Function target, CallType type) { resolveClassCall(call, cls) and target = invokedFunctionFromClassConstruction(cls) ) + or + type instanceof CallTypeClassInstanceCall and + resolveClassInstanceCall(call, target, _) } // ============================================================================= @@ -953,6 +979,15 @@ predicate getCallArg( or normalCallArg(call, arg, apos) ) + or + // call on class instance, which goes to `__call__` method + type instanceof CallTypeClassInstanceCall and + ( + apos.isSelf() and + resolveClassInstanceCall(call, target, arg) + or + normalCallArg(call, arg, apos) + ) ) } @@ -1010,7 +1045,8 @@ abstract class ExtractedDataFlowCall extends DataFlowCall { * A resolved call in source code with an underlying `CallNode`. * * This is considered normal, compared with special calls such as `obj[0]` calling the - * `__getitem__` method on the object. + * `__getitem__` method on the object. However, this also includes calls that go to the + * `__call__` special method. */ class NormalCall extends ExtractedDataFlowCall, TNormalCall { CallNode call; diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index aa48df91c0c..d184dc4117c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -51,6 +51,9 @@ newtype TNode = node = call.getArg(_) or node = call.getArgByName(_) + or + // `self` argument when handling class instance calls (`__call__` special method)) + node = call.getFunction() ) or node = any(AttrNode a).getObject() diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 74263f31a52..133f740596c 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -47,6 +47,7 @@ | test.py:7:1:7:1 | ControlFlowNode for b | test.py:7:1:7:1 | ControlFlowNode for b | | test.py:7:1:7:1 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index 97d7e313dac..cfd8effd77b 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -20,6 +20,7 @@ | test.py:7:1:7:1 | ControlFlowNode for b | | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | | test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index 97d7e313dac..cfd8effd77b 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -20,6 +20,7 @@ | test.py:7:1:7:1 | ControlFlowNode for b | | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:7:5:7:17 | [post] ControlFlowNode for obfuscated_id | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | | test.py:7:5:7:20 | [pre] ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 10031cecde5..e748746b01a 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -24,6 +24,10 @@ typeTracker_found_pointsTo_notFound | code/class_more_mro2.py:21:1:21:8 | ControlFlowNode for Attribute() | A.foo | | code/class_more_mro.py:24:9:24:21 | ControlFlowNode for Attribute() | A.foo | | code/class_more_mro.py:34:1:34:16 | ControlFlowNode for Attribute() | A.foo | +| code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Base.__call__ | +| code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Sub.__call__ | +| code/class_special_methods.py:33:1:33:5 | ControlFlowNode for b() | Base.__call__ | +| code/class_special_methods.py:59:1:59:7 | ControlFlowNode for sub() | Sub.__call__ | | code/class_super.py:43:9:43:21 | ControlFlowNode for Attribute() | A.bar | | code/class_super.py:44:9:44:27 | ControlFlowNode for Attribute() | A.bar | | code/class_super.py:63:1:63:18 | ControlFlowNode for Attribute() | A.foo | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py index 454eb5207a1..e765f155f3c 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py @@ -19,7 +19,7 @@ class Base(object): def wat(self): print("Base.wat") - self(43) # $ MISSING: tt=Base.__call__ tt=Sub.__call__ + self(43) # $ tt=Base.__call__ tt=Sub.__call__ b = Base(1) # $ tt=Base.__init__ @@ -30,7 +30,7 @@ print(b) print("\n! calls") -b(42) # $ MISSING: tt=Base.__call__ +b(42) # $ tt=Base.__call__ b.wat() # $ pt,tt=Base.wat b.__call__(44) # $ pt,tt=Base.__call__ @@ -56,7 +56,7 @@ class Sub(Base): sub = Sub(10) # $ tt=Base.__init__ sub + 42 -sub(55) # $ MISSING: tt=Sub.__call__ +sub(55) # $ tt=Sub.__call__ sub.wat() # $ pt,tt=Base.wat # not possible to indirectly access addition of subclass From 61410191e7d85122f5f6d33eb33be5f91eee9fe3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 1 Nov 2022 15:43:16 +0100 Subject: [PATCH 019/415] Python: Fix bug in `argumentRoutingTest.ql` Since `DataFlowPrivate::DataFlowCall` only exists for calls resolved to a function, we didn't have any results before... but allowing any call helps things! --- .../experimental/dataflow/coverage/argumentRoutingTest.ql | 4 ++-- python/ql/test/experimental/dataflow/coverage/classes.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql index 1a58715fc1c..6a4db891996 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql @@ -22,10 +22,10 @@ class Argument1RoutingConfig extends DataFlow::Configuration { override predicate isSource(DataFlow::Node node) { node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg1" or - exists(AssignmentDefinition def, DataFlowPrivate::DataFlowCall call | + exists(AssignmentDefinition def, DataFlow::CallCfgNode call | def.getVariable() = node.(DataFlow::EssaNode).getVar() and def.getValue() = call.getNode() and - call.getNode().(CallNode).getFunction().(NameNode).getId().matches("With\\_%") + call.getFunction().asCfgNode().(NameNode).getId().matches("With\\_%") ) and node.(DataFlow::EssaNode).getVar().getName().matches("with\\_%") } diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index af8d19354e7..bd60a93f243 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -506,7 +506,7 @@ class With_call: def test_call(): - with_call = With_call() #$ MISSING: arg1="SSA variable with_call" func=With_call.__call__ + with_call = With_call() #$ arg1="SSA variable with_call" func=With_call.__call__ with_call() From 7014be204707ec5e0facc9727a0716a205294bad Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 8 Sep 2022 17:13:57 +0200 Subject: [PATCH 020/415] Python: Reduce size of `attrReadTracker` On pallets/flask, this reduced the number of tuples from 100866 results => 33060 results --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 3a6b431de6e..83680b04247 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -585,7 +585,11 @@ Function findFunctionAccordingToMroKnownStartingClass(Class startingClass, strin /** Gets a reference to the attribute read `attr` */ private TypeTrackingNode attrReadTracker(TypeTracker t, AttrRead attr) { t.start() and - result = attr + result = attr and + attr.getObject() in [ + classTracker(_), classInstanceTracker(_), selfTracker(_), clsTracker(_), + superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _) + ] or exists(TypeTracker t2 | result = attrReadTracker(t2, attr).track(t2, t)) } From e7a337991af0505ee361631fe333f1bcae23df8d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 8 Sep 2022 17:17:04 +0200 Subject: [PATCH 021/415] Python: Accept fix from extractor change namely the variable access mentioned in https://github.com/github/codeql/pull/10171 --- .../test/experimental/library-tests/CallGraph/code/shadowing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py b/python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py index fdbf554084e..ad91712c481 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/shadowing.py @@ -16,7 +16,7 @@ def test(): class A(object): def foo(self): print("A.foo") - foo() # $ pt=foo MISSING: tt=foo + foo() # $ pt,tt=foo a = A() a.foo() # $ pt,tt=A.foo From 5a976cfb1460a37e51c128ae5f7edf71644d6030 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 8 Sep 2022 21:11:29 +0200 Subject: [PATCH 022/415] Python: Add more `**kwargs` arg passing tests --- .../dataflow/coverage/argumentPassing.py | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 7129cded015..68657c2ae05 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -38,6 +38,14 @@ SINK5 = functools.partial(SINK, expected=arg5) SINK6 = functools.partial(SINK, expected=arg6) SINK7 = functools.partial(SINK, expected=arg7) +SINK1_F = functools.partial(SINK_F, unexpected=arg1) +SINK2_F = functools.partial(SINK_F, unexpected=arg2) +SINK3_F = functools.partial(SINK_F, unexpected=arg3) +SINK4_F = functools.partial(SINK_F, unexpected=arg4) +SINK5_F = functools.partial(SINK_F, unexpected=arg5) +SINK6_F = functools.partial(SINK_F, unexpected=arg6) +SINK7_F = functools.partial(SINK_F, unexpected=arg7) + def argument_passing( a, @@ -64,7 +72,7 @@ def argument_passing( @expects(7) def test_argument_passing1(): - argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 MISSING: arg2 arg3 arg4 arg6 arg7 + argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 MISSING: arg2 arg3 arg4 arg6 arg7 @expects(7) @@ -112,32 +120,6 @@ def test_default_arguments(): with_default_arguments(**{"c": arg3}) #$ MISSING: arg3 -# Nested constructor pattern -def grab_foo_bar_baz(foo, **kwargs): - SINK1(foo) - grab_bar_baz(**kwargs) - - -# It is not possible to pass `bar` into `kwargs`, -# since `bar` is a valid keyword argument. -def grab_bar_baz(bar, **kwargs): - SINK2(bar) - try: - SINK2_F(kwargs["bar"]) - except: - print("OK") - grab_baz(**kwargs) - - -def grab_baz(baz): - SINK3(baz) - - -@expects(4) -def test_grab(): - grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1 MISSING: arg2 func=grab_bar_baz arg3 func=grab_baz - - # All combinations def test_pos_pos(): def with_pos(a): @@ -183,7 +165,38 @@ def test_kw_kw(): def test_kw_doublestar(): - def with_doublestar(**a): - SINK1(a["a"]) + def with_doublestar(**kwargs): + SINK1(kwargs["a"]) with_doublestar(a=arg1) #$ MISSING: arg1 func=test_kw_doublestar.with_doublestar + + +def only_kwargs(**kwargs): + SINK1(kwargs["a"]) + SINK2(kwargs["b"]) + SINK3_F(kwargs["c"]) + +@expects(3) +def test_kwargs(): + args = {"a": arg1, "b": arg2, "c": "safe"} # $ MISSING: arg1 arg2 func=only_kwargs + only_kwargs(**args) + + +def mixed(a, **kwargs): + SINK1(a) + try: + SINK1_F(kwargs["a"]) # since 'a' is a keyword argument, it cannot be part of **kwargs + except KeyError: + print("OK") + SINK2(kwargs["b"]) + SINK3_F(kwargs["c"]) + +@expects(4*3) +def test_mixed(): + mixed(a=arg1, b=arg2, c="safe") # $ arg1 MISSING: arg2 + + args = {"b": arg2, "c": "safe"} # $ MISSING: arg2 func=mixed + mixed(a=arg1, **args) # $ arg1 + + args = {"a": arg1, "b": arg2, "c": "safe"} # $ MISSING: arg2 func=mixed MISSING: arg1 + mixed(**args) From 9b2663034d30d9e129491f8e9aa3e6892f800ada Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 9 Sep 2022 10:16:25 +0200 Subject: [PATCH 023/415] Python: Change test .ql to also show bad argument flow --- .../coverage/argumentPassing_bad_flow_test.py | 63 +++++++++ .../dataflow/coverage/argumentRoutingTest.ql | 129 ++++++++++++------ 2 files changed, 149 insertions(+), 43 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/coverage/argumentPassing_bad_flow_test.py diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing_bad_flow_test.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing_bad_flow_test.py new file mode 100644 index 00000000000..44451801a9e --- /dev/null +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing_bad_flow_test.py @@ -0,0 +1,63 @@ +import sys +import os +import functools + +sys.path.append(os.path.dirname(os.path.dirname((__file__)))) +from testlib import expects + +arg = "source" +arg1 = "source1" +arg2 = "source2" +arg3 = "source3" +arg4 = "source4" +arg5 = "source5" +arg6 = "source6" +arg7 = "source7" + + +def SINK_TEST(x, test): + if test(x): + print("OK") + else: + print("Unexpected flow", x) + + +def SINK(x, expected=arg): + SINK_TEST(x, test=lambda x: x == expected) + + +def SINK_F(x, unexpected=arg): + SINK_TEST(x, test=lambda x: x != unexpected) + + +SINK1 = functools.partial(SINK, expected=arg1) +SINK2 = functools.partial(SINK, expected=arg2) +SINK3 = functools.partial(SINK, expected=arg3) +SINK4 = functools.partial(SINK, expected=arg4) +SINK5 = functools.partial(SINK, expected=arg5) +SINK6 = functools.partial(SINK, expected=arg6) +SINK7 = functools.partial(SINK, expected=arg7) + +SINK1_F = functools.partial(SINK_F, unexpected=arg1) +SINK2_F = functools.partial(SINK_F, unexpected=arg2) +SINK3_F = functools.partial(SINK_F, unexpected=arg3) +SINK4_F = functools.partial(SINK_F, unexpected=arg4) +SINK5_F = functools.partial(SINK_F, unexpected=arg5) +SINK6_F = functools.partial(SINK_F, unexpected=arg6) +SINK7_F = functools.partial(SINK_F, unexpected=arg7) + + +def bad_argument_flow_func(arg): + SINK1_F(arg) + +def bad_argument_flow_func2(arg): + SINK2(arg) + +def test_bad_argument_flow(): + # this is just a test to show that the testing setup works + + # in the first one, we pretend we expected no flow for arg1 + bad_argument_flow_func(arg1) # $ bad1="arg1" + + # in the second one, we pretend we wanted flow for arg2 instead + bad_argument_flow_func2(arg1) # $ bad2="arg1" diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql index 6a4db891996..2adbd635090 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRoutingTest.ql @@ -9,19 +9,60 @@ class Argument1RoutingTest extends RoutingTest { override string flowTag() { result = "arg1" } override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { - exists(Argument1RoutingConfig cfg | cfg.hasFlow(source, sink)) + exists(Argument1ExtraRoutingConfig cfg | cfg.hasFlow(source, sink)) + or + exists(ArgumentRoutingConfig cfg | + cfg.hasFlow(source, sink) and + cfg.isArgSource(source, 1) and + cfg.isGoodSink(sink, 1) + ) } } -/** - * A configuration to check routing of arguments through magic methods. - */ -class Argument1RoutingConfig extends DataFlow::Configuration { - Argument1RoutingConfig() { this = "Argument1RoutingConfig" } +class ArgNumber extends int { + ArgNumber() { this in [1 .. 7] } +} + +class ArgumentRoutingConfig extends DataFlow::Configuration { + ArgumentRoutingConfig() { this = "ArgumentRoutingConfig" } + + predicate isArgSource(DataFlow::Node node, ArgNumber argNumber) { + node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg" + argNumber + } + + override predicate isSource(DataFlow::Node node) { this.isArgSource(node, _) } + + predicate isGoodSink(DataFlow::Node node, ArgNumber argNumber) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" + argNumber and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + predicate isBadSink(DataFlow::Node node, ArgNumber argNumber) { + exists(CallNode call | + call.getFunction().(NameNode).getId() = "SINK" + argNumber + "_F" and + node.(DataFlow::CfgNode).getNode() = call.getAnArg() + ) + } + + override predicate isSink(DataFlow::Node node) { + this.isGoodSink(node, _) or this.isBadSink(node, _) + } + + /** + * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. + * Use-use flow lets the argument to the first call reach the sink inside the second call, + * making it seem like we handle all cases even if we only handle the last one. + * We make the test honest by preventing flow into source nodes. + */ + override predicate isBarrierIn(DataFlow::Node node) { this.isSource(node) } +} + +class Argument1ExtraRoutingConfig extends DataFlow::Configuration { + Argument1ExtraRoutingConfig() { this = "Argument1ExtraRoutingConfig" } override predicate isSource(DataFlow::Node node) { - node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg1" - or exists(AssignmentDefinition def, DataFlow::CallCfgNode call | def.getVariable() = node.(DataFlow::EssaNode).getVar() and def.getValue() = call.getNode() and @@ -46,57 +87,59 @@ class Argument1RoutingConfig extends DataFlow::Configuration { override predicate isBarrierIn(DataFlow::Node node) { this.isSource(node) } } -// for argument 2 and up, we use a generic approach. Change `maxNumArgs` below if we -// need to increase the maximum number of arguments. -private int maxNumArgs() { result = 7 } - class RestArgumentRoutingTest extends RoutingTest { - int argNumber; + ArgNumber argNumber; RestArgumentRoutingTest() { - argNumber in [2 .. maxNumArgs()] and + argNumber > 1 and this = "Argument" + argNumber + "RoutingTest" } override string flowTag() { result = "arg" + argNumber } override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { - exists(RestArgumentRoutingConfig cfg | cfg.getArgNumber() = argNumber | - cfg.hasFlow(source, sink) + exists(ArgumentRoutingConfig cfg | + cfg.hasFlow(source, sink) and + cfg.isArgSource(source, argNumber) and + cfg.isGoodSink(sink, argNumber) ) } } -/** - * A configuration to check routing of arguments through magic methods. - */ -class RestArgumentRoutingConfig extends DataFlow::Configuration { - int argNumber; +/** Bad flow from `arg` to `SINK_F` */ +class BadArgumentRoutingTestSinkF extends RoutingTest { + ArgNumber argNumber; - RestArgumentRoutingConfig() { - argNumber in [2 .. maxNumArgs()] and - this = "Argument" + argNumber + "RoutingConfig" - } + BadArgumentRoutingTestSinkF() { this = "BadArgumentRoutingTestSinkF" + argNumber } - /** Gets the argument number this configuration is for. */ - int getArgNumber() { result = argNumber } + override string flowTag() { result = "bad" + argNumber } - override predicate isSource(DataFlow::Node node) { - node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg" + argNumber - } - - override predicate isSink(DataFlow::Node node) { - exists(CallNode call | - call.getFunction().(NameNode).getId() = "SINK" + argNumber and - node.(DataFlow::CfgNode).getNode() = call.getAnArg() + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(ArgumentRoutingConfig cfg | + cfg.hasFlow(source, sink) and + cfg.isArgSource(source, argNumber) and + cfg.isBadSink(sink, argNumber) + ) + } +} + +/** Bad flow from `arg` to `SINK` or `SINK_F`, where `n != m`. */ +class BadArgumentRoutingTestWrongSink extends RoutingTest { + ArgNumber argNumber; + + BadArgumentRoutingTestWrongSink() { this = "BadArgumentRoutingTestWrongSink" + argNumber } + + override string flowTag() { result = "bad" + argNumber } + + override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) { + exists(ArgumentRoutingConfig cfg | + cfg.hasFlow(source, sink) and + cfg.isArgSource(source, any(ArgNumber i | not i = argNumber)) and + ( + cfg.isGoodSink(sink, argNumber) + or + cfg.isBadSink(sink, argNumber) + ) ) } - - /** - * We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`. - * Use-use flow lets the argument to the first call reach the sink inside the second call, - * making it seem like we handle all cases even if we only handle the last one. - * We make the test honest by preventing flow into source nodes. - */ - override predicate isBarrierIn(DataFlow::Node node) { this.isSource(node) } } From 5722d231bdae159f391945c762b3834d013733ef Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 6 Sep 2022 16:21:13 +0200 Subject: [PATCH 024/415] Python: Add basic support for `**kwargs` For now this is JUST from `**kwargs` in arguments, to `**kwargs` parameters, and this part is based on field-flow Note that dataflow-library complains about missing post update nodes for these. This needs to be ignored, since post update nodes for `**kwargs` arguments doesn't make sense, it's not possible to alter the dictionary inside the method. --- python/ql/lib/semmle/python/Flow.qll | 6 +++++ .../new/internal/DataFlowDispatch.qll | 22 +++++++++++++++++-- .../dataflow/coverage/argumentPassing.py | 8 +++---- .../coverage/dataflow-consistency.expected | 15 +++++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index e736749bba5..bd491d527cc 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -411,6 +411,12 @@ class CallNode extends ControlFlowNode { result.getNode() = this.getNode().getStarArg() and result.getBasicBlock().dominates(this.getBasicBlock()) } + + /** Gets a dictionary (**) argument of this call, if any. */ + ControlFlowNode getKwargs() { + result.getNode() = this.getNode().getKwargs() and + result.getBasicBlock().dominates(this.getBasicBlock()) + } } /** A control flow corresponding to an attribute expression, such as `value.attr` */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 83680b04247..bcf1ae97940 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -41,7 +41,8 @@ newtype TParameterPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfParameterPosition() or TPositionalParameterPosition(int pos) { pos = any(Parameter p).getPosition() } or - TKeywordParameterPosition(string name) { name = any(Parameter p).getName() } + TKeywordParameterPosition(string name) { name = any(Parameter p).getName() } or + TDictSplatParameterPosition() /** A parameter position. */ class ParameterPosition extends TParameterPosition { @@ -54,6 +55,9 @@ class ParameterPosition extends TParameterPosition { /** Holds if this position represents a keyword parameter named `name`. */ predicate isKeyword(string name) { this = TKeywordParameterPosition(name) } + /** Holds if this position represents a `**kwargs` parameter. */ + predicate isDictSplat() { this = TDictSplatParameterPosition() } + /** Gets a textual representation of this element. */ string toString() { this.isSelf() and result = "self" @@ -61,6 +65,8 @@ class ParameterPosition extends TParameterPosition { exists(int index | this.isPositional(index) and result = "position " + index) or exists(string name | this.isKeyword(name) and result = "keyword " + name) + or + this.isDictSplat() and result = "**" } } @@ -68,7 +74,8 @@ newtype TArgumentPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfArgumentPosition() or TPositionalArgumentPosition(int pos) { exists(any(CallNode c).getArg(pos)) } or - TKeywordArgumentPosition(string name) { exists(any(CallNode c).getArgByName(name)) } + TKeywordArgumentPosition(string name) { exists(any(CallNode c).getArgByName(name)) } or + TDictSplatArgumentPosition() /** An argument position. */ class ArgumentPosition extends TArgumentPosition { @@ -81,6 +88,9 @@ class ArgumentPosition extends TArgumentPosition { /** Holds if this position represents a keyword argument named `name`. */ predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) } + /** Holds if this position represents a `**kwargs` argument. */ + predicate isDictSplat() { this = TDictSplatArgumentPosition() } + /** Gets a textual representation of this element. */ string toString() { this.isSelf() and result = "self" @@ -88,6 +98,8 @@ class ArgumentPosition extends TArgumentPosition { exists(int pos | this.isPositional(pos) and result = "position " + pos) or exists(string name | this.isKeyword(name) and result = "keyword " + name) + or + this.isDictSplat() and result = "**" } } @@ -99,6 +111,8 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { exists(int index | ppos.isPositional(index) and apos.isPositional(index)) or exists(string name | ppos.isKeyword(name) and apos.isKeyword(name)) + or + ppos.isDictSplat() and apos.isDictSplat() } // ============================================================================= @@ -183,6 +197,8 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { ) or exists(string name | ppos.isKeyword(name) | result.getParameter() = func.getArgByName(name)) + or + ppos.isDictSplat() and result.getParameter() = func.getKwarg() } } @@ -893,6 +909,8 @@ private predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) apos.isKeyword(name) and arg.asCfgNode() = call.getArgByName(name) ) + or + apos.isDictSplat() and arg.asCfgNode() = call.getKwargs() } /** diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 68657c2ae05..b2bd64ec268 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -72,7 +72,7 @@ def argument_passing( @expects(7) def test_argument_passing1(): - argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 MISSING: arg2 arg3 arg4 arg6 arg7 + argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 arg7 func=argument_passing MISSING: arg2 arg3 arg4 arg6 @expects(7) @@ -178,7 +178,7 @@ def only_kwargs(**kwargs): @expects(3) def test_kwargs(): - args = {"a": arg1, "b": arg2, "c": "safe"} # $ MISSING: arg1 arg2 func=only_kwargs + args = {"a": arg1, "b": arg2, "c": "safe"} # $ arg1 arg2 func=only_kwargs only_kwargs(**args) @@ -195,8 +195,8 @@ def mixed(a, **kwargs): def test_mixed(): mixed(a=arg1, b=arg2, c="safe") # $ arg1 MISSING: arg2 - args = {"b": arg2, "c": "safe"} # $ MISSING: arg2 func=mixed + args = {"b": arg2, "c": "safe"} # $ arg2 func=mixed mixed(a=arg1, **args) # $ arg1 - args = {"a": arg1, "b": arg2, "c": "safe"} # $ MISSING: arg2 func=mixed MISSING: arg1 + args = {"a": arg1, "b": arg2, "c": "safe"} # $ bad1="arg1" arg2 func=mixed mixed(**args) diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected index 8f4dbd04742..ec828310226 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected @@ -17,5 +17,20 @@ uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate +| argumentPassing.py:75:59:75:80 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:105:35:105:45 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:106:29:106:39 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:106:44:106:54 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:106:59:106:69 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:120:30:120:40 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:182:19:182:22 | ControlFlowNode for args | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:196:21:196:24 | ControlFlowNode for args | ArgumentNode is missing PostUpdateNode. | +| argumentPassing.py:199:13:199:16 | ControlFlowNode for args | ArgumentNode is missing PostUpdateNode. | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/functools.py:400:58:400:70 | ControlFlowNode for Attribute | ArgumentNode is missing PostUpdateNode. | +| test.py:396:30:396:42 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| test.py:422:33:422:46 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| test.py:512:30:512:42 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| test.py:529:33:529:46 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | +| test.py:838:17:838:18 | ControlFlowNode for dd | ArgumentNode is missing PostUpdateNode. | postWithInFlow viableImplInCallContextTooLarge From eb600f07b74e6dd10f360248945992c40d63314f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 8 Sep 2022 21:32:36 +0200 Subject: [PATCH 025/415] Python: Use config for `dataflow-consistency.ql` And ignore post-update nodes for `**kwargs` arguments --- .../dataflow/TestUtil/DataFlowConsistency.qll | 11 +++++++++++ .../dataflow/basic/dataflow-consistency.ql | 3 ++- .../callgraph_crosstalk/dataflow-consistency.ql | 3 ++- .../dataflow/calls/dataflow-consistency.ql | 3 ++- .../dataflow/consistency/dataflow-consistency.ql | 3 ++- .../coverage/dataflow-consistency.expected | 15 --------------- .../dataflow/coverage/dataflow-consistency.ql | 3 ++- .../dataflow/fieldflow/dataflow-consistency.ql | 3 ++- .../dataflow/global-flow/dataflow-consistency.ql | 3 ++- .../dataflow/match/dataflow-consistency.ql | 3 ++- .../dataflow/pep_328/dataflow-consistency.ql | 3 ++- .../dataflow/regression/dataflow-consistency.ql | 3 ++- .../strange-essaflow/dataflow-consistency.ql | 3 ++- .../tainttracking/basic/dataflow-consistency.ql | 3 ++- .../commonSanitizer/dataflow-consistency.ql | 3 ++- .../customSanitizer/dataflow-consistency.ql | 3 ++- .../dataflow-consistency.ql | 3 ++- .../dataflow-consistency.ql | 3 ++- .../unwanted-global-flow/dataflow-consistency.ql | 3 ++- .../dataflow/typetracking/dataflow-consistency.ql | 3 ++- .../variable-capture/dataflow-consistency.ql | 3 ++- .../CallGraph/dataflow-consistency.ql | 3 ++- .../ApiGraphs/py3/dataflow-consistency.ql | 3 ++- .../frameworks/django-orm/dataflow-consistency.ql | 3 ++- 24 files changed, 55 insertions(+), 37 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll new file mode 100644 index 00000000000..b11c3ecd838 --- /dev/null +++ b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll @@ -0,0 +1,11 @@ +import semmle.python.dataflow.new.DataFlow::DataFlow +import semmle.python.dataflow.new.internal.DataFlowPrivate +import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency + +// TODO: this should be promoted to be a REAL consistency query by being placed in +// `python/ql/consistency-queries`. For for now it resides here. +private class MyConsistencyConfiguration extends ConsistencyConfiguration { + override predicate argHasPostUpdateExclude(ArgumentNode n) { + exists(ArgumentPosition apos | n.argumentOf(_, apos) and apos.isDictSplat()) + } +} diff --git a/python/ql/test/experimental/dataflow/basic/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/basic/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/basic/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/basic/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/calls/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/calls/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/calls/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/calls/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected index ec828310226..8f4dbd04742 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected @@ -17,20 +17,5 @@ uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate -| argumentPassing.py:75:59:75:80 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:105:35:105:45 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:106:29:106:39 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:106:44:106:54 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:106:59:106:69 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:120:30:120:40 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:182:19:182:22 | ControlFlowNode for args | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:196:21:196:24 | ControlFlowNode for args | ArgumentNode is missing PostUpdateNode. | -| argumentPassing.py:199:13:199:16 | ControlFlowNode for args | ArgumentNode is missing PostUpdateNode. | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/functools.py:400:58:400:70 | ControlFlowNode for Attribute | ArgumentNode is missing PostUpdateNode. | -| test.py:396:30:396:42 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| test.py:422:33:422:46 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| test.py:512:30:512:42 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| test.py:529:33:529:46 | ControlFlowNode for Dict | ArgumentNode is missing PostUpdateNode. | -| test.py:838:17:838:18 | ControlFlowNode for dd | ArgumentNode is missing PostUpdateNode. | postWithInFlow viableImplInCallContextTooLarge diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/fieldflow/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/fieldflow/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/fieldflow/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/global-flow/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/global-flow/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/global-flow/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/global-flow/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/match/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/match/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/match/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/match/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/pep_328/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/pep_328/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/pep_328/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/pep_328/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/regression/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/regression/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/regression/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/strange-essaflow/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/strange-essaflow/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/strange-essaflow/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/strange-essaflow/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/tainttracking/basic/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/tainttracking/basic/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/basic/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/basic/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/commonSanitizer/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/customSanitizer/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep-py3/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/tainttracking/unwanted-global-flow/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/typetracking/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/typetracking/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/typetracking/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/typetracking/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/dataflow/variable-capture/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/variable-capture/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/variable-capture/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/variable-capture/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/library-tests/ApiGraphs/py3/dataflow-consistency.ql b/python/ql/test/library-tests/ApiGraphs/py3/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/library-tests/ApiGraphs/py3/dataflow-consistency.ql +++ b/python/ql/test/library-tests/ApiGraphs/py3/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency diff --git a/python/ql/test/library-tests/frameworks/django-orm/dataflow-consistency.ql b/python/ql/test/library-tests/frameworks/django-orm/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/library-tests/frameworks/django-orm/dataflow-consistency.ql +++ b/python/ql/test/library-tests/frameworks/django-orm/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency From 503ad544e95ba051d5adf1935ef7c45bb497b27c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 9 Sep 2022 13:53:01 +0200 Subject: [PATCH 026/415] Python: Remove impossible flow for `**kwargs` params --- .../dataflow/new/internal/DataFlowPrivate.qll | 24 +++++++++++++++++++ .../dataflow/coverage/argumentPassing.py | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 8c4c807d3a8..cab77c83290 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -54,6 +54,28 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { override Location getLocation() { result = node.getLocation() } } +/** + * Ensures that the a `**kwargs` parameter will not contain elements with names of + * keyword parameters. + * + * For example, for the function below, it's not possible that the `kwargs` dictionary + * can contain an element with the name `a`, since that parameter can be given as a + * keyword argument. + * + * ```py + * def func(a, **kwargs): + * ... + * ``` + */ +private predicate dictSplatParameterNodeClearStep(ParameterNode n, DictionaryElementContent c) { + exists(DataFlowCallable callable, ParameterPosition dictSplatPos, ParameterPosition keywordPos | + dictSplatPos.isDictSplat() and + n = callable.getParameter(dictSplatPos) and + exists(callable.getParameter(keywordPos)) and + keywordPos.isKeyword(c.getKey()) + ) +} + abstract class PostUpdateNodeImpl extends Node { /** Gets the node before the state update. */ abstract Node getPreUpdateNode(); @@ -673,6 +695,8 @@ predicate clearsContent(Node n, Content c) { attributeClearStep(n, c) or FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) + or + dictSplatParameterNodeClearStep(n, c) } /** diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index b2bd64ec268..eca8ec9c1f5 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -198,5 +198,5 @@ def test_mixed(): args = {"b": arg2, "c": "safe"} # $ arg2 func=mixed mixed(a=arg1, **args) # $ arg1 - args = {"a": arg1, "b": arg2, "c": "safe"} # $ bad1="arg1" arg2 func=mixed + args = {"a": arg1, "b": arg2, "c": "safe"} # $ arg2 func=mixed MISSING: arg1 mixed(**args) From 215a03d94811468101f4c7b776c1bb2d94b7843e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 9 Sep 2022 13:59:54 +0200 Subject: [PATCH 027/415] Python: Support flow to `**kwargs` param from keyword arg --- .../new/internal/DataFlowDispatch.qll | 7 ++++- .../dataflow/new/internal/DataFlowPrivate.qll | 31 +++++++++++++++++++ .../dataflow/new/internal/DataFlowPublic.qll | 3 +- .../dataflow/coverage/argumentPassing.py | 4 +-- .../experimental/dataflow/coverage/test.py | 4 +-- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index bcf1ae97940..1b9e2ded82f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -910,7 +910,12 @@ private predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) arg.asCfgNode() = call.getArgByName(name) ) or - apos.isDictSplat() and arg.asCfgNode() = call.getKwargs() + apos.isDictSplat() and + ( + arg.asCfgNode() = call.getKwargs() + or + arg = TSynthDictSplatArgumentNode(call) + ) } /** diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index cab77c83290..d6abd40e721 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -54,6 +54,33 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { override Location getLocation() { result = node.getLocation() } } +/** + * A (synthetic) data-flow node that represents all keyword arguments, as if they had + * been passed in a `**kwargs` argument. + */ +class SynthDictSplatArgumentNode extends Node, TSynthDictSplatArgumentNode { + CallNode node; + + SynthDictSplatArgumentNode() { this = TSynthDictSplatArgumentNode(node) } + + override string toString() { result = "SynthDictSplatArgumentNode" } + + override Scope getScope() { result = node.getScope() } + + override Location getLocation() { result = node.getLocation() } +} + +private predicate synthDictSplatArgumentNodeStoreStep( + ArgumentNode nodeFrom, DictionaryElementContent c, SynthDictSplatArgumentNode nodeTo +) { + exists(string name, CallNode call, ArgumentPosition keywordPos | + nodeTo = TSynthDictSplatArgumentNode(call) and + getCallArg(call, _, _, nodeFrom, keywordPos) and + keywordPos.isKeyword(name) and + c.getKey() = name + ) +} + /** * Ensures that the a `**kwargs` parameter will not contain elements with names of * keyword parameters. @@ -426,6 +453,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) { any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo) or FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom, c, nodeTo) + or + synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo) } /** @@ -752,6 +781,8 @@ predicate nodeIsHidden(Node n) { n instanceof SummaryNode or n instanceof SummaryParameterNode + or + n instanceof SynthDictSplatArgumentNode } class LambdaCallKind = Unit; diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index d184dc4117c..761202ecb94 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -112,7 +112,8 @@ newtype TNode = } or TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) { FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos) - } + } or + TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } class TParameterNode = TCfgNode or TSummaryParameterNode; diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index eca8ec9c1f5..4d87e750572 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -168,7 +168,7 @@ def test_kw_doublestar(): def with_doublestar(**kwargs): SINK1(kwargs["a"]) - with_doublestar(a=arg1) #$ MISSING: arg1 func=test_kw_doublestar.with_doublestar + with_doublestar(a=arg1) #$ arg1 func=test_kw_doublestar.with_doublestar def only_kwargs(**kwargs): @@ -193,7 +193,7 @@ def mixed(a, **kwargs): @expects(4*3) def test_mixed(): - mixed(a=arg1, b=arg2, c="safe") # $ arg1 MISSING: arg2 + mixed(a=arg1, b=arg2, c="safe") # $ arg1 arg2 args = {"b": arg2, "c": "safe"} # $ arg2 func=mixed mixed(a=arg1, **args) # $ arg1 diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 0e06a828700..f4aadf433b2 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -409,7 +409,7 @@ def f_extra_keyword(a, **b): def test_call_extra_keyword(): - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_keyword(..)" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" # return the name of the first extra keyword argument @@ -519,7 +519,7 @@ def test_lambda_extra_pos(): def test_lambda_extra_keyword(): f_extra_keyword = lambda a, **b: b["b"] - SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_keyword(..)" + SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)" # call the function with our source as the name of the keyword argument From c687df4ddc862ae8737f916e771de5938db87909 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 9 Sep 2022 17:05:08 +0200 Subject: [PATCH 028/415] Python: Support flow to keyword param from `**kwargs` arg When resolving merge conflict after flow-summaries was merged, this is the original commit where I introduced ParameterNodeImpl, so this is the commit where differences in that implementation was committed... I removed TParameterNode, since I could not see we we gain anything from having it. --- .../new/internal/DataFlowDispatch.qll | 6 +- .../dataflow/new/internal/DataFlowPrivate.qll | 69 +++++++++++++++++++ .../dataflow/new/internal/DataFlowPublic.qll | 17 +++-- .../dataflow/TestUtil/DataFlowConsistency.qll | 8 +++ .../dataflow/basic/callGraphSinks.expected | 1 + .../dataflow/basic/local.expected | 1 + .../dataflow/basic/sinks.expected | 1 + .../dataflow/basic/sources.expected | 1 + .../dataflow/coverage/argumentPassing.py | 10 +-- .../experimental/dataflow/coverage/test.py | 4 +- 10 files changed, 101 insertions(+), 17 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 1b9e2ded82f..ffca8390d86 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -199,6 +199,8 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { exists(string name | ppos.isKeyword(name) | result.getParameter() = func.getArgByName(name)) or ppos.isDictSplat() and result.getParameter() = func.getKwarg() + or + ppos.isDictSplat() and result = TSynthDictSplatParameterNode(this) } } @@ -1194,7 +1196,9 @@ abstract class ParameterNodeImpl extends Node { * Holds if this node is the parameter of callable `c` at the * position `ppos`. */ - abstract predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos); + predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos) { + this = c.getParameter(ppos) + } } /** A parameter for a library callable with a flow summary. */ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index d6abd40e721..7b2a1d81580 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -39,6 +39,9 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) //-------- predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr } +// ============================================================================= +// SyntheticPreUpdateNode +// ============================================================================= class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { CallNode node; @@ -54,6 +57,9 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { override Location getLocation() { result = node.getLocation() } } +// ============================================================================= +// **kwargs (DictSplat) related +// ============================================================================= /** * A (synthetic) data-flow node that represents all keyword arguments, as if they had * been passed in a `**kwargs` argument. @@ -98,11 +104,70 @@ private predicate dictSplatParameterNodeClearStep(ParameterNode n, DictionaryEle exists(DataFlowCallable callable, ParameterPosition dictSplatPos, ParameterPosition keywordPos | dictSplatPos.isDictSplat() and n = callable.getParameter(dictSplatPos) and + not n instanceof SynthDictSplatParameterNode and exists(callable.getParameter(keywordPos)) and keywordPos.isKeyword(c.getKey()) ) } +/** + * A synthetic data-flow node to allow flow to keyword parameters from a `**kwargs` argument. + * + * Take the code snippet below as an example. Since the call only has a `**kwargs` argument, + * with a `**` argument position, we add this synthetic parameter node with `**` parameter position, + * and a read step to the `p1` parameter. + * + * ```py + * def foo(p1): ... + * + * kwargs = {"p1": 42} + * foo(**kwargs) + * ``` + * + * + * Note that this will introduce a bit of redundancy in cases like + * + * ```py + * foo(p1=taint(1), p2=taint(2)) + * ``` + * + * where direct keyword matching is possible, since we construct a synthesized dict + * splat argument (`SynthDictSplatArgumentNode`) at the call site, which means that + * `taint(1)` will flow into `p1` both via normal keyword matching and via the synthesized + * nodes (and similarly for `p2`). However, this redundancy is OK since + * (a) it means that type-tracking through keyword arguments also works in most cases, + * (b) read/store steps can be avoided when direct keyword matching is possible, and + * hence access path limits are not a concern, and + * (c) since the synthesized nodes are hidden, the reported data-flow paths will be + * collapsed anyway. + */ +class SynthDictSplatParameterNode extends ParameterNodeImpl, TSynthDictSplatParameterNode { + DataFlowCallable callable; + + SynthDictSplatParameterNode() { this = TSynthDictSplatParameterNode(callable) } + + override string toString() { result = "SynthDictSplatParameterNode" } + + override Scope getScope() { result = callable.getScope() } + + override Location getLocation() { result = callable.getLocation() } + + override Parameter getParameter() { none() } +} + +predicate synthDictSplatParameterNodeReadStep( + SynthDictSplatParameterNode nodeFrom, DictionaryElementContent c, ParameterNode nodeTo +) { + exists(DataFlowCallable callable, ParameterPosition ppos | + nodeFrom = TSynthDictSplatParameterNode(callable) and + nodeTo = callable.getParameter(ppos) and + ppos.isKeyword(c.getKey()) + ) +} + +// ============================================================================= +// PostUpdateNode +// ============================================================================= abstract class PostUpdateNodeImpl extends Node { /** Gets the node before the state update. */ abstract Node getPreUpdateNode(); @@ -624,6 +689,8 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) { attributeReadStep(nodeFrom, c, nodeTo) or FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom, c, nodeTo) + or + synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) } /** Data flows from a sequence to a subscript of the sequence. */ @@ -783,6 +850,8 @@ predicate nodeIsHidden(Node n) { n instanceof SummaryParameterNode or n instanceof SynthDictSplatArgumentNode + or + n instanceof SynthDictSplatParameterNode } class LambdaCallKind = Unit; diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 761202ecb94..94d7bb70543 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -64,7 +64,7 @@ newtype TNode = exists(Class cls, Function func, ParameterDefinition def | func = cls.getAMethod() and not hasStaticmethodDecorator(func) and - // this matches what we do in ParameterNode + // this matches what we do in ExtractedParameterNode def.getDefiningNode() = node and def.getParameter() = func.getArg(0) ) @@ -113,9 +113,12 @@ newtype TNode = TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) { FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos) } or - TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } - -class TParameterNode = TCfgNode or TSummaryParameterNode; + /** A synthetic node to capture keyword arguments that are passed to a `**kwargs` parameter. */ + TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } or + /** A synthetic node to allow flow to keyword parameters from a `**kwargs` argument. */ + TSynthDictSplatParameterNode(DataFlowCallable callable) { + exists(ParameterPosition ppos | ppos.isKeyword(_) | exists(callable.getParameter(ppos))) + } /** Helper for `Node::getEnclosingCallable`. */ private DataFlowCallable getCallableScope(Scope s) { @@ -292,7 +295,7 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e } * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ -class ParameterNode extends Node, TParameterNode instanceof ParameterNodeImpl { +class ParameterNode extends Node instanceof ParameterNodeImpl { /** Gets the parameter corresponding to this node, if any. */ final Parameter getParameter() { result = super.getParameter() } } @@ -304,10 +307,6 @@ class ExtractedParameterNode extends ParameterNodeImpl, CfgNode { ExtractedParameterNode() { node = def.getDefiningNode() } - override predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos) { - this = c.getParameter(ppos) - } - override Parameter getParameter() { result = def.getParameter() } } diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll index b11c3ecd838..442c5fff770 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll @@ -8,4 +8,12 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration { override predicate argHasPostUpdateExclude(ArgumentNode n) { exists(ArgumentPosition apos | n.argumentOf(_, apos) and apos.isDictSplat()) } + + override predicate reverseReadExclude(Node n) { + // since `self`/`cls` parameters can be marked as implicit argument to `super()`, + // they will have PostUpdateNodes. We have a read-step from the synthetic `**kwargs` + // parameter, but dataflow-consistency queries should _not_ complain about there not + // being a post-update node for the synthetic `**kwargs` parameter. + n instanceof SynthDictSplatParameterNode + } } diff --git a/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected b/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected index 17f3028ae23..e4b8f905530 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected +++ b/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected @@ -1,2 +1,3 @@ +| test.py:1:1:1:21 | SynthDictSplatParameterNode | | test.py:1:19:1:19 | ControlFlowNode for x | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 133f740596c..cdf40018ed0 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -5,6 +5,7 @@ | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:1:1:21 | SynthDictSplatParameterNode | test.py:1:1:1:21 | SynthDictSplatParameterNode | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index cfd8effd77b..944f8190aa5 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -3,6 +3,7 @@ | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | +| test.py:1:1:1:21 | SynthDictSplatParameterNode | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index cfd8effd77b..944f8190aa5 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -3,6 +3,7 @@ | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | +| test.py:1:1:1:21 | SynthDictSplatParameterNode | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 4d87e750572..a3e4752ffd2 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -72,7 +72,7 @@ def argument_passing( @expects(7) def test_argument_passing1(): - argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 arg7 func=argument_passing MISSING: arg2 arg3 arg4 arg6 + argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg5 arg6 arg7 func=argument_passing MISSING: arg2 arg3 arg4 @expects(7) @@ -102,8 +102,8 @@ def with_multiple_kw_args(a, b, c): def test_multiple_kw_args(): with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1 arg2 arg3 with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1 MISSING: arg2 arg3 - with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1 arg2 MISSING: arg3 - with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ MISSING: arg1 arg2 arg3 + with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1 arg2 arg3 func=with_multiple_kw_args + with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1 arg2 arg3 func=with_multiple_kw_args def with_default_arguments(a=arg1, b=arg2, c=arg3): #$ arg1 arg2 arg3 func=with_default_arguments @@ -117,7 +117,7 @@ def test_default_arguments(): with_default_arguments() with_default_arguments(arg1) #$ arg1 with_default_arguments(b=arg2) #$ arg2 - with_default_arguments(**{"c": arg3}) #$ MISSING: arg3 + with_default_arguments(**{"c": arg3}) #$ arg3 func=with_default_arguments # All combinations @@ -198,5 +198,5 @@ def test_mixed(): args = {"b": arg2, "c": "safe"} # $ arg2 func=mixed mixed(a=arg1, **args) # $ arg1 - args = {"a": arg1, "b": arg2, "c": "safe"} # $ arg2 func=mixed MISSING: arg1 + args = {"a": arg1, "b": arg2, "c": "safe"} # $ arg1 arg2 func=mixed mixed(**args) diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index f4aadf433b2..1a7b2cbb6fa 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -393,7 +393,7 @@ def test_call_unpack_iterable(): def test_call_unpack_mapping(): - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ MISSING: flow="SOURCE -> second(..)" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" def f_extra_pos(a, *b): @@ -509,7 +509,7 @@ def test_lambda_unpack_mapping(): def second(a, b): return b - SINK(second(NONSOURCE, **{"b": SOURCE})) #$ MISSING: flow="SOURCE -> second(..)" + SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)" def test_lambda_extra_pos(): From b6314dd19ddda18b7f4f1dc25560082fc37350ea Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 12 Sep 2022 15:44:10 +0200 Subject: [PATCH 029/415] Python: Add `*args` tests --- .../dataflow/coverage/argumentPassing.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index a3e4752ffd2..c825d86b9f5 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -200,3 +200,51 @@ def test_mixed(): args = {"a": arg1, "b": arg2, "c": "safe"} # $ arg1 arg2 func=mixed mixed(**args) + + +def starargs_only(*args): + SINK1(args[0]) + SINK2(args[1]) + SINK3_F(args[2]) + +@expects(3*3) +def test_only_starargs(): + starargs_only(arg1, arg2, "safe") # $ MISSING: arg1 arg2 + + args = (arg2, "safe") + starargs_only(arg1, *args) # $ MISSING: arg1 arg2 + + args = (arg1, arg2, "safe") + starargs_only(*args) # $ MISSING: arg1 arg2 + + +def starargs_mixed(a, *args): + SINK1(a) + SINK2(args[0]) + SINK3_F(args[1]) + +@expects(3*8) +def test_stararg_mixed(): + starargs_mixed(arg1, arg2, "safe") # $ arg1 MISSING: arg2 + + args = (arg2, "safe") + starargs_mixed(arg1, *args) # $ arg1 MISSING: arg2 + + args = (arg1, arg2, "safe") + starargs_mixed(*args) # $ MISSING: arg1 arg2 + + args = (arg1, arg2, "safe") + more_args = ("foo", "bar") + starargs_mixed(*args, *more_args) # $ MISSING: arg1 arg2 + + empty_args = () + + # adding first/last + starargs_mixed(arg1, arg2, "safe", *empty_args) # $ arg1 MISSING: arg2 + starargs_mixed(*empty_args, arg1, arg2, "safe") # $ MISSING: arg1 arg2 + + # adding before/after *args + args = (arg2, "safe") + starargs_mixed(arg1, *args, *empty_args) # $ arg1 MISSING: arg2 + args = (arg2, "safe") + starargs_mixed(arg1, *empty_args, *args) # $ arg1 MISSING: arg2 From db921ac036f1b5ad8aead972f4d985f6baf79816 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 12 Sep 2022 16:45:57 +0200 Subject: [PATCH 030/415] Python: Add basic support for `*args` --- .../new/internal/DataFlowDispatch.qll | 42 +++++++++++++++++++ .../dataflow/TestUtil/DataFlowConsistency.qll | 2 + .../dataflow/coverage/argumentPassing.py | 8 ++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index ffca8390d86..f5b628f7e45 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -42,6 +42,13 @@ newtype TParameterPosition = TSelfParameterPosition() or TPositionalParameterPosition(int pos) { pos = any(Parameter p).getPosition() } or TKeywordParameterPosition(string name) { name = any(Parameter p).getName() } or + TStarArgsParameterPosition(int pos) { + // since `.getPosition` does not work for `*args`, we need *args parameter positions + // at index 1 larger than the largest positional parameter position (and 0 must be + // included as well). This is a bit of an over-approximation. + pos = 0 or + pos = any(Parameter p).getPosition() + 1 + } or TDictSplatParameterPosition() /** A parameter position. */ @@ -55,6 +62,9 @@ class ParameterPosition extends TParameterPosition { /** Holds if this position represents a keyword parameter named `name`. */ predicate isKeyword(string name) { this = TKeywordParameterPosition(name) } + /** Holds if this position represents a `*args` parameter at (0-based) `index`. */ + predicate isStarArgs(int index) { this = TStarArgsParameterPosition(index) } + /** Holds if this position represents a `**kwargs` parameter. */ predicate isDictSplat() { this = TDictSplatParameterPosition() } @@ -66,6 +76,8 @@ class ParameterPosition extends TParameterPosition { or exists(string name | this.isKeyword(name) and result = "keyword " + name) or + exists(int index | this.isStarArgs(index) and result = "*args at " + index) + or this.isDictSplat() and result = "**" } } @@ -75,6 +87,7 @@ newtype TArgumentPosition = TSelfArgumentPosition() or TPositionalArgumentPosition(int pos) { exists(any(CallNode c).getArg(pos)) } or TKeywordArgumentPosition(string name) { exists(any(CallNode c).getArgByName(name)) } or + TStarArgsArgumentPosition(int pos) { exists(Call c | c.getPositionalArg(pos) instanceof Starred) } or TDictSplatArgumentPosition() /** An argument position. */ @@ -88,6 +101,9 @@ class ArgumentPosition extends TArgumentPosition { /** Holds if this position represents a keyword argument named `name`. */ predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) } + /** Holds if this position represents a `*args` argument at (0-based) `index`. */ + predicate isStarArgs(int index) { this = TStarArgsArgumentPosition(index) } + /** Holds if this position represents a `**kwargs` argument. */ predicate isDictSplat() { this = TDictSplatArgumentPosition() } @@ -99,6 +115,8 @@ class ArgumentPosition extends TArgumentPosition { or exists(string name | this.isKeyword(name) and result = "keyword " + name) or + exists(int index | this.isStarArgs(index) and result = "*args at " + index) + or this.isDictSplat() and result = "**" } } @@ -112,6 +130,8 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { or exists(string name | ppos.isKeyword(name) and apos.isKeyword(name)) or + exists(int index | ppos.isStarArgs(index) and apos.isStarArgs(index)) + or ppos.isDictSplat() and apos.isDictSplat() } @@ -198,6 +218,22 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { or exists(string name | ppos.isKeyword(name) | result.getParameter() = func.getArgByName(name)) or + exists(int index | + ppos.isStarArgs(index) and + result.getParameter() = func.getVararg() + | + // a `*args` parameter comes after the last positional parameter. We need to take + // self parameter into account, so for + // `def func(foo, bar, *args)` it should be index 2 (1 + max-index == 1 + 1) + // `class A: def func(self, foo, bar, *args)` it should be index 2 (1 + max-index - 1 == 1 + 2 - 1) + index = + 1 + max(int positionalIndex | exists(func.getArg(positionalIndex)) | positionalIndex) - + this.positionalOffset() + or + // no positional argument + not exists(func.getArg(_)) and index = 0 + ) + or ppos.isDictSplat() and result.getParameter() = func.getKwarg() or ppos.isDictSplat() and result = TSynthDictSplatParameterNode(this) @@ -912,6 +948,12 @@ private predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) arg.asCfgNode() = call.getArgByName(name) ) or + exists(int index | + apos.isStarArgs(index) and + arg.asCfgNode() = call.getStarArg() and + call.getStarArg().getNode() = call.getNode().getPositionalArg(index).(Starred).getValue() + ) + or apos.isDictSplat() and ( arg.asCfgNode() = call.getKwargs() diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll index 442c5fff770..8d85437b7d3 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll @@ -6,6 +6,8 @@ import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency // `python/ql/consistency-queries`. For for now it resides here. private class MyConsistencyConfiguration extends ConsistencyConfiguration { override predicate argHasPostUpdateExclude(ArgumentNode n) { + exists(ArgumentPosition apos | n.argumentOf(_, apos) and apos.isStarArgs(_)) + or exists(ArgumentPosition apos | n.argumentOf(_, apos) and apos.isDictSplat()) } diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index c825d86b9f5..4e55bc48cd7 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -214,8 +214,8 @@ def test_only_starargs(): args = (arg2, "safe") starargs_only(arg1, *args) # $ MISSING: arg1 arg2 - args = (arg1, arg2, "safe") - starargs_only(*args) # $ MISSING: arg1 arg2 + args = (arg1, arg2, "safe") # $ arg1 arg2 func=starargs_only + starargs_only(*args) def starargs_mixed(a, *args): @@ -227,8 +227,8 @@ def starargs_mixed(a, *args): def test_stararg_mixed(): starargs_mixed(arg1, arg2, "safe") # $ arg1 MISSING: arg2 - args = (arg2, "safe") - starargs_mixed(arg1, *args) # $ arg1 MISSING: arg2 + args = (arg2, "safe") # $ arg2 func=starargs_mixed + starargs_mixed(arg1, *args) # $ arg1 args = (arg1, arg2, "safe") starargs_mixed(*args) # $ MISSING: arg1 arg2 From 035d08351567fb8dc741c4dcc4214fa9c888f2bd Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 19 Sep 2022 16:50:48 +0200 Subject: [PATCH 031/415] Python: Support flow to `*args` param from positional arg --- .../new/internal/DataFlowDispatch.qll | 28 ++++++- .../dataflow/new/internal/DataFlowPrivate.qll | 76 +++++++++++++++++++ .../dataflow/new/internal/DataFlowPublic.qll | 4 + .../dataflow/coverage/argumentPassing.py | 14 ++-- .../experimental/dataflow/coverage/test.py | 6 +- 5 files changed, 116 insertions(+), 12 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index f5b628f7e45..3e6f82284c4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -49,6 +49,7 @@ newtype TParameterPosition = pos = 0 or pos = any(Parameter p).getPosition() + 1 } or + TSynthStarArgsElementParameterPosition(int pos) { exists(TStarArgsParameterPosition(pos)) } or TDictSplatParameterPosition() /** A parameter position. */ @@ -65,6 +66,15 @@ class ParameterPosition extends TParameterPosition { /** Holds if this position represents a `*args` parameter at (0-based) `index`. */ predicate isStarArgs(int index) { this = TStarArgsParameterPosition(index) } + /** + * Holds if this position represents a synthetic parameter at or after (0-based) + * position `index`, from which there will be made a store step to the real + * `*args` parameter. + */ + predicate isSynthStarArgsElement(int index) { + this = TSynthStarArgsElementParameterPosition(index) + } + /** Holds if this position represents a `**kwargs` parameter. */ predicate isDictSplat() { this = TDictSplatParameterPosition() } @@ -78,6 +88,11 @@ class ParameterPosition extends TParameterPosition { or exists(int index | this.isStarArgs(index) and result = "*args at " + index) or + exists(int index | + this.isSynthStarArgsElement(index) and + result = "synthetic *args element at (or after) " + index + ) + or this.isDictSplat() and result = "**" } } @@ -132,6 +147,10 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { or exists(int index | ppos.isStarArgs(index) and apos.isStarArgs(index)) or + exists(int paramIndex, int argIndex | argIndex >= paramIndex | + ppos.isSynthStarArgsElement(paramIndex) and apos.isPositional(argIndex) + ) + or ppos.isDictSplat() and apos.isDictSplat() } @@ -219,8 +238,13 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { exists(string name | ppos.isKeyword(name) | result.getParameter() = func.getArgByName(name)) or exists(int index | - ppos.isStarArgs(index) and - result.getParameter() = func.getVararg() + ( + ppos.isStarArgs(index) and + result.getParameter() = func.getVararg() + or + ppos.isSynthStarArgsElement(index) and + result = TSynthStarArgsElementParameterNode(this) + ) | // a `*args` parameter comes after the last positional parameter. We need to take // self parameter into account, so for diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 7b2a1d81580..136bdc85f8d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -57,6 +57,78 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { override Location getLocation() { result = node.getLocation() } } +// ============================================================================= +// *args (StarArgs) related +// ============================================================================= +/** + * A (synthetic) data-flow parameter node to capture all positional arguments that + * should be passed to the `*args` parameter. + * + * To handle + * ```py + * def func(*args): + * for arg in args: + * sink(arg) + * + * func(source1, source2, ...) + * ``` + * + * we add a synthetic parameter to `func` that accepts any positional argument at (or + * after) the index for the `*args` parameter. We add a store step (at any list index) to the real + * `*args` parameter. This means we can handle the code above, but if the code had done `sink(args[0])` + * we would (wrongly) add flow for `source2` as well. + * + * To solve this more precisely, we could add a synthetic argument with position `*args` + * that had store steps with the correct index (like we do for mapping keyword arguments to a + * `**kwargs` parameter). However, if a single call could go to 2 different + * targets with `*args` parameters at different positions, as in the example below, it's unclear what + * index to store `2` at. For the `foo` callable it should be 1, for the `bar` callable it should be 0. + * So this information would need to be encoded in the arguments of a `ArgumentPosition` branch, and + * one of the arguments would be which callable is the target. However, we cannot build `ArgumentPosition` + * branches based on the call-graph, so this strategy doesn't work. + * + * Another approach to solving it precisely is to add multiple synthetic parameters that have store steps + * to the real `*args` parameter. So for the example below, `foo` would need to have synthetic parameter + * nodes for indexes 1 and 2 (which would have store step for index 0 and 1 of the `*args` parameter), + * and `bar` would need it for indexes 1, 2, and 3. The question becomes how many synthetic parameters to + * create, which _must_ be `max(Call call, int i | exists(call.getArg(i)))`, since (again) we can't base + * this on the call-graph. And each function with a `*args` parameter would need this many extra synthetic + * nodes. My gut feeling at that this simple approach will be good enough, but if we need to get it more + * precise, it should be possible to do it like this. + * + * ```py + * def foo(one, *args): ... + * def bar(*args): ... + * + * func = foo if else bar + * func(1, 2, 3) + */ +class SynthStarArgsElementParameterNode extends ParameterNodeImpl, + TSynthStarArgsElementParameterNode { + DataFlowCallable callable; + + SynthStarArgsElementParameterNode() { this = TSynthStarArgsElementParameterNode(callable) } + + override string toString() { result = "SynthStarArgsElementParameterNode" } + + override Scope getScope() { result = callable.getScope() } + + override Location getLocation() { result = callable.getLocation() } + + override Parameter getParameter() { none() } +} + +predicate synthStarArgsElementParameterNodeStoreStep( + SynthStarArgsElementParameterNode nodeFrom, ListElementContent c, ParameterNode nodeTo +) { + c = c and // suppress warning about unused parameter + exists(DataFlowCallable callable, ParameterPosition ppos | + nodeFrom = TSynthStarArgsElementParameterNode(callable) and + nodeTo = callable.getParameter(ppos) and + ppos.isStarArgs(_) + ) +} + // ============================================================================= // **kwargs (DictSplat) related // ============================================================================= @@ -519,6 +591,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) { or FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom, c, nodeTo) or + synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo) + or synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo) } @@ -849,6 +923,8 @@ predicate nodeIsHidden(Node n) { or n instanceof SummaryParameterNode or + n instanceof SynthStarArgsElementParameterNode + or n instanceof SynthDictSplatArgumentNode or n instanceof SynthDictSplatParameterNode diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 94d7bb70543..6d6113bc5af 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -113,6 +113,10 @@ newtype TNode = TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) { FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos) } or + /** A synthetic node to capture positional arguments that are passed to a `*args` parameter. */ + TSynthStarArgsElementParameterNode(DataFlowCallable callable) { + exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos))) + } or /** A synthetic node to capture keyword arguments that are passed to a `**kwargs` parameter. */ TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } or /** A synthetic node to allow flow to keyword parameters from a `**kwargs` argument. */ diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 4e55bc48cd7..d9191c4bd80 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -140,7 +140,7 @@ def test_pos_star(): if len(a) > 0: SINK1(a[0]) - with_star(arg1) #$ MISSING: arg1 func=test_pos_star.with_star + with_star(arg1) #$ arg1 func=test_pos_star.with_star def test_pos_kw(): @@ -209,10 +209,10 @@ def starargs_only(*args): @expects(3*3) def test_only_starargs(): - starargs_only(arg1, arg2, "safe") # $ MISSING: arg1 arg2 + starargs_only(arg1, arg2, "safe") # $ arg1 arg2 SPURIOUS: bad2,bad3="arg1" bad1,bad3="arg2" args = (arg2, "safe") - starargs_only(arg1, *args) # $ MISSING: arg1 arg2 + starargs_only(arg1, *args) # $ arg1 SPURIOUS: bad2,bad3="arg1" MISSING: arg2 args = (arg1, arg2, "safe") # $ arg1 arg2 func=starargs_only starargs_only(*args) @@ -225,7 +225,7 @@ def starargs_mixed(a, *args): @expects(3*8) def test_stararg_mixed(): - starargs_mixed(arg1, arg2, "safe") # $ arg1 MISSING: arg2 + starargs_mixed(arg1, arg2, "safe") # $ arg1 arg2 SPURIOUS: bad3="arg2" args = (arg2, "safe") # $ arg2 func=starargs_mixed starargs_mixed(arg1, *args) # $ arg1 @@ -240,11 +240,11 @@ def test_stararg_mixed(): empty_args = () # adding first/last - starargs_mixed(arg1, arg2, "safe", *empty_args) # $ arg1 MISSING: arg2 + starargs_mixed(arg1, arg2, "safe", *empty_args) # $ arg1 arg2 SPURIOUS: bad3="arg2" starargs_mixed(*empty_args, arg1, arg2, "safe") # $ MISSING: arg1 arg2 # adding before/after *args - args = (arg2, "safe") - starargs_mixed(arg1, *args, *empty_args) # $ arg1 MISSING: arg2 + args = (arg2, "safe") # $ arg2 func=starargs_mixed + starargs_mixed(arg1, *args, *empty_args) # $ arg1 args = (arg2, "safe") starargs_mixed(arg1, *empty_args, *args) # $ arg1 MISSING: arg2 diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 1a7b2cbb6fa..65f915cfd9b 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -401,7 +401,7 @@ def f_extra_pos(a, *b): def test_call_extra_pos(): - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_pos(..)" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" def f_extra_keyword(a, **b): @@ -514,7 +514,7 @@ def test_lambda_unpack_mapping(): def test_lambda_extra_pos(): f_extra_pos = lambda a, *b: b[0] - SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ MISSING: flow="SOURCE -> f_extra_pos(..)" + SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)" def test_lambda_extra_keyword(): @@ -689,7 +689,7 @@ def test_iterable_star_unpacking_in_for_2(): def iterate_star_args(first, second, *args): for arg in args: - SINK(arg) #$ MISSING: flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg" + SINK(arg) #$ flow="SOURCE, l:+5 -> arg" flow="SOURCE, l:+6 -> arg" # FP reported here: https://github.com/github/codeql-python-team/issues/49 @expects(2) From 98a849405f6c54ec3a78d8339531b6559d31fbf6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 20 Sep 2022 09:12:00 +0200 Subject: [PATCH 032/415] Python: Add support for late `*args` arguments --- .../new/internal/DataFlowDispatch.qll | 21 +++++++++ .../dataflow/new/internal/DataFlowPrivate.qll | 47 +++++++++++++++++++ .../dataflow/new/internal/DataFlowPublic.qll | 8 ++++ .../dataflow/coverage/argumentPassing.py | 4 +- 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 3e6f82284c4..ea8c4a76158 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -50,6 +50,7 @@ newtype TParameterPosition = pos = any(Parameter p).getPosition() + 1 } or TSynthStarArgsElementParameterPosition(int pos) { exists(TStarArgsParameterPosition(pos)) } or + TSynthLateStarArgsParameterPosition(int pos) { exists(TStarArgsParameterPosition(pos)) } or TDictSplatParameterPosition() /** A parameter position. */ @@ -75,6 +76,14 @@ class ParameterPosition extends TParameterPosition { this = TSynthStarArgsElementParameterPosition(index) } + /** + * Holds if this position represents a synthetic `*args` parameter after the real + * `*args` parameter. The real `*args` parameter is at the 0-based index `index`. + */ + predicate isSynthLateStarArgsParameterPosition(int index) { + this = TSynthLateStarArgsParameterPosition(index) + } + /** Holds if this position represents a `**kwargs` parameter. */ predicate isDictSplat() { this = TDictSplatParameterPosition() } @@ -93,6 +102,11 @@ class ParameterPosition extends TParameterPosition { result = "synthetic *args element at (or after) " + index ) or + exists(int index | + this.isSynthLateStarArgsParameterPosition(index) and + result = "synthetic late *args after " + index + ) + or this.isDictSplat() and result = "**" } } @@ -151,6 +165,10 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos.isSynthStarArgsElement(paramIndex) and apos.isPositional(argIndex) ) or + exists(int realStarArgsIndex, int argIndex | argIndex > realStarArgsIndex | + ppos.isSynthLateStarArgsParameterPosition(realStarArgsIndex) and apos.isStarArgs(argIndex) + ) + or ppos.isDictSplat() and apos.isDictSplat() } @@ -244,6 +262,9 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { or ppos.isSynthStarArgsElement(index) and result = TSynthStarArgsElementParameterNode(this) + or + ppos.isSynthLateStarArgsParameterPosition(index) and + result = TSynthLateStarArgsParameterNode(this) ) | // a `*args` parameter comes after the last positional parameter. We need to take diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 136bdc85f8d..8d4f45bcdeb 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -129,6 +129,49 @@ predicate synthStarArgsElementParameterNodeStoreStep( ) } +/** + * A synthetic node to capture a `*args` argument that is passed to a `*args` + * parameter, but "too late" in the argument list, so we cannot just do a 1-1 mapping + * without messing up the indexes; instead we make a list/tuple/set read step to + * `SynthStarArgsElementParameterNode`. + * + * Example. The `*args` arguments starts at index 1, while the `*args` parameter accepts + * arguments starting at index 0. + * + * ```py + * def func(*args): ... + * func(1, *args) + */ +class SynthLateStarArgsParameterNode extends ParameterNodeImpl, TSynthLateStarArgsParameterNode { + DataFlowCallable callable; + + SynthLateStarArgsParameterNode() { this = TSynthLateStarArgsParameterNode(callable) } + + override string toString() { result = "SynthLateStarArgsParameterNode" } + + override Scope getScope() { result = callable.getScope() } + + override Location getLocation() { result = callable.getLocation() } + + override Parameter getParameter() { none() } +} + +predicate synthLateStarArgsParameterNodeReadStep( + SynthLateStarArgsParameterNode nodeFrom, Content c, ParameterNode nodeTo +) { + ( + c instanceof ListElementContent + or + c instanceof TupleElementContent + or + c instanceof SetElementContent + ) and + exists(DataFlowCallable callable | + nodeFrom = TSynthLateStarArgsParameterNode(callable) and + nodeTo = TSynthStarArgsElementParameterNode(callable) + ) +} + // ============================================================================= // **kwargs (DictSplat) related // ============================================================================= @@ -764,6 +807,8 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) { or FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom, c, nodeTo) or + synthLateStarArgsParameterNodeReadStep(nodeFrom, c, nodeTo) + or synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) } @@ -925,6 +970,8 @@ predicate nodeIsHidden(Node n) { or n instanceof SynthStarArgsElementParameterNode or + n instanceof SynthLateStarArgsParameterNode + or n instanceof SynthDictSplatArgumentNode or n instanceof SynthDictSplatParameterNode diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 6d6113bc5af..336330ad924 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -117,6 +117,14 @@ newtype TNode = TSynthStarArgsElementParameterNode(DataFlowCallable callable) { exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos))) } or + /** + * A synthetic node to capture a `*args` argument that is passed to a `*args` + * parameter, but "too late" in the argument list, so we cannot just do a 1-1 mapping + * without messing up the indexes. + */ + TSynthLateStarArgsParameterNode(DataFlowCallable callable) { + exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos))) + } or /** A synthetic node to capture keyword arguments that are passed to a `**kwargs` parameter. */ TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } or /** A synthetic node to allow flow to keyword parameters from a `**kwargs` argument. */ diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index d9191c4bd80..2a07a99801f 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -211,8 +211,8 @@ def starargs_only(*args): def test_only_starargs(): starargs_only(arg1, arg2, "safe") # $ arg1 arg2 SPURIOUS: bad2,bad3="arg1" bad1,bad3="arg2" - args = (arg2, "safe") - starargs_only(arg1, *args) # $ arg1 SPURIOUS: bad2,bad3="arg1" MISSING: arg2 + args = (arg2, "safe") # $ arg2 func=starargs_only SPURIOUS: bad1,bad3="arg2" + starargs_only(arg1, *args) # $ arg1 SPURIOUS: bad2,bad3="arg1" args = (arg1, arg2, "safe") # $ arg1 arg2 func=starargs_only starargs_only(*args) From 5fc127cb2c5ae38c6be506e71a79a19d93089f98 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 20 Sep 2022 14:29:14 +0200 Subject: [PATCH 033/415] Python: Make `UnresolvedCalls.qll` handle class calls without __init__ This commit used to make sense to have here in the ordering of commits, but due to various rebases it no longer changes any test output.. it's still a good change though, so I'll keep it. --- .../experimental/dataflow/TestUtil/UnresolvedCalls.qll | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll b/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll index ea123e9ca45..fbdcca3ef04 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll @@ -12,13 +12,8 @@ class UnresolvedCallExpectations extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(CallNode call | - not exists(DataFlowPrivate::DataFlowCall dfc | dfc.getNode() = call | - // For every `CallNode`, there is a `DataFlowCall` in the form of a `NormalCall`. - // It does not really count, as it has some abstract overrides. For instance, it does not - // define `getCallable`, so checking for the existence of this guarantees that we are in a - // properly resolved call. - exists(dfc.getCallable()) - ) and + not exists(DataFlowPrivate::DataFlowCall dfc | dfc.getNode() = call) and + not DataFlowPrivate::resolveClassCall(call, _) and not call = API::builtin(_).getACall().asCfgNode() and location = call.getLocation() and tag = "unresolved_call" and From 6351defe0d95da1676f4a67acd001dc4b00a7da9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 20 Sep 2022 14:34:12 +0200 Subject: [PATCH 034/415] Python: Add call-graph tests with `isinstance` --- .../CallGraph/InlineCallGraphTest.expected | 13 ++++++ .../CallGraph/code/isinstance.py | 40 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/isinstance.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index e748746b01a..d095fc73dbb 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -39,5 +39,18 @@ typeTracker_found_pointsTo_notFound | code/class_super.py:101:1:101:7 | ControlFlowNode for Attribute() | Z.foo | | code/class_super.py:108:1:108:8 | ControlFlowNode for Attribute() | Z.foo | | code/def_in_function.py:22:5:22:11 | ControlFlowNode for Attribute() | test.A.foo | +| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | A.foo | +| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | ASub.foo | +| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | B.foo | +| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | Base.foo | +| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | A.foo | +| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | ASub.foo | +| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | B.foo | +| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | Base.foo | +| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | A.foo | +| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | ASub.foo | +| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | B.foo | +| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | Base.foo | +| code/isinstance.py:40:5:40:11 | ControlFlowNode for Attribute() | B.foo | | code/nested_class.py:83:9:83:16 | ControlFlowNode for Attribute() | X.class_def_in_func.Y.meth | | code/underscore_prefix_func_name.py:14:5:14:19 | ControlFlowNode for some_function() | some_function | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/isinstance.py b/python/ql/test/experimental/library-tests/CallGraph/code/isinstance.py new file mode 100644 index 00000000000..a8fbcc32d43 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/isinstance.py @@ -0,0 +1,40 @@ +import os + +class Base: + def foo(self): + print("Base.foo") + + def call(self): + if isinstance(self, A): + self.foo() # $ tt=A.foo tt=ASub.foo SPURIOUS: tt=B.foo tt=Base.foo + + # This is a silly test, but just to show that second argument of isinstance as + # tuple is handled + if isinstance(self, (A, B)): + self.foo() # $ tt=A.foo tt=ASub.foo tt=B.foo SPURIOUS: tt=Base.foo + + if isinstance(self, ASubNoDef): + self.foo() # $ tt=A.foo SPURIOUS: tt=ASub.foo tt=B.foo tt=Base.foo + + +class A(Base): + def foo(self): + print("A.foo") + +class ASub(A): + def foo(self): + print("ASub.foo") + +class ASubNoDef(A): pass + +class B(Base): + def foo(self): + print("B.foo") + +cond = os.urandom(1)[0] > 128 + +x = A() if cond else B() +x.foo() # $ pt,tt=A.foo pt,tt=B.foo + +if isinstance(x, A): + x.foo() # $ pt,tt=A.foo SPURIOUS: tt=B.foo From 4416037dc68969d439ccb7a32e8d11b42426ffc5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 20 Sep 2022 14:45:08 +0200 Subject: [PATCH 035/415] Python: Ignore SPURIOUS call-graph edges in points-to vs. type-tracker results --- .../InlineCallGraphTest.expected | 2 +- .../CallGraph/InlineCallGraphTest.expected | 11 ----- .../CallGraph/InlineCallGraphTest.ql | 49 ++++++++++++------- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected index 2836800d300..7bba932e8f4 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected @@ -1,5 +1,5 @@ failures debug_callableNotUnique pointsTo_found_typeTracker_notFound -| pkg/use.py:10:5:10:10 | ControlFlowNode for func() | func | +| pkg/use.py:10:5:10:10 | ControlFlowNode for func() | "pkg/func_def.py:func" | typeTracker_found_pointsTo_notFound diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index d095fc73dbb..534633980c3 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -20,10 +20,6 @@ pointsTo_found_typeTracker_notFound | code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func | typeTracker_found_pointsTo_notFound | code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm | -| code/class_more_mro2.py:18:9:18:21 | ControlFlowNode for Attribute() | A.foo | -| code/class_more_mro2.py:21:1:21:8 | ControlFlowNode for Attribute() | A.foo | -| code/class_more_mro.py:24:9:24:21 | ControlFlowNode for Attribute() | A.foo | -| code/class_more_mro.py:34:1:34:16 | ControlFlowNode for Attribute() | A.foo | | code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Base.__call__ | | code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Sub.__call__ | | code/class_special_methods.py:33:1:33:5 | ControlFlowNode for b() | Base.__call__ | @@ -41,16 +37,9 @@ typeTracker_found_pointsTo_notFound | code/def_in_function.py:22:5:22:11 | ControlFlowNode for Attribute() | test.A.foo | | code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | A.foo | | code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | ASub.foo | -| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | B.foo | -| code/isinstance.py:9:13:9:22 | ControlFlowNode for Attribute() | Base.foo | | code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | A.foo | | code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | ASub.foo | | code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | B.foo | -| code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | Base.foo | | code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | A.foo | -| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | ASub.foo | -| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | B.foo | -| code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | Base.foo | -| code/isinstance.py:40:5:40:11 | ControlFlowNode for Attribute() | B.foo | | code/nested_class.py:83:9:83:16 | ControlFlowNode for Attribute() | X.class_def_in_func.Y.meth | | code/underscore_prefix_func_name.py:14:5:14:19 | ControlFlowNode for some_function() | some_function | diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql index 327621fb7f2..d613460e749 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql @@ -53,24 +53,25 @@ class CallGraphTest extends InlineExpectationsTest { | location = call.getLocation() and element = call.toString() and - if call.getLocation().getFile() = target.getLocation().getFile() - then value = betterQualName(target) - else - exists(string fixedRelativePath | - fixedRelativePath = - target - .getLocation() - .getFile() - .getRelativePath() - .regexpCapture(".*/CallGraph[^/]*/(.*)", 1) - | - // the value needs to be enclosed in quotes to allow special characters - value = "\"" + fixedRelativePath + ":" + betterQualName(target) + "\"" - ) + value = getCallEdgeValue(call, target) ) } } +bindingset[call, target] +string getCallEdgeValue(CallNode call, Function target) { + if call.getLocation().getFile() = target.getLocation().getFile() + then result = betterQualName(target) + else + exists(string fixedRelativePath | + fixedRelativePath = + target.getLocation().getFile().getRelativePath().regexpCapture(".*/CallGraph[^/]*/(.*)", 1) + | + // the value needs to be enclosed in quotes to allow special characters + result = "\"" + fixedRelativePath + ":" + betterQualName(target) + "\"" + ) +} + bindingset[func] string betterQualName(Function func) { // note: `target.getQualifiedName` for Lambdas is just "lambda", so is not very useful :| @@ -99,7 +100,14 @@ query predicate pointsTo_found_typeTracker_notFound(CallNode call, string qualna exists(Function target | pointsToCallEdge(call, target) and not typeTrackerCallEdge(call, target) and - qualname = betterQualName(target) + qualname = getCallEdgeValue(call, target) and + // ignore SPURIOUS call edges + not exists(FalsePositiveExpectation spuriousResult | + spuriousResult.getTag() = "pt" and + spuriousResult.getValue() = getCallEdgeValue(call, target) and + spuriousResult.getLocation().getFile() = call.getLocation().getFile() and + spuriousResult.getLocation().getStartLine() = call.getLocation().getStartLine() + ) ) } @@ -107,10 +115,17 @@ query predicate typeTracker_found_pointsTo_notFound(CallNode call, string qualna exists(Function target | not pointsToCallEdge(call, target) and typeTrackerCallEdge(call, target) and - qualname = betterQualName(target) and + qualname = getCallEdgeValue(call, target) and // We filter out result differences for points-to and type-tracking for class calls, // since otherwise it gives too much noise (these are just handled differently // between the two). - not typeTrackerClassCall(call, target) + not typeTrackerClassCall(call, target) and + // ignore SPURIOUS call edges + not exists(FalsePositiveExpectation spuriousResult | + spuriousResult.getTag() = "tt" and + spuriousResult.getValue() = getCallEdgeValue(call, target) and + spuriousResult.getLocation().getFile() = call.getLocation().getFile() and + spuriousResult.getLocation().getStartLine() = call.getLocation().getStartLine() + ) ) } From 8e0bb625168cbc434bf5790f5b8d66646befac21 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 23 Sep 2022 16:28:58 +0200 Subject: [PATCH 036/415] Python: Remove `pragma[inline]` from `parameterMatch` It's gotten complex enough that it doesn't by definition seem necessary to inline it. (in the range of ~2200 results for django and pandas) --- .../lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index ea8c4a76158..b9d0b65e876 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -151,7 +151,6 @@ class ArgumentPosition extends TArgumentPosition { } /** Holds if arguments at position `apos` match parameters at position `ppos`. */ -pragma[inline] predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos.isSelf() and apos.isSelf() or From 0cf13e99762ba128c722d59430b84a0b9de45d31 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 20 Oct 2022 15:19:11 +0200 Subject: [PATCH 037/415] Python: Expand argument highlighting test --- .../test/experimental/dataflow/calls/test.py | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/python/ql/test/experimental/dataflow/calls/test.py b/python/ql/test/experimental/dataflow/calls/test.py index 3332d2caa9e..afb22f3659c 100644 --- a/python/ql/test/experimental/dataflow/calls/test.py +++ b/python/ql/test/experimental/dataflow/calls/test.py @@ -14,14 +14,23 @@ class MyClass(object): def my_method(self, arg): pass + def other_method(self): + self.my_method(42) # $ arg[self]=self call=self.my_method(..) callType=CallTypeNormalMethod arg[position 0]=42 + self.sm(42) # $ call=self.sm(..) callType=CallTypeStaticMethod arg[position 0]=42 + @staticmethod - def staticmethod(arg): + def sm(arg): pass @classmethod - def classmethod(cls, arg): + def cm(cls, arg): pass + @classmethod + def other_classmethod(cls): + cls.cm(42) # $ call=cls.cm(..) callType=CallTypeClassMethod arg[position 0]=42 MISSING: arg[self]=cls + cls.sm(42) # $ call=cls.sm(..) callType=CallTypeStaticMethod arg[position 0]=42 + def __getitem__(self, key): pass @@ -34,11 +43,11 @@ mm = x.my_method mm(2) # $ call=mm(..) arg[self]=x arg[position 0]=2 callType=CallTypeNormalMethod MyClass.my_method(x, 2) # $ call=MyClass.my_method(..) arg[position 0]=2 arg[self]=x callType=CallTypeMethodAsPlainFunction -x.staticmethod(3) # $ call=x.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod -MyClass.staticmethod(3) # $ call=MyClass.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod +x.sm(3) # $ call=x.sm(..) arg[position 0]=3 callType=CallTypeStaticMethod +MyClass.sm(3) # $ call=MyClass.sm(..) arg[position 0]=3 callType=CallTypeStaticMethod -x.classmethod(4) # $ call=x.classmethod(..) arg[position 0]=4 callType=CallTypeClassMethod -MyClass.classmethod(4) # $ call=MyClass.classmethod(..) arg[position 0]=4 arg[self]=MyClass callType=CallTypeClassMethod +x.cm(4) # $ call=x.cm(..) arg[position 0]=4 callType=CallTypeClassMethod +MyClass.cm(4) # $ call=MyClass.cm(..) arg[position 0]=4 arg[self]=MyClass callType=CallTypeClassMethod x[5] # $ MISSING: call=x[5] arg[self]=x arg[position 0]=5 @@ -53,11 +62,11 @@ mm = y.my_method mm(2) # $ call=mm(..) arg[self]=y arg[position 0]=2 callType=CallTypeNormalMethod Subclass.my_method(y, 2) # $ call=Subclass.my_method(..) arg[self]=y arg[position 0]=2 callType=CallTypeMethodAsPlainFunction -y.staticmethod(3) # $ call=y.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod -Subclass.staticmethod(3) # $ call=Subclass.staticmethod(..) arg[position 0]=3 callType=CallTypeStaticMethod +y.sm(3) # $ call=y.sm(..) arg[position 0]=3 callType=CallTypeStaticMethod +Subclass.sm(3) # $ call=Subclass.sm(..) arg[position 0]=3 callType=CallTypeStaticMethod -y.classmethod(4) # $ call=y.classmethod(..) arg[position 0]=4 callType=CallTypeClassMethod -Subclass.classmethod(4) # $ call=Subclass.classmethod(..) arg[self]=Subclass arg[position 0]=4 callType=CallTypeClassMethod +y.cm(4) # $ call=y.cm(..) arg[position 0]=4 callType=CallTypeClassMethod +Subclass.cm(4) # $ call=Subclass.cm(..) arg[self]=Subclass arg[position 0]=4 callType=CallTypeClassMethod y[5] # $ MISSING: call=y[5] arg[self]=y arg[position 0]=5 From 57c7dc8ea9ace2c70ee8872a2b41b4a0fea1bf52 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 20 Oct 2022 15:11:49 +0200 Subject: [PATCH 038/415] Python: Allow `cls` passing to classmethod --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 2 +- python/ql/test/experimental/dataflow/calls/test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index b9d0b65e876..7c2537a3b56 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1054,7 +1054,7 @@ predicate getCallArg( type instanceof CallTypeClassMethod and apos.isSelf() and resolveMethodCall(call, target, type, arg) and - arg = classTracker(_) and + (arg = classTracker(_) or arg = clsTracker(_)) and // dataflow lib has requirement that arguments and calls are in same enclosing callable. exists(CfgNode cfgNode | cfgNode.getNode() = call | cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() diff --git a/python/ql/test/experimental/dataflow/calls/test.py b/python/ql/test/experimental/dataflow/calls/test.py index afb22f3659c..0eb7e262cb4 100644 --- a/python/ql/test/experimental/dataflow/calls/test.py +++ b/python/ql/test/experimental/dataflow/calls/test.py @@ -28,7 +28,7 @@ class MyClass(object): @classmethod def other_classmethod(cls): - cls.cm(42) # $ call=cls.cm(..) callType=CallTypeClassMethod arg[position 0]=42 MISSING: arg[self]=cls + cls.cm(42) # $ call=cls.cm(..) callType=CallTypeClassMethod arg[position 0]=42 arg[self]=cls cls.sm(42) # $ call=cls.sm(..) callType=CallTypeStaticMethod arg[position 0]=42 def __getitem__(self, key): From f040ad8dacd465bd0830e6af4a8203a2585ff221 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 20 Oct 2022 14:32:48 +0200 Subject: [PATCH 039/415] Python: Add test of `__new__` handling --- .../dataflow/calls/new_cls_param.py | 16 ++++++++++++ .../experimental/dataflow/fieldflow/test.py | 26 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 python/ql/test/experimental/dataflow/calls/new_cls_param.py diff --git a/python/ql/test/experimental/dataflow/calls/new_cls_param.py b/python/ql/test/experimental/dataflow/calls/new_cls_param.py new file mode 100644 index 00000000000..38274a9e160 --- /dev/null +++ b/python/ql/test/experimental/dataflow/calls/new_cls_param.py @@ -0,0 +1,16 @@ +# We want to ensure that the __new__ method is considered a classmethod even though it +# doesn't have a decorator. This means that the `cls` parameter should be considered a +# reference to the class (or subclass), and not an instance of the class. We can detect +# this from looking at the arguments passed in the `cls.foo` call. if we see a `self` +# argument, this means it has correct behavior (because we're targeting a classmethod), +# if there is no `self` argument, this means we've only considered `cls` to be a class +# instance, since we don't want to pass that to the `cls` parameter of the classmethod `WithNewImpl.foo`. + +class WithNewImpl(object): + def __new__(cls): + print("WithNewImpl.foo") + cls.foo() # $ call=cls.foo() callType=CallTypeClassMethod MISSING: arg[self]=cls + + @classmethod + def foo(cls): + print("WithNewImpl.foo") diff --git a/python/ql/test/experimental/dataflow/fieldflow/test.py b/python/ql/test/experimental/dataflow/fieldflow/test.py index 68bb71bd278..5f1f6f47058 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/test.py +++ b/python/ql/test/experimental/dataflow/fieldflow/test.py @@ -385,6 +385,32 @@ def test_potential_crosstalk_same_class(cond=True): SINK_F(objx2.x) +class NewTest(object): + def __new__(cls, arg): + cls.foo = arg + return super().__new__(cls) # $ unresolved_call=super().__new__(..) + +@expects(4) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..) +def test__new__(): + # we want to make sure that we DON'T pass the synthetic pre-update node for + # the class instance to __new__, like we do for __init__. + nt = NewTest(SOURCE) + # the __new__ implementation sets the foo attribute on THE CLASS itself. The + # attribute lookup on the class instance will go to the class itself when the + # attribute isn't defined on the class instance, so we will actually see `nt.foo` + # contain the source, but the point of this test is that we should see identical + # behavior between NewTest.foo and nt.foo, which we dont! + # + # Also note that we currently (October 2022) dont' model writes to classes very + # well. + + SINK(NewTest.foo) # $ MISSING: flow="SOURCE, l:-10 -> NewTest.foo" + SINK(nt.foo) # $ flow="SOURCE, l:-11 -> nt.foo" + + NewTest.foo = NONSOURCE + SINK_F(NewTest.foo) + SINK_F(nt.foo) # $ SPURIOUS: flow="SOURCE, l:-15 -> nt.foo" + # ------------------------------------------------------------------------------ # Global scope # ------------------------------------------------------------------------------ From 6fefd545336be7809729b8d868a78d1da5c0ede2 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 12 Oct 2022 14:29:54 +0200 Subject: [PATCH 040/415] Python: Consider `__new__` a classmethod --- .../new/internal/DataFlowDispatch.qll | 45 ++++++++++++------- .../dataflow/new/internal/DataFlowPublic.qll | 2 +- .../dataflow/calls/new_cls_param.py | 2 +- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 7c2537a3b56..c239c66e55c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -174,18 +174,31 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { // ============================================================================= // Helper predicates // ============================================================================= -/** Holds if the function has a `staticmethod` decorator. */ -predicate hasStaticmethodDecorator(Function func) { +/** + * Holds if the function `func` is a staticmethod -- either by having a + * `@staticmethod` decorator or by convention + * (like a `__new__` method on a class is a classmethod even without the decorator). + */ +predicate isStaticmethod(Function func) { exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() | func.getADecorator() = id.getNode() ) } -/** Holds if the function has a `classmethod` decorator. */ -predicate hasClassmethodDecorator(Function func) { +/** + * Holds if the function `func` is a classmethod -- either by having a + * `@classmethod` decorator or by convention + * (like a `__new__` method on a class is a classmethod even without the decorator). + */ +predicate isClassmethod(Function func) { exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() | func.getADecorator() = id.getNode() ) + or + exists(Class cls | + cls.getAMethod() = func and + func.getName() = "__new__" + ) } // ============================================================================= @@ -309,12 +322,12 @@ class DataFlowMethod extends DataFlowFunction { /** A classmethod. */ class DataFlowClassmethod extends DataFlowMethod { - DataFlowClassmethod() { hasClassmethodDecorator(func) } + DataFlowClassmethod() { isClassmethod(func) } } /** A staticmethod. */ class DataFlowStaticmethod extends DataFlowMethod, DataFlowFunction { - DataFlowStaticmethod() { hasStaticmethodDecorator(func) } + DataFlowStaticmethod() { isStaticmethod(func) } override int positionalOffset() { result = 0 } @@ -457,8 +470,8 @@ private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) { t.start() and exists(Function func | func = classWithMethod.getAMethod() and - not hasStaticmethodDecorator(func) and - not hasClassmethodDecorator(func) + not isStaticmethod(func) and + not isClassmethod(func) | result.asExpr() = func.getArg(0) ) @@ -482,7 +495,7 @@ private TypeTrackingNode clsTracker(TypeTracker t, Class classWithMethod) { ( exists(Function func | func = classWithMethod.getAMethod() and - hasClassmethodDecorator(func) + isClassmethod(func) | result.asExpr() = func.getArg(0) ) @@ -507,7 +520,7 @@ Node clsTracker(Class classWithMethod) { * call happened in the method `func` (either a method or a classmethod). */ private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func) { - not hasStaticmethodDecorator(func) and + not isStaticmethod(func) and t.start() and exists(CallCfgNode call | result = call | call = getSuperCall() and @@ -884,22 +897,22 @@ private module MethodCalls { or self = selfTracker(_) ) and - not hasStaticmethodDecorator(target) and - not hasClassmethodDecorator(target) + not isStaticmethod(target) and + not isClassmethod(target) or // method as plain function call type instanceof CallTypeMethodAsPlainFunction and self = classTracker(_) and - not hasStaticmethodDecorator(target) and - not hasClassmethodDecorator(target) + not isStaticmethod(target) and + not isClassmethod(target) or // staticmethod call type instanceof CallTypeStaticMethod and - hasStaticmethodDecorator(target) + isStaticmethod(target) or // classmethod call type instanceof CallTypeClassMethod and - hasClassmethodDecorator(target) + isClassmethod(target) ) } } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 336330ad924..79b711db9e8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -63,7 +63,7 @@ newtype TNode = // self parameter when used implicitly in `super()` exists(Class cls, Function func, ParameterDefinition def | func = cls.getAMethod() and - not hasStaticmethodDecorator(func) and + not isStaticmethod(func) and // this matches what we do in ExtractedParameterNode def.getDefiningNode() = node and def.getParameter() = func.getArg(0) diff --git a/python/ql/test/experimental/dataflow/calls/new_cls_param.py b/python/ql/test/experimental/dataflow/calls/new_cls_param.py index 38274a9e160..c2ec88acd51 100644 --- a/python/ql/test/experimental/dataflow/calls/new_cls_param.py +++ b/python/ql/test/experimental/dataflow/calls/new_cls_param.py @@ -9,7 +9,7 @@ class WithNewImpl(object): def __new__(cls): print("WithNewImpl.foo") - cls.foo() # $ call=cls.foo() callType=CallTypeClassMethod MISSING: arg[self]=cls + cls.foo() # $ call=cls.foo() callType=CallTypeClassMethod arg[self]=cls @classmethod def foo(cls): From 9949824810163dbecb5c2dd61385feb11a3bf0cc Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 12 Oct 2022 14:37:15 +0200 Subject: [PATCH 041/415] Python: Expand implicit classmethods --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index c239c66e55c..2347c8cf0f4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -197,7 +197,11 @@ predicate isClassmethod(Function func) { or exists(Class cls | cls.getAMethod() = func and - func.getName() = "__new__" + func.getName() in [ + "__new__", // https://docs.python.org/3.10/reference/datamodel.html#object.__new__ + "__init_subclass__", // https://docs.python.org/3.10/reference/datamodel.html#object.__init_subclass__ + "__class_getitem__", // https://docs.python.org/3.10/reference/datamodel.html#object.__class_getitem__ + ] ) } From 5e5bab5a7c92d6cfa06e1104513a52b4145d95ce Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 5 Oct 2022 16:56:19 +0200 Subject: [PATCH 042/415] Python: Don't pass synthetic class instance to `__new__` on class calls --- .../dataflow/new/internal/DataFlowDispatch.qll | 17 ++++++++++------- .../experimental/dataflow/coverage/datamodel.py | 2 +- .../experimental/dataflow/fieldflow/test.py | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 2347c8cf0f4..81e6bf904fd 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -937,17 +937,17 @@ predicate resolveClassCall(CallNode call, Class cls) { } /** - * Gets a function (`__init__`/`__new__`) that will be invoked when `cls` is - * constructed -- where the function lookup is based on our MRO calculation. + * Gets a function, either `__init__` or `__new__` as specified by `funcName`, that will + * be invoked when `cls` is constructed -- where the function lookup is based on our MRO + * calculation. */ -Function invokedFunctionFromClassConstruction(Class cls) { - result = findFunctionAccordingToMroKnownStartingClass(cls, "__new__") - or +Function invokedFunctionFromClassConstruction(Class cls, string funcName) { // as described in https://docs.python.org/3/reference/datamodel.html#object.__new__ // __init__ will only be called when __new__ returns an instance of the class (which // is not a requirement). However, for simplicity, we assume that __init__ will always // be called. - result = findFunctionAccordingToMroKnownStartingClass(cls, "__init__") + funcName in ["__init__", "__new__"] and + result = findFunctionAccordingToMroKnownStartingClass(cls, funcName) } /** @@ -984,7 +984,7 @@ predicate resolveCall(ControlFlowNode call, Function target, CallType type) { type instanceof CallTypeClass and exists(Class cls | resolveClassCall(call, cls) and - target = invokedFunctionFromClassConstruction(cls) + target = invokedFunctionFromClassConstruction(cls, _) ) or type instanceof CallTypeClassInstanceCall and @@ -1106,6 +1106,9 @@ predicate getCallArg( // class call type instanceof CallTypeClass and ( + // only pass synthetic node for created object to __init__, and not __new__ since + // __new__ is a classmethod. + target = invokedFunctionFromClassConstruction(_, "__init__") and apos.isSelf() and arg = TSyntheticPreUpdateNode(call) or diff --git a/python/ql/test/experimental/dataflow/coverage/datamodel.py b/python/ql/test/experimental/dataflow/coverage/datamodel.py index e30ffea164a..370fb32ca99 100644 --- a/python/ql/test/experimental/dataflow/coverage/datamodel.py +++ b/python/ql/test/experimental/dataflow/coverage/datamodel.py @@ -232,7 +232,7 @@ class Customized: customized = Customized() SINK(Customized.a) #$ MISSING:flow="SOURCE, l:-8 -> customized.a" SINK_F(Customized.b) -SINK(customized.a) #$ flow="SOURCE, l:-10 -> customized.a" +SINK(customized.a) #$ MISSING: flow="SOURCE, l:-10 -> customized.a" SINK(customized.b) #$ flow="SOURCE, l:-7 -> customized.b" diff --git a/python/ql/test/experimental/dataflow/fieldflow/test.py b/python/ql/test/experimental/dataflow/fieldflow/test.py index 5f1f6f47058..c090aea2089 100644 --- a/python/ql/test/experimental/dataflow/fieldflow/test.py +++ b/python/ql/test/experimental/dataflow/fieldflow/test.py @@ -405,11 +405,11 @@ def test__new__(): # well. SINK(NewTest.foo) # $ MISSING: flow="SOURCE, l:-10 -> NewTest.foo" - SINK(nt.foo) # $ flow="SOURCE, l:-11 -> nt.foo" + SINK(nt.foo) # $ MISSING: flow="SOURCE, l:-11 -> nt.foo" NewTest.foo = NONSOURCE SINK_F(NewTest.foo) - SINK_F(nt.foo) # $ SPURIOUS: flow="SOURCE, l:-15 -> nt.foo" + SINK_F(nt.foo) # ------------------------------------------------------------------------------ # Global scope From 722c69edccc729bf12893bf6c40d5743936c420c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 20 Oct 2022 11:22:38 +0200 Subject: [PATCH 043/415] Python: Add test showing self type-tracking problems --- .../CallGraph/InlineCallGraphTest.expected | 4 + .../CallGraph/code/self_passing.py | 94 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 534633980c3..2e2c1cd655f 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -42,4 +42,8 @@ typeTracker_found_pointsTo_notFound | code/isinstance.py:14:13:14:22 | ControlFlowNode for Attribute() | B.foo | | code/isinstance.py:17:13:17:22 | ControlFlowNode for Attribute() | A.foo | | code/nested_class.py:83:9:83:16 | ControlFlowNode for Attribute() | X.class_def_in_func.Y.meth | +| code/self_passing.py:16:9:16:18 | ControlFlowNode for Attribute() | A.foo | +| code/self_passing.py:16:9:16:18 | ControlFlowNode for Attribute() | B.foo | +| code/self_passing.py:67:9:67:16 | ControlFlowNode for Attribute() | Y.cm | +| code/self_passing.py:69:9:69:17 | ControlFlowNode for Attribute() | X.foo | | code/underscore_prefix_func_name.py:14:5:14:19 | ControlFlowNode for some_function() | some_function | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py b/python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py new file mode 100644 index 00000000000..fcb22ca40e6 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py @@ -0,0 +1,94 @@ +# These test-cases illustrates what can happen if we allow the type trackers that are used +# for tracking class instances to flow into self parameters. + +# This first case shows the problem of the call to `self.bar` inside A.foo, could be +# considered a call to B.bar, if we allow the flow from the `self` parameter of +# `Base.base_meth` to flow into A.foo (through the `self.foo` call). This is +# problematic, and causes us to have different results for the `self.bar()` calls in +# `A.foo` and `A.not_called`. + +from inspect import isclass + + +class Base(object): + def base_meth(self): + print("Base.base_meth") + self.foo() # $ pt,tt=Base.foo tt=A.foo tt=B.foo + + def foo(self): + print("Base.foo") + +class A(Base): + def foo(self): + print("A.foo") + self.bar() # $ pt,tt=A.bar SPURIOUS: tt=B.bar + + def not_called(self): + self.bar() #$ pt,tt=A.bar + + def bar(self): + print("A.bar") + +class B(Base): + def foo(self): + print("B.foo") + + def bar(self): + print("B.bar") + +a = A() +a.foo() # $ pt,tt=A.foo + +# Another problem is mixing up class instances and class references. In the example +# below since `func` takes BOTH an instance of X, and the class Y, we used to end up +# tracking _both_ to the self argument of X.foo, which meant that the self.meth() call +# in X.foo was resolved to BOTH X.meth and Y.meth. + +class X(object): + def meth(self): + print("X.meth") + + def foo(self): + print("X.foo") + self.meth() # $ pt,tt=X.meth SPURIOUS: tt=Y.meth + + +class Y(object): + def meth(self): + print("Y.meth") + + @classmethod + def cm(cls): + print("Y.cm") + + +def func(obj): + if isclass(obj): + obj.cm() # $ tt=Y.cm + else: + obj.foo() # $ tt=X.foo + +func(Y) # $ pt,tt=func +x = X() +func(x) # $ pt,tt=func + + +# While avoiding the two problems above is good, we have to be careful not to prune away +# _all_ type-tracking flow to the self parameter (since it's the local source node for +# all references to it within the function). So in the example below, we still want to +# be able to resolve that some_function is assigned to the attribute `func` on self. + + +class Example3(object): + def wat(self, f): + print("Example3.wat") + self.func = f + self.func() # $ pt,tt=some_function + + +def some_function(): + print("some_function") + + +ex3 = Example3() +ex3.wat(some_function) # $ pt,tt=Example3.wat From b33f02f9dc4f216f6c0c0fa04dfa79c938f46279 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 20 Oct 2022 11:24:33 +0200 Subject: [PATCH 044/415] Python: Fix self-passing problems This also fixes performance problems for pandas-dev/pandas --- .../dataflow/new/internal/DataFlowDispatch.qll | 18 ++++++++++++------ .../new/internal/TypeTrackerSpecific.qll | 1 - .../CallGraph/code/self_passing.py | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 81e6bf904fd..18bff54a023 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -441,7 +441,8 @@ private TypeTrackingNode classTracker(TypeTracker t, Class cls) { result.(CallCfgNode).getArg(0) = classInstanceTracker(cls) ) or - exists(TypeTracker t2 | result = classTracker(t2, cls).track(t2, t)) + exists(TypeTracker t2 | result = classTracker(t2, cls).track(t2, t)) and + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -456,7 +457,8 @@ private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) { t.start() and result.(CallCfgNode).getFunction() = classTracker(cls) or - exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) + exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) and + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -480,7 +482,8 @@ private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) { result.asExpr() = func.getArg(0) ) or - exists(TypeTracker t2 | result = selfTracker(t2, classWithMethod).track(t2, t)) + exists(TypeTracker t2 | result = selfTracker(t2, classWithMethod).track(t2, t)) and + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -509,7 +512,8 @@ private TypeTrackingNode clsTracker(TypeTracker t, Class classWithMethod) { result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) ) or - exists(TypeTracker t2 | result = clsTracker(t2, classWithMethod).track(t2, t)) + exists(TypeTracker t2 | result = clsTracker(t2, classWithMethod).track(t2, t)) and + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -532,7 +536,8 @@ private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func call.getScope() = func ) or - exists(TypeTracker t2 | result = superCallNoArgumentTracker(t2, func).track(t2, t)) + exists(TypeTracker t2 | result = superCallNoArgumentTracker(t2, func).track(t2, t)) and + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** @@ -555,7 +560,8 @@ private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, N call.getArg(1) = obj ) or - exists(TypeTracker t2 | result = superCallTwoArgumentTracker(t2, cls, obj).track(t2, t)) + exists(TypeTracker t2 | result = superCallTwoArgumentTracker(t2, cls, obj).track(t2, t)) and + not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll index e00303d750b..67e3db984e8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackerSpecific.qll @@ -68,7 +68,6 @@ string getPossibleContentName() { * methods is done using API graphs (which uses type tracking). */ predicate callStep(DataFlowPublic::ArgumentNode nodeFrom, DataFlowPublic::ParameterNode nodeTo) { - // TODO: Fix performance problem with pandas exists( DataFlowPrivate::DataFlowCall call, DataFlowPrivate::DataFlowCallable callable, DataFlowPrivate::ArgumentPosition apos, DataFlowPrivate::ParameterPosition ppos diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py b/python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py index fcb22ca40e6..f5618450033 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/self_passing.py @@ -21,7 +21,7 @@ class Base(object): class A(Base): def foo(self): print("A.foo") - self.bar() # $ pt,tt=A.bar SPURIOUS: tt=B.bar + self.bar() # $ pt,tt=A.bar def not_called(self): self.bar() #$ pt,tt=A.bar @@ -50,7 +50,7 @@ class X(object): def foo(self): print("X.foo") - self.meth() # $ pt,tt=X.meth SPURIOUS: tt=Y.meth + self.meth() # $ pt,tt=X.meth class Y(object): From cba93ded77af314bdf109f9f7c0d421ee5236122 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 20 Oct 2022 21:11:01 +0200 Subject: [PATCH 045/415] Python: Add test for `@property` problem --- .../CallGraph/InlineCallGraphTest.expected | 6 +++--- .../library-tests/CallGraph/code/class_properties.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 2e2c1cd655f..ddeba0cf074 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -1,8 +1,8 @@ failures debug_callableNotUnique -| code/class_properties.py:7:5:7:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | -| code/class_properties.py:12:5:12:25 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | -| code/class_properties.py:17:5:17:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | +| code/class_properties.py:10:5:10:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | +| code/class_properties.py:15:5:15:25 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | +| code/class_properties.py:20:5:20:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | pointsTo_found_typeTracker_notFound | code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func | | code/class_attr_assign.py:11:9:11:25 | ControlFlowNode for Attribute() | my_func | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py index 06e4f3f3bd2..de436339115 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py @@ -1,3 +1,6 @@ +def func(): + print("func") + class Prop(object): def __init__(self, arg): self._arg = arg @@ -32,6 +35,11 @@ class Prop(object): arg2 = property(_arg2_getter, _arg2_setter, _arg2_deleter) + @property + def func_prop(self): + print("Prop.func_prop getter") + return func + prop = Prop(42) # $ tt=Prop.__init__ prop.arg @@ -41,3 +49,6 @@ del prop.arg prop.arg2 prop.arg2 = 43 del prop.arg2 + +f = prop.func_prop +f() # $ SPURIOUS: tt=Prop.func_prop MISSING: tt=func From 1e96ced3ab36f5ce621020fb36623e59f2a8d916 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 14 Oct 2022 11:38:45 +0200 Subject: [PATCH 046/415] Python: Ignore functions with `@property` decorator for now --- .../dataflow/new/internal/DataFlowDispatch.qll | 13 ++++++++++++- .../CallGraph/code/class_properties.py | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 18bff54a023..83b41b8ac33 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -205,6 +205,13 @@ predicate isClassmethod(Function func) { ) } +/** Holds if the function `func` has a `property` decorator. */ +predicate hasPropertyDecorator(Function func) { + exists(NameNode id | id.getId() = "property" and id.isGlobal() | + func.getADecorator() = id.getNode() + ) +} + // ============================================================================= // Callables // ============================================================================= @@ -251,7 +258,11 @@ abstract class DataFlowCallable extends TDataFlowCallable { abstract class DataFlowFunction extends DataFlowCallable, TFunction { Function func; - DataFlowFunction() { this = TFunction(func) } + DataFlowFunction() { + this = TFunction(func) and + // TODO: Handle @property decorators + not hasPropertyDecorator(func) + } override string toString() { result = func.toString() } diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py index de436339115..ea7d7847adb 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_properties.py @@ -51,4 +51,4 @@ prop.arg2 = 43 del prop.arg2 f = prop.func_prop -f() # $ SPURIOUS: tt=Prop.func_prop MISSING: tt=func +f() # $ MISSING: tt=func From 16483f7d400e08a2ec4ad1db7e1b869346179cf3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 14:14:08 +0200 Subject: [PATCH 047/415] Python: Add funky call-graph regression I don't even know how to phrase this :D --- .../CallGraph/InlineCallGraphTest.expected | 1 + .../CallGraph/code/funky_regression.py | 63 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index ddeba0cf074..b3bc72cca1e 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -17,6 +17,7 @@ pointsTo_found_typeTracker_notFound | code/func_defined_outside_class.py:39:11:39:21 | ControlFlowNode for _gen() | B._gen | | code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func | | code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func | +| code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 | | code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func | typeTracker_found_pointsTo_notFound | code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py b/python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py new file mode 100644 index 00000000000..bb87bfb47e9 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/funky_regression.py @@ -0,0 +1,63 @@ +# When this regression was discovered, we did not resolve the `self.f2()` call after the +# try-except block, but ONLY when passing an attribute to a method, as indicated in the +# other tests below. + +class Wat(object): + def f1(self, arg): pass + def f2(self): pass + + def func(self, foo): + try: + self.f1(foo.bar) # $ pt,tt=Wat.f1 + except Exception as e: + raise e + + self.f2() # $ pt=Wat.f2 MISSING: tt=Wat.f2 + + +# ============================================================================== +# variants that we are able to handle +# ============================================================================== + + +class Works(object): + "not using attribute" + def f1(self, arg): pass + def f2(self): pass + + def func(self, foo): + try: + self.f1(foo) # $ pt,tt=Works.f1 + except Exception as e: + raise e + + self.f2() # $ pt,tt=Works.f2 + + +class AlsoWorks(object): + "no exception" + def f1(self, arg): pass + def f2(self): pass + + def func(self, foo): + self.f1(foo.bar) # $ pt,tt=AlsoWorks.f1 + + self.f2() # $ pt,tt=AlsoWorks.f2 + + +def safe_func(arg): + pass + + +class Works3(object): + "call to non-self function" + def f1(self, arg): pass + def f2(self): pass + + def func(self, foo): + try: + safe_func(foo.bar) # $ pt,tt=safe_func + except Exception as e: + raise e + + self.f2() # $ pt,tt=Works3.f2 From d43a48c265a2b947fb57a8f62b5cbd1e782b11d5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 14:38:28 +0200 Subject: [PATCH 048/415] Python: Add `type(self)()` tests --- .../CallGraph/InlineCallGraphTest.expected | 1 + .../CallGraph/code/class_construction.py | 24 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index b3bc72cca1e..805054ffc62 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -7,6 +7,7 @@ pointsTo_found_typeTracker_notFound | code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func | | code/class_attr_assign.py:11:9:11:25 | ControlFlowNode for Attribute() | my_func | | code/class_attr_assign.py:26:9:26:25 | ControlFlowNode for Attribute() | DummyObject.method | +| code/class_construction.py:23:1:23:11 | ControlFlowNode for Attribute() | X.foo | | code/class_super.py:50:1:50:6 | ControlFlowNode for Attribute() | outside_def | | code/conditional_in_argument.py:18:5:18:11 | ControlFlowNode for Attribute() | X.bar | | code/func_defined_outside_class.py:21:1:21:11 | ControlFlowNode for Attribute() | A.foo | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py index ce348fee15f..2cf6a8fb32b 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py @@ -1,8 +1,26 @@ class X(object): def __init__(self, arg): print("X.__init__", arg) + self.arg = arg -X(42) # $ tt=X.__init__ + def foo(self): + print("X.foo", self.arg) + + def meth(self): + print("X.meth") + return type(self)(42.1) # $ MISSING: tt=X.__init__ tt=Y.__init__ + + @classmethod + def cm(cls): + print("X.cm") + cls(42.2) # $ MISSING: tt=X.__init__ tt=Y.__init__ + +x = X(42.0) # $ tt=X.__init__ +x_421 = x.meth() # $ pt,tt=X.meth +X.cm() # $ pt,tt=X.cm +x.foo() # $ pt,tt=X.foo +print() +x_421.foo() # $ pt=X.foo MISSING: tt=X.foo print() @@ -11,7 +29,9 @@ class Y(X): print("Y.__init__", arg) super().__init__(-arg) # $ pt,tt=X.__init__ -Y(43) # $ tt=Y.__init__ +y = Y(43) # $ tt=Y.__init__ +y.meth() # $ pt,tt=X.meth +y.cm() # $ pt,tt=X.cm print() # --- From a4e6433942cc72369e0e28eec64ff2badc61f2ff Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 14:40:23 +0200 Subject: [PATCH 049/415] Python: add support for `type(self)()` --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 8 +++++++- .../library-tests/CallGraph/InlineCallGraphTest.expected | 1 - .../library-tests/CallGraph/code/class_construction.py | 6 +++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 83b41b8ac33..d0016c28673 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -466,7 +466,7 @@ Node classTracker(Class cls) { classTracker(TypeTracker::end(), cls).flowsTo(res */ private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) { t.start() and - result.(CallCfgNode).getFunction() = classTracker(cls) + resolveClassCall(result.(CallCfgNode).asCfgNode(), cls) or exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) @@ -951,6 +951,12 @@ import MethodCalls */ predicate resolveClassCall(CallNode call, Class cls) { call.getFunction() = classTracker(cls).asCfgNode() + or + // `cls()` inside a classmethod (which also contains `type(self)()` inside a method) + exists(Class classWithMethod | + call.getFunction() = clsTracker(classWithMethod).asCfgNode() and + getADirectSuperclass*(cls) = classWithMethod + ) } /** diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 805054ffc62..b3bc72cca1e 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -7,7 +7,6 @@ pointsTo_found_typeTracker_notFound | code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func | | code/class_attr_assign.py:11:9:11:25 | ControlFlowNode for Attribute() | my_func | | code/class_attr_assign.py:26:9:26:25 | ControlFlowNode for Attribute() | DummyObject.method | -| code/class_construction.py:23:1:23:11 | ControlFlowNode for Attribute() | X.foo | | code/class_super.py:50:1:50:6 | ControlFlowNode for Attribute() | outside_def | | code/conditional_in_argument.py:18:5:18:11 | ControlFlowNode for Attribute() | X.bar | | code/func_defined_outside_class.py:21:1:21:11 | ControlFlowNode for Attribute() | A.foo | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py index 2cf6a8fb32b..8543fc94ee5 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py @@ -8,19 +8,19 @@ class X(object): def meth(self): print("X.meth") - return type(self)(42.1) # $ MISSING: tt=X.__init__ tt=Y.__init__ + return type(self)(42.1) # $ tt=X.__init__ tt=Y.__init__ @classmethod def cm(cls): print("X.cm") - cls(42.2) # $ MISSING: tt=X.__init__ tt=Y.__init__ + cls(42.2) # $ tt=X.__init__ tt=Y.__init__ x = X(42.0) # $ tt=X.__init__ x_421 = x.meth() # $ pt,tt=X.meth X.cm() # $ pt,tt=X.cm x.foo() # $ pt,tt=X.foo print() -x_421.foo() # $ pt=X.foo MISSING: tt=X.foo +x_421.foo() # $ pt=X.foo tt=X.foo print() From 2b76964f7f7adace6087a9571b871b7d2b4f12ef Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 15:16:26 +0200 Subject: [PATCH 050/415] Python: Expand tests of `__new__` a bit more --- .../CallGraph/code/class_construction.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py index 8543fc94ee5..06669902714 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py @@ -44,15 +44,27 @@ class WithNew(object): inst.some_method() # $ MISSING: pt,tt=WithNew.some_method return inst - def __init__(self, arg): + def __init__(self, arg=None): print("WithNew.__init__", arg) def some_method(self): - print("WithNew.__init__") + print("WithNew.some_method") WithNew(44) # $ tt=WithNew.__new__ tt=WithNew.__init__ print() +class WithNewSub(WithNew): + def __new__(cls): + print("WithNewSub.__new__") + inst = super().__new__(cls, 44.1) # $ pt,tt=WithNew.__new__ + assert isinstance(inst, cls) + inst.some_method() # $ MISSING: pt,tt=WithNew.some_method + return inst + +WithNewSub() # $ tt=WithNewSub.__new__ tt=WithNew.__init__ +print() + +# ------------------------------------------------------------------------------ class ExtraCallToInit(object): def __new__(cls, arg): From 8a56b48357d7a6a59a44bf476a820ed516966444 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 15:35:53 +0200 Subject: [PATCH 051/415] Python: Support `super().__new__(cls)` --- .../dataflow/new/internal/DataFlowDispatch.qll | 17 +++++++++++++++++ .../CallGraph/InlineCallGraphTest.expected | 3 +++ .../CallGraph/code/class_construction.py | 6 +++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index d0016c28673..5f957553a76 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -468,6 +468,13 @@ private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) { t.start() and resolveClassCall(result.(CallCfgNode).asCfgNode(), cls) or + // result of `super().__new__` as used in a `__new__` method implementation + t.start() and + exists(Class classUsedInSuper | + fromSuperNewCall(result.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and + classUsedInSuper = getADirectSuperclass*(cls) + ) + or exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } @@ -856,6 +863,16 @@ private module MethodCalls { attr.accesses(self, functionName) } + /** + * Like `fromSuper`, but only for `__new__`, and without requirement for being able to + * resolve the call to a known target (since the only super class might be the + * builtin `object`, so we never have the implementation of `__new__` in the DB). + */ + predicate fromSuperNewCall(CallNode call, Class classUsedInSuper, AttrRead attr, Node self) { + fromSuper_join(call, "__new__", classUsedInSuper, attr, self) and + self in [classTracker(_), clsTracker(_)] + } + /** * Holds if `call` is a call to a method `target`, derived from a use of `super`, either * as: diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index b3bc72cca1e..2478db5a060 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -21,6 +21,9 @@ pointsTo_found_typeTracker_notFound | code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func | typeTracker_found_pointsTo_notFound | code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm | +| code/class_construction.py:44:9:44:26 | ControlFlowNode for Attribute() | WithNew.some_method | +| code/class_construction.py:61:9:61:26 | ControlFlowNode for Attribute() | WithNew.some_method | +| code/class_construction.py:75:9:75:27 | ControlFlowNode for Attribute() | ExtraCallToInit.__init__ | | code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Base.__call__ | | code/class_special_methods.py:22:9:22:16 | ControlFlowNode for self() | Sub.__call__ | | code/class_special_methods.py:33:1:33:5 | ControlFlowNode for b() | Base.__call__ | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py index 06669902714..1ae696edf61 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_construction.py @@ -41,7 +41,7 @@ class WithNew(object): print("WithNew.__new__", arg) inst = super().__new__(cls) assert isinstance(inst, cls) - inst.some_method() # $ MISSING: pt,tt=WithNew.some_method + inst.some_method() # $ tt=WithNew.some_method return inst def __init__(self, arg=None): @@ -58,7 +58,7 @@ class WithNewSub(WithNew): print("WithNewSub.__new__") inst = super().__new__(cls, 44.1) # $ pt,tt=WithNew.__new__ assert isinstance(inst, cls) - inst.some_method() # $ MISSING: pt,tt=WithNew.some_method + inst.some_method() # $ tt=WithNew.some_method return inst WithNewSub() # $ tt=WithNewSub.__new__ tt=WithNew.__init__ @@ -72,7 +72,7 @@ class ExtraCallToInit(object): inst = super().__new__(cls) assert isinstance(inst, cls) # you're not supposed to do this, since it will cause the __init__ method will be run twice. - inst.__init__(1001) # $ MISSING: pt,tt=ExtraCallToInit.__init__ + inst.__init__(1001) # $ tt=ExtraCallToInit.__init__ return inst def __init__(self, arg): From 276a825cd0d8c8d8574e694ce36b6085e958d7e3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 16:03:04 +0200 Subject: [PATCH 052/415] Python: Allow same function name in call-graph tests --- .../CallGraph/InlineCallGraphTest.expected | 3 --- .../library-tests/CallGraph/InlineCallGraphTest.ql | 10 ++++++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 2478db5a060..31ea3f55ff2 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -1,8 +1,5 @@ failures debug_callableNotUnique -| code/class_properties.py:10:5:10:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | -| code/class_properties.py:15:5:15:25 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | -| code/class_properties.py:20:5:20:18 | Function arg | Qualified function name 'Prop.arg' is not unique within its file. Please fix. | pointsTo_found_typeTracker_notFound | code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func | | code/class_attr_assign.py:11:9:11:25 | ControlFlowNode for Attribute() | my_func | diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql index d613460e749..fa658d892f0 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.ql @@ -76,7 +76,13 @@ bindingset[func] string betterQualName(Function func) { // note: `target.getQualifiedName` for Lambdas is just "lambda", so is not very useful :| not func.isLambda() and - result = func.getQualifiedName() + if + strictcount(Function f | + f.getEnclosingModule() = func.getEnclosingModule() and + f.getQualifiedName() = func.getQualifiedName() + ) = 1 + then result = func.getQualifiedName() + else result = func.getLocation().getStartLine() + ":" + func.getQualifiedName() or func.isLambda() and result = @@ -88,7 +94,7 @@ query predicate debug_callableNotUnique(Function callable, string message) { exists(callable.getLocation().getFile().getRelativePath()) and exists(Function f | f != callable and - f.getQualifiedName() = callable.getQualifiedName() and + betterQualName(f) = betterQualName(callable) and f.getLocation().getFile() = callable.getLocation().getFile() ) and message = From fb0cc184d97e813ce9c14a289808530f3de2c348 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 16:31:39 +0200 Subject: [PATCH 053/415] Python: Add test of multi func def based on runtime decision --- .../CallGraph/InlineCallGraphTest.expected | 2 ++ .../CallGraph/code/runtime_decision.py | 18 ++++++++++++++++++ .../CallGraph/code/runtime_decision_defns.py | 8 ++++++++ 3 files changed, 28 insertions(+) create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision_defns.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 31ea3f55ff2..9e79328c82b 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -15,6 +15,8 @@ pointsTo_found_typeTracker_notFound | code/func_defined_outside_class.py:42:1:42:7 | ControlFlowNode for Attribute() | B._gen.func | | code/func_defined_outside_class.py:43:1:43:7 | ControlFlowNode for Attribute() | B._gen.func | | code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 | +| code/runtime_decision.py:44:1:44:7 | ControlFlowNode for func4() | "code/runtime_decision_defns.py:4:func4" | +| code/runtime_decision.py:44:1:44:7 | ControlFlowNode for func4() | "code/runtime_decision_defns.py:7:func4" | | code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func | typeTracker_found_pointsTo_notFound | code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py index 3901a770188..d3800080589 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision.py @@ -24,3 +24,21 @@ else: func2 = rd_bar func2() # $ pt,tt=rd_foo pt,tt=rd_bar + + +# ============================================================================== +# definition is random + +if random.random() < 0.5: + def func3(): + print("func3 A") +else: + def func3(): + print("func3 B") + +func3() # $ pt,tt=33:func3 pt,tt=36:func3 + + +# func4 uses same setup as func3, it's just defined in an other file +from code.runtime_decision_defns import func4 +func4() # $ pt="code/runtime_decision_defns.py:4:func4" pt="code/runtime_decision_defns.py:7:func4" MISSING: tt diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision_defns.py b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision_defns.py new file mode 100644 index 00000000000..931d9246fa1 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/runtime_decision_defns.py @@ -0,0 +1,8 @@ +import random + +if random.random() < 0.5: + def func4(): + print("func4 A") +else: + def func4(): + print("func4 B") From e5fdeae6fcf290604bf39cf298b43cba3b61f589 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 24 Oct 2022 16:42:02 +0200 Subject: [PATCH 054/415] Python: Add `return (func_ref, ...)` test --- .../CallGraph/InlineCallGraphTest.expected | 1 + .../CallGraph/code/tuple_function_return.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py diff --git a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected index 9e79328c82b..72d792b6623 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/InlineCallGraphTest.expected @@ -17,6 +17,7 @@ pointsTo_found_typeTracker_notFound | code/funky_regression.py:15:9:15:17 | ControlFlowNode for Attribute() | Wat.f2 | | code/runtime_decision.py:44:1:44:7 | ControlFlowNode for func4() | "code/runtime_decision_defns.py:4:func4" | | code/runtime_decision.py:44:1:44:7 | ControlFlowNode for func4() | "code/runtime_decision_defns.py:7:func4" | +| code/tuple_function_return.py:15:1:15:4 | ControlFlowNode for f2() | func | | code/type_tracking_limitation.py:8:1:8:3 | ControlFlowNode for x() | my_func | typeTracker_found_pointsTo_notFound | code/callable_as_argument.py:29:5:29:12 | ControlFlowNode for Attribute() | test_class.InsideTestFunc.sm | diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py b/python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py new file mode 100644 index 00000000000..f87b1aa23e8 --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph/code/tuple_function_return.py @@ -0,0 +1,15 @@ +def func(): + print("func()") + +def return_func(): + return func + +def return_func_in_tuple(): + return (func, 42) + +f1 = return_func() # $ pt,tt=return_func +f1() # $ pt,tt=func + + +f2, _ = return_func_in_tuple() # $ pt,tt=return_func_in_tuple +f2() # $ pt=func MISSING: tt From c4122275dc95b48568ae01304dae914bedec97ef Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 31 Oct 2022 18:11:07 +0100 Subject: [PATCH 055/415] Python: Bring back support for flow-summaries Also needed to fix up `TestUtil/UnresolvedCalls.qll` after a bad merge conflict resolution. Since all calls are now DataFlowCall, and not JUST the ones that can be resolved, we need to put in the restriction that the callable can also be resolved. --- .../new/internal/DataFlowDispatch.qll | 92 ++++++++++++------- .../dataflow/new/internal/DataFlowPrivate.qll | 16 +--- .../dataflow/new/internal/DataFlowPublic.qll | 14 ++- .../new/internal/FlowSummaryImplSpecific.qll | 78 ++++++++++++---- .../dataflow/TestUtil/UnresolvedCalls.qll | 4 +- .../dataflow/basic/callGraphSinks.expected | 1 + .../dataflow/basic/callGraphSources.expected | 1 + .../dataflow/basic/global.expected | 1 + .../dataflow/basic/globalStep.expected | 1 + .../dataflow/basic/local.expected | 5 + .../dataflow/basic/localStep.expected | 1 + .../dataflow/basic/sinks.expected | 4 + .../dataflow/basic/sources.expected | 4 + .../NormalTaintTrackingTest.expected | 12 --- .../dataflow/summaries/summaries.expected | 76 ++++++++++++--- .../basic/LocalTaintStep.expected | 1 + 16 files changed, 218 insertions(+), 93 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 5f957553a76..b6524382a71 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -36,12 +36,25 @@ private import python private import DataFlowPublic private import DataFlowPrivate private import FlowSummaryImpl as FlowSummaryImpl +private import FlowSummaryImplSpecific as FlowSummaryImplSpecific newtype TParameterPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfParameterPosition() or - TPositionalParameterPosition(int pos) { pos = any(Parameter p).getPosition() } or - TKeywordParameterPosition(string name) { name = any(Parameter p).getName() } or + TPositionalParameterPosition(int pos) { + pos = any(Parameter p).getPosition() + or + // since synthetic parameters are made for a synthetic summary callable, based on + // what Argument positions they have flow for, we need to make sure we have such + // parameter positions available. + FlowSummaryImplSpecific::ParsePositions::isParsedPositionalArgumentPosition(_, pos) + } or + TKeywordParameterPosition(string name) { + name = any(Parameter p).getName() + or + // see comment for TPositionalParameterPosition + FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name) + } or TStarArgsParameterPosition(int pos) { // since `.getPosition` does not work for `*args`, we need *args parameter positions // at index 1 larger than the largest positional parameter position (and 0 must be @@ -114,8 +127,20 @@ class ParameterPosition extends TParameterPosition { newtype TArgumentPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfArgumentPosition() or - TPositionalArgumentPosition(int pos) { exists(any(CallNode c).getArg(pos)) } or - TKeywordArgumentPosition(string name) { exists(any(CallNode c).getArgByName(name)) } or + TPositionalArgumentPosition(int pos) { + exists(any(CallNode c).getArg(pos)) + or + // since synthetic calls within a summarized callable could use a unique argument + // position, we need to ensure we make these available (these are specified as + // parameters in the flow-summary spec) + FlowSummaryImplSpecific::ParsePositions::isParsedPositionalParameterPosition(_, pos) + } or + TKeywordArgumentPosition(string name) { + exists(any(CallNode c).getArgByName(name)) + or + // see comment for TPositionalArgumentPosition + FlowSummaryImplSpecific::ParsePositions::isParsedKeywordParameterPosition(_, name) + } or TStarArgsArgumentPosition(int pos) { exists(Call c | c.getPositionalArg(pos) instanceof Starred) } or TDictSplatArgumentPosition() @@ -376,7 +401,7 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { LibraryCallableValue() { this = TLibraryCallable(callable) } - override string toString() { result = callable.toString() } + override string toString() { result = "LibraryCallableValue: " + callable.toString() } override string getQualifiedName() { result = callable.toString() } @@ -1038,7 +1063,8 @@ predicate resolveCall(ControlFlowNode call, Function target, CallType type) { * Holds if the argument of `call` at position `apos` is `arg`. This is just a helper * predicate that maps ArgumentPositions to the arguments of the underlying `CallNode`. */ -private predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { +cached +predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { exists(int index | apos.isPositional(index) and arg.asCfgNode() = call.getArg(index) @@ -1170,8 +1196,8 @@ predicate getCallArg( // DataFlowCall // ============================================================================= newtype TDataFlowCall = - TNormalCall(CallNode call, Function target, CallType type) { resolveCall(call, target, type) } - or + TNormalCall(CallNode call, Function target, CallType type) { resolveCall(call, target, type) } or + TPotentialLibraryCall(CallNode call) or /** A synthesized call inside a summarized callable */ TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) { FlowSummaryImpl::Private::summaryCallbackRange(c, receiver) @@ -1253,49 +1279,44 @@ class NormalCall extends ExtractedDataFlowCall, TNormalCall { } /** - * A call to a summarized callable, a `LibraryCallable`. + * A potential call to a summarized callable, a `LibraryCallable`. * * We currently exclude all resolved calls. This means that a call to, say, `map`, which * is a `ClassCall`, cannot currently be given a summary. * We hope to lift this restriction in the future and include all potential calls to summaries * in this class. */ -class LibraryCall extends DataFlowCall { - LibraryCall() { - // TODO(call-graph): implement this! - none() - } +class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall { + CallNode call; + + PotentialLibraryCall() { this = TPotentialLibraryCall(call) } override string toString() { - // TODO(call-graph): implement this! - none() + // note: if we used toString directly on the CallNode we would get + // `ControlFlowNode for func()` + // but the `ControlFlowNode` part is just clutter, so we go directly to the AST node + // instead. + result = call.getNode().toString() } - // We cannot refer to a `LibraryCallable` here, + // We cannot refer to a `PotentialLibraryCall` here, // as that could in turn refer to type tracking. - // This call will be tied to a `LibraryCallable` via - // `getViableCallabe` when the global data flow is assembled. + // This call will be tied to a `PotentialLibraryCall` via + // `viableCallable` when the global data flow is assembled. override DataFlowCallable getCallable() { none() } override ArgumentNode getArgument(ArgumentPosition apos) { - // TODO(call-graph): implement this! - none() + normalCallArg(call, result, apos) + or + // potential self argument, from `foo.bar()` -- note that this could also just be a + // module reference, but we really don't have a good way of knowing :| + apos.isSelf() and + result = any(MethodCallNode mc | mc.getFunction().asCfgNode() = call.getFunction()).getObject() } - override ControlFlowNode getNode() { - // TODO(call-graph): implement this! - none() - } + override ControlFlowNode getNode() { result = call } - override DataFlowCallable getEnclosingCallable() { - // TODO(call-graph): implement this! - none() - } - - override Location getLocation() { - // TODO(call-graph): implement this! - none() - } + override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getScope() } } /** @@ -1433,7 +1454,8 @@ DataFlowCallable viableCallable(ExtractedDataFlowCall call) { // Instead we resolve the call from the summary. exists(LibraryCallable callable | result = TLibraryCallable(callable) and - call.getNode() = callable.getACall().getNode() + call.getNode() = callable.getACall().getNode() and + call instanceof PotentialLibraryCall ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 8d4f45bcdeb..ed611c93549 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -981,18 +981,10 @@ class LambdaCallKind = Unit; /** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { - // TODO(call-graph): implement this! - // - // // lambda - // kind = kind and - // creation.asExpr() = c.(DataFlowLambda).getDefinition() - // or - // // normal function - // exists(FunctionDef def | - // def.defines(creation.asVar().getSourceVariable()) and - // def.getDefinedFunction() = c.(DataFlowCallableValue).getCallableValue().getScope() - // ) - // or + // lambda and plain functions + kind = kind and + creation.asExpr() = c.(DataFlowPlainFunction).getScope().getDefinition() + or // summarized function exists(kind) and // avoid warning on unused 'kind' exists(Call call | diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 79b711db9e8..b03bb3de0a0 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -337,11 +337,19 @@ abstract class ArgumentNode extends Node { } /** - * A data flow node that represents a call argument found in the source code, - * where the call can be resolved. + * A data flow node that represents a call argument found in the source code. */ class ExtractedArgumentNode extends ArgumentNode { - ExtractedArgumentNode() { getCallArg(_, _, _, this, _) } + ExtractedArgumentNode() { + // for resolved calls, we need to allow all argument nodes + getCallArg(_, _, _, this, _) + or + // for potential summaries we allow all normal call arguments + normalCallArg(_, this, _) + or + // and self arguments + this = any(MethodCallNode mc).getObject() + } final override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { this = call.getArgument(pos) and 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 5d950247369..90411e658b2 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll @@ -115,10 +115,34 @@ string getComponentSpecificCsv(SummaryComponent sc) { } /** Gets the textual representation of a parameter position in the format used for flow summaries. */ -string getParameterPositionCsv(ParameterPosition pos) { result = pos.toString() } +string getParameterPositionCsv(ParameterPosition pos) { + pos.isSelf() and result = "self" + or + exists(int i | + pos.isPositional(i) and + result = i.toString() + ) + or + exists(string name | + pos.isKeyword(name) and + result = name + ":" + ) +} /** Gets the textual representation of an argument position in the format used for flow summaries. */ -string getArgumentPositionCsv(ArgumentPosition pos) { result = pos.toString() } +string getArgumentPositionCsv(ArgumentPosition pos) { + pos.isSelf() and result = "self" + or + exists(int i | + pos.isPositional(i) and + result = i.toString() + ) + or + exists(string name | + pos.isKeyword(name) and + result = name + ":" + ) +} /** Holds if input specification component `c` needs a reference. */ predicate inputNeedsReferenceSpecific(string c) { none() } @@ -200,33 +224,55 @@ module ParsePositions { ) } - predicate isParsedParameterPosition(string c, int i) { + predicate isParsedPositionalParameterPosition(string c, int i) { isParamBody(c) and i = AccessPath::parseInt(c) } - predicate isParsedArgumentPosition(string c, int i) { + predicate isParsedKeywordParameterPosition(string c, string paramName) { + isParamBody(c) and + c = paramName + ":" + } + + predicate isParsedPositionalArgumentPosition(string c, int i) { isArgBody(c) and i = AccessPath::parseInt(c) } + + predicate isParsedKeywordArgumentPosition(string c, string argName) { + isArgBody(c) and + c = argName + ":" + } } /** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */ ArgumentPosition parseParamBody(string s) { - none() - // TODO(call-graph): implement this! - // exists(int i | - // ParsePositions::isParsedParameterPosition(s, i) and - // result.isPositional(i) - // ) + exists(int i | + ParsePositions::isParsedPositionalParameterPosition(s, i) and + result.isPositional(i) + ) + or + exists(string name | + ParsePositions::isParsedKeywordParameterPosition(s, name) and + result.isKeyword(name) + ) + or + s = "self" and + result.isSelf() } /** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */ ParameterPosition parseArgBody(string s) { - none() - // TODO(call-graph): implement this! - // exists(int i | - // ParsePositions::isParsedArgumentPosition(s, i) and - // result.isPositional(i) - // ) + exists(int i | + ParsePositions::isParsedPositionalArgumentPosition(s, i) and + result.isPositional(i) + ) + or + exists(string name | + ParsePositions::isParsedKeywordArgumentPosition(s, name) and + result.isKeyword(name) + ) + or + s = "self" and + result.isSelf() } diff --git a/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll b/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll index fbdcca3ef04..b84f8e6f165 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/UnresolvedCalls.qll @@ -12,7 +12,9 @@ class UnresolvedCallExpectations extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(location.getFile().getRelativePath()) and exists(CallNode call | - not exists(DataFlowPrivate::DataFlowCall dfc | dfc.getNode() = call) and + not exists(DataFlowPrivate::DataFlowCall dfc | + exists(dfc.getCallable()) and dfc.getNode() = call + ) and not DataFlowPrivate::resolveClassCall(call, _) and not call = API::builtin(_).getACall().asCfgNode() and location = call.getLocation() and diff --git a/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected b/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected index e4b8f905530..0f87376ef1a 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected +++ b/python/ql/test/experimental/dataflow/basic/callGraphSinks.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | parameter position 0 of builtins.reversed | | test.py:1:1:1:21 | SynthDictSplatParameterNode | | test.py:1:19:1:19 | ControlFlowNode for x | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/basic/callGraphSources.expected b/python/ql/test/experimental/dataflow/basic/callGraphSources.expected index 4023ba8f3ea..0b4613c42de 100644 --- a/python/ql/test/experimental/dataflow/basic/callGraphSources.expected +++ b/python/ql/test/experimental/dataflow/basic/callGraphSources.expected @@ -1,2 +1,3 @@ +| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:7:19:7:19 | ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/basic/global.expected b/python/ql/test/experimental/dataflow/basic/global.expected index 8894bcc190a..800312b07be 100644 --- a/python/ql/test/experimental/dataflow/basic/global.expected +++ b/python/ql/test/experimental/dataflow/basic/global.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | diff --git a/python/ql/test/experimental/dataflow/basic/globalStep.expected b/python/ql/test/experimental/dataflow/basic/globalStep.expected index 9f228998b9c..fa5b20486c2 100644 --- a/python/ql/test/experimental/dataflow/basic/globalStep.expected +++ b/python/ql/test/experimental/dataflow/basic/globalStep.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index cdf40018ed0..2354efea8e5 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -1,3 +1,8 @@ +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | +| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | +| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | +| file://:0:0:0:0 | parameter position 0 of builtins.reversed | file://:0:0:0:0 | parameter position 0 of builtins.reversed | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | diff --git a/python/ql/test/experimental/dataflow/basic/localStep.expected b/python/ql/test/experimental/dataflow/basic/localStep.expected index e147bb9f4fc..534c31da1a6 100644 --- a/python/ql/test/experimental/dataflow/basic/localStep.expected +++ b/python/ql/test/experimental/dataflow/basic/localStep.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | SSA variable x | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index 944f8190aa5..aafff76bbe2 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -1,3 +1,7 @@ +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | +| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | +| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | +| file://:0:0:0:0 | parameter position 0 of builtins.reversed | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index 944f8190aa5..aafff76bbe2 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -1,3 +1,7 @@ +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | +| file://:0:0:0:0 | [summary] to write: return (return) in builtins.reversed | +| file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | +| file://:0:0:0:0 | parameter position 0 of builtins.reversed | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | diff --git a/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected index 8e04ba142cb..3875da4e143 100644 --- a/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected +++ b/python/ql/test/experimental/dataflow/summaries/NormalTaintTrackingTest.expected @@ -1,14 +1,2 @@ missingAnnotationOnSink -| summaries.py:33:6:33:12 | summaries.py:33 | ERROR, you should add `# $ MISSING: flow` annotation | tainted | -| summaries.py:37:6:37:19 | summaries.py:37 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_lambda | -| summaries.py:52:6:52:22 | summaries.py:52 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_mapped[0] | -| summaries.py:58:6:58:31 | summaries.py:58 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_mapped_explicit[0] | -| summaries.py:61:6:61:30 | summaries.py:61 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_mapped_summary[0] | -| summaries.py:64:6:64:20 | summaries.py:64 | ERROR, you should add `# $ MISSING: flow` annotation | tainted_list[0] | failures -| summaries.py:33:16:33:49 | Comment # $ flow="SOURCE, l:-1 -> tainted" | Missing result:flow="SOURCE, l:-1 -> tainted" | -| summaries.py:37:23:37:63 | Comment # $ flow="SOURCE, l:-1 -> tainted_lambda" | Missing result:flow="SOURCE, l:-1 -> tainted_lambda" | -| summaries.py:52:26:52:69 | Comment # $ flow="SOURCE, l:-1 -> tainted_mapped[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_mapped[0]" | -| summaries.py:58:35:58:87 | Comment # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" | -| summaries.py:61:34:61:85 | Comment # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" | -| summaries.py:64:24:64:65 | Comment # $ flow="SOURCE, l:-1 -> tainted_list[0]" | Missing result:flow="SOURCE, l:-1 -> tainted_list[0]" | diff --git a/python/ql/test/experimental/dataflow/summaries/summaries.expected b/python/ql/test/experimental/dataflow/summaries/summaries.expected index 8f5366ed6c2..b566cbdedc6 100644 --- a/python/ql/test/experimental/dataflow/summaries/summaries.expected +++ b/python/ql/test/experimental/dataflow/summaries/summaries.expected @@ -1,29 +1,77 @@ edges +| summaries.py:32:11:32:26 | ControlFlowNode for identity() | summaries.py:33:6:33:12 | ControlFlowNode for tainted | +| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:32:11:32:26 | ControlFlowNode for identity() | +| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | +| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | +| summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | | summaries.py:44:25:44:32 | ControlFlowNode for List | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | +| summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:44:25:44:32 | ControlFlowNode for List | +| summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | +| summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | +| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | +| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | +| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | +| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | summaries.py:52:6:52:22 | ControlFlowNode for Subscript | +| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | +| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | +| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | +| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | summaries.py:58:6:58:31 | ControlFlowNode for Subscript | +| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | +| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | +| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | +| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | summaries.py:61:6:61:30 | ControlFlowNode for Subscript | +| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | +| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | +| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | summaries.py:64:6:64:20 | ControlFlowNode for Subscript | +| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | +| summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | +| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | nodes +| summaries.py:32:11:32:26 | ControlFlowNode for identity() | semmle.label | ControlFlowNode for identity() | +| summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:33:6:33:12 | ControlFlowNode for tainted | semmle.label | ControlFlowNode for tainted | +| summaries.py:36:18:36:54 | ControlFlowNode for apply_lambda() | semmle.label | ControlFlowNode for apply_lambda() | +| summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | semmle.label | ControlFlowNode for tainted_lambda | +| summaries.py:44:16:44:33 | ControlFlowNode for reversed() [List element] | semmle.label | ControlFlowNode for reversed() [List element] | | summaries.py:44:25:44:32 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | +| summaries.py:44:25:44:32 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:45:6:45:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| summaries.py:51:18:51:46 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | +| summaries.py:51:38:51:45 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:52:6:52:19 | ControlFlowNode for tainted_mapped [List element] | semmle.label | ControlFlowNode for tainted_mapped [List element] | +| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| summaries.py:57:27:57:63 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | +| summaries.py:57:55:57:62 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:58:6:58:28 | ControlFlowNode for tainted_mapped_explicit [List element] | semmle.label | ControlFlowNode for tainted_mapped_explicit [List element] | +| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| summaries.py:60:26:60:53 | ControlFlowNode for list_map() [List element] | semmle.label | ControlFlowNode for list_map() [List element] | +| summaries.py:60:45:60:52 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] | +| summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:61:6:61:27 | ControlFlowNode for tainted_mapped_summary [List element] | semmle.label | ControlFlowNode for tainted_mapped_summary [List element] | +| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| summaries.py:63:16:63:41 | ControlFlowNode for append_to_list() [List element] | semmle.label | ControlFlowNode for append_to_list() [List element] | +| summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:64:6:64:17 | ControlFlowNode for tainted_list [List element] | semmle.label | ControlFlowNode for tainted_list [List element] | +| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| summaries.py:67:22:67:39 | ControlFlowNode for json_loads() [List element] | semmle.label | ControlFlowNode for json_loads() [List element] | | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| summaries.py:68:6:68:23 | ControlFlowNode for tainted_resultlist [List element] | semmle.label | ControlFlowNode for tainted_resultlist [List element] | | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | subpaths invalidSpecComponent -| append_to_list | Argument[0] | Argument[0] | -| append_to_list | Argument[1] | Argument[1] | -| apply_lambda | Argument[0].Parameter[0] | Argument[0] | -| apply_lambda | Argument[0].Parameter[0] | Parameter[0] | -| apply_lambda | Argument[0].ReturnValue | Argument[0] | -| apply_lambda | Argument[1] | Argument[1] | -| builtins.reversed | Argument[0].ListElement | Argument[0] | -| identity | Argument[0] | Argument[0] | -| json.loads | Argument[0] | Argument[0] | -| list_map | Argument[0].Parameter[0] | Argument[0] | -| list_map | Argument[0].Parameter[0] | Parameter[0] | -| list_map | Argument[0].ReturnValue | Argument[0] | -| list_map | Argument[1].ListElement | Argument[1] | -| reversed | Argument[0].ListElement | Argument[0] | #select +| summaries.py:33:6:33:12 | ControlFlowNode for tainted | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | summaries.py:33:6:33:12 | ControlFlowNode for tainted | $@ | summaries.py:32:20:32:25 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | +| summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | summaries.py:37:6:37:19 | ControlFlowNode for tainted_lambda | $@ | summaries.py:36:48:36:53 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | summaries.py:45:6:45:20 | ControlFlowNode for Subscript | $@ | summaries.py:44:26:44:31 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | +| summaries.py:52:6:52:22 | ControlFlowNode for Subscript | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | summaries.py:52:6:52:22 | ControlFlowNode for Subscript | $@ | summaries.py:51:39:51:44 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | +| summaries.py:58:6:58:31 | ControlFlowNode for Subscript | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | summaries.py:58:6:58:31 | ControlFlowNode for Subscript | $@ | summaries.py:57:56:57:61 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | +| summaries.py:61:6:61:30 | ControlFlowNode for Subscript | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | summaries.py:61:6:61:30 | ControlFlowNode for Subscript | $@ | summaries.py:60:46:60:51 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | +| summaries.py:64:6:64:20 | ControlFlowNode for Subscript | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | summaries.py:64:6:64:20 | ControlFlowNode for Subscript | $@ | summaries.py:63:35:63:40 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | summaries.py:68:6:68:26 | ControlFlowNode for Subscript | $@ | summaries.py:67:33:67:38 | ControlFlowNode for SOURCE | ControlFlowNode for SOURCE | diff --git a/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected b/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected index 3b3f18c5b9e..05b64297f71 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected @@ -1,3 +1,4 @@ +| file://:0:0:0:0 | [summary] read: argument position 0.List element in builtins.reversed | file://:0:0:0:0 | [summary] to write: return (return).List element in builtins.reversed | | test.py:3:1:3:7 | GSSA Variable tainted | test.py:4:6:4:12 | ControlFlowNode for tainted | | test.py:3:11:3:16 | ControlFlowNode for SOURCE | test.py:3:1:3:7 | GSSA Variable tainted | | test.py:6:1:6:11 | ControlFlowNode for FunctionExpr | test.py:6:5:6:8 | GSSA Variable func | From 478f5ffe965db5f062af74ebd9ce21bc7fc623c6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 1 Nov 2022 10:03:23 +0100 Subject: [PATCH 056/415] Python: Limit `self` argument for `PotentialLibraryCall` Using the object from `MethodCallNode` meant that in the code below, `lib` from the import expression would be considered a self argument (this showed up in dataflow-consistency query results, that were not comitted... sorry) ``` from lib import func func() ``` --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 2 +- .../lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index b6524382a71..55c4b0ae240 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1311,7 +1311,7 @@ class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall // potential self argument, from `foo.bar()` -- note that this could also just be a // module reference, but we really don't have a good way of knowing :| apos.isSelf() and - result = any(MethodCallNode mc | mc.getFunction().asCfgNode() = call.getFunction()).getObject() + result.asCfgNode() = call.getFunction().(AttrNode).getObject() } override ControlFlowNode getNode() { result = call } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index b03bb3de0a0..d46712738cf 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -348,7 +348,7 @@ class ExtractedArgumentNode extends ArgumentNode { normalCallArg(_, this, _) or // and self arguments - this = any(MethodCallNode mc).getObject() + this.asCfgNode() = any(CallNode c).getFunction().(AttrNode).getObject() } final override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { From df4d09b3f9ed863c27acf24cc347fe34bbb3ce0a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 1 Nov 2022 16:04:25 +0100 Subject: [PATCH 057/415] Python: Don't rely on all `DataFlowCall` being resolved I've been living dangerously with that assumption :| --- python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll | 1 + python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index 76aa68c5162..dbc92f9d151 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -87,6 +87,7 @@ newtype TInterestingExternalApiCall = } or TResolvedCall(DataFlowPrivate::DataFlowCall call) { exists(call.getLocation().getFile().getRelativePath()) and + exists(call.getCallable()) and not call.getCallable() = any(SafeExternalApi safe).getSafeCallable() and // ignore calls inside codebase, and ignore calls that are marked as safe. This is // only needed as long as we extract dependencies. When we stop doing that, all diff --git a/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql b/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql index b71e92db337..d939b3092e4 100644 --- a/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql +++ b/python/ql/test/experimental/dataflow/calls/DataFlowCallTest.ql @@ -17,7 +17,8 @@ class DataFlowCallTest extends InlineExpectationsTest { exists(location.getFile().getRelativePath()) and exists(DataFlowDispatch::DataFlowCall call | location = call.getLocation() and - element = call.toString() + element = call.toString() and + exists(call.getCallable()) | value = prettyExpr(call.getNode().getNode()) and tag = "call" From 9d29a0a04418a346c1e9cb6e3bb5e284eced5978 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 24 Aug 2022 13:27:51 +0200 Subject: [PATCH 058/415] Python: Accept changes to .expected from more pathlib flow But we don't want to keep this, this commit is just to show why we need a fix :) --- .../frameworks/stdlib-py3/FileSystemAccess.py | 2 +- .../CWE-312-CleartextStorage-py3/CleartextStorage.expected | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py b/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py index 4de7f3a3c32..0da230d66fc 100644 --- a/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py +++ b/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py @@ -13,7 +13,7 @@ with p.open() as f: # $ getAPathArgument=p p.write_bytes(b"hello") # $ getAPathArgument=p fileWriteData=b"hello" p.write_text("hello") # $ getAPathArgument=p fileWriteData="hello" -p.open("wt").write("hello") # $ getAPathArgument=p fileWriteData="hello" +p.open("wt").write("hello") # $ getAPathArgument=p fileWriteData="hello" SPURIOUS: getAPathArgument=self name = windows.parent.name o = open diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected index f2b0894ec0a..b27e24e30d7 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected @@ -1,14 +1,21 @@ edges +| file:///usr/lib/python3.8/pathlib.py:1248:26:1248:29 | ControlFlowNode for data | file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | +| test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:12:21:12:24 | ControlFlowNode for cert | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:12:21:12:24 | ControlFlowNode for cert | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:13:22:13:41 | ControlFlowNode for Attribute() | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:15:26:15:29 | ControlFlowNode for cert | +| test.py:12:21:12:24 | ControlFlowNode for cert | file:///usr/lib/python3.8/pathlib.py:1248:26:1248:29 | ControlFlowNode for data | nodes +| file:///usr/lib/python3.8/pathlib.py:1248:26:1248:29 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | +| file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() | | test.py:12:21:12:24 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert | +| test.py:12:21:12:24 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert | | test.py:13:22:13:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:15:26:15:29 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert | subpaths #select +| file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | test.py:9:12:9:21 | ControlFlowNode for get_cert() | file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:12:21:12:24 | ControlFlowNode for cert | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:12:21:12:24 | ControlFlowNode for cert | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:13:22:13:41 | ControlFlowNode for Attribute() | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:13:22:13:41 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:15:26:15:29 | ControlFlowNode for cert | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:15:26:15:29 | ControlFlowNode for cert | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | From edcaff26af11e33879ffe6d1771cd443863e8d03 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 24 Aug 2022 14:12:10 +0200 Subject: [PATCH 059/415] Python: Add path-injection test using pathlib Since it has the same problem of showing sinks inside the extracted stdlib --- .../PathInjection.expected | 22 +++++++++++++++++++ .../CWE-022-PathInjection/pathlib_use.py | 17 ++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected index 4d92275ff36..231b111f44b 100644 --- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected @@ -1,4 +1,5 @@ edges +| file:///usr/lib/python3.8/pathlib.py:1214:14:1214:17 | ControlFlowNode for self | file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | | flask_path_injection.py:0:0:0:0 | ModuleVariableNode for flask_path_injection.request | flask_path_injection.py:19:15:19:21 | ControlFlowNode for request | | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:1:26:1:32 | GSSA Variable request | | flask_path_injection.py:1:26:1:32 | GSSA Variable request | flask_path_injection.py:0:0:0:0 | ModuleVariableNode for flask_path_injection.request | @@ -49,6 +50,14 @@ edges | path_injection.py:138:16:138:27 | ControlFlowNode for Attribute | path_injection.py:142:14:142:17 | ControlFlowNode for path | | path_injection.py:149:16:149:22 | ControlFlowNode for request | path_injection.py:149:16:149:27 | ControlFlowNode for Attribute | | path_injection.py:149:16:149:27 | ControlFlowNode for Attribute | path_injection.py:152:18:152:21 | ControlFlowNode for path | +| pathlib_use.py:0:0:0:0 | ModuleVariableNode for pathlib_use.request | pathlib_use.py:12:16:12:22 | ControlFlowNode for request | +| pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:3:26:3:32 | GSSA Variable request | +| pathlib_use.py:3:26:3:32 | GSSA Variable request | pathlib_use.py:0:0:0:0 | ModuleVariableNode for pathlib_use.request | +| pathlib_use.py:12:16:12:22 | ControlFlowNode for request | pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | +| pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | +| pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | +| pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | +| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | file:///usr/lib/python3.8/pathlib.py:1214:14:1214:17 | ControlFlowNode for self | | test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:9:12:9:18 | ControlFlowNode for request | | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:3:26:3:32 | GSSA Variable request | | test.py:3:26:3:32 | GSSA Variable request | test.py:0:0:0:0 | ModuleVariableNode for test.request | @@ -71,6 +80,8 @@ edges | test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | | test.py:48:23:48:23 | ControlFlowNode for x | test.py:48:13:48:24 | ControlFlowNode for normalize() | nodes +| file:///usr/lib/python3.8/pathlib.py:1214:14:1214:17 | ControlFlowNode for self | semmle.label | ControlFlowNode for self | +| file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | semmle.label | ControlFlowNode for self | | flask_path_injection.py:0:0:0:0 | ModuleVariableNode for flask_path_injection.request | semmle.label | ModuleVariableNode for flask_path_injection.request | | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | flask_path_injection.py:1:26:1:32 | GSSA Variable request | semmle.label | GSSA Variable request | @@ -125,6 +136,14 @@ nodes | path_injection.py:149:16:149:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | | path_injection.py:149:16:149:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | path_injection.py:152:18:152:21 | ControlFlowNode for path | semmle.label | ControlFlowNode for path | +| pathlib_use.py:0:0:0:0 | ModuleVariableNode for pathlib_use.request | semmle.label | ModuleVariableNode for pathlib_use.request | +| pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | +| pathlib_use.py:3:26:3:32 | GSSA Variable request | semmle.label | GSSA Variable request | +| pathlib_use.py:12:16:12:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| pathlib_use.py:14:5:14:5 | ControlFlowNode for p | semmle.label | ControlFlowNode for p | +| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | semmle.label | ControlFlowNode for p2 | +| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | semmle.label | ControlFlowNode for p2 | | test.py:0:0:0:0 | ModuleVariableNode for test.request | semmle.label | ModuleVariableNode for test.request | | test.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | test.py:3:26:3:32 | GSSA Variable request | semmle.label | GSSA Variable request | @@ -150,6 +169,7 @@ subpaths | test.py:25:19:25:19 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:25:9:25:20 | ControlFlowNode for normalize() | | test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:48:13:48:24 | ControlFlowNode for normalize() | #select +| file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | path_injection.py:21:14:21:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:21:14:21:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | @@ -164,6 +184,8 @@ subpaths | path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:132:14:132:22 | ControlFlowNode for sanitized | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | path_injection.py:142:14:142:17 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:142:14:142:17 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | path_injection.py:152:18:152:21 | ControlFlowNode for path | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:152:18:152:21 | ControlFlowNode for path | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| pathlib_use.py:14:5:14:5 | ControlFlowNode for p | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | +| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | test.py:19:10:19:10 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:19:10:19:10 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | test.py:26:10:26:10 | ControlFlowNode for y | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:26:10:26:10 | ControlFlowNode for y | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | test.py:33:14:33:14 | ControlFlowNode for x | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:33:14:33:14 | ControlFlowNode for x | This path depends on a $@. | test.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py new file mode 100644 index 00000000000..4eb5909a61d --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py @@ -0,0 +1,17 @@ +import pathlib + +from flask import Flask, request +app = Flask(__name__) + + +STATIC_DIR = pathlib.Path("/server/static/") + + +@app.route("/pathlib_use") +def path_injection(): + filename = request.args.get('filename', '') + p = STATIC_DIR / filename + p.open() # NOT OK + + p2 = pathlib.Path(STATIC_DIR, filename) + p2.open() # NOT OK From 39ce50fadc775ed5b70a7f0e1876cff76576d7c8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 24 Aug 2022 14:14:41 +0200 Subject: [PATCH 060/415] Python: Fix problems with sinks in pathlib This must mean that we did not have this flow with the old call-graph, which means the new call-graph is doing a better job (yay). --- .../lib/semmle/python/frameworks/Stdlib.qll | 14 ++++++++- .../CleartextStorageCustomizations.qll | 29 ++++++++++++++++++- .../CommandInjectionCustomizations.qll | 2 ++ .../dataflow/PathInjectionCustomizations.qll | 28 +++++++++++++++++- .../frameworks/stdlib-py3/FileSystemAccess.py | 2 +- .../PathInjection.expected | 7 ----- .../CleartextStorage.expected | 7 ----- 7 files changed, 71 insertions(+), 18 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index f5d6dd8df1c..29c0e0f77b1 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -1462,7 +1462,19 @@ private module StdlibPrivate { t.start() and result = openCall and ( - openCall instanceof OpenCall + openCall instanceof OpenCall and + // don't include the open call inside of Path.open in pathlib.py since + // the call to `path_obj.open` is covered by `PathLibOpenCall`. + not exists(Module mod, Class cls, Function func | + openCall.(OpenCall).asCfgNode().getScope() = func and + func.getName() = "open" and + func.getScope() = cls and + cls.getName() = "Path" and + cls.getScope() = mod and + mod.getName() = "pathlib" and + // do allow this call if we're analyzing pathlib.py as part of CPython though + not exists(mod.getFile().getRelativePath()) + ) or openCall instanceof PathLibOpenCall ) diff --git a/python/ql/lib/semmle/python/security/dataflow/CleartextStorageCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CleartextStorageCustomizations.qll index 0ff32823d68..001b9395ef4 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CleartextStorageCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CleartextStorageCustomizations.qll @@ -50,7 +50,34 @@ module CleartextStorage { /** The data written to a file, considered as a flow sink. */ class FileWriteDataAsSink extends Sink { - FileWriteDataAsSink() { this = any(FileSystemWriteAccess write).getADataNode() } + FileWriteDataAsSink() { + this = any(FileSystemWriteAccess write).getADataNode() and + // since implementation of Path.write_bytes in pathlib.py is like + // ```py + // def write_bytes(self, data): + // with self.open(mode='wb') as f: + // return f.write(data) + // ``` + // any time we would report flow to the `Path.write_bytes` sink, we can ALSO report + // the flow from the `data` parameter to the `f.write` sink -- obviously we + // don't want that. + // + // However, simply removing taint edges out of a sink is not a good enough solution, + // since we would only flag one of the `p.write` calls in the following example + // due to use-use flow + // ```py + // p.write(user_controlled) + // p.write(user_controlled) + // ``` + // + // The same approach is used in the command injection query. + not exists(Module pathlib | + pathlib.getName() = "pathlib" and + this.getScope().getEnclosingModule() = pathlib and + // do allow this call if we're analyzing pathlib.py as part of CPython though + not exists(pathlib.getFile().getRelativePath()) + ) + } } /** The data written to a cookie on a HTTP response, considered as a flow sink. */ diff --git a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll index a18bfe73372..8d688bf357a 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll @@ -76,6 +76,8 @@ module CommandInjection { // `subprocess`. See: // https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/os.py#L974 // https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341 + // + // The same approach is used in the path-injection and cleartext-storage queries. not this.getScope().getEnclosingModule().getName() in [ "os", "subprocess", "platform", "popen2" ] diff --git a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll index a96bbb996bc..b50ff70fde2 100644 --- a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll @@ -58,7 +58,33 @@ module PathInjection { * A file system access, considered as a flow sink. */ class FileSystemAccessAsSink extends Sink { - FileSystemAccessAsSink() { this = any(FileSystemAccess e).getAPathArgument() } + FileSystemAccessAsSink() { + this = any(FileSystemAccess e).getAPathArgument() and + // since implementation of Path.open in pathlib.py is like + // ```py + // def open(self, ...): + // return io.open(self, ...) + // ``` + // any time we would report flow to the `path_obj.open` sink, we can ALSO report + // the flow from the `self` parameter to the `io.open` sink -- obviously we + // don't want that. + // + // However, simply removing taint edges out of a sink is not a good enough solution, + // since we would only flag one of the `p.open` calls in the following example + // due to use-use flow + // ```py + // p.open() + // p.open() + // ``` + // + // The same approach is used in the command injection query. + not exists(Module pathlib | + pathlib.getName() = "pathlib" and + this.getScope().getEnclosingModule() = pathlib and + // do allow this call if we're analyzing pathlib.py as part of CPython though + not exists(pathlib.getFile().getRelativePath()) + ) + } } private import semmle.python.frameworks.data.ModelsAsData diff --git a/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py b/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py index 0da230d66fc..4de7f3a3c32 100644 --- a/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py +++ b/python/ql/test/library-tests/frameworks/stdlib-py3/FileSystemAccess.py @@ -13,7 +13,7 @@ with p.open() as f: # $ getAPathArgument=p p.write_bytes(b"hello") # $ getAPathArgument=p fileWriteData=b"hello" p.write_text("hello") # $ getAPathArgument=p fileWriteData="hello" -p.open("wt").write("hello") # $ getAPathArgument=p fileWriteData="hello" SPURIOUS: getAPathArgument=self +p.open("wt").write("hello") # $ getAPathArgument=p fileWriteData="hello" name = windows.parent.name o = open diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected index 231b111f44b..a824d44adfa 100644 --- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected @@ -1,5 +1,4 @@ edges -| file:///usr/lib/python3.8/pathlib.py:1214:14:1214:17 | ControlFlowNode for self | file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | | flask_path_injection.py:0:0:0:0 | ModuleVariableNode for flask_path_injection.request | flask_path_injection.py:19:15:19:21 | ControlFlowNode for request | | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:1:26:1:32 | GSSA Variable request | | flask_path_injection.py:1:26:1:32 | GSSA Variable request | flask_path_injection.py:0:0:0:0 | ModuleVariableNode for flask_path_injection.request | @@ -56,8 +55,6 @@ edges | pathlib_use.py:12:16:12:22 | ControlFlowNode for request | pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | | pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | | pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | -| pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | -| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | file:///usr/lib/python3.8/pathlib.py:1214:14:1214:17 | ControlFlowNode for self | | test.py:0:0:0:0 | ModuleVariableNode for test.request | test.py:9:12:9:18 | ControlFlowNode for request | | test.py:3:26:3:32 | ControlFlowNode for ImportMember | test.py:3:26:3:32 | GSSA Variable request | | test.py:3:26:3:32 | GSSA Variable request | test.py:0:0:0:0 | ModuleVariableNode for test.request | @@ -80,8 +77,6 @@ edges | test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | | test.py:48:23:48:23 | ControlFlowNode for x | test.py:48:13:48:24 | ControlFlowNode for normalize() | nodes -| file:///usr/lib/python3.8/pathlib.py:1214:14:1214:17 | ControlFlowNode for self | semmle.label | ControlFlowNode for self | -| file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | semmle.label | ControlFlowNode for self | | flask_path_injection.py:0:0:0:0 | ModuleVariableNode for flask_path_injection.request | semmle.label | ModuleVariableNode for flask_path_injection.request | | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | flask_path_injection.py:1:26:1:32 | GSSA Variable request | semmle.label | GSSA Variable request | @@ -143,7 +138,6 @@ nodes | pathlib_use.py:12:16:12:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | pathlib_use.py:14:5:14:5 | ControlFlowNode for p | semmle.label | ControlFlowNode for p | | pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | semmle.label | ControlFlowNode for p2 | -| pathlib_use.py:17:5:17:6 | ControlFlowNode for p2 | semmle.label | ControlFlowNode for p2 | | test.py:0:0:0:0 | ModuleVariableNode for test.request | semmle.label | ModuleVariableNode for test.request | | test.py:3:26:3:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | | test.py:3:26:3:32 | GSSA Variable request | semmle.label | GSSA Variable request | @@ -169,7 +163,6 @@ subpaths | test.py:25:19:25:19 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:25:9:25:20 | ControlFlowNode for normalize() | | test.py:48:23:48:23 | ControlFlowNode for x | test.py:12:15:12:15 | ControlFlowNode for x | test.py:13:12:13:30 | ControlFlowNode for Attribute() | test.py:48:13:48:24 | ControlFlowNode for normalize() | #select -| file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | file:///usr/lib/python3.8/pathlib.py:1222:24:1222:27 | ControlFlowNode for self | This path depends on a $@. | pathlib_use.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | flask_path_injection.py:21:32:21:38 | ControlFlowNode for dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value | | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:13:14:13:47 | ControlFlowNode for Attribute() | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | | path_injection.py:21:14:21:18 | ControlFlowNode for npath | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | path_injection.py:21:14:21:18 | ControlFlowNode for npath | This path depends on a $@. | path_injection.py:3:26:3:32 | ControlFlowNode for ImportMember | user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected index b27e24e30d7..f2b0894ec0a 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextStorage-py3/CleartextStorage.expected @@ -1,21 +1,14 @@ edges -| file:///usr/lib/python3.8/pathlib.py:1248:26:1248:29 | ControlFlowNode for data | file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | -| test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:12:21:12:24 | ControlFlowNode for cert | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:12:21:12:24 | ControlFlowNode for cert | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:13:22:13:41 | ControlFlowNode for Attribute() | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:15:26:15:29 | ControlFlowNode for cert | -| test.py:12:21:12:24 | ControlFlowNode for cert | file:///usr/lib/python3.8/pathlib.py:1248:26:1248:29 | ControlFlowNode for data | nodes -| file:///usr/lib/python3.8/pathlib.py:1248:26:1248:29 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | -| file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | semmle.label | ControlFlowNode for data | | test.py:9:12:9:21 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() | | test.py:12:21:12:24 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert | -| test.py:12:21:12:24 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert | | test.py:13:22:13:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:15:26:15:29 | ControlFlowNode for cert | semmle.label | ControlFlowNode for cert | subpaths #select -| file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | test.py:9:12:9:21 | ControlFlowNode for get_cert() | file:///usr/lib/python3.8/pathlib.py:1256:28:1256:31 | ControlFlowNode for data | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:12:21:12:24 | ControlFlowNode for cert | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:12:21:12:24 | ControlFlowNode for cert | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:13:22:13:41 | ControlFlowNode for Attribute() | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:13:22:13:41 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:15:26:15:29 | ControlFlowNode for cert | test.py:9:12:9:21 | ControlFlowNode for get_cert() | test.py:15:26:15:29 | ControlFlowNode for cert | This expression stores $@ as clear text. | test.py:9:12:9:21 | ControlFlowNode for get_cert() | sensitive data (certificate) | From 0a41d8d2c1a8affa740c4298e018998e538859e9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 1 Nov 2022 16:22:12 +0100 Subject: [PATCH 061/415] Python: Accept bad `CleartextLogging.expected` --- .../CleartextLogging.expected | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected index e9b5ac67585..2d6dafde6ab 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected @@ -1,18 +1,111 @@ edges +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:23 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:23 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:26 | ControlFlowNode for Subscript | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:26 | ControlFlowNode for Subscript | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:21:311:24 | ControlFlowNode for args | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:21:311:24 | ControlFlowNode for args | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:9:311:12 | [post] ControlFlowNode for self [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:939:22:939:27 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1178:20:1178:25 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:989:27:989:32 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:64 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1022:59:1023:69 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:64 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:69 | ControlFlowNode for Attribute | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:69 | ControlFlowNode for Attribute | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1022:59:1023:69 | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1091:30:1091:35 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1091:30:1091:35 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:989:27:989:32 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1178:20:1178:25 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1187:34:1187:39 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1187:34:1187:39 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1424:27:1424:30 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1434:35:1434:38 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1434:35:1434:38 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1446:34:1446:37 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1446:34:1446:37 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1497:32:1497:35 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1512:35:1512:38 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1512:35:1512:38 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1563:16:1563:17 | ControlFlowNode for rv [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1589:21:1589:26 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1589:21:1589:26 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1591:22:1591:27 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1591:22:1591:27 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1599:31:1599:36 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1599:31:1599:36 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1645:28:1645:33 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1645:28:1645:33 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1669:39:1669:44 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1669:39:1669:44 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:939:22:939:27 | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2089:16:2089:19 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2097:21:2097:24 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2097:21:2097:24 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2099:17:2099:20 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2107:22:2107:25 | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2107:22:2107:25 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1424:27:1424:30 | ControlFlowNode for args [List element] | +| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | +| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | +| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | +| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | +| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | +| test.py:20:48:20:55 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2089:16:2089:19 | ControlFlowNode for args [List element] | +| test.py:22:58:22:65 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1497:32:1497:35 | ControlFlowNode for args [List element] | +| test.py:23:58:23:65 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | +| test.py:27:40:27:47 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | +| test.py:30:58:30:65 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | +| test.py:34:30:34:39 | ControlFlowNode for get_cert() | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2099:17:2099:20 | ControlFlowNode for args [List element] | | test.py:65:14:68:5 | ControlFlowNode for Dict | test.py:69:11:69:31 | ControlFlowNode for Subscript | | test.py:67:21:67:37 | ControlFlowNode for Attribute | test.py:65:14:68:5 | ControlFlowNode for Dict | nodes +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:23 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:26 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:9:311:12 | [post] ControlFlowNode for self [Attribute args] | semmle.label | [post] ControlFlowNode for self [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:21:311:24 | ControlFlowNode for args | semmle.label | ControlFlowNode for args | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:939:22:939:27 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:989:27:989:32 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1022:59:1023:69 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:64 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:69 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1091:30:1091:35 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1178:20:1178:25 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1187:34:1187:39 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1424:27:1424:30 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1434:35:1434:38 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1446:34:1446:37 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1497:32:1497:35 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1512:35:1512:38 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | semmle.label | ControlFlowNode for _logRecordFactory() [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1563:16:1563:17 | ControlFlowNode for rv [Attribute args] | semmle.label | ControlFlowNode for rv [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | semmle.label | ControlFlowNode for Attribute() [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1589:21:1589:26 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1591:22:1591:27 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1599:31:1599:36 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1645:28:1645:33 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1669:39:1669:44 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2089:16:2089:19 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2097:21:2097:24 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2099:17:2099:20 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2107:22:2107:25 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | | test.py:19:16:19:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | | test.py:20:48:20:55 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| test.py:20:48:20:55 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| test.py:22:58:22:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:22:58:22:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:23:58:23:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| test.py:23:58:23:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| test.py:27:40:27:47 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:27:40:27:47 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:30:58:30:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| test.py:30:58:30:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | +| test.py:34:30:34:39 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() | | test.py:34:30:34:39 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() | | test.py:37:11:37:24 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | | test.py:39:22:39:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | @@ -21,7 +114,11 @@ nodes | test.py:67:21:67:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:69:11:69:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | subpaths +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:9:311:12 | [post] ControlFlowNode for self [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1563:16:1563:17 | ControlFlowNode for rv [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | #select +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | test.py:19:16:19:29 | ControlFlowNode for get_password() | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | +| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | test.py:34:30:34:39 | ControlFlowNode for get_cert() | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | This expression logs $@ as clear text. | test.py:34:30:34:39 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | | test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | | test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | From a301c93ebff6114083b386ddf113fc637d3dc7ea Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 1 Nov 2022 16:36:31 +0100 Subject: [PATCH 062/415] Python: Fix results outside DB for `CleartextLogging` --- .../CleartextLoggingCustomizations.qll | 47 +++++++-- .../CommandInjectionCustomizations.qll | 3 +- .../CleartextLogging.expected | 97 ------------------- 3 files changed, 39 insertions(+), 108 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/CleartextLoggingCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CleartextLoggingCustomizations.qll index fcf8885f3f4..ae61bd04314 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CleartextLoggingCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CleartextLoggingCustomizations.qll @@ -57,16 +57,43 @@ module CleartextLogging { /** A piece of data printed, considered as a flow sink. */ class PrintedDataAsSink extends Sink { PrintedDataAsSink() { - this = API::builtin("print").getACall().getArg(_) - or - // special handling of writing to `sys.stdout` and `sys.stderr`, which is - // essentially the same as printing - this = - API::moduleImport("sys") - .getMember(["stdout", "stderr"]) - .getMember("write") - .getACall() - .getArg(0) + ( + this = API::builtin("print").getACall().getArg(_) + or + // special handling of writing to `sys.stdout` and `sys.stderr`, which is + // essentially the same as printing + this = + API::moduleImport("sys") + .getMember(["stdout", "stderr"]) + .getMember("write") + .getACall() + .getArg(0) + ) and + // since some of the inner error handling implementation of the logging module is + // ```py + // sys.stderr.write('Message: %r\n' + // 'Arguments: %s\n' % (record.msg, + // record.args)) + // ``` + // any time we would report flow to such a logging sink, we can ALSO report + // the flow to the `record.msg`/`record.args` sinks -- obviously we + // don't want that. + // + // However, simply removing taint edges out of a sink is not a good enough solution, + // since we would only flag one of the `logging.info` calls in the following example + // due to use-use flow + // ```py + // logging.info(user_controlled) + // logging.info(user_controlled) + // ``` + // + // The same approach is used in the command injection query. + not exists(Module loggingInit | + loggingInit.getName() = "logging.__init__" and + this.getScope().getEnclosingModule() = loggingInit and + // do allow this call if we're analyzing logging/__init__.py as part of CPython though + not exists(loggingInit.getFile().getRelativePath()) + ) } } } diff --git a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll index 8d688bf357a..d43095a04f8 100644 --- a/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll @@ -77,7 +77,8 @@ module CommandInjection { // https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/os.py#L974 // https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341 // - // The same approach is used in the path-injection and cleartext-storage queries. + // The same approach is used in the path-injection, cleartext-storage, and + // cleartext-logging queries. not this.getScope().getEnclosingModule().getName() in [ "os", "subprocess", "platform", "popen2" ] diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected index 2d6dafde6ab..e9b5ac67585 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected @@ -1,111 +1,18 @@ edges -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:23 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:23 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:26 | ControlFlowNode for Subscript | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:26 | ControlFlowNode for Subscript | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:21:311:24 | ControlFlowNode for args | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:21:311:24 | ControlFlowNode for args | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:9:311:12 | [post] ControlFlowNode for self [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:939:22:939:27 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1178:20:1178:25 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:989:27:989:32 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:64 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1022:59:1023:69 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:64 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:69 | ControlFlowNode for Attribute | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:69 | ControlFlowNode for Attribute | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1022:59:1023:69 | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1091:30:1091:35 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1091:30:1091:35 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:989:27:989:32 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1178:20:1178:25 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1187:34:1187:39 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1187:34:1187:39 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1424:27:1424:30 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1434:35:1434:38 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1434:35:1434:38 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1446:34:1446:37 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1446:34:1446:37 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1497:32:1497:35 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1512:35:1512:38 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1512:35:1512:38 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1563:16:1563:17 | ControlFlowNode for rv [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1589:21:1589:26 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1589:21:1589:26 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1591:22:1591:27 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1591:22:1591:27 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1599:31:1599:36 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1599:31:1599:36 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1645:28:1645:33 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1645:28:1645:33 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1669:39:1669:44 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1669:39:1669:44 | ControlFlowNode for record [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:939:22:939:27 | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2089:16:2089:19 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2097:21:2097:24 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2097:21:2097:24 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2099:17:2099:20 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2107:22:2107:25 | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2107:22:2107:25 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1424:27:1424:30 | ControlFlowNode for args [List element] | -| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | -| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | -| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | -| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | -| test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | -| test.py:20:48:20:55 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2089:16:2089:19 | ControlFlowNode for args [List element] | -| test.py:22:58:22:65 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1497:32:1497:35 | ControlFlowNode for args [List element] | -| test.py:23:58:23:65 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | -| test.py:27:40:27:47 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | -| test.py:30:58:30:65 | ControlFlowNode for password | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | -| test.py:34:30:34:39 | ControlFlowNode for get_cert() | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2099:17:2099:20 | ControlFlowNode for args [List element] | | test.py:65:14:68:5 | ControlFlowNode for Dict | test.py:69:11:69:31 | ControlFlowNode for Subscript | | test.py:67:21:67:37 | ControlFlowNode for Attribute | test.py:65:14:68:5 | ControlFlowNode for Dict | nodes -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:23 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:310:20:310:26 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:9:311:12 | [post] ControlFlowNode for self [Attribute args] | semmle.label | [post] ControlFlowNode for self [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:21:311:24 | ControlFlowNode for args | semmle.label | ControlFlowNode for args | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:939:22:939:27 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:952:27:952:32 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:989:27:989:32 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1022:59:1023:69 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:64 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1023:59:1023:69 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1071:20:1071:25 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1091:30:1091:35 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1178:20:1178:25 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1187:34:1187:39 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1424:27:1424:30 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1434:35:1434:38 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1436:26:1436:29 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1446:34:1446:37 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1497:32:1497:35 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1512:35:1512:38 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | semmle.label | ControlFlowNode for _logRecordFactory() [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1563:16:1563:17 | ControlFlowNode for rv [Attribute args] | semmle.label | ControlFlowNode for rv [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1565:32:1565:35 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | semmle.label | ControlFlowNode for Attribute() [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1589:21:1589:26 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1591:22:1591:27 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1599:31:1599:36 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1645:28:1645:33 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1669:39:1669:44 | ControlFlowNode for record [Attribute args] | semmle.label | ControlFlowNode for record [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2089:16:2089:19 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2097:21:2097:24 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2099:17:2099:20 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:2107:22:2107:25 | ControlFlowNode for args [List element] | semmle.label | ControlFlowNode for args [List element] | | test.py:19:16:19:29 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | | test.py:20:48:20:55 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:20:48:20:55 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:22:58:22:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:22:58:22:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:23:58:23:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:23:58:23:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:27:40:27:47 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:27:40:27:47 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | | test.py:30:58:30:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:30:58:30:65 | ControlFlowNode for password | semmle.label | ControlFlowNode for password | -| test.py:34:30:34:39 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() | | test.py:34:30:34:39 | ControlFlowNode for get_cert() | semmle.label | ControlFlowNode for get_cert() | | test.py:37:11:37:24 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | | test.py:39:22:39:35 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() | @@ -114,11 +21,7 @@ nodes | test.py:67:21:67:37 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:69:11:69:31 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | subpaths -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:59:1556:62 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:283:23:283:26 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:311:9:311:12 | [post] ControlFlowNode for self [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1556:14:1557:35 | ControlFlowNode for _logRecordFactory() [Attribute args] | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:66:1587:69 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1550:53:1550:56 | ControlFlowNode for args [List element] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1563:16:1563:17 | ControlFlowNode for rv [Attribute args] | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1587:18:1588:62 | ControlFlowNode for Attribute() [Attribute args] | #select -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | test.py:19:16:19:29 | ControlFlowNode for get_password() | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | -| file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | test.py:34:30:34:39 | ControlFlowNode for get_cert() | file:///home/rasmus/.pyenv/versions/3.9.5/lib/python3.9/logging/__init__.py:1021:38:1023:70 | ControlFlowNode for BinaryExpr | This expression logs $@ as clear text. | test.py:34:30:34:39 | ControlFlowNode for get_cert() | sensitive data (certificate) | | test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | | test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | | test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) | From 972cfa5cf6480005b58da576edb2cfc47c6d3330 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 2 Nov 2022 09:49:32 +0100 Subject: [PATCH 063/415] Python: Accept bad `StackTraceExposure.expected` This is only Python 2 though --- .../StackTraceExposure.expected | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected index 07b208caaac..23ba9142daa 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected @@ -1,4 +1,56 @@ edges +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:16:178:53 | ControlFlowNode for List | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:201:12:201:16 | ControlFlowNode for lines | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:214:16:214:25 | ControlFlowNode for str() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:219:16:219:56 | ControlFlowNode for Attribute() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 0] | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 1] | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 0] | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 1] | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | test.py:49:15:49:36 | ControlFlowNode for Attribute() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | | test.py:23:25:23:25 | SSA variable e | test.py:24:16:24:16 | ControlFlowNode for e | | test.py:31:25:31:25 | SSA variable e | test.py:32:16:32:30 | ControlFlowNode for Attribute | | test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:50:29:50:31 | ControlFlowNode for err | @@ -7,6 +59,50 @@ edges | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | | test.py:65:25:65:25 | SSA variable e | test.py:66:24:66:40 | ControlFlowNode for Dict | nodes +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | semmle.label | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | semmle.label | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | semmle.label | ControlFlowNode for list | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | semmle.label | ControlFlowNode for list | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:16:178:53 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:201:12:201:16 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | semmle.label | ControlFlowNode for _some_str() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | semmle.label | ControlFlowNode for line | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | semmle.label | ControlFlowNode for line | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:214:16:214:25 | ControlFlowNode for str() | semmle.label | ControlFlowNode for str() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:219:16:219:56 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | semmle.label | SSA variable etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | semmle.label | IterableElement | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | semmle.label | SSA variable value | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | semmle.label | ControlFlowNode for format_exception() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | | test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:23:25:23:25 | SSA variable e | semmle.label | SSA variable e | | test.py:24:16:24:16 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | @@ -20,10 +116,24 @@ nodes | test.py:65:25:65:25 | SSA variable e | semmle.label | SSA variable e | | test.py:66:24:66:40 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | subpaths +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:16:178:53 | ControlFlowNode for List | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:201:12:201:16 | ControlFlowNode for lines | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:214:16:214:25 | ControlFlowNode for str() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:219:16:219:56 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | +| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | | test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() | #select +| test.py:16:16:16:37 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | $@ flows to this location and may be exposed to an external user. | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | Stack trace information | | test.py:16:16:16:37 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | $@ flows to this location and may be exposed to an external user. | test.py:16:16:16:37 | ControlFlowNode for Attribute() | Stack trace information | | test.py:24:16:24:16 | ControlFlowNode for e | test.py:23:25:23:25 | SSA variable e | test.py:24:16:24:16 | ControlFlowNode for e | $@ flows to this location and may be exposed to an external user. | test.py:23:25:23:25 | SSA variable e | Stack trace information | | test.py:32:16:32:30 | ControlFlowNode for Attribute | test.py:31:25:31:25 | SSA variable e | test.py:32:16:32:30 | ControlFlowNode for Attribute | $@ flows to this location and may be exposed to an external user. | test.py:31:25:31:25 | SSA variable e | Stack trace information | +| test.py:50:16:50:32 | ControlFlowNode for format_error() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | test.py:50:16:50:32 | ControlFlowNode for format_error() | $@ flows to this location and may be exposed to an external user. | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | Stack trace information | | test.py:50:16:50:32 | ControlFlowNode for format_error() | test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:50:16:50:32 | ControlFlowNode for format_error() | $@ flows to this location and may be exposed to an external user. | test.py:49:15:49:36 | ControlFlowNode for Attribute() | Stack trace information | | test.py:66:24:66:40 | ControlFlowNode for Dict | test.py:65:25:65:25 | SSA variable e | test.py:66:24:66:40 | ControlFlowNode for Dict | $@ flows to this location and may be exposed to an external user. | test.py:65:25:65:25 | SSA variable e | Stack trace information | From 6646e98d20971983dd507063d70038bfca9ccb78 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 2 Nov 2022 09:55:59 +0100 Subject: [PATCH 064/415] Python: Fix results outside DB for `StackTraceExposure` --- .../StackTraceExposureCustomizations.qll | 26 ++++- .../StackTraceExposure.expected | 110 ------------------ 2 files changed, 25 insertions(+), 111 deletions(-) diff --git a/python/ql/lib/semmle/python/security/dataflow/StackTraceExposureCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/StackTraceExposureCustomizations.qll index 09f84327a63..6d0b9dc5c77 100644 --- a/python/ql/lib/semmle/python/security/dataflow/StackTraceExposureCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/StackTraceExposureCustomizations.qll @@ -42,7 +42,31 @@ module StackTraceExposure { * A source of exception info, considered as a flow source. */ class ExceptionInfoAsSource extends Source { - ExceptionInfoAsSource() { this instanceof ExceptionInfo } + ExceptionInfoAsSource() { + this instanceof ExceptionInfo and + // since `traceback.format_exc()` in Python 2 is internally implemented as + // ```py + // def format_exc(limit=None): + // """Like print_exc() but return a string.""" + // try: + // etype, value, tb = sys.exc_info() + // return ''.join(format_exception(etype, value, tb, limit)) + // finally: + // etype = value = tb = None + // ``` + // any time we would report flow to such from a call to format_exc, we can ALSO report + // the flow from the `sys.exc_info()` source -- obviously we don't want that. + // + // + // To avoid this, we use the same approach as for sinks in the command injection + // query (and others). + not exists(Module traceback | + traceback.getName() = "traceback" and + this.getScope().getEnclosingModule() = traceback and + // do allow this call if we're analyzing traceback.py as part of CPython though + not exists(traceback.getFile().getRelativePath()) + ) + } } /** diff --git a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected index 23ba9142daa..07b208caaac 100644 --- a/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected +++ b/python/ql/test/query-tests/Security/CWE-209-StackTraceExposure/StackTraceExposure.expected @@ -1,56 +1,4 @@ edges -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:16:178:53 | ControlFlowNode for List | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:201:12:201:16 | ControlFlowNode for lines | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:214:16:214:25 | ControlFlowNode for str() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:219:16:219:56 | ControlFlowNode for Attribute() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 0] | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 1] | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 0] | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 1] | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | test.py:49:15:49:36 | ControlFlowNode for Attribute() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | | test.py:23:25:23:25 | SSA variable e | test.py:24:16:24:16 | ControlFlowNode for e | | test.py:31:25:31:25 | SSA variable e | test.py:32:16:32:30 | ControlFlowNode for Attribute | | test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:50:29:50:31 | ControlFlowNode for err | @@ -59,50 +7,6 @@ edges | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | | test.py:65:25:65:25 | SSA variable e | test.py:66:24:66:40 | ControlFlowNode for Dict | nodes -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | semmle.label | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | semmle.label | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | semmle.label | ControlFlowNode for list | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | semmle.label | ControlFlowNode for list | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:16:178:53 | ControlFlowNode for List | semmle.label | ControlFlowNode for List | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | semmle.label | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:201:12:201:16 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | semmle.label | ControlFlowNode for _some_str() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:209:30:209:44 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | semmle.label | ControlFlowNode for line | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | semmle.label | ControlFlowNode for line | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:214:16:214:25 | ControlFlowNode for str() | semmle.label | ControlFlowNode for str() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:219:16:219:56 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:13 | SSA variable etype | semmle.label | SSA variable etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:9:241:24 | IterableElement | semmle.label | IterableElement | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:16:241:20 | SSA variable value | semmle.label | SSA variable value | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:16:242:65 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | semmle.label | ControlFlowNode for format_exception() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | semmle.label | ControlFlowNode for etype | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | semmle.label | ControlFlowNode for value | | test.py:16:16:16:37 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | test.py:23:25:23:25 | SSA variable e | semmle.label | SSA variable e | | test.py:24:16:24:16 | ControlFlowNode for e | semmle.label | ControlFlowNode for e | @@ -116,24 +20,10 @@ nodes | test.py:65:25:65:25 | SSA variable e | semmle.label | SSA variable e | | test.py:66:24:66:40 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict | subpaths -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:41:144:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:27:147:31 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:16:173:53 | ControlFlowNode for List | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:16:178:53 | ControlFlowNode for List | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:48:144:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:147:34:147:38 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:201:12:201:16 | ControlFlowNode for lines | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:144:19:144:53 | ControlFlowNode for format_exception_only() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:40:173:44 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:28:203:32 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:47:173:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:173:17:173:52 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:47:178:51 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:178:17:178:52 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:48:200:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:203:35:203:39 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:210:12:210:15 | ControlFlowNode for line | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:200:18:200:53 | ControlFlowNode for _format_final_exc_line() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:214:16:214:25 | ControlFlowNode for str() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:26:205:30 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:212:15:212:19 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:219:16:219:56 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:205:16:205:31 | ControlFlowNode for _some_str() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:41:242:45 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:22:130:26 | ControlFlowNode for etype | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | -| file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:48:242:52 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:130:29:130:33 | ControlFlowNode for value | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:145:12:145:15 | ControlFlowNode for list | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:242:24:242:64 | ControlFlowNode for format_exception() | | test.py:50:29:50:31 | ControlFlowNode for err | test.py:52:18:52:20 | ControlFlowNode for msg | test.py:53:12:53:27 | ControlFlowNode for BinaryExpr | test.py:50:16:50:32 | ControlFlowNode for format_error() | #select -| test.py:16:16:16:37 | ControlFlowNode for Attribute() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | $@ flows to this location and may be exposed to an external user. | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | Stack trace information | | test.py:16:16:16:37 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | test.py:16:16:16:37 | ControlFlowNode for Attribute() | $@ flows to this location and may be exposed to an external user. | test.py:16:16:16:37 | ControlFlowNode for Attribute() | Stack trace information | | test.py:24:16:24:16 | ControlFlowNode for e | test.py:23:25:23:25 | SSA variable e | test.py:24:16:24:16 | ControlFlowNode for e | $@ flows to this location and may be exposed to an external user. | test.py:23:25:23:25 | SSA variable e | Stack trace information | | test.py:32:16:32:30 | ControlFlowNode for Attribute | test.py:31:25:31:25 | SSA variable e | test.py:32:16:32:30 | ControlFlowNode for Attribute | $@ flows to this location and may be exposed to an external user. | test.py:31:25:31:25 | SSA variable e | Stack trace information | -| test.py:50:16:50:32 | ControlFlowNode for format_error() | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | test.py:50:16:50:32 | ControlFlowNode for format_error() | $@ flows to this location and may be exposed to an external user. | file:///home/rasmus/.pyenv/versions/2.7.18/lib/python2.7/traceback.py:241:28:241:41 | ControlFlowNode for Attribute() | Stack trace information | | test.py:50:16:50:32 | ControlFlowNode for format_error() | test.py:49:15:49:36 | ControlFlowNode for Attribute() | test.py:50:16:50:32 | ControlFlowNode for format_error() | $@ flows to this location and may be exposed to an external user. | test.py:49:15:49:36 | ControlFlowNode for Attribute() | Stack trace information | | test.py:66:24:66:40 | ControlFlowNode for Dict | test.py:65:25:65:25 | SSA variable e | test.py:66:24:66:40 | ControlFlowNode for Dict | $@ flows to this location and may be exposed to an external user. | test.py:65:25:65:25 | SSA variable e | Stack trace information | From bd46b7deaa0c9715b07f1b116a2f0980d14cdd6e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 23 Sep 2022 16:27:23 +0200 Subject: [PATCH 065/415] Python: Cache a few call-graph predicates We DON'T want to recompute these ones for sure! --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 55c4b0ae240..26764e96670 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1039,6 +1039,7 @@ predicate resolveClassInstanceCall(CallNode call, Function target, Node self) { /** * Holds if `call` is a call to the `target`, with call-type `type`. */ +cached predicate resolveCall(ControlFlowNode call, Function target, CallType type) { type instanceof CallTypePlainFunction and call.(CallNode).getFunction() = functionTracker(target).asCfgNode() and @@ -1114,6 +1115,7 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { * Note: If `Bar.meth` and `Foo.meth` resolves to the same function, we will end up * sending both `self` arguments to that function, which is by definition the right thing to do. */ +cached predicate getCallArg( ControlFlowNode call, Function target, CallType type, Node arg, ArgumentPosition apos ) { From fc0545561e3c6a1de824bea3b5cb063ea296786c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 17 Oct 2022 10:52:44 +0200 Subject: [PATCH 066/415] Python: Introduce points-to cached stage With points-to not being used for the call-graph any longer, it's time to split them. --- python/ql/lib/semmle/python/Flow.qll | 2 +- .../semmle/python/internal/CachedStages.qll | 60 +++++++++++++------ .../semmle/python/objects/ObjectInternal.qll | 2 +- python/ql/lib/semmle/python/pointsto/Base.qll | 2 +- .../lib/semmle/python/pointsto/PointsTo.qll | 2 +- python/ql/lib/semmle/python/types/Object.qll | 6 +- 6 files changed, 49 insertions(+), 25 deletions(-) diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index bd491d527cc..a26a7ac7d8a 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -125,7 +125,7 @@ class ControlFlowNode extends @py_flow_node { /** Gets a textual representation of this element. */ cached string toString() { - Stages::DataFlow::ref() and + Stages::PointsTo::ref() and exists(Scope s | s.getEntryNode() = this | result = "Entry node for " + s.toString()) or exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) diff --git a/python/ql/lib/semmle/python/internal/CachedStages.qll b/python/ql/lib/semmle/python/internal/CachedStages.qll index 290a90f5a73..8b5701b3115 100644 --- a/python/ql/lib/semmle/python/internal/CachedStages.qll +++ b/python/ql/lib/semmle/python/internal/CachedStages.qll @@ -125,6 +125,48 @@ module Stages { } } + /** + * The points-to stage. + */ + cached + module PointsTo { + /** + * Always holds. + * Ensures that a predicate is evaluated as part of the points-to stage. + */ + cached + predicate ref() { 1 = 1 } + + private import semmle.python.pointsto.Base as PointsToBase + private import semmle.python.types.Object as TypeObject + private import semmle.python.objects.TObject as TObject + private import semmle.python.Flow as Flow + private import semmle.python.objects.ObjectInternal as ObjectInternal + // have to alias since this module is also called PointsTo + private import semmle.python.pointsto.PointsTo as RealPointsTo + + /** + * DONT USE! + * Contains references to each predicate that use the above `ref` predicate. + */ + cached + predicate backref() { + 1 = 1 + or + PointsToBase::BaseFlow::scope_entry_value_transfer_from_earlier(_, _, _, _) + or + exists(TypeObject::Object a) + or + exists(TObject::TObject f) + or + exists(any(Flow::ControlFlowNode c).toString()) + or + exists(any(ObjectInternal::ObjectInternal o).toString()) + or + RealPointsTo::AttributePointsTo::variableAttributePointsTo(_, _, _, _, _) + } + } + /** * The `dataflow` stage. */ @@ -140,12 +182,6 @@ module Stages { private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic private import semmle.python.dataflow.new.internal.LocalSources as LocalSources private import semmle.python.internal.Awaited as Awaited - private import semmle.python.pointsto.Base as PointsToBase - private import semmle.python.types.Object as TypeObject - private import semmle.python.objects.TObject as TObject - private import semmle.python.Flow as Flow - private import semmle.python.objects.ObjectInternal as ObjectInternal - private import semmle.python.pointsto.PointsTo as PointsTo /** * DONT USE! @@ -162,18 +198,6 @@ module Stages { any(LocalSources::LocalSourceNode n).flowsTo(_) or exists(Awaited::awaited(_)) - or - PointsToBase::BaseFlow::scope_entry_value_transfer_from_earlier(_, _, _, _) - or - exists(TypeObject::Object a) - or - exists(TObject::TObject f) - or - exists(any(Flow::ControlFlowNode c).toString()) - or - exists(any(ObjectInternal::ObjectInternal o).toString()) - or - PointsTo::AttributePointsTo::variableAttributePointsTo(_, _, _, _, _) } } } diff --git a/python/ql/lib/semmle/python/objects/ObjectInternal.qll b/python/ql/lib/semmle/python/objects/ObjectInternal.qll index b6725e87cb6..a58b8b5f0a9 100644 --- a/python/ql/lib/semmle/python/objects/ObjectInternal.qll +++ b/python/ql/lib/semmle/python/objects/ObjectInternal.qll @@ -216,7 +216,7 @@ class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject { override Builtin getBuiltin() { this = TBuiltinOpaqueObject(result) } override string toString() { - Stages::DataFlow::ref() and + Stages::PointsTo::ref() and result = this.getBuiltin().getClass().getName() + " object" } diff --git a/python/ql/lib/semmle/python/pointsto/Base.qll b/python/ql/lib/semmle/python/pointsto/Base.qll index a3407419da2..96437cfed7e 100644 --- a/python/ql/lib/semmle/python/pointsto/Base.qll +++ b/python/ql/lib/semmle/python/pointsto/Base.qll @@ -318,7 +318,7 @@ module BaseFlow { predicate scope_entry_value_transfer_from_earlier( EssaVariable pred_var, Scope pred_scope, ScopeEntryDefinition succ_def, Scope succ_scope ) { - Stages::DataFlow::ref() and + Stages::PointsTo::ref() and exists(SsaSourceVariable var | essa_var_scope(var, pred_scope, pred_var) and scope_entry_def_scope(var, succ_scope, succ_def) diff --git a/python/ql/lib/semmle/python/pointsto/PointsTo.qll b/python/ql/lib/semmle/python/pointsto/PointsTo.qll index a5732e3bbd4..f4118100841 100644 --- a/python/ql/lib/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/lib/semmle/python/pointsto/PointsTo.qll @@ -2569,7 +2569,7 @@ module AttributePointsTo { predicate variableAttributePointsTo( EssaVariable var, Context context, string name, ObjectInternal value, CfgOrigin origin ) { - Stages::DataFlow::ref() and + Stages::PointsTo::ref() and definitionAttributePointsTo(var.getDefinition(), context, name, value, origin) or exists(EssaVariable prev | diff --git a/python/ql/lib/semmle/python/types/Object.qll b/python/ql/lib/semmle/python/types/Object.qll index e0d252929f9..b408fc7ba1c 100644 --- a/python/ql/lib/semmle/python/types/Object.qll +++ b/python/ql/lib/semmle/python/types/Object.qll @@ -5,7 +5,7 @@ private import semmle.python.internal.CachedStages cached private predicate is_an_object(@py_object obj) { - Stages::DataFlow::ref() and + Stages::PointsTo::ref() and /* CFG nodes for numeric literals, all of which have a @py_cobject for the value of that literal */ obj instanceof ControlFlowNode and not obj.(ControlFlowNode).getNode() instanceof IntegerLiteral and @@ -78,7 +78,7 @@ class Object extends @py_object { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - Stages::DataFlow::ref() and + Stages::PointsTo::ref() and this.hasOrigin() and this.getOrigin() .getLocation() @@ -98,7 +98,7 @@ class Object extends @py_object { /** Gets a textual representation of this element. */ cached string toString() { - Stages::DataFlow::ref() and + Stages::PointsTo::ref() and not this = undefinedVariable() and not this = unknownValue() and exists(ClassObject type | type.asBuiltin() = this.asBuiltin().getClass() | From 36e8b8bfb9af1bb82083e312b76be09cd63d6a3f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 20 Oct 2022 21:19:12 +0200 Subject: [PATCH 067/415] Python: Add call-graph to cached dataflow stage I didn't do any performance investigation on this, since it just seems so much like the right approach. --- .../new/internal/DataFlowDispatch.qll | 159 +++++++++--------- .../semmle/python/internal/CachedStages.qll | 5 + 2 files changed, 88 insertions(+), 76 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 26764e96670..bf5da859c90 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -37,6 +37,7 @@ private import DataFlowPublic private import DataFlowPrivate private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImplSpecific as FlowSummaryImplSpecific +private import semmle.python.internal.CachedStages newtype TParameterPosition = /** Used for `self` in methods, and `cls` in classmethods. */ @@ -1041,20 +1042,23 @@ predicate resolveClassInstanceCall(CallNode call, Function target, Node self) { */ cached predicate resolveCall(ControlFlowNode call, Function target, CallType type) { - type instanceof CallTypePlainFunction and - call.(CallNode).getFunction() = functionTracker(target).asCfgNode() and - not exists(Class cls | cls.getAMethod() = target) - or - resolveMethodCall(call, target, type, _) - or - type instanceof CallTypeClass and - exists(Class cls | - resolveClassCall(call, cls) and - target = invokedFunctionFromClassConstruction(cls, _) + Stages::DataFlow::ref() and + ( + type instanceof CallTypePlainFunction and + call.(CallNode).getFunction() = functionTracker(target).asCfgNode() and + not exists(Class cls | cls.getAMethod() = target) + or + resolveMethodCall(call, target, type, _) + or + type instanceof CallTypeClass and + exists(Class cls | + resolveClassCall(call, cls) and + target = invokedFunctionFromClassConstruction(cls, _) + ) + or + type instanceof CallTypeClassInstanceCall and + resolveClassInstanceCall(call, target, _) ) - or - type instanceof CallTypeClassInstanceCall and - resolveClassInstanceCall(call, target, _) } // ============================================================================= @@ -1119,77 +1123,80 @@ cached predicate getCallArg( ControlFlowNode call, Function target, CallType type, Node arg, ArgumentPosition apos ) { - // normal calls with a real call node - resolveCall(call, target, type) and - call instanceof CallNode and + Stages::DataFlow::ref() and ( - type instanceof CallTypePlainFunction and - normalCallArg(call, arg, apos) - or - // self argument for normal method calls - type instanceof CallTypeNormalMethod and - apos.isSelf() and - resolveMethodCall(call, target, type, arg) and - // dataflow lib has requirement that arguments and calls are in same enclosing callable. - exists(CfgNode cfgNode | cfgNode.getNode() = call | - cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() - ) - or - // cls argument for classmethod calls - type instanceof CallTypeClassMethod and - apos.isSelf() and - resolveMethodCall(call, target, type, arg) and - (arg = classTracker(_) or arg = clsTracker(_)) and - // dataflow lib has requirement that arguments and calls are in same enclosing callable. - exists(CfgNode cfgNode | cfgNode.getNode() = call | - cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() - ) - or - // normal arguments for method calls + // normal calls with a real call node + resolveCall(call, target, type) and + call instanceof CallNode and ( - type instanceof CallTypeNormalMethod or - type instanceof CallTypeStaticMethod or - type instanceof CallTypeClassMethod - ) and - normalCallArg(call, arg, apos) - or - // method as plain function call. - // - // argument index 0 of call has position self (and MUST be given as positional - // argument in call). This also means that call-arguments are shifted by 1, such - // that argument index 1 of call has argument position 0 - type instanceof CallTypeMethodAsPlainFunction and - ( - apos.isSelf() and arg.asCfgNode() = call.(CallNode).getArg(0) + type instanceof CallTypePlainFunction and + normalCallArg(call, arg, apos) or - not apos.isPositional(_) and normalCallArg(call, arg, apos) - or - exists(ArgumentPosition normalPos, int index | - apos.isPositional(index - 1) and - normalPos.isPositional(index) and - normalCallArg(call, arg, normalPos) + // self argument for normal method calls + type instanceof CallTypeNormalMethod and + apos.isSelf() and + resolveMethodCall(call, target, type, arg) and + // dataflow lib has requirement that arguments and calls are in same enclosing callable. + exists(CfgNode cfgNode | cfgNode.getNode() = call | + cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() ) - ) - or - // class call - type instanceof CallTypeClass and - ( - // only pass synthetic node for created object to __init__, and not __new__ since - // __new__ is a classmethod. - target = invokedFunctionFromClassConstruction(_, "__init__") and - apos.isSelf() and - arg = TSyntheticPreUpdateNode(call) or - normalCallArg(call, arg, apos) - ) - or - // call on class instance, which goes to `__call__` method - type instanceof CallTypeClassInstanceCall and - ( + // cls argument for classmethod calls + type instanceof CallTypeClassMethod and apos.isSelf() and - resolveClassInstanceCall(call, target, arg) + resolveMethodCall(call, target, type, arg) and + (arg = classTracker(_) or arg = clsTracker(_)) and + // dataflow lib has requirement that arguments and calls are in same enclosing callable. + exists(CfgNode cfgNode | cfgNode.getNode() = call | + cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() + ) or + // normal arguments for method calls + ( + type instanceof CallTypeNormalMethod or + type instanceof CallTypeStaticMethod or + type instanceof CallTypeClassMethod + ) and normalCallArg(call, arg, apos) + or + // method as plain function call. + // + // argument index 0 of call has position self (and MUST be given as positional + // argument in call). This also means that call-arguments are shifted by 1, such + // that argument index 1 of call has argument position 0 + type instanceof CallTypeMethodAsPlainFunction and + ( + apos.isSelf() and arg.asCfgNode() = call.(CallNode).getArg(0) + or + not apos.isPositional(_) and normalCallArg(call, arg, apos) + or + exists(ArgumentPosition normalPos, int index | + apos.isPositional(index - 1) and + normalPos.isPositional(index) and + normalCallArg(call, arg, normalPos) + ) + ) + or + // class call + type instanceof CallTypeClass and + ( + // only pass synthetic node for created object to __init__, and not __new__ since + // __new__ is a classmethod. + target = invokedFunctionFromClassConstruction(_, "__init__") and + apos.isSelf() and + arg = TSyntheticPreUpdateNode(call) + or + normalCallArg(call, arg, apos) + ) + or + // call on class instance, which goes to `__call__` method + type instanceof CallTypeClassInstanceCall and + ( + apos.isSelf() and + resolveClassInstanceCall(call, target, arg) + or + normalCallArg(call, arg, apos) + ) ) ) } diff --git a/python/ql/lib/semmle/python/internal/CachedStages.qll b/python/ql/lib/semmle/python/internal/CachedStages.qll index 8b5701b3115..58bb9716195 100644 --- a/python/ql/lib/semmle/python/internal/CachedStages.qll +++ b/python/ql/lib/semmle/python/internal/CachedStages.qll @@ -180,6 +180,7 @@ module Stages { predicate ref() { 1 = 1 } private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic + private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch private import semmle.python.dataflow.new.internal.LocalSources as LocalSources private import semmle.python.internal.Awaited as Awaited @@ -195,6 +196,10 @@ module Stages { or any(DataFlowPublic::Node node).hasLocationInfo(_, _, _, _, _) or + DataFlowDispatch::resolveCall(_, _, _) + or + DataFlowDispatch::getCallArg(_, _, _, _, _) + or any(LocalSources::LocalSourceNode n).flowsTo(_) or exists(Awaited::awaited(_)) From aa382ac042423d418404893c01d1494d9f22fd7e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 4 Nov 2022 11:40:19 +0100 Subject: [PATCH 068/415] Python: Add test for strange generator taint flow I did check, and this was not a problem with the old call-graph on main! I'm absolutely baffled! --- .../generator-flow/InlineTaintTest.expected | 3 ++ .../generator-flow/InlineTaintTest.ql | 1 + .../NormalDataflowTest.expected | 2 + .../generator-flow/NormalDataflowTest.ql | 2 + .../generator-flow/test_dataflow.py | 34 +++++++++++++++++ .../generator-flow/test_taint.py | 37 +++++++++++++++++++ 6 files changed, 79 insertions(+) create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.ql create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_dataflow.py create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected new file mode 100644 index 00000000000..79d760d87f4 --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.expected @@ -0,0 +1,3 @@ +argumentToEnsureNotTaintedNotMarkedAsSpurious +untaintedArgumentToEnsureTaintedNotMarkedAsMissing +failures diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql new file mode 100644 index 00000000000..027ad8667be --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/InlineTaintTest.ql @@ -0,0 +1 @@ +import experimental.meta.InlineTaintTest diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected new file mode 100644 index 00000000000..3875da4e143 --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.expected @@ -0,0 +1,2 @@ +missingAnnotationOnSink +failures diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.ql new file mode 100644 index 00000000000..3ee344d0b87 --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/NormalDataflowTest.ql @@ -0,0 +1,2 @@ +import python +import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_dataflow.py b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_dataflow.py new file mode 100644 index 00000000000..d1becb7bbba --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_dataflow.py @@ -0,0 +1,34 @@ +def normal_helper(arg): + l = [arg] + return l[0] + + +def generator_helper(arg): + l = [arg] + l = [x for x in l] + return l[0] + + +def generator_helper_wo_source_use(arg): + l = [arg] + l = [x for x in l] + return l[0] + + +def test_source(): + x = normal_helper(SOURCE) + SINK(x) # $ flow="SOURCE, l:-1 -> x" + + x = generator_helper(SOURCE) + SINK(x) # $ flow="SOURCE, l:-1 -> x" + + +def test_non_source(): + x = normal_helper(NONSOURCE) + SINK_F(x) + + x = generator_helper(NONSOURCE) + SINK_F(x) + + x = generator_helper_wo_source_use(NONSOURCE) + SINK_F(x) diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py new file mode 100644 index 00000000000..858a23bcfb8 --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py @@ -0,0 +1,37 @@ +def normal_helper(arg): + l = [arg] + return l[0] + +# we had a regression where flow from a source to the argument of this function would +# cause _all_ returns from this function to be treated as tainted. That is, the +# `generator_helper(NONSOURCE)` call in `test_non_source` would result in taint :| This +# is specific to taint-tracking, and does NOT appear in pure data-flow (see the +# test_dataflow file) +def generator_helper(arg): + l = [arg] + l = [x for x in l] + return l[0] + + +def generator_helper_wo_source_use(arg): + l = [arg] + l = [x for x in l] + return l[0] + +def test_source(): + x = normal_helper(TAINTED_STRING) + ensure_tainted(x) # $ tainted + + x = generator_helper(TAINTED_STRING) + ensure_tainted(x) # $ tainted + + +def test_non_source(): + x = normal_helper(NONSOURCE) + ensure_not_tainted(x) + + x = generator_helper(NONSOURCE) + ensure_not_tainted(x) # $ SPURIOUS: tainted + + x = generator_helper_wo_source_use(NONSOURCE) + ensure_not_tainted(x) From d86f98d60b005eb7288f58c64eca538662134310 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Sun, 13 Nov 2022 20:46:45 +0100 Subject: [PATCH 069/415] Python: Accept changes for `enclosing-callable` test --- .../EnclosingCallable.expected | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected b/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected index a1e3de562f5..9ab214dc672 100644 --- a/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected +++ b/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected @@ -1,24 +1,24 @@ -| file://:0:0:0:0 | Function generator_func | generator.py:1:20:1:21 | ControlFlowNode for xs | -| file://:0:0:0:0 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for .0 | -| file://:0:0:0:0 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for .0 | -| file://:0:0:0:0 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for ListComp | -| file://:0:0:0:0 | Function generator_func | generator.py:2:13:2:13 | ControlFlowNode for Yield | -| file://:0:0:0:0 | Function generator_func | generator.py:2:13:2:13 | ControlFlowNode for x | -| file://:0:0:0:0 | Function generator_func | generator.py:2:19:2:19 | ControlFlowNode for x | -| file://:0:0:0:0 | Function generator_func | generator.py:2:24:2:25 | ControlFlowNode for xs | -| file://:0:0:0:0 | Module class_example | class_example.py:1:1:1:3 | ControlFlowNode for wat | -| file://:0:0:0:0 | Module class_example | class_example.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | -| file://:0:0:0:0 | Module class_example | class_example.py:3:1:3:10 | ControlFlowNode for ClassExpr | -| file://:0:0:0:0 | Module class_example | class_example.py:3:7:3:9 | ControlFlowNode for Wat | -| file://:0:0:0:0 | Module class_example | class_example.py:4:5:4:7 | ControlFlowNode for wat | -| file://:0:0:0:0 | Module class_example | class_example.py:4:11:4:11 | ControlFlowNode for IntegerLiteral | -| file://:0:0:0:0 | Module class_example | class_example.py:5:5:5:9 | ControlFlowNode for print | -| file://:0:0:0:0 | Module class_example | class_example.py:5:5:5:26 | ControlFlowNode for print() | -| file://:0:0:0:0 | Module class_example | class_example.py:5:11:5:20 | ControlFlowNode for Str | -| file://:0:0:0:0 | Module class_example | class_example.py:5:23:5:25 | ControlFlowNode for wat | -| file://:0:0:0:0 | Module class_example | class_example.py:7:1:7:5 | ControlFlowNode for print | -| file://:0:0:0:0 | Module class_example | class_example.py:7:1:7:23 | ControlFlowNode for print() | -| file://:0:0:0:0 | Module class_example | class_example.py:7:7:7:17 | ControlFlowNode for Str | -| file://:0:0:0:0 | Module class_example | class_example.py:7:20:7:22 | ControlFlowNode for wat | -| file://:0:0:0:0 | Module generator | generator.py:1:1:1:23 | ControlFlowNode for FunctionExpr | -| file://:0:0:0:0 | Module generator | generator.py:1:5:1:18 | ControlFlowNode for generator_func | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:1:1:1:3 | ControlFlowNode for wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:1:7:1:7 | ControlFlowNode for IntegerLiteral | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:3:1:3:10 | ControlFlowNode for ClassExpr | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:3:7:3:9 | ControlFlowNode for Wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:4:5:4:7 | ControlFlowNode for wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:4:11:4:11 | ControlFlowNode for IntegerLiteral | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:5:5:9 | ControlFlowNode for print | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:5:5:26 | ControlFlowNode for print() | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:11:5:20 | ControlFlowNode for Str | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:5:23:5:25 | ControlFlowNode for wat | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:1:7:5 | ControlFlowNode for print | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:1:7:23 | ControlFlowNode for print() | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:7:7:17 | ControlFlowNode for Str | +| class_example.py:0:0:0:0 | Module class_example | class_example.py:7:20:7:22 | ControlFlowNode for wat | +| generator.py:0:0:0:0 | Module generator | generator.py:1:1:1:23 | ControlFlowNode for FunctionExpr | +| generator.py:0:0:0:0 | Module generator | generator.py:1:5:1:18 | ControlFlowNode for generator_func | +| generator.py:1:1:1:23 | Function generator_func | generator.py:1:20:1:21 | ControlFlowNode for xs | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for ListComp | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:24:2:25 | ControlFlowNode for xs | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for Yield | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for x | +| generator.py:2:12:2:26 | Function listcomp | generator.py:2:19:2:19 | ControlFlowNode for x | From c0ad870949f91bc6df5c002ba517837853d8e018 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Sun, 13 Nov 2022 21:08:02 +0100 Subject: [PATCH 070/415] Python: Exclude synthetic generator functions from DataFlowCallable --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 9 ++++++++- .../experimental/dataflow/coverage/localFlow.expected | 6 ++++++ .../enclosing-callable/EnclosingCallable.expected | 10 +++++----- .../tainttracking/generator-flow/test_taint.py | 2 +- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index bf5da859c90..ccef7dd161d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -254,7 +254,14 @@ abstract class LibraryCallable extends string { } newtype TDataFlowCallable = - TFunction(Function func) or + TFunction(Function func) { + // For generators/list-comprehensions we create a synthetic function. In the + // points-to call-graph these were not considered callable, and instead we added + // data-flow steps (read/write) for these. As an easy solution for now, we do the + // same to keep things easy to reason about (and therefore exclude things that do + // not have a definition) + exists(func.getDefinition()) + } or /** see QLDoc for `DataFlowModuleScope` for why we need this. */ TModule(Module m) or TLibraryCallable(LibraryCallable callable) diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.expected b/python/ql/test/experimental/dataflow/coverage/localFlow.expected index 7ca11daba51..30b25979df3 100644 --- a/python/ql/test/experimental/dataflow/coverage/localFlow.expected +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.expected @@ -8,4 +8,10 @@ | test.py:187:1:187:53 | GSSA Variable SINK | test.py:189:5:189:8 | ControlFlowNode for SINK | | test.py:187:1:187:53 | GSSA Variable SOURCE | test.py:188:25:188:30 | ControlFlowNode for SOURCE | | test.py:188:5:188:5 | SSA variable x | test.py:189:10:189:10 | ControlFlowNode for x | +| test.py:188:9:188:68 | ControlFlowNode for .0 | test.py:188:9:188:68 | SSA variable .0 | | test.py:188:9:188:68 | ControlFlowNode for ListComp | test.py:188:5:188:5 | SSA variable x | +| test.py:188:9:188:68 | SSA variable .0 | test.py:188:9:188:68 | ControlFlowNode for .0 | +| test.py:188:16:188:16 | SSA variable v | test.py:188:45:188:45 | ControlFlowNode for v | +| test.py:188:40:188:40 | SSA variable u | test.py:188:56:188:56 | ControlFlowNode for u | +| test.py:188:51:188:51 | SSA variable z | test.py:188:67:188:67 | ControlFlowNode for z | +| test.py:188:62:188:62 | SSA variable y | test.py:188:10:188:10 | ControlFlowNode for y | diff --git a/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected b/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected index 9ab214dc672..3bd4cd81d54 100644 --- a/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected +++ b/python/ql/test/experimental/dataflow/enclosing-callable/EnclosingCallable.expected @@ -15,10 +15,10 @@ | generator.py:0:0:0:0 | Module generator | generator.py:1:1:1:23 | ControlFlowNode for FunctionExpr | | generator.py:0:0:0:0 | Module generator | generator.py:1:5:1:18 | ControlFlowNode for generator_func | | generator.py:1:1:1:23 | Function generator_func | generator.py:1:20:1:21 | ControlFlowNode for xs | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for .0 | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for .0 | | generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for ListComp | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:13:2:13 | ControlFlowNode for Yield | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:13:2:13 | ControlFlowNode for x | +| generator.py:1:1:1:23 | Function generator_func | generator.py:2:19:2:19 | ControlFlowNode for x | | generator.py:1:1:1:23 | Function generator_func | generator.py:2:24:2:25 | ControlFlowNode for xs | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for Yield | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for x | -| generator.py:2:12:2:26 | Function listcomp | generator.py:2:19:2:19 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py index 858a23bcfb8..4ec13583dcc 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/test_taint.py @@ -31,7 +31,7 @@ def test_non_source(): ensure_not_tainted(x) x = generator_helper(NONSOURCE) - ensure_not_tainted(x) # $ SPURIOUS: tainted + ensure_not_tainted(x) x = generator_helper_wo_source_use(NONSOURCE) ensure_not_tainted(x) From 8de5cfef43c6a2a83a0af969d55787ba85cff112 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 22 Nov 2022 14:41:48 +0100 Subject: [PATCH 071/415] Python: Update `dataflow-consistency.expected` After merging in main --- .../dataflow/callgraph_crosstalk/dataflow-consistency.expected | 2 ++ .../library-tests/CallGraph/dataflow-consistency.expected | 2 ++ 2 files changed, 4 insertions(+) diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected index 9fedaf9f663..8f4dbd04742 100644 --- a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected @@ -6,6 +6,8 @@ uniqueNodeToString missingToString parameterCallable localFlowIsLocal +readStepIsLocal +storeStepIsLocal compatibleTypesReflexive unreachableNodeCCtx localCallNodes diff --git a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected index 9fedaf9f663..8f4dbd04742 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected @@ -6,6 +6,8 @@ uniqueNodeToString missingToString parameterCallable localFlowIsLocal +readStepIsLocal +storeStepIsLocal compatibleTypesReflexive unreachableNodeCCtx localCallNodes From ee2f7401e82e8c4f7b156cb874789c2327db7dd8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 22 Nov 2022 14:42:10 +0100 Subject: [PATCH 072/415] Python: Add `generator-flow/dataflow-consistency.ql` --- .../dataflow-consistency.expected | 21 +++++++++++++++++++ .../generator-flow/dataflow-consistency.ql | 2 ++ 2 files changed, 23 insertions(+) create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected create mode 100644 python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.ql diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected new file mode 100644 index 00000000000..8f4dbd04742 --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected @@ -0,0 +1,21 @@ +uniqueEnclosingCallable +uniqueType +uniqueNodeLocation +missingLocation +uniqueNodeToString +missingToString +parameterCallable +localFlowIsLocal +readStepIsLocal +storeStepIsLocal +compatibleTypesReflexive +unreachableNodeCCtx +localCallNodes +postIsNotPre +postHasUniquePre +uniquePostUpdate +postIsInSameCallable +reverseRead +argHasPostUpdate +postWithInFlow +viableImplInCallContextTooLarge diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.ql new file mode 100644 index 00000000000..3dda6701a83 --- /dev/null +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.ql @@ -0,0 +1,2 @@ +import python +import experimental.dataflow.TestUtil.DataFlowConsistency From 00ec3a23ba61e9406c57f04735c31654be69191c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 22 Nov 2022 14:43:04 +0100 Subject: [PATCH 073/415] Python: Accept fix from module-resolution PR --- .../CallGraph-imports/InlineCallGraphTest.expected | 1 - .../experimental/library-tests/CallGraph-imports/pkg/use.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected index 7bba932e8f4..d5ed453c51a 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/InlineCallGraphTest.expected @@ -1,5 +1,4 @@ failures debug_callableNotUnique pointsTo_found_typeTracker_notFound -| pkg/use.py:10:5:10:10 | ControlFlowNode for func() | "pkg/func_def.py:func" | typeTracker_found_pointsTo_notFound diff --git a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py index 861359b5d91..fd1d957ba81 100644 --- a/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py +++ b/python/ql/test/experimental/library-tests/CallGraph-imports/pkg/use.py @@ -7,7 +7,7 @@ test_direct_import() # $ pt,tt=test_direct_import def test_alias_problem(): from .alias_problem import func - func() # $ pt="pkg/func_def.py:func" MISSING: tt="pkg/func_def.py:func" + func() # $ pt,tt="pkg/func_def.py:func" test_alias_problem() # $ pt,tt=test_alias_problem From 69b43f147aceeed864dc4444530d36621ad2882c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 22 Nov 2022 16:24:47 +0100 Subject: [PATCH 074/415] Python: Fix ql4ql alerts The rest will be ignored. --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 6 +++--- .../ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll | 7 +++---- python/ql/src/meta/analysis-quality/CallGraphQuality.qll | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index ccef7dd161d..f2e2ace7fda 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -478,7 +478,7 @@ private TypeTrackingNode classTracker(TypeTracker t, Class cls) { or // when a class is decorated, it's the result of the (last) decorator call that // is used - result.asExpr() = cls.getParent().(ClassExpr).getADecoratorCall() + result.asExpr() = cls.getParent().getADecoratorCall() or // `type(obj)`, where obj is an instance of this class result = getTypeCall() and @@ -1102,8 +1102,8 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { } /** - * Gets the argument of `call` at position `apos`, if any, where we can resolve `call` - * to `target` with CallType `type`. + * Gets the argument `arg` of `call` at position `apos`, if any. Requires that we can + * resolve `call` to `target` with CallType `type`. * * It might seem like it's enough to know the CallType to resolve arguments. The reason * we also need the `target`, is to avoid cross-talk. In the example below, assuming diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index dbc92f9d151..e01cd33aa5c 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -157,11 +157,10 @@ class UnresolvedCall extends InterestingExternalApiCall, TUnresolvedCall { /** A node representing data being passed to an external API through a call. */ class ExternalApiDataNode extends DataFlow::Node { - InterestingExternalApiCall call; - DataFlowPrivate::ArgumentPosition apos; - ExternalApiDataNode() { - this = call.getArgument(apos) and + exists(InterestingExternalApiCall call, DataFlowPrivate::ArgumentPosition apos | + this = call.getArgument(apos) + ) and // Not already modeled as a taint step not exists(DataFlow::Node next | TaintTrackingPrivate::defaultAdditionalTaintStep(this, next)) and // for `list.append(x)`, we have a additional taint step from x -> [post] list. diff --git a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll index cdb143017db..b1f29b52cc7 100644 --- a/python/ql/src/meta/analysis-quality/CallGraphQuality.qll +++ b/python/ql/src/meta/analysis-quality/CallGraphQuality.qll @@ -81,7 +81,7 @@ module PointsToBasedCallGraph { */ class ResolvableCallRelevantTarget extends ResolvableCall { ResolvableCallRelevantTarget() { - exists(Target target | target = getTarget() | + exists(Target target | target = this.getTarget() | exists(target.getLocation().getFile().getRelativePath()) ) } @@ -137,7 +137,7 @@ module TypeTrackingBasedCallGraph { */ class ResolvableCallRelevantTarget extends ResolvableCall { ResolvableCallRelevantTarget() { - exists(Target target | target = getTarget() | + exists(Target target | target = this.getTarget() | exists(target.getLocation().getFile().getRelativePath()) ) } From d151e21f15c38c4a0c1d8aff3a0b61d547ce2150 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 24 Nov 2022 10:14:39 +0100 Subject: [PATCH 075/415] Python: Move `ControlFlowNode.toString()` to AST cached stage This means points-to is no longer evaluated for sql injection :tada: Thanks @asgerf :muscle: --- python/ql/lib/semmle/python/Flow.qll | 2 +- python/ql/lib/semmle/python/internal/CachedStages.qll | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index a26a7ac7d8a..d5f25fd7b9f 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -125,7 +125,7 @@ class ControlFlowNode extends @py_flow_node { /** Gets a textual representation of this element. */ cached string toString() { - Stages::PointsTo::ref() and + Stages::AST::ref() and exists(Scope s | s.getEntryNode() = this | result = "Entry node for " + s.toString()) or exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString()) diff --git a/python/ql/lib/semmle/python/internal/CachedStages.qll b/python/ql/lib/semmle/python/internal/CachedStages.qll index 58bb9716195..40dda556caa 100644 --- a/python/ql/lib/semmle/python/internal/CachedStages.qll +++ b/python/ql/lib/semmle/python/internal/CachedStages.qll @@ -93,6 +93,8 @@ module Stages { exists(PyFlow::DefinitionNode b) or exists(any(PyFlow::SequenceNode n).getElement(_)) + or + exists(any(PyFlow::ControlFlowNode c).toString()) } } @@ -140,7 +142,6 @@ module Stages { private import semmle.python.pointsto.Base as PointsToBase private import semmle.python.types.Object as TypeObject private import semmle.python.objects.TObject as TObject - private import semmle.python.Flow as Flow private import semmle.python.objects.ObjectInternal as ObjectInternal // have to alias since this module is also called PointsTo private import semmle.python.pointsto.PointsTo as RealPointsTo @@ -159,8 +160,6 @@ module Stages { or exists(TObject::TObject f) or - exists(any(Flow::ControlFlowNode c).toString()) - or exists(any(ObjectInternal::ObjectInternal o).toString()) or RealPointsTo::AttributePointsTo::variableAttributePointsTo(_, _, _, _, _) From 68fd75ca34dd9d792cdce7f400a72acd8b473b54 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Mon, 5 Dec 2022 17:20:22 +0100 Subject: [PATCH 076/415] UnpackUnsafe query and tests --- .../Security/CWE-022bis/UnsafeUnpack.qhelp | 56 +++++++++++++++++++ .../Security/CWE-022bis/UnsafeUnpack.ql | 56 +++++++++++++++++++ .../CWE-022bis/examples/HIT_UnsafeUnpack.py | 12 ++++ .../CWE-022bis/examples/NoHIT_UnsafeUnpack.py | 17 ++++++ .../Security/CWE-022/UnsafeUnpack.expected | 10 ++++ .../Security/CWE-022/UnsafeUnpack.py | 12 ++++ .../Security/CWE-022/UnsafeUnpack.qlref | 1 + 7 files changed, 164 insertions(+) create mode 100644 python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp create mode 100644 python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql create mode 100644 python/ql/src/experimental/Security/CWE-022bis/examples/HIT_UnsafeUnpack.py create mode 100644 python/ql/src/experimental/Security/CWE-022bis/examples/NoHIT_UnsafeUnpack.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.qlref diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp new file mode 100644 index 00000000000..c1115e819b9 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp @@ -0,0 +1,56 @@ + + + + +

Extracting files from a malicious tarball without validating that the destination file path +is within the destination directory using `shutil.unpack_archive()` can cause files outside the +destination directory to be overwritten, due to the possible presence of directory traversal elements + (..) in archive path names.

+ +

Tarball contain archive entries representing each file in the archive. These entries +include a file path for the entry, but these file paths are not restricted and may contain +unexpected special elements such as the directory traversal element (..). If these +file paths are used to determine an output file to write the contents of the archive item to, then +the file may be written to an unexpected location. This can result in sensitive information being +revealed or deleted, or an attacker being able to influence behavior by modifying unexpected +files.

+ +

For example, if a tarball contains a file entry ../sim4n6.txt, and the tarball +is extracted to the directory /tmp/tmp123, then naively combining the paths would result +in an output file path of /tmp/tmp123/../sim4n6.txt, which would cause the file to be +written to /tmp/.

+ +
+ + +

Ensure that output paths constructed from tarball entries are validated +to prevent writing files to unexpected locations.

+ +

Consider using a safer module, such as: zipfile

+ +
+ + +

+In this example an archive is extracted without validating file paths. +

+ + + +

To fix this vulnerability, we need to call the function tarfile.extract() + on each member after verifying that it does not contain either `..` or startswith `/`. +

+ + + +
+ + +
  • + Shutil official documentation + shutil.unpack_archive() warning. +
  • +
    +
    diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql new file mode 100644 index 00000000000..eb78b13cd0a --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -0,0 +1,56 @@ +/** + * @name Arbitrary file write during a remotely downloaded tarball extraction + * @description Extracting files from a malicious tarball using `shutil.unpack_archive()` without validating + * that the destination file path is within the destination directory can cause files outside + * the destination directory to be overwritten. More precisely, if the tarball comes from a remote location. + * @kind path-problem + * @id py/unsafe-unpacking + * @problem.severity error + * @security-severity 7.5 + * @precision high + * @tags security + * external/cwe/cwe-022bis + */ + +import python +import experimental.semmle.python.Concepts +import DataFlow::PathGraph +import semmle.python.ApiGraphs +import semmle.python.dataflow.new.internal.Attributes +import semmle.python.dataflow.new.DataFlow +import semmle.python.ApiGraphs +import semmle.python.dataflow.new.TaintTracking +import semmle.python.Concepts + +class UnsafeUnpackingConfig extends TaintTracking::Configuration { + UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" } + + override predicate isSource(DataFlow::Node source) { + // A source coming from a remote location + exists(Http::Client::Request request | source = request) and + not source.getScope().getLocation().getFile().inStdlib() + } + + override predicate isSink(DataFlow::Node sink) { + // A sink capturing method calls to `unpack_archive`. + sink = + API::moduleImport("shutil").getMember("unpack_archive").getACall().getParameter(0).asSink() and + not sink.getScope().getLocation().getFile().inStdlib() + } + + override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Writing the response data to the archive + exists(API::CallNode call, MethodCallNode w | + nodeTo = call.getArg(0) and + call = API::builtin("open").getACall() and + w.getMethodName() = "write" and + w.getObject() = call.getReturn().getAValueReachableFromSource() and + nodeFrom = w.getArg(0) + ) + } +} + +from UnsafeUnpackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select source.getNode(), source, sink, "Unsafe extraction from a malicious tarball, is used in a $@", + source.getAQlClass(), "during archive unpacking." \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-022bis/examples/HIT_UnsafeUnpack.py b/python/ql/src/experimental/Security/CWE-022bis/examples/HIT_UnsafeUnpack.py new file mode 100644 index 00000000000..cc0f857f8c0 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-022bis/examples/HIT_UnsafeUnpack.py @@ -0,0 +1,12 @@ +import requests +import shutil + +url = "https://www.someremote.location/tarball.tar.gz" +response = requests.get(url, stream=True) + +tarpath = "/tmp/tmp456/tarball.tar.gz" +with open(tarpath, "wb") as f: + f.write(response.raw.read()) + +untarredpath = "/tmp/tmp123" +shutil.unpack_archive(tarpath, untarredpath) \ No newline at end of file diff --git a/python/ql/src/experimental/Security/CWE-022bis/examples/NoHIT_UnsafeUnpack.py b/python/ql/src/experimental/Security/CWE-022bis/examples/NoHIT_UnsafeUnpack.py new file mode 100644 index 00000000000..426bcd71481 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-022bis/examples/NoHIT_UnsafeUnpack.py @@ -0,0 +1,17 @@ +import requests +import tarfile + +url = "https://www.someremote.location/tarball.tar.gz" +response = requests.get(url, stream=True) + +tarpath = "/tmp/tmp456/tarball.tar.gz" +with open(tarpath, "wb") as f: + f.write(response.raw.read()) + +untarredpath = "/tmp/tmp123" +with tarfile.open(tarpath) as tar: + for member in tar.getmembers(): + if member.name.startswith("/") or ".." in member.name: + raise Exception("Path traversal identified in tarball") + + tar.extract(untarredpath, member) \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected new file mode 100644 index 00000000000..96d25c65a30 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -0,0 +1,10 @@ +edges +| UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | +nodes +| UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | +subpaths +#select +| UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball, is used in a $@ | PathNode | during archive unpacking. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py new file mode 100644 index 00000000000..cc0f857f8c0 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -0,0 +1,12 @@ +import requests +import shutil + +url = "https://www.someremote.location/tarball.tar.gz" +response = requests.get(url, stream=True) + +tarpath = "/tmp/tmp456/tarball.tar.gz" +with open(tarpath, "wb") as f: + f.write(response.raw.read()) + +untarredpath = "/tmp/tmp123" +shutil.unpack_archive(tarpath, untarredpath) \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.qlref b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.qlref new file mode 100644 index 00000000000..90e5db651a0 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-022bis/UnsafeUnpack.ql \ No newline at end of file From 054c06be6579ef2338f900df58539a29c8a3fc75 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Tue, 6 Dec 2022 02:51:07 +0100 Subject: [PATCH 077/415] Update UnsafeUnpack.ql --- .../Security/CWE-022bis/UnsafeUnpack.ql | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index eb78b13cd0a..c80dda11cea 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -8,49 +8,54 @@ * @problem.severity error * @security-severity 7.5 * @precision high - * @tags security + * @tags securityimport semmle.python.dataflow.TaintTracking * external/cwe/cwe-022bis */ import python -import experimental.semmle.python.Concepts -import DataFlow::PathGraph -import semmle.python.ApiGraphs -import semmle.python.dataflow.new.internal.Attributes -import semmle.python.dataflow.new.DataFlow -import semmle.python.ApiGraphs -import semmle.python.dataflow.new.TaintTracking import semmle.python.Concepts +import semmle.python.dataflow.new.internal.DataFlowPublic +import semmle.python.ApiGraphs +import DataFlow::PathGraph +import semmle.python.dataflow.new.TaintTracking class UnsafeUnpackingConfig extends TaintTracking::Configuration { UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" } override predicate isSource(DataFlow::Node source) { // A source coming from a remote location - exists(Http::Client::Request request | source = request) and - not source.getScope().getLocation().getFile().inStdlib() + exists(Http::Client::Request request | source = request) } override predicate isSink(DataFlow::Node sink) { // A sink capturing method calls to `unpack_archive`. - sink = - API::moduleImport("shutil").getMember("unpack_archive").getACall().getParameter(0).asSink() and - not sink.getScope().getLocation().getFile().inStdlib() + sink = API::moduleImport("shutil").getMember("unpack_archive").getACall().getArg(0) } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { // Writing the response data to the archive - exists(API::CallNode call, MethodCallNode w | - nodeTo = call.getArg(0) and + (exists(API::CallNode call, MethodCallNode mc, Node f | + mc.getMethodName() = "write" and + f = mc.getObject() and + nodeTo = mc.getArg(0) and call = API::builtin("open").getACall() and - w.getMethodName() = "write" and - w.getObject() = call.getReturn().getAValueReachableFromSource() and - nodeFrom = w.getArg(0) + call.flowsTo(f) and + nodeFrom = call.getArg(0) ) + or + // Reading the response + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and + mc.getMethodName() = "read" and + nodeTo = mc + ) + or + // Accessing the name + exists(AttrRead ar | ar.accesses(nodeFrom, "name") and nodeTo = ar)) } } from UnsafeUnpackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink where config.hasFlowPath(source, sink) -select source.getNode(), source, sink, "Unsafe extraction from a malicious tarball, is used in a $@", - source.getAQlClass(), "during archive unpacking." \ No newline at end of file +select sink.getNode(), source, sink, + "Unsafe extraction from a malicious tarball retrieved from a remote location." From a5849eb9b0cd434a14dfb849adad7c7ca194ba52 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Tue, 6 Dec 2022 14:00:08 +0100 Subject: [PATCH 078/415] Improved the additional taint step using InstanceSource --- .../Security/CWE-022bis/UnsafeUnpack.ql | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index c80dda11cea..bd3d17ff71b 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -18,6 +18,7 @@ import semmle.python.dataflow.new.internal.DataFlowPublic import semmle.python.ApiGraphs import DataFlow::PathGraph import semmle.python.dataflow.new.TaintTracking +import semmle.python.frameworks.Stdlib class UnsafeUnpackingConfig extends TaintTracking::Configuration { UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" } @@ -34,24 +35,25 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { // Writing the response data to the archive - (exists(API::CallNode call, MethodCallNode mc, Node f | - mc.getMethodName() = "write" and - f = mc.getObject() and - nodeTo = mc.getArg(0) and - call = API::builtin("open").getACall() and - call.flowsTo(f) and - nodeFrom = call.getArg(0) + ( + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc.getMethodName() = "write" and + f = mc.getObject() and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) + or + // Reading the response + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and + mc.getMethodName() = "read" and + nodeTo = mc + ) + or + // Accessing the name + exists(AttrRead ar | ar.accesses(nodeFrom, "name") and nodeTo = ar) ) - or - // Reading the response - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and - mc.getMethodName() = "read" and - nodeTo = mc - ) - or - // Accessing the name - exists(AttrRead ar | ar.accesses(nodeFrom, "name") and nodeTo = ar)) } } From c22c0b502940478b5434eab1c43895a691c22f59 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 6 Dec 2022 14:39:16 +0100 Subject: [PATCH 079/415] Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- .../ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp index c1115e819b9..d1fd1f4f414 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp @@ -40,7 +40,7 @@ In this example an archive is extracted without validating file paths.

    To fix this vulnerability, we need to call the function tarfile.extract() - on each member after verifying that it does not contain either `..` or startswith `/`. + on each member after verifying that it does not contain either .. or startswith /.

    From 9a60202de62da63e842b35eddbef838c4de08ca1 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 6 Dec 2022 14:40:35 +0100 Subject: [PATCH 080/415] Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- .../ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp index d1fd1f4f414..cc42d88de1d 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp @@ -5,7 +5,7 @@

    Extracting files from a malicious tarball without validating that the destination file path -is within the destination directory using `shutil.unpack_archive()` can cause files outside the +is within the destination directory using shutil.unpack_archive() can cause files outside the destination directory to be overwritten, due to the possible presence of directory traversal elements (..) in archive path names.

    From 58570b4d2c2b09dae1558b1f6bee2c77d0ffcdbb Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Tue, 6 Dec 2022 14:40:48 +0100 Subject: [PATCH 081/415] Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index bd3d17ff71b..4c57e087dd3 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -8,7 +8,7 @@ * @problem.severity error * @security-severity 7.5 * @precision high - * @tags securityimport semmle.python.dataflow.TaintTracking + * @tags security * external/cwe/cwe-022bis */ From 4896e62117c20dd2f5737a80f0e1cdd21401f8c4 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Tue, 6 Dec 2022 14:44:52 +0100 Subject: [PATCH 082/415] Use of more generic terms --- .../src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp index cc42d88de1d..1219bbe43bc 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.qhelp @@ -17,9 +17,9 @@ the file may be written to an unexpected location. This can result in sensitive revealed or deleted, or an attacker being able to influence behavior by modifying unexpected files.

    -

    For example, if a tarball contains a file entry ../sim4n6.txt, and the tarball +

    For example, if a tarball contains a file entry ../sneaky-file.txt, and the tarball is extracted to the directory /tmp/tmp123, then naively combining the paths would result -in an output file path of /tmp/tmp123/../sim4n6.txt, which would cause the file to be +in an output file path of /tmp/tmp123/../sneaky-file.txt, which would cause the file to be written to /tmp/.

    From 2801b8495aefcdcf7710bfcd5a5a3748c6da0145 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Tue, 6 Dec 2022 14:50:47 +0100 Subject: [PATCH 083/415] A fix of the tag name --- python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 4c57e087dd3..d550b2a4a37 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -9,7 +9,7 @@ * @security-severity 7.5 * @precision high * @tags security - * external/cwe/cwe-022bis + * external/cwe/cwe-022 */ import python From 9336f4f1a2db7d557f398a229985505870697a91 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Thu, 8 Dec 2022 12:26:59 +0100 Subject: [PATCH 084/415] Considering the use of contextlib.closing() method --- .../Security/CWE-022bis/UnsafeUnpack.ql | 11 ++++- .../Security/CWE-022/UnsafeUnpack.expected | 6 ++- .../Security/CWE-022/UnsafeUnpack.py | 46 ++++++++++++++++++- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index d550b2a4a37..e793e670771 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -34,8 +34,8 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Writing the response data to the archive ( + // Writing the response data to the archive exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | is.flowsTo(f) and mc.getMethodName() = "write" and @@ -48,11 +48,18 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { exists(MethodCallNode mc | nodeFrom = mc.getObject() and mc.getMethodName() = "read" and - nodeTo = mc + mc.flowsTo(nodeTo) ) or // Accessing the name exists(AttrRead ar | ar.accesses(nodeFrom, "name") and nodeTo = ar) + or + // Considering closing use + exists(API::Node closing | + closing = API::moduleImport("contextlib").getMember("closing") and + closing.getACall().flowsTo(nodeTo) and + nodeFrom = closing.getACall().getArg(0) + ) ) } } diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected index 96d25c65a30..b1e93bf3ab2 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -1,10 +1,14 @@ edges | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | +| UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | nodes | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | +| UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | semmle.label | ControlFlowNode for to_path | subpaths #select -| UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball, is used in a $@ | PathNode | during archive unpacking. | +| UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index cc0f857f8c0..c7820e52b04 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -9,4 +9,48 @@ with open(tarpath, "wb") as f: f.write(response.raw.read()) untarredpath = "/tmp/tmp123" -shutil.unpack_archive(tarpath, untarredpath) \ No newline at end of file +shutil.unpack_archive(tarpath, untarredpath) + + +import tempfile +import os +from urllib import request +import contextlib +import shutil + +unpack = True +to_path = "/tmp/tmp123" +uri = "https://www.goog.com/zzz.tar.gz" +scheme = "https" + +with tempfile.TemporaryDirectory() as temp_dir: + if unpack and (str(uri).endswith("zip") or str(uri).endswith("tar.gz")): + unpack_path = to_path + to_path = temp_dir + else: + unpack_path = None + if scheme in ["http", "https", "ftp"]: + if os.path.isdir(to_path): + to_path = os.path.join(to_path, os.path.basename(uri)) + url = uri + url_response = request.urlopen(url) + with contextlib.closing(url_response) as fp: + with open(to_path, "wb") as out_file: + block_size = DEFAULT_BUFFER_SIZE * 8 + while True: + block = fp.read(block_size) + if not block: + break + out_file.write(block) + else: + if scheme == "oci" and not storage_options: + storage_options = default_signer() + fs = fsspec.filesystem(scheme, **storage_options) + if os.path.isdir(to_path): + to_path = os.path.join( + to_path, os.path.basename(str(uri).rstrip("/")) + ) + fs.get(uri, to_path, recursive=True) + if unpack_path: + shutil.unpack_archive(to_path, unpack_path) + to_path = unpack_path From 545aab0e07d5ee9cbfdb56b16e057db59fecd9e7 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Fri, 9 Dec 2022 15:54:43 +0100 Subject: [PATCH 085/415] tarball path provided using CLI argument (source) --- .../Security/CWE-022bis/UnsafeUnpack.ql | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index e793e670771..33ecb3d5dc2 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -1,8 +1,9 @@ /** - * @name Arbitrary file write during a remotely downloaded tarball extraction - * @description Extracting files from a malicious tarball using `shutil.unpack_archive()` without validating + * @name Arbitrary file write during a tarball extraction from user controlled source + * @description Extracting files from a potentially malicious tarball using `shutil.unpack_archive()` without validating * that the destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. More precisely, if the tarball comes from a remote location. + * the destination directory to be overwritten. More precisely, if the tarball comes from a user controlled + * location either a remote one or cli argument. * @kind path-problem * @id py/unsafe-unpacking * @problem.severity error @@ -26,6 +27,14 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { // A source coming from a remote location exists(Http::Client::Request request | source = request) + or + // A source coming from a CLI argparse module + exists(Node o, API::Node ap, MethodCallNode args | + ap = API::moduleImport("argparse").getMember("ArgumentParser").getACall().getReturn() and + args = ap.getMember("parse_args").getACall() and + args.flowsTo(o) and + source.(AttrRead).accesses(o, any(string s)) + ) } override predicate isSink(DataFlow::Node sink) { @@ -54,7 +63,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // Accessing the name exists(AttrRead ar | ar.accesses(nodeFrom, "name") and nodeTo = ar) or - // Considering closing use + // Considering the use of closing() exists(API::Node closing | closing = API::moduleImport("contextlib").getMember("closing") and closing.getACall().flowsTo(nodeTo) and From eff132512c3bae3140c87e477d5d62c89d0a7db8 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Sat, 10 Dec 2022 08:15:42 +0100 Subject: [PATCH 086/415] Copying the response data to the archive --- .../Security/CWE-022bis/UnsafeUnpack.ql | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 33ecb3d5dc2..cb87b16432e 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -53,6 +53,15 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeTo = is.(CallCfgNode).getArg(0) ) or + // Copying the response data to the archive + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc = API::moduleImport("shutil").getMember("copyfileobj").getACall() and + f = mc.getArg(1) and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) + or // Reading the response exists(MethodCallNode mc | nodeFrom = mc.getObject() and @@ -60,8 +69,8 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { mc.flowsTo(nodeTo) ) or - // Accessing the name - exists(AttrRead ar | ar.accesses(nodeFrom, "name") and nodeTo = ar) + // Accessing the name or raw content + exists(AttrRead ar | ar.accesses(nodeFrom, ["name","raw"]) and nodeTo = ar) or // Considering the use of closing() exists(API::Node closing | From b19452467df781552790be5fc5bdcce2acacc5f7 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Sat, 10 Dec 2022 21:59:14 +0100 Subject: [PATCH 087/415] read by chunks as additional step --- .../Security/CWE-022bis/UnsafeUnpack.ql | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index cb87b16432e..159a19b4bee 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -1,8 +1,8 @@ /** - * @name Arbitrary file write during a tarball extraction from user controlled source + * @name Arbitrary file write during a tarball extraction from a user controlled source * @description Extracting files from a potentially malicious tarball using `shutil.unpack_archive()` without validating * that the destination file path is within the destination directory can cause files outside - * the destination directory to be overwritten. More precisely, if the tarball comes from a user controlled + * the destination directory to be overwritten. More precisely, if the tarball comes from a user controlled * location either a remote one or cli argument. * @kind path-problem * @id py/unsafe-unpacking @@ -28,11 +28,11 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // A source coming from a remote location exists(Http::Client::Request request | source = request) or - // A source coming from a CLI argparse module + //A source coming from a CLI argparse module exists(Node o, API::Node ap, MethodCallNode args | ap = API::moduleImport("argparse").getMember("ArgumentParser").getACall().getReturn() and args = ap.getMember("parse_args").getACall() and - args.flowsTo(o) and + args.flowsTo(o) and source.(AttrRead).accesses(o, any(string s)) ) } @@ -57,7 +57,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | is.flowsTo(f) and mc = API::moduleImport("shutil").getMember("copyfileobj").getACall() and - f = mc.getArg(1) and + f = mc.getArg(1) and nodeFrom = mc.getArg(0) and nodeTo = is.(CallCfgNode).getArg(0) ) @@ -70,13 +70,25 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { ) or // Accessing the name or raw content - exists(AttrRead ar | ar.accesses(nodeFrom, ["name","raw"]) and nodeTo = ar) + exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) + or + //Use of join of filename + exists(API::CallNode mcn | + mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and + nodeFrom = mcn.getArg(1) and + mcn.flowsTo(nodeTo) + ) + or + // Read by chunks + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) + ) or // Considering the use of closing() - exists(API::Node closing | - closing = API::moduleImport("contextlib").getMember("closing") and - closing.getACall().flowsTo(nodeTo) and - nodeFrom = closing.getACall().getArg(0) + exists(API::CallNode closing | + closing = API::moduleImport("contextlib").getMember("closing").getACall() and + closing.flowsTo(nodeTo) and + nodeFrom = closing.getArg(0) ) ) } From 2f68b54b27a6e6ba51e27351715823bde362f176 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Mon, 12 Dec 2022 19:46:34 +0100 Subject: [PATCH 088/415] A simple download_file() call from maybe boto3 --- python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 159a19b4bee..17604c00426 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -35,6 +35,9 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { args.flowsTo(o) and source.(AttrRead).accesses(o, any(string s)) ) + or + // A source catching a S3 filename download + exists(API::Node s3 | source = s3.getMember("download_file").getACall().getArg(2)) } override predicate isSink(DataFlow::Node sink) { From 54109b8ea7ce7b413f2d672b52e2ccfde8795e72 Mon Sep 17 00:00:00 2001 From: ALJI Mohamed Date: Tue, 13 Dec 2022 15:34:01 +0100 Subject: [PATCH 089/415] Add source wget.download --- .../ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 17604c00426..f8dfb78fced 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -38,6 +38,11 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { or // A source catching a S3 filename download exists(API::Node s3 | source = s3.getMember("download_file").getACall().getArg(2)) + or + // A source download a file using wget + exists(MethodCallNode mcn | + mcn = API::moduleImport("wget").getMember("download").getACall() and source = mcn.getArg(1) + ) } override predicate isSink(DataFlow::Node sink) { From 4376870a518262146c3c2446cd2512be2038b577 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 15 Dec 2022 23:39:02 +0100 Subject: [PATCH 090/415] An uploded file is considered a source --- .../Security/CWE-022bis/UnsafeUnpack.ql | 122 +++++++++++------- 1 file changed, 75 insertions(+), 47 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index f8dfb78fced..1ebdf48397c 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -43,6 +43,21 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { exists(MethodCallNode mcn | mcn = API::moduleImport("wget").getMember("download").getACall() and source = mcn.getArg(1) ) + or + // catch the uploaded files as a source + exists(Subscript s, Attribute at | + at = s.getObject() and at.getAttr() = "FILES" and source.asExpr() = s + ) + or + exists(Node obj, AttrRead ar | + ar.getAMethodCall("get").flowsTo(source) and + ar.accesses(obj, "FILES") + ) + or + exists(Node obj, AttrRead ar | + ar.getAMethodCall("getlist").flowsTo(source) and + ar.accesses(obj, "FILES") + ) } override predicate isSink(DataFlow::Node sink) { @@ -51,53 +66,66 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - ( - // Writing the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc.getMethodName() = "write" and - f = mc.getObject() and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) - or - // Copying the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc = API::moduleImport("shutil").getMember("copyfileobj").getACall() and - f = mc.getArg(1) and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) - or - // Reading the response - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and - mc.getMethodName() = "read" and - mc.flowsTo(nodeTo) - ) - or - // Accessing the name or raw content - exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) - or - //Use of join of filename - exists(API::CallNode mcn | - mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and - nodeFrom = mcn.getArg(1) and - mcn.flowsTo(nodeTo) - ) - or - // Read by chunks - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) - ) - or - // Considering the use of closing() - exists(API::CallNode closing | - closing = API::moduleImport("contextlib").getMember("closing").getACall() and - closing.flowsTo(nodeTo) and - nodeFrom = closing.getArg(0) - ) + // Writing the response data to the archive + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc.getMethodName() = "write" and + f = mc.getObject() and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) + or + // Copying the response data to the archive + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc = API::moduleImport("shutil").getMember("copyfileobj").getACall() and + f = mc.getArg(1) and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) + or + // Reading the response + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and + mc.getMethodName() = "read" and + mc.flowsTo(nodeTo) + ) + or + // Accessing the name or raw content + exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) + or + //Use of join of filename + exists(API::CallNode mcn | + mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and + nodeFrom = mcn.getArg(1) and + mcn.flowsTo(nodeTo) + ) + or + // Read by chunks + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) + ) + or + // Considering the use of closing() + exists(API::CallNode closing | + closing = API::moduleImport("contextlib").getMember("closing").getACall() and + closing.flowsTo(nodeTo) and + nodeFrom = closing.getArg(0) + ) + or + // Considering the use of "fs" + exists(API::CallNode fs, MethodCallNode mcn | + fs = + API::moduleImport("django") + .getMember("core") + .getMember("files") + .getMember("storage") + .getMember("FileSystemStorage") + .getACall() and + fs.flowsTo(mcn.getObject()) and + mcn.getMethodName() = ["save", "path"] and + nodeFrom = mcn.getArg(0) and + nodeTo = mcn ) } } From e5e5d84361a8bef27fadbf4660271cf43af2c6be Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 16 Jan 2023 13:44:24 +0100 Subject: [PATCH 091/415] Python: Add change-note --- python/ql/lib/change-notes/2023-01-16-new-call-graph.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2023-01-16-new-call-graph.md diff --git a/python/ql/lib/change-notes/2023-01-16-new-call-graph.md b/python/ql/lib/change-notes/2023-01-16-new-call-graph.md new file mode 100644 index 00000000000..1dbfd05a80f --- /dev/null +++ b/python/ql/lib/change-notes/2023-01-16-new-call-graph.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* We use a new analysis for the call-graph (determining which function is called). This can lead to changed results. In most cases this is much more accurate than the old call-graph that was based on points-to, but we do loose a few valid edges in the call-graph, especially around methods that are not defined inside its' class. From dfbb744a7a0c4045400e2e8e0e04413831758bff Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 16 Jan 2023 14:04:25 +0100 Subject: [PATCH 092/415] Python: Add comment on `*args` argument handling --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index f2e2ace7fda..7314d5dad14 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1090,6 +1090,9 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { exists(int index | apos.isStarArgs(index) and arg.asCfgNode() = call.getStarArg() and + // since `CallNode.getArg` doesn't include `*args`, we need to drop to the AST level + // to get the index. Notice that we only use the AST for getting the index, so we + // don't need to check for dominance in regards to splitting. call.getStarArg().getNode() = call.getNode().getPositionalArg(index).(Starred).getValue() ) or From a1513cc1d39d73dd45af6a7be8d0c9671b208f95 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 16 Jan 2023 14:07:11 +0100 Subject: [PATCH 093/415] Python: Minor QLDoc fix --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 7314d5dad14..96272a85791 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -350,7 +350,7 @@ class DataFlowPlainFunction extends DataFlowFunction { DataFlowPlainFunction() { not this instanceof DataFlowMethod } } -/** A method, except staticmethods. */ +/** A method. */ class DataFlowMethod extends DataFlowFunction { Class cls; From 3fcb8f3f4b26595b8b15db0a9a250da2d8815fce Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 16 Jan 2023 14:11:13 +0100 Subject: [PATCH 094/415] Python: Accept suggestions from code-review --- .../new/internal/DataFlowDispatch.qll | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 96272a85791..b01f3453201 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -42,13 +42,13 @@ private import semmle.python.internal.CachedStages newtype TParameterPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfParameterPosition() or - TPositionalParameterPosition(int pos) { - pos = any(Parameter p).getPosition() + TPositionalParameterPosition(int index) { + index = any(Parameter p).getPosition() or // since synthetic parameters are made for a synthetic summary callable, based on // what Argument positions they have flow for, we need to make sure we have such // parameter positions available. - FlowSummaryImplSpecific::ParsePositions::isParsedPositionalArgumentPosition(_, pos) + FlowSummaryImplSpecific::ParsePositions::isParsedPositionalArgumentPosition(_, index) } or TKeywordParameterPosition(string name) { name = any(Parameter p).getName() @@ -56,15 +56,15 @@ newtype TParameterPosition = // see comment for TPositionalParameterPosition FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name) } or - TStarArgsParameterPosition(int pos) { + TStarArgsParameterPosition(int index) { // since `.getPosition` does not work for `*args`, we need *args parameter positions // at index 1 larger than the largest positional parameter position (and 0 must be // included as well). This is a bit of an over-approximation. - pos = 0 or - pos = any(Parameter p).getPosition() + 1 + index = 0 or + index = any(Parameter p).getPosition() + 1 } or - TSynthStarArgsElementParameterPosition(int pos) { exists(TStarArgsParameterPosition(pos)) } or - TSynthLateStarArgsParameterPosition(int pos) { exists(TStarArgsParameterPosition(pos)) } or + TSynthStarArgsElementParameterPosition(int index) { exists(TStarArgsParameterPosition(index)) } or + TSynthLateStarArgsParameterPosition(int index) { exists(TStarArgsParameterPosition(index)) } or TDictSplatParameterPosition() /** A parameter position. */ @@ -128,13 +128,13 @@ class ParameterPosition extends TParameterPosition { newtype TArgumentPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfArgumentPosition() or - TPositionalArgumentPosition(int pos) { - exists(any(CallNode c).getArg(pos)) + TPositionalArgumentPosition(int index) { + exists(any(CallNode c).getArg(index)) or // since synthetic calls within a summarized callable could use a unique argument // position, we need to ensure we make these available (these are specified as // parameters in the flow-summary spec) - FlowSummaryImplSpecific::ParsePositions::isParsedPositionalParameterPosition(_, pos) + FlowSummaryImplSpecific::ParsePositions::isParsedPositionalParameterPosition(_, index) } or TKeywordArgumentPosition(string name) { exists(any(CallNode c).getArgByName(name)) @@ -142,7 +142,9 @@ newtype TArgumentPosition = // see comment for TPositionalArgumentPosition FlowSummaryImplSpecific::ParsePositions::isParsedKeywordParameterPosition(_, name) } or - TStarArgsArgumentPosition(int pos) { exists(Call c | c.getPositionalArg(pos) instanceof Starred) } or + TStarArgsArgumentPosition(int index) { + exists(Call c | c.getPositionalArg(index) instanceof Starred) + } or TDictSplatArgumentPosition() /** An argument position. */ @@ -329,11 +331,9 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { | // a `*args` parameter comes after the last positional parameter. We need to take // self parameter into account, so for - // `def func(foo, bar, *args)` it should be index 2 (1 + max-index == 1 + 1) - // `class A: def func(self, foo, bar, *args)` it should be index 2 (1 + max-index - 1 == 1 + 2 - 1) - index = - 1 + max(int positionalIndex | exists(func.getArg(positionalIndex)) | positionalIndex) - - this.positionalOffset() + // `def func(foo, bar, *args)` it should be index 2 (pos-param-count == 2) + // `class A: def func(self, foo, bar, *args)` it should be index 2 (pos-param-count - 1 == 3 - 1) + index = func.getPositionalParameterCount() - this.positionalOffset() or // no positional argument not exists(func.getArg(_)) and index = 0 @@ -579,8 +579,8 @@ Node clsTracker(Class classWithMethod) { * call happened in the method `func` (either a method or a classmethod). */ private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func) { - not isStaticmethod(func) and t.start() and + not isStaticmethod(func) and exists(CallCfgNode call | result = call | call = getSuperCall() and not exists(call.getArg(_)) and From a3b7273844807575fce4709d337137307bc716fd Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 16 Jan 2023 14:19:18 +0100 Subject: [PATCH 095/415] Python: Fix duplicated meta query id --- python/ql/src/meta/analysis-quality/TTCallGraph.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/meta/analysis-quality/TTCallGraph.ql b/python/ql/src/meta/analysis-quality/TTCallGraph.ql index 67faca55893..d6383a32eb1 100644 --- a/python/ql/src/meta/analysis-quality/TTCallGraph.ql +++ b/python/ql/src/meta/analysis-quality/TTCallGraph.ql @@ -2,7 +2,7 @@ * @name New call graph edge from using type-tracking instead of points-to * @kind problem * @problem.severity recommendation - * @id py/meta/call-graph-new + * @id py/meta/type-tracking-call-graph * @tags meta * @precision very-low */ From 690a09d9b640b30d0ef293913dea906639d2fe10 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 16 Jan 2023 20:45:44 +0100 Subject: [PATCH 096/415] Python: new-call-graph: `pragma[noinline]` => `pragma[nomagic]` As suggested by @tausbn. Obviously, this needs to be performance tested. --- .../dataflow/new/internal/DataFlowDispatch.qll | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index b01f3453201..32b319c43d6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -841,7 +841,7 @@ private module MethodCalls { * reference to the class `cls`, or to an instance of the class `cls`. The reference the * attribute-read is made on is `self`. */ - pragma[noinline] + pragma[nomagic] private predicate directCall( CallNode call, Function target, string functionName, Class cls, AttrRead attr, Node self ) { @@ -850,7 +850,7 @@ private module MethodCalls { } /** Extracted to give good join order */ - pragma[noinline] + pragma[nomagic] private predicate directCall_join( CallNode call, string functionName, Class cls, AttrRead attr, Node self ) { @@ -872,7 +872,7 @@ private module MethodCalls { * reference to an implicit `self`/`cls` argument. The reference the attribute-read is * made on is `self`. */ - pragma[noinline] + pragma[nomagic] private predicate callWithinMethodImplicitSelfOrCls( CallNode call, Function target, string functionName, Class classWithMethod, AttrRead attr, Node self @@ -882,7 +882,7 @@ private module MethodCalls { } /** Extracted to give good join order */ - pragma[noinline] + pragma[nomagic] private predicate callWithinMethodImplicitSelfOrCls_join( CallNode call, string functionName, Class classWithMethod, AttrRead attr, Node self ) { @@ -921,7 +921,7 @@ private module MethodCalls { * The method call is found by making an attribute read `attr` with the name * `functionName` on the return value from the `super` call. */ - pragma[noinline] + pragma[nomagic] predicate fromSuper( CallNode call, Function target, string functionName, Class classUsedInSuper, AttrRead attr, Node self @@ -931,7 +931,7 @@ private module MethodCalls { } /** Extracted to give good join order */ - pragma[noinline] + pragma[nomagic] private predicate fromSuper_join( CallNode call, string functionName, Class classUsedInSuper, AttrRead attr, Node self ) { From 7c242b1409ae92d45617e93d7a170bf9dfedc490 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 10:25:19 +0100 Subject: [PATCH 097/415] Python: Minor QLDoc fix Co-authored-by: Taus --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 32b319c43d6..35a01380364 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -24,7 +24,7 @@ * any special logic that requires an AST call to be made before we care to figure out * what callable this call might end up targeting. * - * Specifically this means that we cannot use type-backtrackes from the function of a + * Specifically this means that we cannot use type-backtrackers from the function of a * `CallNode`, since there is no `CallNode` to backtrack from for `func` in the example * above. * From 4f3876f18411d43dc655411de3ea887303d60168 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 10:30:29 +0100 Subject: [PATCH 098/415] Python: Accept rewrite for `_join(` predicates Co-authored-by: yoff --- .../new/internal/DataFlowDispatch.qll | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 35a01380364..81950a016ad 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -854,14 +854,9 @@ private module MethodCalls { private predicate directCall_join( CallNode call, string functionName, Class cls, AttrRead attr, Node self ) { - ( - call.getFunction() = attrReadTracker(attr).asCfgNode() and - attr.accesses(classTracker(cls), functionName) - or - call.getFunction() = attrReadTracker(attr).asCfgNode() and - attr.accesses(classInstanceTracker(cls), functionName) - ) and - attr.accesses(self, functionName) + call.getFunction() = attrReadTracker(attr).asCfgNode() and + attr.accesses(self, functionName) and + self in [classTracker(cls), classInstanceTracker(cls)] } /** @@ -886,14 +881,9 @@ private module MethodCalls { private predicate callWithinMethodImplicitSelfOrCls_join( CallNode call, string functionName, Class classWithMethod, AttrRead attr, Node self ) { - ( - call.getFunction() = attrReadTracker(attr).asCfgNode() and - attr.accesses(clsTracker(classWithMethod), functionName) - or - call.getFunction() = attrReadTracker(attr).asCfgNode() and - attr.accesses(selfTracker(classWithMethod), functionName) - ) and - attr.accesses(self, functionName) + call.getFunction() = attrReadTracker(attr).asCfgNode() and + attr.accesses(self, functionName) and + self in [clsTracker(classWithMethod), selfTracker(classWithMethod)] } /** From 700e40b11bbe6f4dfe16d4df98db2603a9c455f0 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 10:35:20 +0100 Subject: [PATCH 099/415] Python: Fix ql4ql --- python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index 285c351ccdc..9d7c153e15a 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -158,9 +158,7 @@ class UnresolvedCall extends InterestingExternalApiCall, TUnresolvedCall { /** A node representing data being passed to an external API through a call. */ class ExternalApiDataNode extends DataFlow::Node { ExternalApiDataNode() { - exists(InterestingExternalApiCall call, DataFlowPrivate::ArgumentPosition apos | - this = call.getArgument(apos) - ) and + exists(InterestingExternalApiCall call | this = call.getArgument(_)) and // Not already modeled as a taint step not TaintTrackingPrivate::defaultAdditionalTaintStep(this, _) and // for `list.append(x)`, we have a additional taint step from x -> [post] list. From 608b16c98a375e8e85456be744c13ff3f7d617ad Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 10:56:53 +0100 Subject: [PATCH 100/415] Python: Minor adjustment in QLDoc Co-authored-by: yoff --- python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index 9d7c153e15a..30e68cd00c0 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -12,7 +12,7 @@ private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPr private import semmle.python.dataflow.new.internal.TaintTrackingPrivate as TaintTrackingPrivate /** - * An external API that is considered a "safe" from a security perspective. + * An external API that is considered "safe" from a security perspective. */ class SafeExternalApi extends Unit { /** From 479f019eb09597771df2c5f87055c68c6fa11714 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 10:40:31 +0100 Subject: [PATCH 101/415] Python: Minor rewrite removing unnecessary `exists` Co-authored-by: Taus --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 81950a016ad..644efbfbf8e 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -702,7 +702,7 @@ Function findFunctionAccordingToMro(Class cls, string name) { result = cls.getAMethod() and result.getName() = name or - not exists(Function f | f.getName() = name and f = cls.getAMethod()) and + not cls.getAMethod().getName() = name and result = findFunctionAccordingToMro(getNextClassInMro(cls), name) } @@ -733,7 +733,7 @@ private Function findFunctionAccordingToMroKnownStartingClass( result.getName() = name and cls = getADirectSuperclass*(startingClass) or - not exists(Function f | f.getName() = name and f = cls.getAMethod()) and + not cls.getAMethod().getName() = name and result = findFunctionAccordingToMroKnownStartingClass(getNextClassInMroKnownStartingClass(cls, startingClass), startingClass, name) From b6f76d784ce70d04be52216d204c0b944669a103 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 10:51:01 +0100 Subject: [PATCH 102/415] Python: Remove accidentally committed files --- python/ql/test/library-tests/fuck/options | 1 - python/ql/test/library-tests/fuck/test.py | 17 ----------------- python/ql/test/library-tests/fuck/wat.expected | 1 - 3 files changed, 19 deletions(-) delete mode 100644 python/ql/test/library-tests/fuck/options delete mode 100644 python/ql/test/library-tests/fuck/test.py delete mode 100644 python/ql/test/library-tests/fuck/wat.expected diff --git a/python/ql/test/library-tests/fuck/options b/python/ql/test/library-tests/fuck/options deleted file mode 100644 index efa237f03c4..00000000000 --- a/python/ql/test/library-tests/fuck/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=0 diff --git a/python/ql/test/library-tests/fuck/test.py b/python/ql/test/library-tests/fuck/test.py deleted file mode 100644 index 3029c8be234..00000000000 --- a/python/ql/test/library-tests/fuck/test.py +++ /dev/null @@ -1,17 +0,0 @@ -def my_func(arg): - print("my_func", arg) - -class Foo: - def foo(self, arg=42): - print("Foo.foo", self, arg) - - -my_func(43) - -import random -if random.choice([True, False]): - func = my_func -else: - func = Foo.foo - -func(44) diff --git a/python/ql/test/library-tests/fuck/wat.expected b/python/ql/test/library-tests/fuck/wat.expected deleted file mode 100644 index 2a4f078a25f..00000000000 --- a/python/ql/test/library-tests/fuck/wat.expected +++ /dev/null @@ -1 +0,0 @@ -| 1 | From ae1d4decc36841ae3987bf3a30305794f16ac5ab Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 11:01:47 +0100 Subject: [PATCH 103/415] Python: `ExternalAPIs.qll`: Swap order of classes Co-authored-by: yoff --- .../CWE-020-ExternalAPIs/ExternalAPIs.qll | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index 30e68cd00c0..94762ace98c 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -111,27 +111,6 @@ abstract class InterestingExternalApiCall extends TInterestingExternalApiCall { abstract string getApiName(); } -class ResolvedCall extends InterestingExternalApiCall, TResolvedCall { - DataFlowPrivate::DataFlowCall dfCall; - - ResolvedCall() { this = TResolvedCall(dfCall) } - - override DataFlow::Node getArgument(DataFlowPrivate::ArgumentPosition apos) { - result = dfCall.getArgument(apos) - } - - override string toString() { - result = "ExternalAPI:ResolvedCall: " + dfCall.getNode().getNode().toString() - } - - override string getApiName() { - exists(DataFlow::CallCfgNode call, API::Node apiNode | dfCall.getNode() = call.getNode() | - result = apiNodeToStringRepr(apiNode) and - apiNode.getACall() = call - ) - } -} - class UnresolvedCall extends InterestingExternalApiCall, TUnresolvedCall { DataFlow::CallCfgNode call; @@ -155,6 +134,27 @@ class UnresolvedCall extends InterestingExternalApiCall, TUnresolvedCall { } } +class ResolvedCall extends InterestingExternalApiCall, TResolvedCall { + DataFlowPrivate::DataFlowCall dfCall; + + ResolvedCall() { this = TResolvedCall(dfCall) } + + override DataFlow::Node getArgument(DataFlowPrivate::ArgumentPosition apos) { + result = dfCall.getArgument(apos) + } + + override string toString() { + result = "ExternalAPI:ResolvedCall: " + dfCall.getNode().getNode().toString() + } + + override string getApiName() { + exists(DataFlow::CallCfgNode call, API::Node apiNode | dfCall.getNode() = call.getNode() | + result = apiNodeToStringRepr(apiNode) and + apiNode.getACall() = call + ) + } +} + /** A node representing data being passed to an external API through a call. */ class ExternalApiDataNode extends DataFlow::Node { ExternalApiDataNode() { From f8d7a367adacc625f16d00baf02e3a17beec9019 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 11:45:57 +0100 Subject: [PATCH 104/415] Python: Rewrite test for __add__ special method Co-authored-by: yoff --- .../library-tests/CallGraph/code/class_special_methods.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py index e765f155f3c..23dcefdb852 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py +++ b/python/ql/test/experimental/library-tests/CallGraph/code/class_special_methods.py @@ -38,9 +38,9 @@ b.__call__(44) # $ pt,tt=Base.__call__ print("\n! b2") b2 = Base(2) # $ tt=Base.__init__ -# __add__ is called -b + b2 -b + 100 + +b + b2 # $ MISSING: tt=Base.__add__ +b + 100 # $ MISSING: tt=Base.__add__ # ======== From e3fcfd0a661d51fb4239afd1e7e9c65c27467fa5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 13:53:12 +0100 Subject: [PATCH 105/415] Python: Use configuration for dataflow consistency checks in `dataflow/exceptions` --- .../experimental/dataflow/exceptions/dataflow-consistency.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/exceptions/dataflow-consistency.ql b/python/ql/test/experimental/dataflow/exceptions/dataflow-consistency.ql index 6743fa10d27..3dda6701a83 100644 --- a/python/ql/test/experimental/dataflow/exceptions/dataflow-consistency.ql +++ b/python/ql/test/experimental/dataflow/exceptions/dataflow-consistency.ql @@ -1 +1,2 @@ -import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency +import python +import experimental.dataflow.TestUtil.DataFlowConsistency From 7a423622f8afe1c6ba8140d2c57c85a16274e2c8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 12:17:25 +0100 Subject: [PATCH 106/415] DataFlow: Add `uniqueParameterNodeAtPositionExclude` --- .../cpp/ir/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../code/cpp/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../cpp/ir/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../csharp/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../code/java/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../dataflow/new/internal/DataFlowImplConsistency.qll | 6 ++++++ .../ruby/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../swift/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ 8 files changed, 48 insertions(+) diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll index 533899e8a85..245de04d3ce 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll @@ -45,6 +45,11 @@ module Consistency { ) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */ + predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -246,6 +251,7 @@ module Consistency { query predicate uniqueParameterNodeAtPosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and msg = "Parameters with overlapping positions." From a6fd5b6e59431bafbd5cbc19d0401f3cba47b555 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 11:55:49 +0100 Subject: [PATCH 107/415] DataFlow: Add `uniqueParameterNodePositionExclude` --- .../cpp/ir/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../code/cpp/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../cpp/ir/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../csharp/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../code/java/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../dataflow/new/internal/DataFlowImplConsistency.qll | 6 ++++++ .../ruby/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ .../swift/dataflow/internal/DataFlowImplConsistency.qll | 6 ++++++ 8 files changed, 48 insertions(+) diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll index 245de04d3ce..9bbc70fbdf9 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplConsistency.qll @@ -50,6 +50,11 @@ module Consistency { predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { none() } + + /** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */ + predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) { + none() + } } private class RelevantNode extends Node { @@ -260,6 +265,7 @@ module Consistency { query predicate uniqueParameterNodePosition( DataFlowCallable c, ParameterPosition pos, Node p, string msg ) { + not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and isParameterNode(p, c, pos) and not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and msg = "Parameter node with multiple positions." From b6272b383da0657d420079dac5df52ec6469810a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 12:05:18 +0100 Subject: [PATCH 108/415] Python: Allow non-unique parameter positions for normal parameters --- .../dataflow/TestUtil/DataFlowConsistency.qll | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll index 8d85437b7d3..e4a6306dc5a 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll @@ -1,3 +1,4 @@ +import python import semmle.python.dataflow.new.DataFlow::DataFlow import semmle.python.dataflow.new.internal.DataFlowPrivate import semmle.python.dataflow.new.internal.DataFlowImplConsistency::Consistency @@ -18,4 +19,20 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration { // being a post-update node for the synthetic `**kwargs` parameter. n instanceof SynthDictSplatParameterNode } + + override predicate uniqueParameterNodePositionExclude( + DataFlowCallable c, ParameterPosition pos, Node p + ) { + // For normal parameters that can both be passed as positional arguments or keyword + // arguments, we currently have parameter positions for both cases.. + // + // TODO: Figure out how bad breaking this consistency check is + exists(Function func, Parameter param | + c.getScope() = func and + p = parameterNode(param) and + c.getParameter(pos) = p and + param = func.getArg(_) and + param = func.getArgByName(_) + ) + } } From 749e81367dbc67a04d4d4413884032a28fd82b5e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 12:21:50 +0100 Subject: [PATCH 109/415] Python: Allow multiple `**kwargs` parameters outside our test code --- .../dataflow/TestUtil/DataFlowConsistency.qll | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll index e4a6306dc5a..456b18e2a87 100644 --- a/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll +++ b/python/ql/test/experimental/dataflow/TestUtil/DataFlowConsistency.qll @@ -20,6 +20,15 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration { n instanceof SynthDictSplatParameterNode } + override predicate uniqueParameterNodeAtPositionExclude( + DataFlowCallable c, ParameterPosition pos, Node p + ) { + // TODO: This can be removed once we solve the overlap of dictionary splat parameters + c.getParameter(pos) = p and + pos.isDictSplat() and + not exists(p.getLocation().getFile().getRelativePath()) + } + override predicate uniqueParameterNodePositionExclude( DataFlowCallable c, ParameterPosition pos, Node p ) { From dad6221b61ebe5983bb8308148c4778fa7d34c00 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 13:53:41 +0100 Subject: [PATCH 110/415] Python: Accept `dataflow-consistency.expected` changes for now As highlighted in the configuration file, there are some things to catch up on, and we also need to apply the same fix as Ruby for **kwargs handling. --- .../callgraph_crosstalk/dataflow-consistency.expected | 3 +++ .../dataflow/consistency/dataflow-consistency.expected | 2 ++ .../dataflow/coverage/dataflow-consistency.expected | 10 ++++++++++ .../generator-flow/dataflow-consistency.expected | 3 +++ .../CallGraph/dataflow-consistency.expected | 3 +++ 5 files changed, 21 insertions(+) diff --git a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected index 8f4dbd04742..410b626ffff 100644 --- a/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/callgraph_crosstalk/dataflow-consistency.expected @@ -19,3 +19,6 @@ reverseRead argHasPostUpdate postWithInFlow viableImplInCallContextTooLarge +uniqueParameterNodeAtPosition +uniqueParameterNodePosition +uniqueContentApprox diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index 410b626ffff..ab832392cf5 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -20,5 +20,7 @@ argHasPostUpdate postWithInFlow viableImplInCallContextTooLarge uniqueParameterNodeAtPosition +| test.py:239:1:239:42 | Function overflowCallee | ** | test.py:239:1:239:42 | SynthDictSplatParameterNode | Parameters with overlapping positions. | +| test.py:239:1:239:42 | Function overflowCallee | ** | test.py:239:35:239:40 | ControlFlowNode for kwargs | Parameters with overlapping positions. | uniqueParameterNodePosition uniqueContentApprox diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected index 410b626ffff..4ee8d7f0fcc 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected @@ -20,5 +20,15 @@ argHasPostUpdate postWithInFlow viableImplInCallContextTooLarge uniqueParameterNodeAtPosition +| argumentPassing.py:50:1:60:2 | Function argument_passing | ** | argumentPassing.py:50:1:60:2 | SynthDictSplatParameterNode | Parameters with overlapping positions. | +| argumentPassing.py:50:1:60:2 | Function argument_passing | ** | argumentPassing.py:59:7:59:7 | ControlFlowNode for g | Parameters with overlapping positions. | +| argumentPassing.py:185:1:185:23 | Function mixed | ** | argumentPassing.py:185:1:185:23 | SynthDictSplatParameterNode | Parameters with overlapping positions. | +| argumentPassing.py:185:1:185:23 | Function mixed | ** | argumentPassing.py:185:16:185:21 | ControlFlowNode for kwargs | Parameters with overlapping positions. | +| classes.py:441:5:441:41 | Function __prepare__ | ** | classes.py:441:5:441:41 | SynthDictSplatParameterNode | Parameters with overlapping positions. | +| classes.py:441:5:441:41 | Function __prepare__ | ** | classes.py:441:36:441:39 | ControlFlowNode for kwds | Parameters with overlapping positions. | +| test.py:407:1:407:28 | Function f_extra_keyword | ** | test.py:407:1:407:28 | SynthDictSplatParameterNode | Parameters with overlapping positions. | +| test.py:407:1:407:28 | Function f_extra_keyword | ** | test.py:407:26:407:26 | ControlFlowNode for b | Parameters with overlapping positions. | +| test.py:521:23:521:43 | Function lambda | ** | test.py:521:23:521:43 | SynthDictSplatParameterNode | Parameters with overlapping positions. | +| test.py:521:23:521:43 | Function lambda | ** | test.py:521:35:521:35 | ControlFlowNode for b | Parameters with overlapping positions. | uniqueParameterNodePosition uniqueContentApprox diff --git a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected index 8f4dbd04742..410b626ffff 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/generator-flow/dataflow-consistency.expected @@ -19,3 +19,6 @@ reverseRead argHasPostUpdate postWithInFlow viableImplInCallContextTooLarge +uniqueParameterNodeAtPosition +uniqueParameterNodePosition +uniqueContentApprox diff --git a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected index 8f4dbd04742..410b626ffff 100644 --- a/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected +++ b/python/ql/test/experimental/library-tests/CallGraph/dataflow-consistency.expected @@ -19,3 +19,6 @@ reverseRead argHasPostUpdate postWithInFlow viableImplInCallContextTooLarge +uniqueParameterNodeAtPosition +uniqueParameterNodePosition +uniqueContentApprox From 1c8cc6a32a863681d40a72309cbc25835e0f18c8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 14:14:05 +0100 Subject: [PATCH 111/415] Python: Add QLDoc for TFunction --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 644efbfbf8e..cf610428e4f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -256,6 +256,10 @@ abstract class LibraryCallable extends string { } newtype TDataFlowCallable = + /** + * Is used as the target for all calls: plain functions, lambdas, methods on classes, + * class instantiations, and (in the future) special methods. + */ TFunction(Function func) { // For generators/list-comprehensions we create a synthetic function. In the // points-to call-graph these were not considered callable, and instead we added From 24892801ec2034ccf63d48d36264f8c40e4fa18e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 14:16:56 +0100 Subject: [PATCH 112/415] Python: `clsTracker` => `clsArgumentTracker` Co-authored-by: Taus --- .../dataflow/new/internal/DataFlowDispatch.qll | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index cf610428e4f..ebe2737ec09 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -552,7 +552,7 @@ Node selfTracker(Class classWithMethod) { /** * Gets a reference to the `cls` argument of a classmethod on class `classWithMethod`. */ -private TypeTrackingNode clsTracker(TypeTracker t, Class classWithMethod) { +private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod) { t.start() and ( exists(Function func | @@ -567,15 +567,15 @@ private TypeTrackingNode clsTracker(TypeTracker t, Class classWithMethod) { result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) ) or - exists(TypeTracker t2 | result = clsTracker(t2, classWithMethod).track(t2, t)) and + exists(TypeTracker t2 | result = clsArgumentTracker(t2, classWithMethod).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } /** * Gets a reference to the `cls` argument of a classmethod on class `classWithMethod`. */ -Node clsTracker(Class classWithMethod) { - clsTracker(TypeTracker::end(), classWithMethod).flowsTo(result) +Node clsArgumentTracker(Class classWithMethod) { + clsArgumentTracker(TypeTracker::end(), classWithMethod).flowsTo(result) } /** @@ -763,7 +763,7 @@ private TypeTrackingNode attrReadTracker(TypeTracker t, AttrRead attr) { t.start() and result = attr and attr.getObject() in [ - classTracker(_), classInstanceTracker(_), selfTracker(_), clsTracker(_), + classTracker(_), classInstanceTracker(_), selfTracker(_), clsArgumentTracker(_), superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _) ] or @@ -887,7 +887,7 @@ private module MethodCalls { ) { call.getFunction() = attrReadTracker(attr).asCfgNode() and attr.accesses(self, functionName) and - self in [clsTracker(classWithMethod), selfTracker(classWithMethod)] + self in [clsArgumentTracker(classWithMethod), selfTracker(classWithMethod)] } /** @@ -897,7 +897,7 @@ private module MethodCalls { */ predicate fromSuperNewCall(CallNode call, Class classUsedInSuper, AttrRead attr, Node self) { fromSuper_join(call, "__new__", classUsedInSuper, attr, self) and - self in [classTracker(_), clsTracker(_)] + self in [classTracker(_), clsArgumentTracker(_)] } /** @@ -998,7 +998,7 @@ predicate resolveClassCall(CallNode call, Class cls) { or // `cls()` inside a classmethod (which also contains `type(self)()` inside a method) exists(Class classWithMethod | - call.getFunction() = clsTracker(classWithMethod).asCfgNode() and + call.getFunction() = clsArgumentTracker(classWithMethod).asCfgNode() and getADirectSuperclass*(cls) = classWithMethod ) } @@ -1149,7 +1149,7 @@ predicate getCallArg( type instanceof CallTypeClassMethod and apos.isSelf() and resolveMethodCall(call, target, type, arg) and - (arg = classTracker(_) or arg = clsTracker(_)) and + (arg = classTracker(_) or arg = clsArgumentTracker(_)) and // dataflow lib has requirement that arguments and calls are in same enclosing callable. exists(CfgNode cfgNode | cfgNode.getNode() = call | cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() From b83fc3b6eb8a0a51a9617af41ee5afc775789692 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 17 Jan 2023 14:38:56 +0100 Subject: [PATCH 113/415] Python: Update QLDoc for `clsArgumentTracker` --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index ebe2737ec09..74fb1531aef 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -550,7 +550,9 @@ Node selfTracker(Class classWithMethod) { } /** - * Gets a reference to the `cls` argument of a classmethod on class `classWithMethod`. + * Gets a reference to the enclosing class `classWithMethod` from within one of its + * methods, either through the `cls` argument from a `classmethod` or from `type(self)` + * from a normal method. */ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod) { t.start() and @@ -572,7 +574,9 @@ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod } /** - * Gets a reference to the `cls` argument of a classmethod on class `classWithMethod`. + * Gets a reference to the enclosing class `classWithMethod` from within one of its + * methods, either through the `cls` argument from a `classmethod` or from `type(self)` + * from a normal method. */ Node clsArgumentTracker(Class classWithMethod) { clsArgumentTracker(TypeTracker::end(), classWithMethod).flowsTo(result) From 4df946b16158cdadaa02ad0afeabbf14cda08c9a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 18 Jan 2023 12:29:17 +0100 Subject: [PATCH 114/415] Python: call-graph: Don't design for special method calls yet The `call` arguments were not `CallNode`s before, to allow for easier support of special method calls, such as `a + b` going to `__add__`. However, this is not implemented yet, so for now we can keep things simple. Co-authored-by: Taus --- .../new/internal/DataFlowDispatch.qll | 138 +++++++++--------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 74fb1531aef..a25c5994ada 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -950,7 +950,7 @@ private module MethodCalls { ) } - predicate resolveMethodCall(ControlFlowNode call, Function target, CallType type, Node self) { + predicate resolveMethodCall(CallNode call, Function target, CallType type, Node self) { ( directCall(call, target, _, _, _, self) or @@ -1046,11 +1046,11 @@ predicate resolveClassInstanceCall(CallNode call, Function target, Node self) { * Holds if `call` is a call to the `target`, with call-type `type`. */ cached -predicate resolveCall(ControlFlowNode call, Function target, CallType type) { +predicate resolveCall(CallNode call, Function target, CallType type) { Stages::DataFlow::ref() and ( type instanceof CallTypePlainFunction and - call.(CallNode).getFunction() = functionTracker(target).asCfgNode() and + call.getFunction() = functionTracker(target).asCfgNode() and not exists(Class cls | cls.getAMethod() = target) or resolveMethodCall(call, target, type, _) @@ -1128,83 +1128,77 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { * sending both `self` arguments to that function, which is by definition the right thing to do. */ cached -predicate getCallArg( - ControlFlowNode call, Function target, CallType type, Node arg, ArgumentPosition apos -) { +predicate getCallArg(CallNode call, Function target, CallType type, Node arg, ArgumentPosition apos) { Stages::DataFlow::ref() and + resolveCall(call, target, type) and ( - // normal calls with a real call node - resolveCall(call, target, type) and - call instanceof CallNode and + type instanceof CallTypePlainFunction and + normalCallArg(call, arg, apos) + or + // self argument for normal method calls + type instanceof CallTypeNormalMethod and + apos.isSelf() and + resolveMethodCall(call, target, type, arg) and + // dataflow lib has requirement that arguments and calls are in same enclosing callable. + exists(CfgNode cfgNode | cfgNode.getNode() = call | + cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() + ) + or + // cls argument for classmethod calls + type instanceof CallTypeClassMethod and + apos.isSelf() and + resolveMethodCall(call, target, type, arg) and + (arg = classTracker(_) or arg = clsArgumentTracker(_)) and + // dataflow lib has requirement that arguments and calls are in same enclosing callable. + exists(CfgNode cfgNode | cfgNode.getNode() = call | + cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() + ) + or + // normal arguments for method calls ( - type instanceof CallTypePlainFunction and - normalCallArg(call, arg, apos) + type instanceof CallTypeNormalMethod or + type instanceof CallTypeStaticMethod or + type instanceof CallTypeClassMethod + ) and + normalCallArg(call, arg, apos) + or + // method as plain function call. + // + // argument index 0 of call has position self (and MUST be given as positional + // argument in call). This also means that call-arguments are shifted by 1, such + // that argument index 1 of call has argument position 0 + type instanceof CallTypeMethodAsPlainFunction and + ( + apos.isSelf() and arg.asCfgNode() = call.(CallNode).getArg(0) or - // self argument for normal method calls - type instanceof CallTypeNormalMethod and + not apos.isPositional(_) and normalCallArg(call, arg, apos) + or + exists(ArgumentPosition normalPos, int index | + apos.isPositional(index - 1) and + normalPos.isPositional(index) and + normalCallArg(call, arg, normalPos) + ) + ) + or + // class call + type instanceof CallTypeClass and + ( + // only pass synthetic node for created object to __init__, and not __new__ since + // __new__ is a classmethod. + target = invokedFunctionFromClassConstruction(_, "__init__") and apos.isSelf() and - resolveMethodCall(call, target, type, arg) and - // dataflow lib has requirement that arguments and calls are in same enclosing callable. - exists(CfgNode cfgNode | cfgNode.getNode() = call | - cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() - ) + arg = TSyntheticPreUpdateNode(call) or - // cls argument for classmethod calls - type instanceof CallTypeClassMethod and - apos.isSelf() and - resolveMethodCall(call, target, type, arg) and - (arg = classTracker(_) or arg = clsArgumentTracker(_)) and - // dataflow lib has requirement that arguments and calls are in same enclosing callable. - exists(CfgNode cfgNode | cfgNode.getNode() = call | - cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() - ) - or - // normal arguments for method calls - ( - type instanceof CallTypeNormalMethod or - type instanceof CallTypeStaticMethod or - type instanceof CallTypeClassMethod - ) and normalCallArg(call, arg, apos) + ) + or + // call on class instance, which goes to `__call__` method + type instanceof CallTypeClassInstanceCall and + ( + apos.isSelf() and + resolveClassInstanceCall(call, target, arg) or - // method as plain function call. - // - // argument index 0 of call has position self (and MUST be given as positional - // argument in call). This also means that call-arguments are shifted by 1, such - // that argument index 1 of call has argument position 0 - type instanceof CallTypeMethodAsPlainFunction and - ( - apos.isSelf() and arg.asCfgNode() = call.(CallNode).getArg(0) - or - not apos.isPositional(_) and normalCallArg(call, arg, apos) - or - exists(ArgumentPosition normalPos, int index | - apos.isPositional(index - 1) and - normalPos.isPositional(index) and - normalCallArg(call, arg, normalPos) - ) - ) - or - // class call - type instanceof CallTypeClass and - ( - // only pass synthetic node for created object to __init__, and not __new__ since - // __new__ is a classmethod. - target = invokedFunctionFromClassConstruction(_, "__init__") and - apos.isSelf() and - arg = TSyntheticPreUpdateNode(call) - or - normalCallArg(call, arg, apos) - ) - or - // call on class instance, which goes to `__call__` method - type instanceof CallTypeClassInstanceCall and - ( - apos.isSelf() and - resolveClassInstanceCall(call, target, arg) - or - normalCallArg(call, arg, apos) - ) + normalCallArg(call, arg, apos) ) ) } From 0df3dd68d6eef76e97625883a4ce08b3aaf87f20 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 20 Jan 2023 15:13:02 +0100 Subject: [PATCH 115/415] Python: Remove (now) redundant cast --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index a25c5994ada..fd0ca01c00b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1169,7 +1169,7 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar // that argument index 1 of call has argument position 0 type instanceof CallTypeMethodAsPlainFunction and ( - apos.isSelf() and arg.asCfgNode() = call.(CallNode).getArg(0) + apos.isSelf() and arg.asCfgNode() = call.getArg(0) or not apos.isPositional(_) and normalCallArg(call, arg, apos) or From d9fbe58ad5a4f515806de4c4baeeb43cde336bc5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 20 Jan 2023 16:34:59 +0100 Subject: [PATCH 116/415] Python: Expand `starargs_only` test --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 1 + .../ql/test/experimental/dataflow/coverage/argumentPassing.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index fd0ca01c00b..ea7c5aab858 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1085,6 +1085,7 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { arg.asCfgNode() = call.getArgByName(name) ) or + // the first `*args` exists(int index | apos.isStarArgs(index) and arg.asCfgNode() = call.getStarArg() and diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 2a07a99801f..81c51d3de1e 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -217,6 +217,10 @@ def test_only_starargs(): args = (arg1, arg2, "safe") # $ arg1 arg2 func=starargs_only starargs_only(*args) + args = (arg1, arg2) # $ arg1 arg2 func=starargs_only + more_args = (arg3, arg4) + starargs_only(*args, *more_args) + def starargs_mixed(a, *args): SINK1(a) From 41ebb4fb555c100993aa1234358b57926c8cfff6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 20 Jan 2023 16:40:39 +0100 Subject: [PATCH 117/415] Python: Add `p2` in QLDoc example code for synthetic **kwargs --- .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 2de56d73e8d..3daf64294de 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -233,9 +233,9 @@ private predicate dictSplatParameterNodeClearStep(ParameterNode n, DictionaryEle * and a read step to the `p1` parameter. * * ```py - * def foo(p1): ... + * def foo(p1, p2): ... * - * kwargs = {"p1": 42} + * kwargs = {"p1": 42, "p2": 43} * foo(**kwargs) * ``` * From 25a68c4d71fd55182beb8e95963168dcfae98841 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 20 Jan 2023 16:49:33 +0100 Subject: [PATCH 118/415] Python: Include @yoff's suggestion on synthetic *args handling --- .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 3daf64294de..ddccd0cccfc 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -96,6 +96,12 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { * nodes. My gut feeling at that this simple approach will be good enough, but if we need to get it more * precise, it should be possible to do it like this. * + * In PR review, @yoff suggested an alternative approach for more precise handling: + * + * - At the call site, all positional arguments are stored into a synthetic starArgs argument, always tarting at index 0 + * - This is sent to a synthetic star parameter + * - At the receiving end, we know the offset of a potential real star parameter, so we can define read steps accordingly: In foo, we read from the synthetic star parameter at index 1 and store to the real star parameter at index 0. + * * ```py * def foo(one, *args): ... * def bar(*args): ... From 80324735bb6e9366a6b0dfcf7ee3373dcfc89a3f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 23 Jan 2023 11:31:23 +0100 Subject: [PATCH 119/415] Python: Fixup annotation for `CWE-022-PathInjection/pathlib_use.py` --- .../query-tests/Security/CWE-022-PathInjection/pathlib_use.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py index 4eb5909a61d..6f703f903dc 100644 --- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/pathlib_use.py @@ -11,7 +11,7 @@ STATIC_DIR = pathlib.Path("/server/static/") def path_injection(): filename = request.args.get('filename', '') p = STATIC_DIR / filename - p.open() # NOT OK + p.open() # $ result=BAD p2 = pathlib.Path(STATIC_DIR, filename) - p2.open() # NOT OK + p2.open() # $ result=BAD From 0879c8f8e1e59371e1a18f7fa33c12024dff8991 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 23 Jan 2023 14:24:57 +0100 Subject: [PATCH 120/415] Python: Expand comments on C3 MRO --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index ea7c5aab858..87601631557 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -679,6 +679,7 @@ Class getADirectSubclass(Class cls) { cls = getADirectSuperclass(result) } * For more info on the C3 MRO used in Python see: * - https://docs.python.org/3/glossary.html#term-method-resolution-order * - https://www.python.org/download/releases/2.3/mro/ + * - https://opendylan.org/_static/c3-linearization.pdf */ private Class getNextClassInMro(Class cls) { // class A(B, ...): @@ -693,13 +694,21 @@ private Class getNextClassInMro(Class cls) { sub.getBase(i + 1) = classTracker(result).asExpr() and not result = cls ) - // There are two important properties for MRO computed with C3 in Python: + // There are three important properties for MRO computed with C3 in Python: // // 1) monotonicity: if C1 precedes C2 in the MRO of C, then C1 precedes C2 in the MRO // of any subclass of C. // 2) local precedence ordering: if C1 precedes C2 in the list of superclasses for C, // they will keep the same order in the MRO for C (and due to monotonicity, any // subclass). + // 3) consistency with the extended precedence graph: if A and B (that are part of the + // class hierarchy of C) do not have a subclass/superclass relationship on their + // own, the ordering of A and B in the MRO of C will be determined by the local + // precedence ordering in the classes that use both A and B, either directly or + // through a subclass. (see paper for more details) + // + // Note that not all class hierarchies are allowed with C3, see the Python 2.3 article + // for examples. } /** From 63b2bd08715d4a0c9daeec7bd5b4bdb57fb37317 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 25 Jan 2023 09:32:37 +0100 Subject: [PATCH 121/415] Python: Fixup `test_only_starargs` addition validTest.py did not pass, since we use `SINK3_F`. I initially tried swapping the order ``` args = (arg1, arg2) # $ arg1 arg2 func=starargs_only more_args = (arg4, arg3) starargs_only(*args, *more_args) ``` But then asked myself, what is it _actually_ we're testing here? and it seems to be the way we handle multiple *args arguments in the same call, so I converted the test to be that instead! (and it matches what we do in test_stararg_mixed) --- .../experimental/dataflow/coverage/argumentPassing.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 81c51d3de1e..2f80571de7c 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -207,7 +207,7 @@ def starargs_only(*args): SINK2(args[1]) SINK3_F(args[2]) -@expects(3*3) +@expects(5*3) def test_only_starargs(): starargs_only(arg1, arg2, "safe") # $ arg1 arg2 SPURIOUS: bad2,bad3="arg1" bad1,bad3="arg2" @@ -217,9 +217,12 @@ def test_only_starargs(): args = (arg1, arg2, "safe") # $ arg1 arg2 func=starargs_only starargs_only(*args) - args = (arg1, arg2) # $ arg1 arg2 func=starargs_only - more_args = (arg3, arg4) - starargs_only(*args, *more_args) + empty_args = () + + args = (arg1, arg2, "safe") # $ arg1 arg2 func=starargs_only + starargs_only(*args, *empty_args) + args = (arg1, arg2, "safe") # $ MISSING: arg1 arg2 func=starargs_only + starargs_only(*empty_args, *args) def starargs_mixed(a, *args): From f262dc68f86cb984140bdba2665b25c9e1847e4d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 25 Jan 2023 10:07:41 +0100 Subject: [PATCH 122/415] Python: Reword note about debugging `getNextClassInMro` --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 87601631557..7bc4aa9f215 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -673,8 +673,9 @@ Class getADirectSubclass(Class cls) { cls = getADirectSuperclass(result) } * * NOTE for debugging the results of this predicate: Since a class can be part of * multiple MROs, results from this predicate might only be valid in some, but not all, - * inheritance chains (such as the result `C` for `cls=B` in the first example -- this - * might make it difficult to see if the definition of `D` is located in an other file) + * inheritance chains: This is the case with the result `C` for `cls=B` in the first + * example -- if `B` and `C` are defined in the same file, but `D` in a different file, + * this might make the results from this predicate difficult to comprehend at first. * * For more info on the C3 MRO used in Python see: * - https://docs.python.org/3/glossary.html#term-method-resolution-order From 10d6ebf95b5231c09440f401521376049c2325a6 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Wed, 25 Jan 2023 19:28:05 +0100 Subject: [PATCH 123/415] Use of inline tests for dataflow queries --- .../query-tests/Security/CWE-022/DataflowQueryTest.expected | 4 ++++ .../query-tests/Security/CWE-022/DataflowQueryTest.ql | 2 ++ .../experimental/query-tests/Security/CWE-022/UnsafeUnpack.py | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected new file mode 100644 index 00000000000..34c94194924 --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected @@ -0,0 +1,4 @@ +missingAnnotationOnSink +failures +| UnsafeUnpack.py:12:46:12:58 | Comment # $result=BAD | Missing result:result=BAD | +| UnsafeUnpack.py:55:53:55:65 | Comment # $result=BAD | Missing result:result=BAD | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql new file mode 100644 index 00000000000..29ccba982aa --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql @@ -0,0 +1,2 @@ +import python +import experimental.dataflow.TestUtil.DataflowQueryTest diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index c7820e52b04..b6015bed908 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -9,7 +9,7 @@ with open(tarpath, "wb") as f: f.write(response.raw.read()) untarredpath = "/tmp/tmp123" -shutil.unpack_archive(tarpath, untarredpath) +shutil.unpack_archive(tarpath, untarredpath) # $result=BAD import tempfile @@ -52,5 +52,5 @@ with tempfile.TemporaryDirectory() as temp_dir: ) fs.get(uri, to_path, recursive=True) if unpack_path: - shutil.unpack_archive(to_path, unpack_path) + shutil.unpack_archive(to_path, unpack_path) # $result=BAD to_path = unpack_path From 0ed480855a8b38dd573e29f6b8112fa4890fd4c9 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Wed, 25 Jan 2023 19:44:28 +0100 Subject: [PATCH 124/415] Update python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql Yes, definitely Co-authored-by: yoff --- python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 1ebdf48397c..2fdbc29dc43 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -69,8 +69,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // Writing the response data to the archive exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | is.flowsTo(f) and - mc.getMethodName() = "write" and - f = mc.getObject() and + mc.calls(f, "write") nodeFrom = mc.getArg(0) and nodeTo = is.(CallCfgNode).getArg(0) ) From 2d38993075a6a5a319b6e493b536f0647e15bf9b Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Wed, 25 Jan 2023 19:46:13 +0100 Subject: [PATCH 125/415] Add a missing "and" --- python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 2fdbc29dc43..6cb52a48994 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -69,7 +69,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // Writing the response data to the archive exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | is.flowsTo(f) and - mc.calls(f, "write") + mc.calls(f, "write") and nodeFrom = mc.getArg(0) and nodeTo = is.(CallCfgNode).getArg(0) ) From 22af6f518272f6e9883bbbc5af3cc1b7dd25c3d1 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Wed, 25 Jan 2023 23:00:00 +0100 Subject: [PATCH 126/415] Restrict download_file() to boto3 lib --- .../Security/CWE-022bis/UnsafeUnpack.ql | 10 ++++++++-- .../query-tests/Security/CWE-022/UnsafeUnpack.py | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 6cb52a48994..965392856c5 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -36,8 +36,14 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { source.(AttrRead).accesses(o, any(string s)) ) or - // A source catching a S3 filename download - exists(API::Node s3 | source = s3.getMember("download_file").getACall().getArg(2)) + // A source catching an S3 filename download + // see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file + exists(MethodCallNode mcn, Node s3, Node bc | + bc = API::moduleImport("boto3").getMember("client").getACall() and + bc = s3.getALocalSource() and + mcn.calls(s3, "download_file") and + source = mcn.getArg(2) + ) or // A source download a file using wget exists(MethodCallNode mcn | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index b6015bed908..13c3a32cd5a 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -54,3 +54,17 @@ with tempfile.TemporaryDirectory() as temp_dir: if unpack_path: shutil.unpack_archive(to_path, unpack_path) # $result=BAD to_path = unpack_path + + +# A source catching an S3 filename download +# see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file +import boto3 + +remote_ziped_name = "remote_name.tar.gz" +base_dir = "/tmp/basedir" +local_ziped_path = os.path.join(base_dir, remote_ziped_name) +bucket_name = "mybucket" + +s3 = boto3.client('s3') +s3.download_file(bucket_name, remote_ziped_name, local_ziped_path) +shutil.unpack_archive(local_ziped_path, base_dir) # $result=BAD \ No newline at end of file From 9b5b0c60b83fcf112dc0e5778d2ead8c77c86bbc Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 00:02:20 +0100 Subject: [PATCH 127/415] Handle the download of a tarball using wget pkg. --- .../Security/CWE-022bis/UnsafeUnpack.ql | 10 +++++++-- .../Security/CWE-022/UnsafeUnpack.py | 21 ++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 965392856c5..d9c5ffd6f76 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -46,8 +46,14 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { ) or // A source download a file using wget - exists(MethodCallNode mcn | - mcn = API::moduleImport("wget").getMember("download").getACall() and source = mcn.getArg(1) + // see wget: https://pypi.org/project/wget/ + exists(API::CallNode mcn | + mcn = API::moduleImport("wget").getMember("download").getACall() and + ( + source = mcn.getArg(1) + or + source = mcn.getReturn().asSource() and not exists(Node arg | arg = mcn.getArg(1)) + ) ) or // catch the uploaded files as a source diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index 13c3a32cd5a..8386f2770b5 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -59,6 +59,7 @@ with tempfile.TemporaryDirectory() as temp_dir: # A source catching an S3 filename download # see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file import boto3 +import os remote_ziped_name = "remote_name.tar.gz" base_dir = "/tmp/basedir" @@ -67,4 +68,22 @@ bucket_name = "mybucket" s3 = boto3.client('s3') s3.download_file(bucket_name, remote_ziped_name, local_ziped_path) -shutil.unpack_archive(local_ziped_path, base_dir) # $result=BAD \ No newline at end of file +shutil.unpack_archive(local_ziped_path, base_dir) # $result=BAD + + +# wget +# see wget: https://pypi.org/project/wget/ +import wget +import os + +url = "https://some.remote/location/remote_name.tar.xz" +compressed_file = "/tmp/basedir/local_name.tar.xz" +base_dir = "/tmp/basedir" + +# download(url, out, bar) contains out parameter +wget.download(url, compressed_file) +shutil.unpack_archive(compressed_file, base_dir) # $result=BAD + +# download(url) returns filename +compressed_file = wget.download(url) +shutil.unpack_archive(compressed_file, base_dir) # $result=BAD From f867c9008fdd5c4d03331b581bf8594149291d30 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 00:08:54 +0100 Subject: [PATCH 128/415] Commit the expected results --- .../Security/CWE-022/DataflowQueryTest.expected | 3 +++ .../Security/CWE-022/UnsafeUnpack.expected | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected index 34c94194924..99e42e4cccb 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected @@ -2,3 +2,6 @@ missingAnnotationOnSink failures | UnsafeUnpack.py:12:46:12:58 | Comment # $result=BAD | Missing result:result=BAD | | UnsafeUnpack.py:55:53:55:65 | Comment # $result=BAD | Missing result:result=BAD | +| UnsafeUnpack.py:71:51:71:63 | Comment # $result=BAD | Missing result:result=BAD | +| UnsafeUnpack.py:85:50:85:62 | Comment # $result=BAD | Missing result:result=BAD | +| UnsafeUnpack.py:89:50:89:62 | Comment # $result=BAD | Missing result:result=BAD | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected index b1e93bf3ab2..78214a634b9 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -2,13 +2,25 @@ edges | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | | UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | +| UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | nodes | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | | UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | semmle.label | ControlFlowNode for to_path | +| UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | subpaths #select | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | From 2e4cb63049307e68d6228969c7fefe682effedaa Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 01:00:01 +0100 Subject: [PATCH 129/415] Optimize the Argparse filename as a source. --- .../Security/CWE-022bis/UnsafeUnpack.ql | 17 +++++++++++------ .../Security/CWE-022/UnsafeUnpack.py | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index d9c5ffd6f76..052ca3e5d98 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -28,12 +28,17 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // A source coming from a remote location exists(Http::Client::Request request | source = request) or - //A source coming from a CLI argparse module - exists(Node o, API::Node ap, MethodCallNode args | - ap = API::moduleImport("argparse").getMember("ArgumentParser").getACall().getReturn() and - args = ap.getMember("parse_args").getACall() and - args.flowsTo(o) and - source.(AttrRead).accesses(o, any(string s)) + // A source coming from a CLI argparse module + // see argparse: https://docs.python.org/3/library/argparse.html + exists(MethodCallNode args | + args = source.(AttrRead).getObject().getALocalSource() and + args = + API::moduleImport("argparse") + .getMember("ArgumentParser") + .getACall() + .getReturn() + .getMember("parse_args") + .getACall() ) or // A source catching an S3 filename download diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index 8386f2770b5..eb0ac597a1a 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -87,3 +87,17 @@ shutil.unpack_archive(compressed_file, base_dir) # $result=BAD # download(url) returns filename compressed_file = wget.download(url) shutil.unpack_archive(compressed_file, base_dir) # $result=BAD + + +# A source coming from a CLI argparse module +# see argparse: https://docs.python.org/3/library/argparse.html +import argparse + +parser = argparse.ArgumentParser(description='Process some integers.') +parser.add_argument('integers', metavar='N', type=int, nargs='+', + help='an integer for the accumulator') +parser.add_argument('filename', help='filename to be provided') + +args = parser.parse_args() +compressed_file = args.filename +shutil.unpack_archive(compressed_file, base_dir) # $result=BAD \ No newline at end of file From 9464940214d59899cc16b61cdb4eaed629010fbf Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 01:00:19 +0100 Subject: [PATCH 130/415] Add expected results for argparse source --- .../query-tests/Security/CWE-022/DataflowQueryTest.expected | 1 + .../query-tests/Security/CWE-022/UnsafeUnpack.expected | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected index 99e42e4cccb..ae1beb23a86 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected @@ -5,3 +5,4 @@ failures | UnsafeUnpack.py:71:51:71:63 | Comment # $result=BAD | Missing result:result=BAD | | UnsafeUnpack.py:85:50:85:62 | Comment # $result=BAD | Missing result:result=BAD | | UnsafeUnpack.py:89:50:89:62 | Comment # $result=BAD | Missing result:result=BAD | +| UnsafeUnpack.py:103:50:103:62 | Comment # $result=BAD | Missing result:result=BAD | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected index 78214a634b9..a2eff1ddd1d 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -5,6 +5,7 @@ edges | UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | | UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | | UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:102:19:102:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | nodes | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | @@ -17,6 +18,8 @@ nodes | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | | UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:102:19:102:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | subpaths #select | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | @@ -24,3 +27,4 @@ subpaths | UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:102:19:102:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | From aaa004061252b19ef77c6084652dbc2bd4ca487c Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 08:53:47 +0100 Subject: [PATCH 131/415] Seperate the dataflow config from the query --- .../Security/CWE-022bis/UnsafeUnpack.ql | 132 +---------------- .../Security/CWE-022bis/UnsafeUnpackQuery.qll | 137 ++++++++++++++++++ .../CWE-022/DataflowQueryTest.expected | 6 - .../Security/CWE-022/DataflowQueryTest.ql | 1 + 4 files changed, 140 insertions(+), 136 deletions(-) create mode 100644 python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 052ca3e5d98..1e17cb728ca 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -10,141 +10,13 @@ * @security-severity 7.5 * @precision high * @tags security + * experimental * external/cwe/cwe-022 */ import python -import semmle.python.Concepts -import semmle.python.dataflow.new.internal.DataFlowPublic -import semmle.python.ApiGraphs +import UnsafeUnpackQuery import DataFlow::PathGraph -import semmle.python.dataflow.new.TaintTracking -import semmle.python.frameworks.Stdlib - -class UnsafeUnpackingConfig extends TaintTracking::Configuration { - UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" } - - override predicate isSource(DataFlow::Node source) { - // A source coming from a remote location - exists(Http::Client::Request request | source = request) - or - // A source coming from a CLI argparse module - // see argparse: https://docs.python.org/3/library/argparse.html - exists(MethodCallNode args | - args = source.(AttrRead).getObject().getALocalSource() and - args = - API::moduleImport("argparse") - .getMember("ArgumentParser") - .getACall() - .getReturn() - .getMember("parse_args") - .getACall() - ) - or - // A source catching an S3 filename download - // see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file - exists(MethodCallNode mcn, Node s3, Node bc | - bc = API::moduleImport("boto3").getMember("client").getACall() and - bc = s3.getALocalSource() and - mcn.calls(s3, "download_file") and - source = mcn.getArg(2) - ) - or - // A source download a file using wget - // see wget: https://pypi.org/project/wget/ - exists(API::CallNode mcn | - mcn = API::moduleImport("wget").getMember("download").getACall() and - ( - source = mcn.getArg(1) - or - source = mcn.getReturn().asSource() and not exists(Node arg | arg = mcn.getArg(1)) - ) - ) - or - // catch the uploaded files as a source - exists(Subscript s, Attribute at | - at = s.getObject() and at.getAttr() = "FILES" and source.asExpr() = s - ) - or - exists(Node obj, AttrRead ar | - ar.getAMethodCall("get").flowsTo(source) and - ar.accesses(obj, "FILES") - ) - or - exists(Node obj, AttrRead ar | - ar.getAMethodCall("getlist").flowsTo(source) and - ar.accesses(obj, "FILES") - ) - } - - override predicate isSink(DataFlow::Node sink) { - // A sink capturing method calls to `unpack_archive`. - sink = API::moduleImport("shutil").getMember("unpack_archive").getACall().getArg(0) - } - - override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Writing the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc.calls(f, "write") and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) - or - // Copying the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc = API::moduleImport("shutil").getMember("copyfileobj").getACall() and - f = mc.getArg(1) and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) - or - // Reading the response - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and - mc.getMethodName() = "read" and - mc.flowsTo(nodeTo) - ) - or - // Accessing the name or raw content - exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) - or - //Use of join of filename - exists(API::CallNode mcn | - mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and - nodeFrom = mcn.getArg(1) and - mcn.flowsTo(nodeTo) - ) - or - // Read by chunks - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) - ) - or - // Considering the use of closing() - exists(API::CallNode closing | - closing = API::moduleImport("contextlib").getMember("closing").getACall() and - closing.flowsTo(nodeTo) and - nodeFrom = closing.getArg(0) - ) - or - // Considering the use of "fs" - exists(API::CallNode fs, MethodCallNode mcn | - fs = - API::moduleImport("django") - .getMember("core") - .getMember("files") - .getMember("storage") - .getMember("FileSystemStorage") - .getACall() and - fs.flowsTo(mcn.getObject()) and - mcn.getMethodName() = ["save", "path"] and - nodeFrom = mcn.getArg(0) and - nodeTo = mcn - ) - } -} from UnsafeUnpackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink where config.hasFlowPath(source, sink) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll new file mode 100644 index 00000000000..5794d9e32f2 --- /dev/null +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll @@ -0,0 +1,137 @@ +/** + * + * Provides a taint-tracking configuration for detecting "UnsafeUnpacking" vulnerabilities. + * + */ + +import python +import semmle.python.Concepts +import semmle.python.dataflow.new.internal.DataFlowPublic +import semmle.python.ApiGraphs +import semmle.python.dataflow.new.TaintTracking +import semmle.python.frameworks.Stdlib + +class UnsafeUnpackingConfig extends TaintTracking::Configuration { + UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" } + + override predicate isSource(DataFlow::Node source) { + // A source coming from a remote location + exists(Http::Client::Request request | source = request) + or + // A source coming from a CLI argparse module + // see argparse: https://docs.python.org/3/library/argparse.html + exists(MethodCallNode args | + args = source.(AttrRead).getObject().getALocalSource() and + args = + API::moduleImport("argparse") + .getMember("ArgumentParser") + .getACall() + .getReturn() + .getMember("parse_args") + .getACall() + ) + or + // A source catching an S3 filename download + // see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file + exists(MethodCallNode mcn, Node s3, Node bc | + bc = API::moduleImport("boto3").getMember("client").getACall() and + bc = s3.getALocalSource() and + mcn.calls(s3, "download_file") and + source = mcn.getArg(2) + ) + or + // A source download a file using wget + // see wget: https://pypi.org/project/wget/ + exists(API::CallNode mcn | + mcn = API::moduleImport("wget").getMember("download").getACall() and + ( + source = mcn.getArg(1) + or + source = mcn.getReturn().asSource() and not exists(Node arg | arg = mcn.getArg(1)) + ) + ) + or + // catch the uploaded files as a source + exists(Subscript s, Attribute at | + at = s.getObject() and at.getAttr() = "FILES" and source.asExpr() = s + ) + or + exists(Node obj, AttrRead ar | + ar.getAMethodCall("get").flowsTo(source) and + ar.accesses(obj, "FILES") + ) + or + exists(Node obj, AttrRead ar | + ar.getAMethodCall("getlist").flowsTo(source) and + ar.accesses(obj, "FILES") + ) + } + + override predicate isSink(DataFlow::Node sink) { + // A sink capturing method calls to `unpack_archive`. + sink = API::moduleImport("shutil").getMember("unpack_archive").getACall().getArg(0) + } + + override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Writing the response data to the archive + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc.calls(f, "write") and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) + or + // Copying the response data to the archive + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc = API::moduleImport("shutil").getMember("copyfileobj").getACall() and + f = mc.getArg(1) and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) + or + // Reading the response + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and + mc.getMethodName() = "read" and + mc.flowsTo(nodeTo) + ) + or + // Accessing the name or raw content + exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) + or + //Use of join of filename + exists(API::CallNode mcn | + mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and + nodeFrom = mcn.getArg(1) and + mcn.flowsTo(nodeTo) + ) + or + // Read by chunks + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) + ) + or + // Considering the use of closing() + exists(API::CallNode closing | + closing = API::moduleImport("contextlib").getMember("closing").getACall() and + closing.flowsTo(nodeTo) and + nodeFrom = closing.getArg(0) + ) + or + // Considering the use of "fs" + exists(API::CallNode fs, MethodCallNode mcn | + fs = + API::moduleImport("django") + .getMember("core") + .getMember("files") + .getMember("storage") + .getMember("FileSystemStorage") + .getACall() and + fs.flowsTo(mcn.getObject()) and + mcn.getMethodName() = ["save", "path"] and + nodeFrom = mcn.getArg(0) and + nodeTo = mcn + ) + } +} diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected index ae1beb23a86..3875da4e143 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected @@ -1,8 +1,2 @@ missingAnnotationOnSink failures -| UnsafeUnpack.py:12:46:12:58 | Comment # $result=BAD | Missing result:result=BAD | -| UnsafeUnpack.py:55:53:55:65 | Comment # $result=BAD | Missing result:result=BAD | -| UnsafeUnpack.py:71:51:71:63 | Comment # $result=BAD | Missing result:result=BAD | -| UnsafeUnpack.py:85:50:85:62 | Comment # $result=BAD | Missing result:result=BAD | -| UnsafeUnpack.py:89:50:89:62 | Comment # $result=BAD | Missing result:result=BAD | -| UnsafeUnpack.py:103:50:103:62 | Comment # $result=BAD | Missing result:result=BAD | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql index 29ccba982aa..e3cd5f784ff 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql @@ -1,2 +1,3 @@ import python import experimental.dataflow.TestUtil.DataflowQueryTest +import UnsafeUnpackQuery \ No newline at end of file From 54cc4d6498d90a5b711a9eead2dca298ae860b64 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 12:51:55 +0100 Subject: [PATCH 132/415] Opt for any source from RemoteFlowSource. --- .../Security/CWE-022bis/UnsafeUnpackQuery.qll | 5 +- .../Security/CWE-022/UnsafeUnpack.expected | 62 +++++++------ .../Security/CWE-022/UnsafeUnpack.py | 91 ++++++++----------- 3 files changed, 76 insertions(+), 82 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll index 5794d9e32f2..c041b710ae0 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll @@ -1,7 +1,5 @@ /** - * * Provides a taint-tracking configuration for detecting "UnsafeUnpacking" vulnerabilities. - * */ import python @@ -10,13 +8,14 @@ import semmle.python.dataflow.new.internal.DataFlowPublic import semmle.python.ApiGraphs import semmle.python.dataflow.new.TaintTracking import semmle.python.frameworks.Stdlib +import semmle.python.dataflow.new.RemoteFlowSources class UnsafeUnpackingConfig extends TaintTracking::Configuration { UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" } override predicate isSource(DataFlow::Node source) { // A source coming from a remote location - exists(Http::Client::Request request | source = request) + source instanceof RemoteFlowSource or // A source coming from a CLI argparse module // see argparse: https://docs.python.org/3/library/argparse.html diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected index a2eff1ddd1d..cda42c13267 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -1,30 +1,40 @@ edges -| UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | -| UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | -| UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | -| UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:102:19:102:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | UnsafeUnpack.py:11:16:11:22 | ControlFlowNode for request | +| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | +| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | +| UnsafeUnpack.py:11:16:11:22 | ControlFlowNode for request | UnsafeUnpack.py:11:16:11:27 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:11:16:11:27 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:23:17:34 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:17:23:17:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | +| UnsafeUnpack.py:34:50:34:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:48:20:48:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:52:19:52:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:66:19:66:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:80:16:80:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:86:15:86:26 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:86:15:86:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | nodes -| UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:9:15:9:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | semmle.label | ControlFlowNode for to_path | -| UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:102:19:102:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | semmle.label | ModuleVariableNode for UnsafeUnpack.request | +| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | +| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | semmle.label | GSSA Variable request | +| UnsafeUnpack.py:11:16:11:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| UnsafeUnpack.py:11:16:11:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:17:23:17:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | +| UnsafeUnpack.py:34:50:34:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:48:20:48:34 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:52:19:52:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:66:19:66:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:80:16:80:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:86:15:86:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | subpaths #select -| UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:12:5:41 | ControlFlowNode for Attribute() | UnsafeUnpack.py:12:23:12:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | UnsafeUnpack.py:36:24:36:43 | ControlFlowNode for Attribute() | UnsafeUnpack.py:55:31:55:37 | ControlFlowNode for to_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:70:50:70:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:71:23:71:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:84:20:84:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:85:23:85:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:88:19:88:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:89:23:89:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:102:19:102:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:23:103:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:50:34:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:20:48:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:52:19:52:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:66:19:66:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:80:16:80:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index eb0ac597a1a..b2d23f2dbe0 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -1,60 +1,24 @@ import requests import shutil +import os -url = "https://www.someremote.location/tarball.tar.gz" -response = requests.get(url, stream=True) +from flask import Flask, request +app = Flask(__name__) -tarpath = "/tmp/tmp456/tarball.tar.gz" -with open(tarpath, "wb") as f: - f.write(response.raw.read()) - -untarredpath = "/tmp/tmp123" -shutil.unpack_archive(tarpath, untarredpath) # $result=BAD - - -import tempfile -import os -from urllib import request -import contextlib -import shutil - -unpack = True -to_path = "/tmp/tmp123" -uri = "https://www.goog.com/zzz.tar.gz" -scheme = "https" - -with tempfile.TemporaryDirectory() as temp_dir: - if unpack and (str(uri).endswith("zip") or str(uri).endswith("tar.gz")): - unpack_path = to_path - to_path = temp_dir - else: - unpack_path = None - if scheme in ["http", "https", "ftp"]: - if os.path.isdir(to_path): - to_path = os.path.join(to_path, os.path.basename(uri)) - url = uri - url_response = request.urlopen(url) - with contextlib.closing(url_response) as fp: - with open(to_path, "wb") as out_file: - block_size = DEFAULT_BUFFER_SIZE * 8 - while True: - block = fp.read(block_size) - if not block: - break - out_file.write(block) - else: - if scheme == "oci" and not storage_options: - storage_options = default_signer() - fs = fsspec.filesystem(scheme, **storage_options) - if os.path.isdir(to_path): - to_path = os.path.join( - to_path, os.path.basename(str(uri).rstrip("/")) - ) - fs.get(uri, to_path, recursive=True) - if unpack_path: - shutil.unpack_archive(to_path, unpack_path) # $result=BAD - to_path = unpack_path +# Consider any RemoteFlowSource as a source +@app.route("/download_from_url") +def download_from_url(): + filename = request.args.get('filename', '') + if not filename: + response = requests.get(filename, stream=True) + + tarpath = "/tmp/tmp456/tarball.tar.gz" + with open(tarpath, "wb") as f: + f.write(response.raw.read()) + untarredpath = "/tmp/tmp123" + shutil.unpack_archive(tarpath, untarredpath) # $result=BAD + # A source catching an S3 filename download # see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file @@ -100,4 +64,25 @@ parser.add_argument('filename', help='filename to be provided') args = parser.parse_args() compressed_file = args.filename -shutil.unpack_archive(compressed_file, base_dir) # $result=BAD \ No newline at end of file +shutil.unpack_archive(compressed_file, base_dir) # $result=BAD + + +# A source coming from a CLI and downloaded +import argparse +import requests + +parser = argparse.ArgumentParser(description='Process some integers.') +parser.add_argument('integers', metavar='N', type=int, nargs='+', + help='an integer for the accumulator') +parser.add_argument('filename', help='url to filename to be provided') + +args = parser.parse_args() +url_filename = args.filename + +response = requests.get(url_filename, stream=True) + +tarpath = "/tmp/tmp456/tarball.tar.gz" +with open(tarpath, "wb") as f: + f.write(response.raw.read()) + +shutil.unpack_archive(tarpath, base_dir) # $result=BAD \ No newline at end of file From 51b11de44a24926449543f837d9d1ef8c91408b9 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 15:16:24 +0100 Subject: [PATCH 133/415] Add a Django Upload examples --- .../Security/CWE-022bis/UnsafeUnpackQuery.qll | 25 ++++++++---- .../Security/CWE-022/UnsafeUnpack.py | 40 ++++++++++++++++++- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll index c041b710ae0..29c41b74dab 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll @@ -55,13 +55,10 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { at = s.getObject() and at.getAttr() = "FILES" and source.asExpr() = s ) or + // Retrieve Django uploaded files + // see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES exists(Node obj, AttrRead ar | - ar.getAMethodCall("get").flowsTo(source) and - ar.accesses(obj, "FILES") - ) - or - exists(Node obj, AttrRead ar | - ar.getAMethodCall("getlist").flowsTo(source) and + ar.getAMethodCall(["getlist", "get"]).flowsTo(source) and ar.accesses(obj, "FILES") ) } @@ -93,7 +90,21 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { exists(MethodCallNode mc | nodeFrom = mc.getObject() and mc.getMethodName() = "read" and - mc.flowsTo(nodeTo) + nodeTo = mc + ) + or + // Open for access + exists(MethodCallNode cn | + nodeTo = cn.getObject() and + cn.getMethodName() = "open" and + cn.flowsTo(nodeFrom) + ) + or + // Write for access + exists(MethodCallNode cn | + nodeTo = cn.getObject() and + cn.getMethodName() = "write" and + nodeFrom = cn.getArg(0) ) or // Accessing the name or raw content diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index b2d23f2dbe0..fe1b6fa6d45 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -85,4 +85,42 @@ tarpath = "/tmp/tmp456/tarball.tar.gz" with open(tarpath, "wb") as f: f.write(response.raw.read()) -shutil.unpack_archive(tarpath, base_dir) # $result=BAD \ No newline at end of file +shutil.unpack_archive(tarpath, base_dir) # $result=BAD + +# the django upload functionality +# see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES +from django.shortcuts import render +from django.core.files.storage import FileSystemStorage +import shutil + +def simple_upload(request): + + base_dir = "/tmp/baase_dir" + if request.method == 'POST': + # Read uploaded files by chunks of data + # see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks + savepath = os.path.join(base_dir, "tarball_compressed.tar.gz") + with open(savepath, 'wb+') as wfile: + for chunk in request.FILES["ufile1"].chunks(): + wfile.write(chunk) + shutil.unpack_archive(savepath, base_dir) # $result=BAD + + # Write in binary the uploaded tarball + myfile = request.FILES.get("ufile1") + file_path = os.path.join(base_dir, "tarball.tar") + with file_path.open('wb') as f: + f.write(myfile.read()) + shutil.unpack_archive(file_path, base_dir) # $result=BAD + + # Save uploaded files using FileSystemStorage Django API + # see FileSystemStorage: https://docs.djangoproject.com/en/4.1/ref/files/storage/#django.core.files.storage.FileSystemStorage + for ufile in request.FILES.getlist(): + fs = FileSystemStorage() + filename = fs.save(ufile.name, ufile) + uploaded_file_path = fs.path(filename) + shutil.unpack_archive(uploaded_file_path, base_dir) # $result=BAD + + return render(request, 'simple_upload.html') + + elif request.method == 'GET': + return render(request, 'simple_upload.html') \ No newline at end of file From 1a211485a47c814f461ccfb8488b3a1626e2a845 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 17:07:59 +0100 Subject: [PATCH 134/415] Restrain the source and add two steps. --- .../Security/CWE-022bis/UnsafeUnpackQuery.qll | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll index 29c41b74dab..7409d30fdfa 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll @@ -50,17 +50,9 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { ) ) or - // catch the uploaded files as a source - exists(Subscript s, Attribute at | - at = s.getObject() and at.getAttr() = "FILES" and source.asExpr() = s - ) - or - // Retrieve Django uploaded files + // catch the Django uploaded files as a source // see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES - exists(Node obj, AttrRead ar | - ar.getAMethodCall(["getlist", "get"]).flowsTo(source) and - ar.accesses(obj, "FILES") - ) + source.(AttrRead).getAttributeName() = "FILES" } override predicate isSink(DataFlow::Node sink) { @@ -107,6 +99,12 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeFrom = cn.getArg(0) ) or + // Retrieve Django uploaded files + // see HttpRequest.FILES.getlist(): https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.QueryDict.getlist + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and mc.getMethodName() = ["getlist", "get"] and nodeTo = mc + ) + or // Accessing the name or raw content exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) or From 998f1bf215ea357943baf702bc98d5efce68ddb8 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 26 Jan 2023 18:54:36 +0100 Subject: [PATCH 135/415] Some reformatting --- .../Security/CWE-022bis/UnsafeUnpackQuery.qll | 71 +++++++++---------- .../Security/CWE-022/UnsafeUnpack.py | 17 +++-- 2 files changed, 40 insertions(+), 48 deletions(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll index 7409d30fdfa..4e7e97188c0 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll @@ -61,23 +61,6 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Writing the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc.calls(f, "write") and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) - or - // Copying the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc = API::moduleImport("shutil").getMember("copyfileobj").getACall() and - f = mc.getArg(1) and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) - or // Reading the response exists(MethodCallNode mc | nodeFrom = mc.getObject() and @@ -94,39 +77,22 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { or // Write for access exists(MethodCallNode cn | - nodeTo = cn.getObject() and + nodeFrom = cn.getObject() and cn.getMethodName() = "write" and - nodeFrom = cn.getArg(0) + nodeTo = cn.getArg(0) ) or // Retrieve Django uploaded files // see HttpRequest.FILES.getlist(): https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.QueryDict.getlist exists(MethodCallNode mc | - nodeFrom = mc.getObject() and mc.getMethodName() = ["getlist", "get"] and nodeTo = mc + nodeFrom = mc.getObject() and + mc.getMethodName() = ["getlist", "get"] and + nodeTo = mc ) or // Accessing the name or raw content exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) or - //Use of join of filename - exists(API::CallNode mcn | - mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and - nodeFrom = mcn.getArg(1) and - mcn.flowsTo(nodeTo) - ) - or - // Read by chunks - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) - ) - or - // Considering the use of closing() - exists(API::CallNode closing | - closing = API::moduleImport("contextlib").getMember("closing").getACall() and - closing.flowsTo(nodeTo) and - nodeFrom = closing.getArg(0) - ) - or // Considering the use of "fs" exists(API::CallNode fs, MethodCallNode mcn | fs = @@ -141,5 +107,32 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeFrom = mcn.getArg(0) and nodeTo = mcn ) + or + //Use of join of filename + exists(API::CallNode mcn | + mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and + nodeFrom = mcn.getArg(1) and + mcn.flowsTo(nodeTo) + ) + or + // Read by chunks + exists(MethodCallNode mc | + nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) + ) + or + // Write access + exists(MethodCallNode cn | + nodeTo = cn.getObject() and + cn.getMethodName() = "write" and + nodeFrom = cn.getArg(0) + ) + or + // Writing the response data to the archive + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc.calls(f, "write") and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) } } diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index fe1b6fa6d45..ae9ee055999 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -8,16 +8,15 @@ app = Flask(__name__) # Consider any RemoteFlowSource as a source @app.route("/download_from_url") def download_from_url(): - filename = request.args.get('filename', '') - if not filename: - response = requests.get(filename, stream=True) - - tarpath = "/tmp/tmp456/tarball.tar.gz" - with open(tarpath, "wb") as f: - f.write(response.raw.read()) + filename = request.args.get('filename', '') + if not filename: + response = requests.get(filename, stream=True) - untarredpath = "/tmp/tmp123" - shutil.unpack_archive(tarpath, untarredpath) # $result=BAD + tarpath = "/tmp/tmp456/tarball.tar.gz" + with open(tarpath, "wb") as f: + f.write(response.raw.read()) + untarredpath = "/tmp/tmp123" + shutil.unpack_archive(tarpath, untarredpath) # $result=BAD # A source catching an S3 filename download From 02b3a1b51597222b4e08ec0befd5ecfce36fc397 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 27 Jan 2023 11:10:02 +0100 Subject: [PATCH 136/415] Python: At most one `**kwargs` `ParameterNode` per callable Similar to the Ruby changes from https://github.com/github/codeql/pull/11461 I feel the change to `DataFlowFunciton.getParameter` where we use `not exists(func.getArgByName(_))` is not very great, but I was not allowed to use `not exists(this.getParameter(any(ParameterPosition _).isKeyword(_)))` because of negative recursion. --- .../new/internal/DataFlowDispatch.qll | 31 ++++++++++++++--- .../dataflow/new/internal/DataFlowPrivate.qll | 34 +++++++++++++++++-- .../consistency/dataflow-consistency.expected | 2 -- .../coverage/dataflow-consistency.expected | 10 ------ 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 7bc4aa9f215..a73be967534 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -321,6 +321,7 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { or exists(string name | ppos.isKeyword(name) | result.getParameter() = func.getArgByName(name)) or + // `*args` exists(int index | ( ppos.isStarArgs(index) and @@ -343,9 +344,22 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { not exists(func.getArg(_)) and index = 0 ) or - ppos.isDictSplat() and result.getParameter() = func.getKwarg() - or - ppos.isDictSplat() and result = TSynthDictSplatParameterNode(this) + // `**kwargs` + // since dataflow library has restriction that we can only have ONE result per + // parameter position, if there is both a synthetic **kwargs and a real **kwargs + // parameter, we only give the result for the synthetic, and add local flow from the + // synthetic to the real. It might seem more natural to do it in the other + // direction, but since we have a clearStep on the real **kwargs parameter, we that + // content-clearing would also affect the synthetic parameter, which we don't want. + ( + not exists(func.getArgByName(_)) and + ppos.isDictSplat() and + result.getParameter() = func.getKwarg() + or + exists(func.getArgByName(_)) and + ppos.isDictSplat() and + result = TSynthDictSplatParameterNode(this) + ) } } @@ -1400,7 +1414,16 @@ class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode { override Parameter getParameter() { none() } override predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos) { - sc = c.asLibraryCallable() and ppos = pos + sc = c.asLibraryCallable() and + ppos = pos and + // avoid overlap with `SynthDictSplatParameterNode` + not ( + pos.isDictSplat() and + exists(ParameterPosition keywordPos | + FlowSummaryImpl::Private::summaryParameterNodeRange(sc, keywordPos) and + keywordPos.isKeyword(_) + ) + ) } override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = sc } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index ddccd0cccfc..e21594c8385 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -224,8 +224,11 @@ private predicate synthDictSplatArgumentNodeStoreStep( private predicate dictSplatParameterNodeClearStep(ParameterNode n, DictionaryElementContent c) { exists(DataFlowCallable callable, ParameterPosition dictSplatPos, ParameterPosition keywordPos | dictSplatPos.isDictSplat() and - n = callable.getParameter(dictSplatPos) and - not n instanceof SynthDictSplatParameterNode and + ( + n.getParameter() = callable.(DataFlowFunction).getScope().getKwarg() + or + n = TSummaryParameterNode(callable.asLibraryCallable(), dictSplatPos) + ) and exists(callable.getParameter(keywordPos)) and keywordPos.isKeyword(c.getKey()) ) @@ -276,6 +279,31 @@ class SynthDictSplatParameterNode extends ParameterNodeImpl, TSynthDictSplatPara override Parameter getParameter() { none() } } +/** + * Flow step from the synthetic `**kwargs` parameter to the real `**kwargs` parameter. + * Due to restriction in dataflow library, we can only give one of them as result for + * `DataFlowCallable.getParameter`, so this is a workaround to ensure there is flow to + * _both_ of them. + */ +private predicate dictSplatParameterNodeFlowStep( + ParameterNodeImpl nodeFrom, ParameterNodeImpl nodeTo +) { + exists(DataFlowCallable callable | + nodeFrom = TSynthDictSplatParameterNode(callable) and + ( + nodeTo.getParameter() = callable.(DataFlowFunction).getScope().getKwarg() + or + exists(ParameterPosition pos | + nodeTo = TSummaryParameterNode(callable.asLibraryCallable(), pos) and + pos.isDictSplat() + ) + ) + ) +} + +/** + * Reads from the synthetic **kwargs parameter to each keyword parameter. + */ predicate synthDictSplatParameterNodeReadStep( SynthDictSplatParameterNode nodeFrom, DictionaryElementContent c, ParameterNode nodeTo ) { @@ -418,6 +446,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStepForTypetracking(nodeFrom, nodeTo) or summaryFlowSteps(nodeFrom, nodeTo) + or + dictSplatParameterNodeFlowStep(nodeFrom, nodeTo) } /** diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index ab832392cf5..410b626ffff 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -20,7 +20,5 @@ argHasPostUpdate postWithInFlow viableImplInCallContextTooLarge uniqueParameterNodeAtPosition -| test.py:239:1:239:42 | Function overflowCallee | ** | test.py:239:1:239:42 | SynthDictSplatParameterNode | Parameters with overlapping positions. | -| test.py:239:1:239:42 | Function overflowCallee | ** | test.py:239:35:239:40 | ControlFlowNode for kwargs | Parameters with overlapping positions. | uniqueParameterNodePosition uniqueContentApprox diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected index 4ee8d7f0fcc..410b626ffff 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow-consistency.expected @@ -20,15 +20,5 @@ argHasPostUpdate postWithInFlow viableImplInCallContextTooLarge uniqueParameterNodeAtPosition -| argumentPassing.py:50:1:60:2 | Function argument_passing | ** | argumentPassing.py:50:1:60:2 | SynthDictSplatParameterNode | Parameters with overlapping positions. | -| argumentPassing.py:50:1:60:2 | Function argument_passing | ** | argumentPassing.py:59:7:59:7 | ControlFlowNode for g | Parameters with overlapping positions. | -| argumentPassing.py:185:1:185:23 | Function mixed | ** | argumentPassing.py:185:1:185:23 | SynthDictSplatParameterNode | Parameters with overlapping positions. | -| argumentPassing.py:185:1:185:23 | Function mixed | ** | argumentPassing.py:185:16:185:21 | ControlFlowNode for kwargs | Parameters with overlapping positions. | -| classes.py:441:5:441:41 | Function __prepare__ | ** | classes.py:441:5:441:41 | SynthDictSplatParameterNode | Parameters with overlapping positions. | -| classes.py:441:5:441:41 | Function __prepare__ | ** | classes.py:441:36:441:39 | ControlFlowNode for kwds | Parameters with overlapping positions. | -| test.py:407:1:407:28 | Function f_extra_keyword | ** | test.py:407:1:407:28 | SynthDictSplatParameterNode | Parameters with overlapping positions. | -| test.py:407:1:407:28 | Function f_extra_keyword | ** | test.py:407:26:407:26 | ControlFlowNode for b | Parameters with overlapping positions. | -| test.py:521:23:521:43 | Function lambda | ** | test.py:521:23:521:43 | SynthDictSplatParameterNode | Parameters with overlapping positions. | -| test.py:521:23:521:43 | Function lambda | ** | test.py:521:35:521:35 | ControlFlowNode for b | Parameters with overlapping positions. | uniqueParameterNodePosition uniqueContentApprox From bca053f85554cd0d21a55219740d275035c70f16 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 13:42:14 +0100 Subject: [PATCH 137/415] Move the config query to the parent directory --- .../experimental/Security/{CWE-022bis => }/UnsafeUnpackQuery.qll | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/ql/src/experimental/Security/{CWE-022bis => }/UnsafeUnpackQuery.qll (100%) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll similarity index 100% rename from python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpackQuery.qll rename to python/ql/src/experimental/Security/UnsafeUnpackQuery.qll From 5f0bf1053a3515faf16ec0ef033ab6b2511c97e6 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 13:42:57 +0100 Subject: [PATCH 138/415] Update the dataflow test query and the expected results --- .../Security/CWE-022/DataflowQueryTest.ql | 2 +- .../Security/CWE-022/UnsafeUnpack.expected | 45 +++---------------- 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql index e3cd5f784ff..df70ff9fe51 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql @@ -1,3 +1,3 @@ import python import experimental.dataflow.TestUtil.DataflowQueryTest -import UnsafeUnpackQuery \ No newline at end of file +import experimental.Security.UnsafeUnpackQuery \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected index cda42c13267..c07d7f1e245 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -1,40 +1,5 @@ -edges -| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | UnsafeUnpack.py:11:16:11:22 | ControlFlowNode for request | -| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | -| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | -| UnsafeUnpack.py:11:16:11:22 | ControlFlowNode for request | UnsafeUnpack.py:11:16:11:27 | ControlFlowNode for Attribute | -| UnsafeUnpack.py:11:16:11:27 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:23:17:34 | ControlFlowNode for Attribute | -| UnsafeUnpack.py:17:23:17:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | -| UnsafeUnpack.py:34:50:34:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:48:20:48:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:52:19:52:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:66:19:66:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:80:16:80:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:86:15:86:26 | ControlFlowNode for Attribute | -| UnsafeUnpack.py:86:15:86:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | -nodes -| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | semmle.label | ModuleVariableNode for UnsafeUnpack.request | -| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | -| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | semmle.label | GSSA Variable request | -| UnsafeUnpack.py:11:16:11:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | -| UnsafeUnpack.py:11:16:11:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:17:23:17:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -| UnsafeUnpack.py:34:50:34:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | -| UnsafeUnpack.py:48:20:48:34 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:52:19:52:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | -| UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:66:19:66:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | -| UnsafeUnpack.py:80:16:80:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:86:15:86:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | -subpaths -#select -| UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:20:31:20:37 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:50:34:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:35:23:35:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:20:48:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:49:23:49:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:52:19:52:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:53:23:53:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:66:19:66:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:67:23:67:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | -| UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:80:16:80:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:88:23:88:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +ERROR: Could not resolve module DataFlow (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:19,8-16) +ERROR: Could not resolve module DataFlow (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:21,36-44) +ERROR: Could not resolve module DataFlow (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:21,63-71) +ERROR: Could not resolve module UnsafeUnpackQuery (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:18,8-25) +ERROR: Could not resolve type UnsafeUnpackingConfig (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:21,6-27) From e41042418aad3922897caaaac0ecdb58da102e97 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 13:46:57 +0100 Subject: [PATCH 139/415] Update the import relative to the dataflow config --- python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 1e17cb728ca..41d46218ec6 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -15,7 +15,7 @@ */ import python -import UnsafeUnpackQuery +import experimental.Security.UnsafeUnpackQuery import DataFlow::PathGraph from UnsafeUnpackingConfig config, DataFlow::PathNode source, DataFlow::PathNode sink From 18d8bbc9a4f09be753ad93c8085f767d6f07755d Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 14:05:25 +0100 Subject: [PATCH 140/415] Updated the expected results accordingly --- .../Security/CWE-022/UnsafeUnpack.expected | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected index c07d7f1e245..eed5e0e45d7 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -1,5 +1,60 @@ -ERROR: Could not resolve module DataFlow (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:19,8-16) -ERROR: Could not resolve module DataFlow (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:21,36-44) -ERROR: Could not resolve module DataFlow (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:21,63-71) -ERROR: Could not resolve module UnsafeUnpackQuery (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:18,8-25) -ERROR: Could not resolve type UnsafeUnpackingConfig (/home/sim4n6/Desktop/Ghsecuritylab/my-codeql-PR-3/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql:21,6-27) +edges +| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | +| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | +| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | +| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | +| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | +| UnsafeUnpack.py:103:23:103:27 | SSA variable chunk | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | +| UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | +| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | UnsafeUnpack.py:103:23:103:27 | SSA variable chunk | +| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | +| UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | +| UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | +nodes +| UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | semmle.label | ModuleVariableNode for UnsafeUnpack.request | +| UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | +| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | semmle.label | GSSA Variable request | +| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request | +| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | +| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | semmle.label | ControlFlowNode for local_ziped_path | +| UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | semmle.label | ControlFlowNode for compressed_file | +| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | semmle.label | ControlFlowNode for tarpath | +| UnsafeUnpack.py:103:23:103:27 | SSA variable chunk | semmle.label | SSA variable chunk | +| UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | semmle.label | ControlFlowNode for savepath | +| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path | +| UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | semmle.label | SSA variable ufile | +| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | semmle.label | ControlFlowNode for uploaded_file_path | +subpaths +#select +| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:47:20:47:34 | ControlFlowNode for compressed_file | UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | From 207ed3da9c3c4aa52b03c34fcfc20eaaeda44f05 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 15:07:20 +0100 Subject: [PATCH 141/415] Constrain the object & the call --- .../Security/UnsafeUnpackQuery.qll | 39 ++++++------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 4e7e97188c0..182ef30f84b 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -61,13 +61,6 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Reading the response - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and - mc.getMethodName() = "read" and - nodeTo = mc - ) - or // Open for access exists(MethodCallNode cn | nodeTo = cn.getObject() and @@ -77,21 +70,20 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { or // Write for access exists(MethodCallNode cn | - nodeFrom = cn.getObject() and - cn.getMethodName() = "write" and + cn.calls(nodeFrom, "write") and nodeTo = cn.getArg(0) ) or // Retrieve Django uploaded files - // see HttpRequest.FILES.getlist(): https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.QueryDict.getlist - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and - mc.getMethodName() = ["getlist", "get"] and - nodeTo = mc - ) + // see getlist(): https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.QueryDict.getlist + // see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks + nodeTo.(MethodCallNode).calls(nodeFrom, ["getlist", "get", "chunks"]) + or + // Reading the response + nodeTo.(MethodCallNode).calls(nodeFrom, "read") or // Accessing the name or raw content - exists(AttrRead ar | ar.accesses(nodeFrom, ["name", "raw"]) and ar.flowsTo(nodeTo)) + nodeTo.(AttrRead).accesses(nodeFrom, ["name", "raw"]) or // Considering the use of "fs" exists(API::CallNode fs, MethodCallNode mcn | @@ -109,21 +101,12 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { ) or //Use of join of filename - exists(API::CallNode mcn | - mcn = API::moduleImport("os").getMember("path").getMember("join").getACall() and - nodeFrom = mcn.getArg(1) and - mcn.flowsTo(nodeTo) - ) - or - // Read by chunks - exists(MethodCallNode mc | - nodeFrom = mc.getObject() and mc.getMethodName() = "chunks" and mc.flowsTo(nodeTo) - ) + nodeTo = API::moduleImport("os").getMember("path").getMember("join").getACall() and + nodeFrom = nodeTo.(API::CallNode).getArg(1) or // Write access exists(MethodCallNode cn | - nodeTo = cn.getObject() and - cn.getMethodName() = "write" and + cn.calls(nodeTo, "write") and nodeFrom = cn.getArg(0) ) or From c099dbd04ce85cd9e4f1f3b1f5395d81448aa651 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 27 Jan 2023 15:27:45 +0100 Subject: [PATCH 142/415] Python: Expand notes around bound methods `self` argument passing --- .../new/internal/DataFlowDispatch.qll | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index a73be967534..9073686d4be 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1151,6 +1151,40 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { * * Note: If `Bar.meth` and `Foo.meth` resolves to the same function, we will end up * sending both `self` arguments to that function, which is by definition the right thing to do. + * + * ### Bound methods + * + * For bound methods, such as `bm = x.m; bm()`, it's a little unclear whether we should + * still use the object in the attribute lookup (`x.m`) as the self argument in the + * call (`bm()`). We currently do this, but there might also be cases where we don't + * want to do this. + * + * In the example below, we want to clear taint from the list before it reaches the + * sink, but because we don't have a use of `l` in the `clear()` call, we currently + * don't have any way to achieve our goal. (Note that this is a contrived example) + * + * ```py + * l = list() + * clear = l.clear + * l.append(tainted) + * clear() + * sink(l) + * ``` + * + * To make the above even worse, bound-methods have a `__self__` property that refers to + * the object of the bound-method, so we can re-write the code as: + * + * ```py + * l = list() + * clear = l.clear + * clear.__self__.append(tainted) + * clear() + * sink(l) + * ``` + * + * One idea to solve this is to track the object in a synthetic data-flow node every + * time the bound method is used, such that the `clear()` call would essentially be + * translated into `l.clear()`, and we can still have use-use flow. */ cached predicate getCallArg(CallNode call, Function target, CallType type, Node arg, ArgumentPosition apos) { @@ -1160,16 +1194,24 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar type instanceof CallTypePlainFunction and normalCallArg(call, arg, apos) or - // self argument for normal method calls + // self argument for normal method calls -- see note above about bound methods type instanceof CallTypeNormalMethod and apos.isSelf() and resolveMethodCall(call, target, type, arg) and - // dataflow lib has requirement that arguments and calls are in same enclosing callable. + // dataflow lib has requirement that arguments and calls are in same enclosing + // callable. This requirement would be broken if we used `my_obj` as the self + // argument in the `f()` call in the example below: + // ```py + // def call_func(f): + // f() + // + // call_func(my_obj.some_method) + // ``` exists(CfgNode cfgNode | cfgNode.getNode() = call | cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() ) or - // cls argument for classmethod calls + // cls argument for classmethod calls -- see ntoe above about bound methods type instanceof CallTypeClassMethod and apos.isSelf() and resolveMethodCall(call, target, type, arg) and From cef933f8139d847f63a7b12c476a3cad372ba8b4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 27 Jan 2023 15:48:59 +0100 Subject: [PATCH 143/415] Python: Add comment explaining `SINK3_F(kwargs["c"])` test Co-authored-by: yoff --- .../ql/test/experimental/dataflow/coverage/argumentPassing.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index 2f80571de7c..ecf4a0d201d 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -174,6 +174,7 @@ def test_kw_doublestar(): def only_kwargs(**kwargs): SINK1(kwargs["a"]) SINK2(kwargs["b"]) + # testing precise content tracking, that content from `a` or `b` does not end up here. SINK3_F(kwargs["c"]) @expects(3) @@ -189,6 +190,7 @@ def mixed(a, **kwargs): except KeyError: print("OK") SINK2(kwargs["b"]) + # testing precise content tracking, that content from `a` or `b` does not end up here. SINK3_F(kwargs["c"]) @expects(4*3) From 8ef2aa00e73814b6c84d40cee53b0a3afdb650c5 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 16:07:39 +0100 Subject: [PATCH 144/415] Update python/ql/src/experimental/Security/UnsafeUnpackQuery.qll Co-authored-by: yoff --- .../src/experimental/Security/UnsafeUnpackQuery.qll | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 182ef30f84b..c0a370fa9f4 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -32,12 +32,13 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { or // A source catching an S3 filename download // see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file - exists(MethodCallNode mcn, Node s3, Node bc | - bc = API::moduleImport("boto3").getMember("client").getACall() and - bc = s3.getALocalSource() and - mcn.calls(s3, "download_file") and - source = mcn.getArg(2) - ) + source = + API::moduleImport("boto3") + .getMember("client") + .getReturn() + .getMember("download_file") + .getACall() + .getArg(2) or // A source download a file using wget // see wget: https://pypi.org/project/wget/ From 0b27b1314af813607a9a4327eced1aeb46b78a04 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 16:12:08 +0100 Subject: [PATCH 145/415] Update python/ql/src/experimental/Security/UnsafeUnpackQuery.qll Co-authored-by: yoff --- python/ql/src/experimental/Security/UnsafeUnpackQuery.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index c0a370fa9f4..f660294cb59 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -24,7 +24,6 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { args = API::moduleImport("argparse") .getMember("ArgumentParser") - .getACall() .getReturn() .getMember("parse_args") .getACall() From ee213123ac76101840c0762b74973fe03c063e1a Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 18:16:11 +0100 Subject: [PATCH 146/415] Add builtin open as an additional step --- .../src/experimental/Security/UnsafeUnpackQuery.qll | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index f660294cb59..837f84ee21f 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -61,18 +61,15 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - // Open for access + // Open a file for access exists(MethodCallNode cn | nodeTo = cn.getObject() and cn.getMethodName() = "open" and cn.flowsTo(nodeFrom) ) or - // Write for access - exists(MethodCallNode cn | - cn.calls(nodeFrom, "write") and - nodeTo = cn.getArg(0) - ) + // Open a file for access using builtin + nodeFrom = API::builtin("open").getACall() and nodeTo = nodeFrom.(API::CallNode).getArg(0) or // Retrieve Django uploaded files // see getlist(): https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.QueryDict.getlist @@ -100,7 +97,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeTo = mcn ) or - //Use of join of filename + // Join the base_dir to the filename nodeTo = API::moduleImport("os").getMember("path").getMember("join").getACall() and nodeFrom = nodeTo.(API::CallNode).getArg(1) or From 0e2f37825ddd56e1dbdd3b131bc4a6e97821cd9c Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 27 Jan 2023 23:58:03 +0100 Subject: [PATCH 147/415] Organize steps to correspond to the sample code --- .../Security/UnsafeUnpackQuery.qll | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 837f84ee21f..bdac41e8812 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -61,6 +61,9 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // Reading the response + nodeTo.(MethodCallNode).calls(nodeFrom, "read") + or // Open a file for access exists(MethodCallNode cn | nodeTo = cn.getObject() and @@ -68,6 +71,12 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { cn.flowsTo(nodeFrom) ) or + // Write access + exists(MethodCallNode cn | + cn.calls(nodeTo, "write") and + nodeFrom = cn.getArg(0) + ) + or // Open a file for access using builtin nodeFrom = API::builtin("open").getACall() and nodeTo = nodeFrom.(API::CallNode).getArg(0) or @@ -76,11 +85,13 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks nodeTo.(MethodCallNode).calls(nodeFrom, ["getlist", "get", "chunks"]) or - // Reading the response - nodeTo.(MethodCallNode).calls(nodeFrom, "read") - or - // Accessing the name or raw content - nodeTo.(AttrRead).accesses(nodeFrom, ["name", "raw"]) + // Writing the response data to the archive + exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | + is.flowsTo(f) and + mc.calls(f, "write") and + nodeFrom = mc.getArg(0) and + nodeTo = is.(CallCfgNode).getArg(0) + ) or // Considering the use of "fs" exists(API::CallNode fs, MethodCallNode mcn | @@ -97,22 +108,11 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeTo = mcn ) or + // Accessing the name or raw content + nodeTo.(AttrRead).accesses(nodeFrom, ["name", "raw"]) + or // Join the base_dir to the filename nodeTo = API::moduleImport("os").getMember("path").getMember("join").getACall() and nodeFrom = nodeTo.(API::CallNode).getArg(1) - or - // Write access - exists(MethodCallNode cn | - cn.calls(nodeTo, "write") and - nodeFrom = cn.getArg(0) - ) - or - // Writing the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc.calls(f, "write") and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) } } From a4aaf0ec6f9ed100ef1966a37cc65c5fc62553a9 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Sat, 28 Jan 2023 09:53:54 +0100 Subject: [PATCH 148/415] Remove a write step & update the builtin open step --- .../Security/UnsafeUnpackQuery.qll | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index bdac41e8812..d449f5f5433 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -66,8 +66,14 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { or // Open a file for access exists(MethodCallNode cn | - nodeTo = cn.getObject() and - cn.getMethodName() = "open" and + cn.calls(nodeTo, "open") and + cn.flowsTo(nodeFrom) + ) + or + // Open a file for access using builtin + exists(API::CallNode cn | + cn = API::builtin("open").getACall() and + nodeTo = cn.(API::CallNode).getArg(0) and cn.flowsTo(nodeFrom) ) or @@ -77,22 +83,11 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeFrom = cn.getArg(0) ) or - // Open a file for access using builtin - nodeFrom = API::builtin("open").getACall() and nodeTo = nodeFrom.(API::CallNode).getArg(0) - or // Retrieve Django uploaded files // see getlist(): https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.QueryDict.getlist // see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks nodeTo.(MethodCallNode).calls(nodeFrom, ["getlist", "get", "chunks"]) or - // Writing the response data to the archive - exists(Stdlib::FileLikeObject::InstanceSource is, Node f, MethodCallNode mc | - is.flowsTo(f) and - mc.calls(f, "write") and - nodeFrom = mc.getArg(0) and - nodeTo = is.(CallCfgNode).getArg(0) - ) - or // Considering the use of "fs" exists(API::CallNode fs, MethodCallNode mcn | fs = From 0707064ab511390a79b359880c97f6034a95a871 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Sat, 28 Jan 2023 10:14:24 +0100 Subject: [PATCH 149/415] Constrain the save/path step --- .../Security/UnsafeUnpackQuery.qll | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index d449f5f5433..99ffb443dca 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -89,19 +89,17 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeTo.(MethodCallNode).calls(nodeFrom, ["getlist", "get", "chunks"]) or // Considering the use of "fs" - exists(API::CallNode fs, MethodCallNode mcn | - fs = - API::moduleImport("django") - .getMember("core") - .getMember("files") - .getMember("storage") - .getMember("FileSystemStorage") - .getACall() and - fs.flowsTo(mcn.getObject()) and - mcn.getMethodName() = ["save", "path"] and - nodeFrom = mcn.getArg(0) and - nodeTo = mcn - ) + // see fs: https://docs.djangoproject.com/en/4.1/ref/files/storage/#the-filesystemstorage-class + nodeTo = + API::moduleImport("django") + .getMember("core") + .getMember("files") + .getMember("storage") + .getMember("FileSystemStorage") + .getReturn() + .getMember(["save", "path"]) + .getACall() and + nodeFrom = nodeTo.(MethodCallNode).getArg(0) or // Accessing the name or raw content nodeTo.(AttrRead).accesses(nodeFrom, ["name", "raw"]) From 7079def7ce31920affd1e585a33116c1ba5a5036 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Mon, 30 Jan 2023 00:49:23 +0100 Subject: [PATCH 150/415] Add an S3 source with Session or download_fileobj --- .../experimental/Security/UnsafeUnpackQuery.qll | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 99ffb443dca..7f305a1d734 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -29,13 +29,25 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { .getACall() ) or - // A source catching an S3 filename download + // A source catching an S3 file download // see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.download_file source = API::moduleImport("boto3") .getMember("client") .getReturn() - .getMember("download_file") + .getMember(["download_file", "download_fileobj"]) + .getACall() + .getArg(2) + or + // A source catching an S3 file download + // see boto3: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html + source = + API::moduleImport("boto3") + .getMember("Session") + .getReturn() + .getMember("client") + .getReturn() + .getMember(["download_file", "download_fileobj"]) .getACall() .getArg(2) or From a1c2f4c13883d3da8fe842c8c6741bf481d38ab7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 30 Jan 2023 09:42:43 +0100 Subject: [PATCH 151/415] Python: Small rewrite of `**kwargs` getParameter logic --- .../dataflow/new/internal/DataFlowDispatch.qll | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 9073686d4be..c05617df47f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -351,15 +351,10 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { // synthetic to the real. It might seem more natural to do it in the other // direction, but since we have a clearStep on the real **kwargs parameter, we that // content-clearing would also affect the synthetic parameter, which we don't want. - ( - not exists(func.getArgByName(_)) and - ppos.isDictSplat() and - result.getParameter() = func.getKwarg() - or - exists(func.getArgByName(_)) and - ppos.isDictSplat() and - result = TSynthDictSplatParameterNode(this) - ) + ppos.isDictSplat() and + if exists(func.getArgByName(_)) + then result = TSynthDictSplatParameterNode(this) + else result.getParameter() = func.getKwarg() } } From c7e552b343ea0cf8ea595c6742fb5b7f11eef7b8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 30 Jan 2023 09:45:45 +0100 Subject: [PATCH 152/415] Python: Fix grammar in qldoc Co-authored-by: yoff --- .../python/dataflow/new/internal/DataFlowDispatch.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index c05617df47f..4641ae4a912 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -345,11 +345,11 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { ) or // `**kwargs` - // since dataflow library has restriction that we can only have ONE result per + // since the dataflow library has the restriction that we can only have ONE result per // parameter position, if there is both a synthetic **kwargs and a real **kwargs // parameter, we only give the result for the synthetic, and add local flow from the // synthetic to the real. It might seem more natural to do it in the other - // direction, but since we have a clearStep on the real **kwargs parameter, we that + // direction, but since we have a clearStep on the real **kwargs parameter, we would have that // content-clearing would also affect the synthetic parameter, which we don't want. ppos.isDictSplat() and if exists(func.getArgByName(_)) @@ -1193,7 +1193,7 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar type instanceof CallTypeNormalMethod and apos.isSelf() and resolveMethodCall(call, target, type, arg) and - // dataflow lib has requirement that arguments and calls are in same enclosing + // the dataflow library has a requirement that arguments and calls are in same enclosing // callable. This requirement would be broken if we used `my_obj` as the self // argument in the `f()` call in the example below: // ```py @@ -1206,7 +1206,7 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() ) or - // cls argument for classmethod calls -- see ntoe above about bound methods + // cls argument for classmethod calls -- see note above about bound methods type instanceof CallTypeClassMethod and apos.isSelf() and resolveMethodCall(call, target, type, arg) and From fdb33ff48efadc5aa07d6b9d8ee912137e70b987 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 1 Feb 2023 14:01:20 +0100 Subject: [PATCH 153/415] Python: Fix grammar in change-note Co-authored-by: Taus --- python/ql/lib/change-notes/2023-01-16-new-call-graph.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/change-notes/2023-01-16-new-call-graph.md b/python/ql/lib/change-notes/2023-01-16-new-call-graph.md index 1dbfd05a80f..3a9e6c3abc0 100644 --- a/python/ql/lib/change-notes/2023-01-16-new-call-graph.md +++ b/python/ql/lib/change-notes/2023-01-16-new-call-graph.md @@ -1,4 +1,4 @@ --- category: majorAnalysis --- -* We use a new analysis for the call-graph (determining which function is called). This can lead to changed results. In most cases this is much more accurate than the old call-graph that was based on points-to, but we do loose a few valid edges in the call-graph, especially around methods that are not defined inside its' class. +* We use a new analysis for the call-graph (determining which function is called). This can lead to changed results. In most cases this is much more accurate than the old call-graph that was based on points-to, but we do lose a few valid edges in the call-graph, especially around methods that are not defined inside its' class. From 1a8c9abee232997cd7d90cb10d65b1bc7c905a60 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 2 Feb 2023 21:09:40 +0100 Subject: [PATCH 154/415] Incorporate Sink & Source as steps from TarSlipQry --- .../Security/UnsafeUnpackQuery.qll | 86 ++++++++++++++++++- .../Security/CWE-022/UnsafeUnpack.py | 78 ++++++++++++++++- 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 7f305a1d734..b43410b14ad 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -10,6 +10,35 @@ import semmle.python.dataflow.new.TaintTracking import semmle.python.frameworks.Stdlib import semmle.python.dataflow.new.RemoteFlowSources +/** + * Handle those three cases of Tarfile opens: + * - `tarfile.open()` + * - `tarfile.TarFile()` + * - `MKtarfile.Tarfile.open()` + */ +API::Node tarfileOpen() { + result in [ + API::moduleImport("tarfile").getMember(["open", "TarFile"]), + API::moduleImport("tarfile").getMember("TarFile").getASubclass().getMember("open") + ] +} + +/** + * Handle the previous three cases, plus the use of `closing` in the previous cases + */ +class AllTarfileOpens extends API::CallNode { + AllTarfileOpens() { + this = tarfileOpen().getACall() + or + exists(API::Node closing, Node arg | + closing = API::moduleImport("contextlib").getMember("closing") and + this = closing.getACall() and + arg = this.getArg(0) and + arg = tarfileOpen().getACall() + ) + } +} + class UnsafeUnpackingConfig extends TaintTracking::Configuration { UnsafeUnpackingConfig() { this = "UnsafeUnpackingConfig" } @@ -68,8 +97,47 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { } override predicate isSink(DataFlow::Node sink) { - // A sink capturing method calls to `unpack_archive`. - sink = API::moduleImport("shutil").getMember("unpack_archive").getACall().getArg(0) + ( + // A sink capturing method calls to `unpack_archive`. + sink = API::moduleImport("shutil").getMember("unpack_archive").getACall().getArg(0) + or + // A sink capturing method calls to `extractall` without `members` argument. + // For a call to `file.extractall` without `members` argument, `file` is considered a sink. + exists(MethodCallNode call, AllTarfileOpens atfo | + call = atfo.getReturn().getMember("extractall").getACall() and + not exists(Node arg | arg = call.getArgByName("members")) and + sink = call.getObject() + ) + or + // A sink capturing method calls to `extractall` with `members` argument. + // For a call to `file.extractall` with `members` argument, `file` is considered a sink if not + // a the `members` argument contains a NameConstant as None, a List or call to the method `getmembers`. + // Otherwise, the argument of `members` is considered a sink. + exists(MethodCallNode call, Node arg, AllTarfileOpens atfo | + call = atfo.getReturn().getMember("extractall").getACall() and + arg = call.getArgByName("members") and + if + arg.asCfgNode() instanceof NameConstantNode or + arg.asCfgNode() instanceof ListNode + then sink = call.getObject() + else + if arg.(MethodCallNode).getMethodName() = "getmembers" + then sink = arg.(MethodCallNode).getObject() + else sink = call.getArgByName("members") + ) + or + // An argument to `extract` is considered a sink. + exists(AllTarfileOpens atfo | + sink = atfo.getReturn().getMember("extract").getACall().getArg(0) + ) + or + //An argument to `_extract_member` is considered a sink. + exists(MethodCallNode call, AllTarfileOpens atfo | + call = atfo.getReturn().getMember("_extract_member").getACall() and + call.getArg(1).(AttrRead).accesses(sink, "name") + ) + ) and + not sink.getScope().getLocation().getFile().inStdlib() } override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { @@ -119,5 +187,19 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // Join the base_dir to the filename nodeTo = API::moduleImport("os").getMember("path").getMember("join").getACall() and nodeFrom = nodeTo.(API::CallNode).getArg(1) + or + // Go through an Open for a Tarfile + nodeTo = tarfileOpen().getACall() and nodeFrom = nodeTo.(MethodCallNode).getArg(0) + or + // Handle the case where the getmembers is used. + 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()`. + nodeTo = API::moduleImport("contextlib").getMember("closing").getACall() and + nodeFrom = nodeTo.(API::CallNode).getArg(0) and + nodeFrom = tarfileOpen().getReturn().getAValueReachableFromSource() } } diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py index ae9ee055999..50574281cbd 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py @@ -122,4 +122,80 @@ def simple_upload(request): return render(request, 'simple_upload.html') elif request.method == 'GET': - return render(request, 'simple_upload.html') \ No newline at end of file + return render(request, 'simple_upload.html') + + +import shutil +import os +import tarfile +import tempfile +import argparse + +parser = argparse.ArgumentParser(description='Process some integers.') +parser.add_argument('integers', metavar='N', type=int, nargs='+', + help='an integer for the accumulator') +parser.add_argument('filename', help='filename to be provided') + +args = parser.parse_args() +unsafe_filename_tar = args.filename +with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar: + tar.extractall(path="/tmp/unpack/", members=tar) # $result=BAD +tar = tarfile.open(unsafe_filename_tar) + + +from django.shortcuts import render +from django.core.files.storage import FileSystemStorage +import shutil + +def simple_upload(request): + + base_dir = "/tmp/baase_dir" + if request.method == 'POST': + # Read uploaded files by chunks of data + # see chunks(): https://docs.djangoproject.com/en/4.1/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.chunks + savepath = os.path.join(base_dir, "tarball_compressed.tar.gz") + with open(savepath, 'wb+') as wfile: + for chunk in request.FILES["ufile1"].chunks(): + wfile.write(chunk) + + tar = tarfile.open(savepath) + result = [] + for member in tar: + if member.issym(): + raise ValueError("But it is a symlink") + result.append(member) + tar.extractall(path=tempfile.mkdtemp(), members=result) # $result=BAD + tar.close() + + +response = requests.get(url_filename, stream=True) +tarpath = "/tmp/tmp456/tarball.tar.gz" +with open(tarpath, "wb") as f: + f.write(response.raw.read()) +target_dir = "/tmp/unpack" +tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) # $result=BAD + + +from pathlib import Path +import tempfile +import boto3 + +def default_session() -> boto3.Session: + _SESSION = None + if _SESSION is None: + _SESSION = boto3.Session() + return _SESSION + +cache = False +cache_dir = "/tmp/artifacts" +object_path = "/objects/obj1" +s3 = default_session().client("s3") +with tempfile.NamedTemporaryFile(suffix=".tar.gz") as tmp: + s3.download_fileobj(bucket_name, object_path, tmp) + tmp.seek(0) + if cache: + cache_dir.mkdir(exist_ok=True, parents=True) + target = cache_dir + else: + target = Path(tempfile.mkdtemp()) + shutil.unpack_archive(tmp.name, target) # $result=BAD \ No newline at end of file From 61095b3c5895700bca5223413a50076dc6ec1300 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 2 Feb 2023 20:27:05 +0000 Subject: [PATCH 155/415] ConceptsShared: Add deprecated DataFlow::Node CryptographicOperation#getInput() predicate --- .../ql/lib/semmle/javascript/internal/ConceptsShared.qll | 6 ++++++ python/ql/lib/semmle/python/internal/ConceptsShared.qll | 6 ++++++ ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 2f6c8bb8b29..5be626877cc 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -43,6 +43,9 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ DataFlow::Node getAnInput() { result = super.getAnInput() } + /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + deprecated final DataFlow::Node getInput() { result = super.getInput() } + /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used @@ -67,6 +70,9 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ abstract DataFlow::Node getAnInput(); + /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + deprecated final DataFlow::Node getInput() { result = this.getAnInput() } + /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 2f6c8bb8b29..5be626877cc 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -43,6 +43,9 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ DataFlow::Node getAnInput() { result = super.getAnInput() } + /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + deprecated final DataFlow::Node getInput() { result = super.getInput() } + /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used @@ -67,6 +70,9 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ abstract DataFlow::Node getAnInput(); + /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + deprecated final DataFlow::Node getInput() { result = this.getAnInput() } + /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 2f6c8bb8b29..5be626877cc 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -43,6 +43,9 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ DataFlow::Node getAnInput() { result = super.getAnInput() } + /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + deprecated final DataFlow::Node getInput() { result = super.getInput() } + /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used @@ -67,6 +70,9 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ abstract DataFlow::Node getAnInput(); + /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + deprecated final DataFlow::Node getInput() { result = this.getAnInput() } + /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used From e5dfbe2c8ddd8620e0c70c51715e15e8e1d13f6c Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 2 Feb 2023 20:27:52 +0000 Subject: [PATCH 156/415] ConceptsShared: Add BlockMode#matchesString(string) predicate --- .../ql/lib/semmle/javascript/internal/ConceptsShared.qll | 4 ++++ python/ql/lib/semmle/python/internal/ConceptsShared.qll | 4 ++++ ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 5be626877cc..23b34592852 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -91,6 +91,10 @@ module Cryptography { /** Holds if this block mode is considered to be insecure. */ predicate isWeak() { this = "ECB" } + + /** Holds if the given string appears to match this block mode. */ + bindingset[s] + predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } } } diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 5be626877cc..23b34592852 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -91,6 +91,10 @@ module Cryptography { /** Holds if this block mode is considered to be insecure. */ predicate isWeak() { this = "ECB" } + + /** Holds if the given string appears to match this block mode. */ + bindingset[s] + predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } } } diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 5be626877cc..23b34592852 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -91,6 +91,10 @@ module Cryptography { /** Holds if this block mode is considered to be insecure. */ predicate isWeak() { this = "ECB" } + + /** Holds if the given string appears to match this block mode. */ + bindingset[s] + predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } } } From 983055b8f9628181ddb19882df6c60ea5f3544bb Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 2 Feb 2023 20:28:37 +0000 Subject: [PATCH 157/415] JS: Use shared CryptographicOperation concept and implement BlockMode getBlockMode() --- .../EndpointCharacteristics.qll | 2 +- .../ql/lib/semmle/javascript/Concepts.qll | 7 + .../javascript/frameworks/CryptoLibraries.qll | 158 ++++++++++++------ .../BrokenCryptoAlgorithmCustomizations.qll | 2 +- ...InsufficientPasswordHashCustomizations.qll | 2 +- .../CryptoLibraries/CryptographicOperation.ql | 2 +- 6 files changed, 121 insertions(+), 52 deletions(-) diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointCharacteristics.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointCharacteristics.qll index e95b2785ceb..fe3286032ad 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointCharacteristics.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointCharacteristics.qll @@ -387,7 +387,7 @@ private class CryptographicOperationFlowCharacteristic extends NotASinkCharacter CryptographicOperationFlowCharacteristic() { this = "CryptographicOperationFlow" } override predicate appliesToEndpoint(DataFlow::Node n) { - any(CryptographicOperation op).getInput() = n + any(CryptographicOperation op).getAnInput() = n } } diff --git a/javascript/ql/lib/semmle/javascript/Concepts.qll b/javascript/ql/lib/semmle/javascript/Concepts.qll index e3c3f0d2357..a760e746030 100644 --- a/javascript/ql/lib/semmle/javascript/Concepts.qll +++ b/javascript/ql/lib/semmle/javascript/Concepts.qll @@ -110,3 +110,10 @@ abstract class PersistentWriteAccess extends DataFlow::Node { */ abstract DataFlow::Node getValue(); } + +/** + * Provides models for cryptographic things. + */ +module Cryptography { + import semmle.javascript.internal.ConceptsShared::Cryptography +} diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll index 9cf4dcfaace..8d2921e48cb 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll @@ -3,22 +3,7 @@ */ import javascript -import semmle.javascript.security.CryptoAlgorithms - -/** - * An application of a cryptographic algorithm. - */ -abstract class CryptographicOperation extends DataFlow::Node { - /** - * Gets the input the algorithm is used on, e.g. the plain text input to be encrypted. - */ - abstract DataFlow::Node getInput(); - - /** - * Gets the applied algorithm. - */ - abstract CryptographicAlgorithm getAlgorithm(); -} +import semmle.javascript.Concepts::Cryptography /** * A key used in a cryptographic algorithm. @@ -52,13 +37,20 @@ class CryptographicKeyCredentialsExpr extends CredentialsNode instanceof Cryptog override string getCredentialsKind() { result = "key" } } +// Holds if `algorithm` is an `EncryptionAlgorithm` that uses a block cipher +private predicate isBlockEncryptionAlgorithm(CryptographicAlgorithm algorithm) { + algorithm instanceof EncryptionAlgorithm and + not algorithm.(EncryptionAlgorithm).isStreamCipher() +} + /** * A model of the asmCrypto library. */ private module AsmCrypto { - private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional + private string algorithmName; Apply() { /* @@ -71,17 +63,22 @@ private module AsmCrypto { * ``` */ - exists(DataFlow::SourceNode asmCrypto, string algorithmName | + exists(DataFlow::SourceNode asmCrypto | asmCrypto = DataFlow::globalVarRef("asmCrypto") and algorithm.matchesName(algorithmName) and this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(_) and - input = this.getAnArgument() + input = this.getArgument(0) ) } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + override BlockMode getBlockMode() { + isBlockEncryptionAlgorithm(this.getAlgorithm()) and + result.matchesString(algorithmName) + } } } @@ -93,7 +90,7 @@ private module BrowserIdCrypto { Key() { this = any(Apply apply).getKey() } } - private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::MethodCallNode { CryptographicAlgorithm algorithm; // non-functional Apply() { @@ -126,10 +123,13 @@ private module BrowserIdCrypto { ) } - override DataFlow::Node getInput() { result = super.getArgument(0) } + override DataFlow::Node getAnInput() { result = super.getArgument(0) } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + // not relevant for browserid-crypto + override BlockMode getBlockMode() { none() } + DataFlow::Node getKey() { result = super.getArgument(1) } } } @@ -140,6 +140,7 @@ private module BrowserIdCrypto { private module NodeJSCrypto { private class InstantiatedAlgorithm extends DataFlow::CallNode { CryptographicAlgorithm algorithm; // non-functional + private string algorithmName; InstantiatedAlgorithm() { /* @@ -158,11 +159,25 @@ private module NodeJSCrypto { exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("crypto") and this = mod.getAMemberCall("create" + ["Hash", "Hmac", "Sign", "Cipher"]) and - algorithm.matchesName(this.getArgument(0).getStringValue()) + algorithmName = this.getArgument(0).getStringValue() and + algorithm.matchesName(algorithmName) ) } CryptographicAlgorithm getAlgorithm() { result = algorithm } + + private BlockMode getExplicitBlockMode() { result.matchesString(algorithmName) } + + BlockMode getBlockMode() { + isBlockEncryptionAlgorithm(this.getAlgorithm()) and + ( + if exists(this.getExplicitBlockMode()) + then result = this.getExplicitBlockMode() + else + // CBC is the default if not explicitly specified + result = "CBC" + ) + } } private class CreateKey extends CryptographicKeyCreation, DataFlow::CallNode { @@ -211,14 +226,16 @@ private module NodeJSCrypto { override predicate isSymmetricKey() { none() } } - private class Apply extends CryptographicOperation instanceof DataFlow::MethodCallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::MethodCallNode { InstantiatedAlgorithm instantiation; Apply() { this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")) } - override DataFlow::Node getInput() { result = super.getArgument(0) } + override DataFlow::Node getAnInput() { result = super.getArgument(0) } override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() } + + override BlockMode getBlockMode() { result = instantiation.getBlockMode() } } private class Key extends CryptographicKey { @@ -307,7 +324,7 @@ private module CryptoJS { input = result.getArgument(0) } - private class Apply extends CryptographicOperation { + private class Apply extends CryptographicOperation::Range, DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional @@ -316,9 +333,31 @@ private module CryptoJS { this = getDirectApplication(input, algorithm) } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + // e.g. CryptoJS.AES.encrypt("msg", "key", { mode: CryptoJS.mode. }) + private BlockMode getExplicitBlockMode() { + exists(DataFlow::ObjectLiteralNode o, DataFlow::SourceNode modeNode, string modeString | + modeNode = API::moduleImport("crypto-js").getMember("mode").getMember(modeString).asSource() and + o.flowsTo(this.getArgument(2)) and + modeNode = o.getAPropertySource("mode") + | + result.matchesString(modeString) + ) + } + + override BlockMode getBlockMode() { + isBlockEncryptionAlgorithm(this.getAlgorithm()) and + ( + if exists(this.getExplicitBlockMode()) + then result = this.getExplicitBlockMode() + else + // CBC is the default if not explicitly specified + result = "CBC" + ) + } } private class Key extends CryptographicKey { @@ -374,7 +413,7 @@ private module CryptoJS { * A model of the TweetNaCl library. */ private module TweetNaCl { - private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; @@ -401,9 +440,12 @@ private module TweetNaCl { ) } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + // No block ciphers implemented + override BlockMode getBlockMode() { none() } } } @@ -434,7 +476,7 @@ private module HashJs { ) } - private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional @@ -456,9 +498,12 @@ private module HashJs { input = super.getArgument(0) } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + // not relevant for hash.js + override BlockMode getBlockMode() { none() } } } @@ -478,19 +523,20 @@ private module Forge { private class KeyCipher extends Cipher { DataFlow::Node key; CryptographicAlgorithm algorithm; // non-functional + private string blockModeString; KeyCipher() { exists(DataFlow::SourceNode mod, string algorithmName | mod = getAnImportNode() and algorithm.matchesName(algorithmName) | - exists(string createName, string cipherName, string cipherPrefix, string cipherSuffix | + exists(string createName, string cipherName, string cipherPrefix | // `require('forge').cipher.createCipher("3DES-CBC").update("secret", "key");` (createName = "createCipher" or createName = "createDecipher") and this = mod.getAPropertyRead("cipher").getAMemberCall(createName) and this.getArgument(0).mayHaveStringValue(cipherName) and - cipherName = cipherPrefix + "-" + cipherSuffix and - cipherSuffix = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and + cipherName = cipherPrefix + "-" + blockModeString and + blockModeString = ["CBC", "CFB", "CTR", "ECB", "GCM", "OFB"] and algorithmName = cipherPrefix and key = this.getArgument(1) ) @@ -500,7 +546,8 @@ private module Forge { createName = "createEncryptionCipher" or createName = "createDecryptionCipher" | this = mod.getAPropertyRead(algorithmName).getAMemberCall(createName) and - key = this.getArgument(0) + key = this.getArgument(0) and + blockModeString = algorithmName ) ) } @@ -508,6 +555,11 @@ private module Forge { override CryptographicAlgorithm getAlgorithm() { result = algorithm } DataFlow::Node getKey() { result = key } + + BlockMode getBlockMode() { + isBlockEncryptionAlgorithm(this.getAlgorithm()) and + result.matchesString(blockModeString) + } } private class NonKeyCipher extends Cipher { @@ -527,21 +579,22 @@ private module Forge { override CryptographicAlgorithm getAlgorithm() { result = algorithm } } - private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional + private Cipher cipher; Apply() { - exists(Cipher cipher | - this = cipher.getAMemberCall("update") and - super.getArgument(0) = input and - algorithm = cipher.getAlgorithm() - ) + this = cipher.getAMemberCall("update") and + super.getArgument(0) = input and + algorithm = cipher.getAlgorithm() } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + override BlockMode getBlockMode() { result = cipher.(KeyCipher).getBlockMode() } } private class Key extends CryptographicKey { @@ -586,7 +639,7 @@ private module Forge { * A model of the md5 library. */ private module Md5 { - private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; @@ -600,9 +653,12 @@ private module Md5 { ) } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + // not relevant for md5 + override BlockMode getBlockMode() { none() } } } @@ -610,7 +666,7 @@ private module Md5 { * A model of the bcrypt, bcryptjs, bcrypt-nodejs libraries. */ private module Bcrypt { - private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; @@ -633,9 +689,12 @@ private module Bcrypt { ) } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + // not relevant for bcrypt + override BlockMode getBlockMode() { none() } } } @@ -643,7 +702,7 @@ private module Bcrypt { * A model of the hasha library. */ private module Hasha { - private class Apply extends CryptographicOperation instanceof DataFlow::CallNode { + private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode { DataFlow::Node input; CryptographicAlgorithm algorithm; @@ -659,9 +718,12 @@ private module Hasha { ) } - override DataFlow::Node getInput() { result = input } + override DataFlow::Node getAnInput() { result = input } override CryptographicAlgorithm getAlgorithm() { result = algorithm } + + // not relevant for hasha + override BlockMode getBlockMode() { none() } } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll index 832f811f67b..01a5b1b260b 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/BrokenCryptoAlgorithmCustomizations.qll @@ -41,7 +41,7 @@ module BrokenCryptoAlgorithm { WeakCryptographicOperationSink() { exists(CryptographicOperation application | application.getAlgorithm().isWeak() and - this = application.getInput() + this = application.getAnInput() ) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll index 1697d55fe0b..8901be9962f 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/InsufficientPasswordHashCustomizations.qll @@ -47,7 +47,7 @@ module InsufficientPasswordHash { application.getAlgorithm().isWeak() or not application.getAlgorithm() instanceof PasswordHashingAlgorithm | - this = application.getInput() + this = application.getAnInput() ) } } diff --git a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql index d085113b9c7..10e5ae851f4 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql +++ b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql @@ -1,4 +1,4 @@ import javascript from CryptographicOperation operation -select operation, operation.getAlgorithm().getName(), operation.getInput() +select operation, operation.getAlgorithm().getName(), operation.getAnInput() From 1435ef186293ff4296931405cc9e50cc53aab905 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 2 Feb 2023 20:20:03 +0000 Subject: [PATCH 158/415] CryptoAlgorithms: make CryptographicAlgorithm#matchesName split on underscores --- .../ql/lib/semmle/javascript/security/CryptoAlgorithms.qll | 4 ++-- python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll | 4 ++-- ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll index 22a2d1c1eb2..766f99c61da 100644 --- a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll +++ b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll @@ -40,12 +40,12 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { /** * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes, underscores, and anything after a dash in the name + * white space, dashes, underscores, and anything after a dash or underscore in the name * (to ignore modes of operation, such as CBC or ECB). */ bindingset[name] predicate matchesName(string name) { - [name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)] + [name.toUpperCase(), name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1)] .regexpReplaceAll("[-_ ]", "") = getName() } diff --git a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll index 22a2d1c1eb2..766f99c61da 100644 --- a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll +++ b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll @@ -40,12 +40,12 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { /** * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes, underscores, and anything after a dash in the name + * white space, dashes, underscores, and anything after a dash or underscore in the name * (to ignore modes of operation, such as CBC or ECB). */ bindingset[name] predicate matchesName(string name) { - [name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)] + [name.toUpperCase(), name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1)] .regexpReplaceAll("[-_ ]", "") = getName() } diff --git a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll index 22a2d1c1eb2..766f99c61da 100644 --- a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll +++ b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll @@ -40,12 +40,12 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { /** * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes, underscores, and anything after a dash in the name + * white space, dashes, underscores, and anything after a dash or underscore in the name * (to ignore modes of operation, such as CBC or ECB). */ bindingset[name] predicate matchesName(string name) { - [name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)] + [name.toUpperCase(), name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1)] .regexpReplaceAll("[-_ ]", "") = getName() } From c25dc978df7cb6a74ac4175940ea853803fd9ef3 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 2 Feb 2023 16:16:44 +0000 Subject: [PATCH 159/415] JS: add blockMode to CryptographicOperation tests --- .../CryptographicOperation.expected | 62 +++++++++---------- .../CryptoLibraries/CryptographicOperation.ql | 14 ++++- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected index 09134c235bc..6408535c0f4 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected +++ b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected @@ -1,31 +1,31 @@ -| tst.js:1:1:1:27 | asmCryp ... (input) | SHA256 | tst.js:1:22:1:26 | input | -| tst.js:5:5:5:43 | jwcrypt ... retKey) | DSA | tst.js:5:19:5:23 | input | -| tst.js:10:18:10:55 | cipher. ... 'hex') | AES192 | tst.js:10:32:10:39 | 'input1' | -| tst.js:11:18:11:54 | cipher. ... 'hex') | AES192 | tst.js:11:31:11:38 | 'input2' | -| tst.js:15:1:15:21 | hash.up ... nput1') | SHA256 | tst.js:15:13:15:20 | 'input1' | -| tst.js:16:1:16:20 | hash.write('input2') | SHA256 | tst.js:16:12:16:19 | 'input2' | -| tst.js:20:1:20:21 | hmac.up ... nput1') | SHA256 | tst.js:20:13:20:20 | 'input1' | -| tst.js:21:1:21:20 | hmac.write('input2') | SHA256 | tst.js:21:12:21:19 | 'input2' | -| tst.js:25:1:25:21 | sign.up ... nput1') | SHA256 | tst.js:25:13:25:20 | 'input1' | -| tst.js:26:1:26:20 | sign.write('input2') | SHA256 | tst.js:26:12:26:19 | 'input2' | -| tst.js:29:1:29:52 | CryptoJ ... y 123') | AES | tst.js:29:22:29:33 | 'my message' | -| tst.js:32:1:32:31 | CryptoJ ... "Key") | SHA1 | tst.js:32:15:32:23 | "Message" | -| tst.js:35:1:35:35 | CryptoJ ... "Key") | SHA1 | tst.js:35:19:35:27 | "Message" | -| tst.js:37:1:37:64 | require ... y 123') | AES | tst.js:37:34:37:45 | 'my message' | -| tst.js:39:1:39:43 | require ... "Key") | SHA1 | tst.js:39:27:39:35 | "Message" | -| tst.js:41:1:41:34 | require ... ssage') | ED25519 | tst.js:41:22:41:33 | 'my message' | -| tst.js:43:1:43:34 | require ... ssage') | SHA512 | tst.js:43:22:43:33 | 'my message' | -| tst.js:45:1:45:39 | require ... ssage') | ED25519 | tst.js:45:27:45:38 | 'my message' | -| tst.js:47:1:47:39 | require ... ssage') | SHA512 | tst.js:47:27:47:38 | 'my message' | -| tst.js:49:1:49:41 | require ... ('abc') | SHA256 | tst.js:49:36:49:40 | 'abc' | -| tst.js:51:1:51:51 | require ... ('abc') | SHA512 | tst.js:51:46:51:50 | 'abc' | -| tst.js:53:1:53:86 | require ... y dog') | MD5 | tst.js:53:41:53:85 | 'The qu ... zy dog' | -| tst.js:55:1:55:91 | require ... y dog') | MD5 | tst.js:55:46:55:90 | 'The qu ... zy dog' | -| tst.js:57:1:57:65 | require ... ecret") | RC2 | tst.js:57:57:57:64 | "secret" | -| tst.js:59:1:59:70 | require ... ecret") | 3DES | tst.js:59:62:59:69 | "secret" | -| tst.js:61:1:61:25 | require ... ssage") | MD5 | tst.js:61:16:61:24 | "message" | -| tst.js:63:1:63:32 | require ... ssword) | BCRYPT | tst.js:63:24:63:31 | password | -| tst.js:65:1:65:36 | require ... ssword) | BCRYPT | tst.js:65:28:65:35 | password | -| tst.js:67:1:67:34 | require ... ssword) | BCRYPT | tst.js:67:26:67:33 | password | -| tst.js:69:1:69:39 | require ... ssword) | BCRYPT | tst.js:69:31:69:38 | password | -| tst.js:71:1:71:49 | require ... md5" }) | MD5 | tst.js:71:18:71:26 | 'unicorn' | +| tst.js:1:1:1:27 | asmCryp ... (input) | SHA256 | tst.js:1:22:1:26 | input | | +| tst.js:5:5:5:43 | jwcrypt ... retKey) | DSA | tst.js:5:19:5:23 | input | | +| tst.js:10:18:10:55 | cipher. ... 'hex') | AES192 | tst.js:10:32:10:39 | 'input1' | CBC | +| tst.js:11:18:11:54 | cipher. ... 'hex') | AES192 | tst.js:11:31:11:38 | 'input2' | CBC | +| tst.js:15:1:15:21 | hash.up ... nput1') | SHA256 | tst.js:15:13:15:20 | 'input1' | | +| tst.js:16:1:16:20 | hash.write('input2') | SHA256 | tst.js:16:12:16:19 | 'input2' | | +| tst.js:20:1:20:21 | hmac.up ... nput1') | SHA256 | tst.js:20:13:20:20 | 'input1' | | +| tst.js:21:1:21:20 | hmac.write('input2') | SHA256 | tst.js:21:12:21:19 | 'input2' | | +| tst.js:25:1:25:21 | sign.up ... nput1') | SHA256 | tst.js:25:13:25:20 | 'input1' | | +| tst.js:26:1:26:20 | sign.write('input2') | SHA256 | tst.js:26:12:26:19 | 'input2' | | +| tst.js:29:1:29:52 | CryptoJ ... y 123') | AES | tst.js:29:22:29:33 | 'my message' | CBC | +| tst.js:32:1:32:31 | CryptoJ ... "Key") | SHA1 | tst.js:32:15:32:23 | "Message" | | +| tst.js:35:1:35:35 | CryptoJ ... "Key") | SHA1 | tst.js:35:19:35:27 | "Message" | | +| tst.js:37:1:37:64 | require ... y 123') | AES | tst.js:37:34:37:45 | 'my message' | CBC | +| tst.js:39:1:39:43 | require ... "Key") | SHA1 | tst.js:39:27:39:35 | "Message" | | +| tst.js:41:1:41:34 | require ... ssage') | ED25519 | tst.js:41:22:41:33 | 'my message' | | +| tst.js:43:1:43:34 | require ... ssage') | SHA512 | tst.js:43:22:43:33 | 'my message' | | +| tst.js:45:1:45:39 | require ... ssage') | ED25519 | tst.js:45:27:45:38 | 'my message' | | +| tst.js:47:1:47:39 | require ... ssage') | SHA512 | tst.js:47:27:47:38 | 'my message' | | +| tst.js:49:1:49:41 | require ... ('abc') | SHA256 | tst.js:49:36:49:40 | 'abc' | | +| tst.js:51:1:51:51 | require ... ('abc') | SHA512 | tst.js:51:46:51:50 | 'abc' | | +| tst.js:53:1:53:86 | require ... y dog') | MD5 | tst.js:53:41:53:85 | 'The qu ... zy dog' | | +| tst.js:55:1:55:91 | require ... y dog') | MD5 | tst.js:55:46:55:90 | 'The qu ... zy dog' | | +| tst.js:57:1:57:65 | require ... ecret") | RC2 | tst.js:57:57:57:64 | "secret" | | +| tst.js:59:1:59:70 | require ... ecret") | 3DES | tst.js:59:62:59:69 | "secret" | CBC | +| tst.js:61:1:61:25 | require ... ssage") | MD5 | tst.js:61:16:61:24 | "message" | | +| tst.js:63:1:63:32 | require ... ssword) | BCRYPT | tst.js:63:24:63:31 | password | | +| tst.js:65:1:65:36 | require ... ssword) | BCRYPT | tst.js:65:28:65:35 | password | | +| tst.js:67:1:67:34 | require ... ssword) | BCRYPT | tst.js:67:26:67:33 | password | | +| tst.js:69:1:69:39 | require ... ssword) | BCRYPT | tst.js:69:31:69:38 | password | | +| tst.js:71:1:71:49 | require ... md5" }) | MD5 | tst.js:71:18:71:26 | 'unicorn' | | diff --git a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql index 10e5ae851f4..33b56f278a0 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql +++ b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.ql @@ -1,4 +1,16 @@ import javascript +string getBlockMode(CryptographicOperation operation) { + if + operation.getAlgorithm() instanceof EncryptionAlgorithm and + not operation.getAlgorithm().(EncryptionAlgorithm).isStreamCipher() + then + if exists(operation.getBlockMode()) + then result = operation.getBlockMode() + else result = "" + else result = "" +} + from CryptographicOperation operation -select operation, operation.getAlgorithm().getName(), operation.getAnInput() +select operation, operation.getAlgorithm().getName(), operation.getAnInput(), + getBlockMode(operation) From aa2c532a7892cfedfc9f3d5d91470ce384efbf3c Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 2 Feb 2023 20:22:02 +0000 Subject: [PATCH 160/415] JS: adjust test whitespace --- .../CryptographicOperation.expected | 60 +++++++++---------- .../test/library-tests/CryptoLibraries/tst.js | 11 ++++ 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected index 6408535c0f4..cd01b1d1b42 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected +++ b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected @@ -1,31 +1,31 @@ | tst.js:1:1:1:27 | asmCryp ... (input) | SHA256 | tst.js:1:22:1:26 | input | | -| tst.js:5:5:5:43 | jwcrypt ... retKey) | DSA | tst.js:5:19:5:23 | input | | -| tst.js:10:18:10:55 | cipher. ... 'hex') | AES192 | tst.js:10:32:10:39 | 'input1' | CBC | -| tst.js:11:18:11:54 | cipher. ... 'hex') | AES192 | tst.js:11:31:11:38 | 'input2' | CBC | -| tst.js:15:1:15:21 | hash.up ... nput1') | SHA256 | tst.js:15:13:15:20 | 'input1' | | -| tst.js:16:1:16:20 | hash.write('input2') | SHA256 | tst.js:16:12:16:19 | 'input2' | | -| tst.js:20:1:20:21 | hmac.up ... nput1') | SHA256 | tst.js:20:13:20:20 | 'input1' | | -| tst.js:21:1:21:20 | hmac.write('input2') | SHA256 | tst.js:21:12:21:19 | 'input2' | | -| tst.js:25:1:25:21 | sign.up ... nput1') | SHA256 | tst.js:25:13:25:20 | 'input1' | | -| tst.js:26:1:26:20 | sign.write('input2') | SHA256 | tst.js:26:12:26:19 | 'input2' | | -| tst.js:29:1:29:52 | CryptoJ ... y 123') | AES | tst.js:29:22:29:33 | 'my message' | CBC | -| tst.js:32:1:32:31 | CryptoJ ... "Key") | SHA1 | tst.js:32:15:32:23 | "Message" | | -| tst.js:35:1:35:35 | CryptoJ ... "Key") | SHA1 | tst.js:35:19:35:27 | "Message" | | -| tst.js:37:1:37:64 | require ... y 123') | AES | tst.js:37:34:37:45 | 'my message' | CBC | -| tst.js:39:1:39:43 | require ... "Key") | SHA1 | tst.js:39:27:39:35 | "Message" | | -| tst.js:41:1:41:34 | require ... ssage') | ED25519 | tst.js:41:22:41:33 | 'my message' | | -| tst.js:43:1:43:34 | require ... ssage') | SHA512 | tst.js:43:22:43:33 | 'my message' | | -| tst.js:45:1:45:39 | require ... ssage') | ED25519 | tst.js:45:27:45:38 | 'my message' | | -| tst.js:47:1:47:39 | require ... ssage') | SHA512 | tst.js:47:27:47:38 | 'my message' | | -| tst.js:49:1:49:41 | require ... ('abc') | SHA256 | tst.js:49:36:49:40 | 'abc' | | -| tst.js:51:1:51:51 | require ... ('abc') | SHA512 | tst.js:51:46:51:50 | 'abc' | | -| tst.js:53:1:53:86 | require ... y dog') | MD5 | tst.js:53:41:53:85 | 'The qu ... zy dog' | | -| tst.js:55:1:55:91 | require ... y dog') | MD5 | tst.js:55:46:55:90 | 'The qu ... zy dog' | | -| tst.js:57:1:57:65 | require ... ecret") | RC2 | tst.js:57:57:57:64 | "secret" | | -| tst.js:59:1:59:70 | require ... ecret") | 3DES | tst.js:59:62:59:69 | "secret" | CBC | -| tst.js:61:1:61:25 | require ... ssage") | MD5 | tst.js:61:16:61:24 | "message" | | -| tst.js:63:1:63:32 | require ... ssword) | BCRYPT | tst.js:63:24:63:31 | password | | -| tst.js:65:1:65:36 | require ... ssword) | BCRYPT | tst.js:65:28:65:35 | password | | -| tst.js:67:1:67:34 | require ... ssword) | BCRYPT | tst.js:67:26:67:33 | password | | -| tst.js:69:1:69:39 | require ... ssword) | BCRYPT | tst.js:69:31:69:38 | password | | -| tst.js:71:1:71:49 | require ... md5" }) | MD5 | tst.js:71:18:71:26 | 'unicorn' | | +| tst.js:7:5:7:43 | jwcrypt ... retKey) | DSA | tst.js:7:19:7:23 | input | | +| tst.js:12:18:12:55 | cipher. ... 'hex') | AES192 | tst.js:12:32:12:39 | 'input1' | CBC | +| tst.js:13:18:13:54 | cipher. ... 'hex') | AES192 | tst.js:13:31:13:38 | 'input2' | CBC | +| tst.js:17:1:17:21 | hash.up ... nput1') | SHA256 | tst.js:17:13:17:20 | 'input1' | | +| tst.js:18:1:18:20 | hash.write('input2') | SHA256 | tst.js:18:12:18:19 | 'input2' | | +| tst.js:22:1:22:21 | hmac.up ... nput1') | SHA256 | tst.js:22:13:22:20 | 'input1' | | +| tst.js:23:1:23:20 | hmac.write('input2') | SHA256 | tst.js:23:12:23:19 | 'input2' | | +| tst.js:27:1:27:21 | sign.up ... nput1') | SHA256 | tst.js:27:13:27:20 | 'input1' | | +| tst.js:28:1:28:20 | sign.write('input2') | SHA256 | tst.js:28:12:28:19 | 'input2' | | +| tst.js:36:1:36:52 | CryptoJ ... y 123') | AES | tst.js:36:22:36:33 | 'my message' | CBC | +| tst.js:39:1:39:31 | CryptoJ ... "Key") | SHA1 | tst.js:39:15:39:23 | "Message" | | +| tst.js:42:1:42:35 | CryptoJ ... "Key") | SHA1 | tst.js:42:19:42:27 | "Message" | | +| tst.js:44:1:44:64 | require ... y 123') | AES | tst.js:44:34:44:45 | 'my message' | CBC | +| tst.js:46:1:46:43 | require ... "Key") | SHA1 | tst.js:46:27:46:35 | "Message" | | +| tst.js:52:1:52:34 | require ... ssage') | ED25519 | tst.js:52:22:52:33 | 'my message' | | +| tst.js:54:1:54:34 | require ... ssage') | SHA512 | tst.js:54:22:54:33 | 'my message' | | +| tst.js:56:1:56:39 | require ... ssage') | ED25519 | tst.js:56:27:56:38 | 'my message' | | +| tst.js:58:1:58:39 | require ... ssage') | SHA512 | tst.js:58:27:58:38 | 'my message' | | +| tst.js:60:1:60:41 | require ... ('abc') | SHA256 | tst.js:60:36:60:40 | 'abc' | | +| tst.js:62:1:62:51 | require ... ('abc') | SHA512 | tst.js:62:46:62:50 | 'abc' | | +| tst.js:64:1:64:86 | require ... y dog') | MD5 | tst.js:64:41:64:85 | 'The qu ... zy dog' | | +| tst.js:66:1:66:91 | require ... y dog') | MD5 | tst.js:66:46:66:90 | 'The qu ... zy dog' | | +| tst.js:68:1:68:65 | require ... ecret") | RC2 | tst.js:68:57:68:64 | "secret" | | +| tst.js:70:1:70:70 | require ... ecret") | 3DES | tst.js:70:62:70:69 | "secret" | CBC | +| tst.js:72:1:72:25 | require ... ssage") | MD5 | tst.js:72:16:72:24 | "message" | | +| tst.js:74:1:74:32 | require ... ssword) | BCRYPT | tst.js:74:24:74:31 | password | | +| tst.js:76:1:76:36 | require ... ssword) | BCRYPT | tst.js:76:28:76:35 | password | | +| tst.js:78:1:78:34 | require ... ssword) | BCRYPT | tst.js:78:26:78:33 | password | | +| tst.js:80:1:80:39 | require ... ssword) | BCRYPT | tst.js:80:31:80:38 | password | | +| tst.js:82:1:82:49 | require ... md5" }) | MD5 | tst.js:82:18:82:26 | 'unicorn' | | diff --git a/javascript/ql/test/library-tests/CryptoLibraries/tst.js b/javascript/ql/test/library-tests/CryptoLibraries/tst.js index 5efd150bd16..a7aa47359d5 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/tst.js +++ b/javascript/ql/test/library-tests/CryptoLibraries/tst.js @@ -1,5 +1,7 @@ asmCrypto.SHA256.hex(input); + + var jwcrypto = require("browserid-crypto"); jwcrypto.generateKeypair({algorithm: 'DSA'}, function(err, keypair) { jwcrypto.sign(input, keypair.secretKey); @@ -25,6 +27,11 @@ const sign = crypto.createSign('SHA256'); sign.update('input1'); sign.write('input2'); + + + + + var CryptoJS = require("crypto-js"); CryptoJS.AES.encrypt('my message', 'secret key 123'); @@ -38,6 +45,10 @@ require("crypto-js/aes").encrypt('my message', 'secret key 123'); require("crypto-js/sha1")("Message", "Key"); + + + + require("nacl").sign('my message'); require("nacl").hash('my message'); From b0b8f8725ea6376cc1c796eca3077110bf17ebad Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 2 Feb 2023 20:22:45 +0000 Subject: [PATCH 161/415] JS: add some CryptographicOperation#getBlockMode() tests --- .../CryptographicOperation.expected | 4 ++++ .../ql/test/library-tests/CryptoLibraries/tst.js | 16 ++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected index cd01b1d1b42..0844cb2c577 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected +++ b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicOperation.expected @@ -1,4 +1,5 @@ | tst.js:1:1:1:27 | asmCryp ... (input) | SHA256 | tst.js:1:22:1:26 | input | | +| tst.js:3:1:3:41 | asmCryp ... ey, iv) | AES | tst.js:3:27:3:31 | input | OFB | | tst.js:7:5:7:43 | jwcrypt ... retKey) | DSA | tst.js:7:19:7:23 | input | | | tst.js:12:18:12:55 | cipher. ... 'hex') | AES192 | tst.js:12:32:12:39 | 'input1' | CBC | | tst.js:13:18:13:54 | cipher. ... 'hex') | AES192 | tst.js:13:31:13:38 | 'input2' | CBC | @@ -8,11 +9,14 @@ | tst.js:23:1:23:20 | hmac.write('input2') | SHA256 | tst.js:23:12:23:19 | 'input2' | | | tst.js:27:1:27:21 | sign.up ... nput1') | SHA256 | tst.js:27:13:27:20 | 'input1' | | | tst.js:28:1:28:20 | sign.write('input2') | SHA256 | tst.js:28:12:28:19 | 'input2' | | +| tst.js:32:1:32:38 | cipher. ... 'hex') | AES | tst.js:32:15:32:22 | 'input1' | ECB | +| tst.js:33:1:33:37 | cipher. ... 'hex') | AES | tst.js:33:14:33:21 | 'input2' | ECB | | tst.js:36:1:36:52 | CryptoJ ... y 123') | AES | tst.js:36:22:36:33 | 'my message' | CBC | | tst.js:39:1:39:31 | CryptoJ ... "Key") | SHA1 | tst.js:39:15:39:23 | "Message" | | | tst.js:42:1:42:35 | CryptoJ ... "Key") | SHA1 | tst.js:42:19:42:27 | "Message" | | | tst.js:44:1:44:64 | require ... y 123') | AES | tst.js:44:34:44:45 | 'my message' | CBC | | tst.js:46:1:46:43 | require ... "Key") | SHA1 | tst.js:46:27:46:35 | "Message" | | +| tst.js:50:1:50:40 | CryptoJ ... , opts) | AES | tst.js:50:22:50:26 | "msg" | CFB | | tst.js:52:1:52:34 | require ... ssage') | ED25519 | tst.js:52:22:52:33 | 'my message' | | | tst.js:54:1:54:34 | require ... ssage') | SHA512 | tst.js:54:22:54:33 | 'my message' | | | tst.js:56:1:56:39 | require ... ssage') | ED25519 | tst.js:56:27:56:38 | 'my message' | | diff --git a/javascript/ql/test/library-tests/CryptoLibraries/tst.js b/javascript/ql/test/library-tests/CryptoLibraries/tst.js index a7aa47359d5..97f373d805b 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/tst.js +++ b/javascript/ql/test/library-tests/CryptoLibraries/tst.js @@ -1,6 +1,6 @@ asmCrypto.SHA256.hex(input); - +asmCrypto.AES_OFB.encrypt(input, key, iv) var jwcrypto = require("browserid-crypto"); jwcrypto.generateKeypair({algorithm: 'DSA'}, function(err, keypair) { @@ -27,10 +27,10 @@ const sign = crypto.createSign('SHA256'); sign.update('input1'); sign.write('input2'); - - - - +var crypto = require('crypto'); +var cipher = crypto.createCipher('aes-192-ecb', 'a password'); +cipher.update('input1', 'utf8', 'hex'); +cipher.write('input2', 'utf8', 'hex'); var CryptoJS = require("crypto-js"); CryptoJS.AES.encrypt('my message', 'secret key 123'); @@ -45,9 +45,9 @@ require("crypto-js/aes").encrypt('my message', 'secret key 123'); require("crypto-js/sha1")("Message", "Key"); - - - +var CryptoJS = require("crypto-js"); +var opts = { mode: CryptoJS.mode.CFB } +CryptoJS.AES.encrypt("msg", "key", opts) require("nacl").sign('my message'); From a0150849cbafae04aaee91d9c6b38c4ef01d4f9d Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 2 Feb 2023 21:42:47 +0100 Subject: [PATCH 162/415] Updated the expected test file --- .../Security/CWE-022/UnsafeUnpack.expected | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected index eed5e0e45d7..94bd7276631 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected @@ -10,6 +10,7 @@ edges | UnsafeUnpack.py:51:19:51:36 | ControlFlowNode for Attribute() | UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | | UnsafeUnpack.py:65:19:65:31 | ControlFlowNode for Attribute | UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | | UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | +| UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | | UnsafeUnpack.py:85:15:85:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | | UnsafeUnpack.py:103:23:103:27 | SSA variable chunk | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | | UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | @@ -18,6 +19,13 @@ edges | UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | | UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | | UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | +| UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | +| UnsafeUnpack.py:158:23:158:27 | SSA variable chunk | UnsafeUnpack.py:163:23:163:28 | SSA variable member | +| UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | +| UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | UnsafeUnpack.py:158:23:158:27 | SSA variable chunk | +| UnsafeUnpack.py:163:23:163:28 | SSA variable member | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | +| UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | +| UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | nodes | UnsafeUnpack.py:0:0:0:0 | ModuleVariableNode for UnsafeUnpack.request | semmle.label | ModuleVariableNode for UnsafeUnpack.request | | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember | @@ -47,6 +55,17 @@ nodes | UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | semmle.label | ControlFlowNode for uploaded_file_path | +| UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar | +| UnsafeUnpack.py:158:23:158:27 | SSA variable chunk | semmle.label | SSA variable chunk | +| UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:158:32:158:54 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| UnsafeUnpack.py:163:23:163:28 | SSA variable member | semmle.label | SSA variable member | +| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | semmle.label | ControlFlowNode for result | +| UnsafeUnpack.py:174:15:174:26 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() | +| UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | semmle.label | ControlFlowNode for tmp | +| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | subpaths #select | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | UnsafeUnpack.py:5:26:5:32 | ControlFlowNode for ImportMember | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | Unsafe extraction from a malicious tarball retrieved from a remote location. | @@ -58,3 +77,7 @@ subpaths | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | Unsafe extraction from a malicious tarball retrieved from a remote location. | | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | UnsafeUnpack.py:140:23:140:35 | ControlFlowNode for Attribute | UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | UnsafeUnpack.py:158:32:158:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | UnsafeUnpack.py:79:16:79:28 | ControlFlowNode for Attribute | UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | Unsafe extraction from a malicious tarball retrieved from a remote location. | +| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | UnsafeUnpack.py:194:53:194:55 | ControlFlowNode for tmp | UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | Unsafe extraction from a malicious tarball retrieved from a remote location. | From 61a8f5e425a6fdbe478c96216e44641dc03e6b2a Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 2 Feb 2023 16:19:20 -0500 Subject: [PATCH 163/415] Java: add signature to createTempDirectory sink --- java/ql/lib/ext/java.nio.file.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml index 129bf048b96..bf79844a514 100644 --- a/java/ql/lib/ext/java.nio.file.model.yml +++ b/java/ql/lib/ext/java.nio.file.model.yml @@ -9,7 +9,7 @@ extensions: - ["java.nio.file", "Files", False, "createFile", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createLink", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createSymbolicLink", "", "", "Argument[0]", "create-file", "manual"] - - ["java.nio.file", "Files", False, "createTempDirectory", "", "", "Argument[0]", "create-file", "manual"] + - ["java.nio.file", "Files", False, "createTempDirectory", "(Path,String,FileAttribute[]])", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createTempFile", "(Path,String,String,FileAttribute[])", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "move", "", "", "Argument[1]", "create-file", "manual"] - ["java.nio.file", "Files", False, "newBufferedWriter", "", "", "Argument[0]", "create-file", "manual"] From 30b1a2edbc90c66d9c7ef89787a4884c14caae72 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 2 Feb 2023 16:20:54 -0500 Subject: [PATCH 164/415] Java: add first argument to copy sink --- java/ql/lib/ext/java.nio.file.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml index bf79844a514..8532cc423f3 100644 --- a/java/ql/lib/ext/java.nio.file.model.yml +++ b/java/ql/lib/ext/java.nio.file.model.yml @@ -3,7 +3,7 @@ extensions: pack: codeql/java-all extensible: sinkModel data: - - ["java.nio.file", "Files", False, "copy", "", "", "Argument[1]", "create-file", "manual"] + - ["java.nio.file", "Files", False, "copy", "", "", "Argument[0..1]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createDirectories", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createDirectory", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createFile", "", "", "Argument[0]", "create-file", "manual"] From dd31be43e07d901bafb543c8f65be8e9b5abb364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 3 Feb 2023 09:35:22 +0100 Subject: [PATCH 165/415] Support for Twirp framework --- ruby/ql/lib/change-notes/2023-02-03-twirp.md | 4 ++ ruby/ql/lib/codeql/ruby/Frameworks.qll | 1 + ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll | 71 +++++++++++++++++++ .../library-tests/frameworks/Twirp/Gemfile | 5 ++ .../library-tests/frameworks/Twirp/Twirp.ql | 10 +++ .../Twirp/hello_world/service.proto | 15 ++++ .../Twirp/hello_world/service_pb.rb | 22 ++++++ .../Twirp/hello_world/service_twirp.rb | 17 +++++ .../frameworks/Twirp/hello_world_client.rb | 13 ++++ .../frameworks/Twirp/hello_world_server.rb | 29 ++++++++ .../frameworks/Twirp/tests.expected | 1 + 11 files changed, 188 insertions(+) create mode 100644 ruby/ql/lib/change-notes/2023-02-03-twirp.md create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/Gemfile create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service.proto create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_pb.rb create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_twirp.rb create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/hello_world_client.rb create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/tests.expected diff --git a/ruby/ql/lib/change-notes/2023-02-03-twirp.md b/ruby/ql/lib/change-notes/2023-02-03-twirp.md new file mode 100644 index 00000000000..c6f0d48837e --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-02-03-twirp.md @@ -0,0 +1,4 @@ +--- + category: minorAnalysis +--- +* Support for [Twirp framework](https://twitchtv.github.io/twirp/docs/intro.html). diff --git a/ruby/ql/lib/codeql/ruby/Frameworks.qll b/ruby/ql/lib/codeql/ruby/Frameworks.qll index c03b6427dec..735178388e8 100644 --- a/ruby/ql/lib/codeql/ruby/Frameworks.qll +++ b/ruby/ql/lib/codeql/ruby/Frameworks.qll @@ -27,3 +27,4 @@ private import codeql.ruby.frameworks.ActionDispatch private import codeql.ruby.frameworks.PosixSpawn private import codeql.ruby.frameworks.StringFormatters private import codeql.ruby.frameworks.Json +private import codeql.ruby.frameworks.Twirp diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll new file mode 100644 index 00000000000..bd8c2cc3bc5 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll @@ -0,0 +1,71 @@ +/** + * Provides classes for modeling the `Twirp` framework. + */ + +private import codeql.ruby.DataFlow +private import codeql.ruby.CFG +private import codeql.ruby.ApiGraphs +private import codeql.ruby.AST as Ast +private import codeql.ruby.security.ServerSideRequestForgeryCustomizations +private import codeql.ruby.Concepts + +/** + * Provides classes for modeling the `Twirp` framework. + */ +module Twirp { + /** + * A Twirp service instantiation + */ + class ServiceInstantiation extends DataFlow::CallNode { + ServiceInstantiation() { + this = + API::getTopLevelMember("Twirp").getMember("Service").getASubclass*().getAnInstantiation() + } + + DataFlow::LocalSourceNode getHandlerSource() { result = this.getArgument(0).getALocalSource() } + + API::Node getHandlerClassApiNode() { result.getAnInstantiation() = this.getHandlerSource() } + + DataFlow::LocalSourceNode getHandlerClassDataFlowNode() { + result = this.getHandlerClassApiNode().asSource() + } + + Ast::Module getHandlerClassAstNode() { + result = + this.getHandlerClassDataFlowNode() + .asExpr() + .(CfgNodes::ExprNodes::ConstantReadAccessCfgNode) + .getExpr() + .getModule() + } + + Ast::Method getHandlerMethod() { result = this.getHandlerClassAstNode().getAnInstanceMethod() } + } + + /** + * A Twirp client + */ + class ClientInstantiation extends DataFlow::CallNode { + ClientInstantiation() { + this = + API::getTopLevelMember("Twirp").getMember("Client").getASubclass*().getAnInstantiation() + } + } + + /** The URL of a Twirp service, considered as a sink. */ + class ServiceUrlAsSsrfSink extends ServerSideRequestForgery::Sink { + ServiceUrlAsSsrfSink() { exists(ClientInstantiation c | c.getArgument(0) = this) } + } + + /** A parameter that will receive parts of the url when handling an incoming request. */ + class UnmarshaledParameter extends Http::Server::RequestInputAccess::Range, + DataFlow::ParameterNode { + UnmarshaledParameter() { + exists(ServiceInstantiation i | i.getHandlerMethod().getParameter(0) = this.asParameter()) + } + + override string getSourceType() { result = "Twirp Unmarhaled Parameter" } + + override Http::Server::RequestInputKind getKind() { result = Http::Server::bodyInputKind() } + } +} diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/Gemfile b/ruby/ql/test/library-tests/frameworks/Twirp/Gemfile new file mode 100644 index 00000000000..9f49fa5ad78 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" + +gem "rack" +gem "webrick" +gem "twirp" diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql new file mode 100644 index 00000000000..e6b1c36bde4 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql @@ -0,0 +1,10 @@ +private import codeql.ruby.frameworks.Twirp +private import codeql.ruby.DataFlow + +query predicate sourceTest(DataFlow::Node s) { s instanceof Twirp::UnmarshaledParameter } + +query predicate ssrfSinkTest(DataFlow::Node n) { n instanceof Twirp::ServiceUrlAsSsrfSink } + +query predicate serviceInstantiationTest(DataFlow::Node n) { + n instanceof Twirp::ServiceInstantiation +} diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service.proto b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service.proto new file mode 100644 index 00000000000..f7b4a818e2f --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package example.hello_world; + + +service HelloWorld { + rpc Hello(HelloRequest) returns (HelloResponse); +} + +message HelloRequest { + string name = 1; +} + +message HelloResponse { + string message = 1; +} diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_pb.rb b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_pb.rb new file mode 100644 index 00000000000..10de1c1f7e8 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_pb.rb @@ -0,0 +1,22 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: hello_world/service.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_file("hello_world/service.proto", :syntax => :proto3) do + add_message "example.hello_world.HelloRequest" do + optional :name, :string, 1 + end + add_message "example.hello_world.HelloResponse" do + optional :message, :string, 1 + end + end +end + +module Example + module HelloWorld + HelloRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("example.hello_world.HelloRequest").msgclass + HelloResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("example.hello_world.HelloResponse").msgclass + end +end diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_twirp.rb b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_twirp.rb new file mode 100644 index 00000000000..ff3b9cc4a81 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world/service_twirp.rb @@ -0,0 +1,17 @@ +# Code generated by protoc-gen-twirp_ruby 1.10.0, DO NOT EDIT. +require 'twirp' +require_relative 'service_pb.rb' + +module Example + module HelloWorld + class HelloWorldService < ::Twirp::Service + package 'example.hello_world' + service 'HelloWorld' + rpc :Hello, HelloRequest, HelloResponse, :ruby_method => :hello + end + + class HelloWorldClient < ::Twirp::Client + client_for HelloWorldService + end + end +end diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_client.rb b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_client.rb new file mode 100644 index 00000000000..68c63796a1e --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_client.rb @@ -0,0 +1,13 @@ +require 'rack' + +require_relative 'hello_world/service_twirp.rb' + +# test: ssrfSink +c = Example::HelloWorld::HelloWorldClient.new("http://localhost:8080/twirp") + +resp = c.hello(name: "World") +if resp.error + puts resp.error +else + puts resp.data.message +end diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb new file mode 100644 index 00000000000..1aa0b9aa8de --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/hello_world_server.rb @@ -0,0 +1,29 @@ +require 'rack' +require 'webrick' + +require_relative 'hello_world/service_twirp.rb' + +class HelloWorldHandler + # test: request + def hello(req, env) + puts ">> Hello #{req.name}" + {message: "Hello #{req.name}"} + end +end + +class FakeHelloWorldHandler + # test: !request + def hello(req, env) + puts ">> Hello #{req.name}" + {message: "Hello #{req.name}"} + end +end + +handler = HelloWorldHandler.new() +# test: serviceInstantiation +service = Example::HelloWorld::HelloWorldService.new(handler) + +path_prefix = "/twirp/" + service.full_name +server = WEBrick::HTTPServer.new(Port: 8080) +server.mount path_prefix, Rack::Handler::WEBrick, service +server.start diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/tests.expected b/ruby/ql/test/library-tests/frameworks/Twirp/tests.expected new file mode 100644 index 00000000000..429c96f804a --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/tests.expected @@ -0,0 +1 @@ +The query depends on an extensional predicate sinkModel which has not been defined. From 3a9d650cb9d8b5dad8d8d83499f92fedb97b1688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 3 Feb 2023 10:09:16 +0100 Subject: [PATCH 166/415] add qldocs for member predicates --- ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll index bd8c2cc3bc5..f6de8c85d3a 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll @@ -22,14 +22,26 @@ module Twirp { API::getTopLevelMember("Twirp").getMember("Service").getASubclass*().getAnInstantiation() } + /** + * Gets a local source node for the Service instantiation argument (the service handler). + */ DataFlow::LocalSourceNode getHandlerSource() { result = this.getArgument(0).getALocalSource() } + /** + * Gets the API::Node for the service handler's class. + */ API::Node getHandlerClassApiNode() { result.getAnInstantiation() = this.getHandlerSource() } + /** + * Gets the local source node for the service handler's class. + */ DataFlow::LocalSourceNode getHandlerClassDataFlowNode() { result = this.getHandlerClassApiNode().asSource() } + /** + * Gets the AST module for the service handler's class. + */ Ast::Module getHandlerClassAstNode() { result = this.getHandlerClassDataFlowNode() From 6b2a92a7ca368a8e64fea94e553066c930ba5ed7 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 3 Feb 2023 12:12:47 +0000 Subject: [PATCH 167/415] JS: update CryptographicKey.expected --- .../CryptoLibraries/CryptographicKey.expected | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected index 4be374d96ae..55b59cb16ad 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected +++ b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected @@ -1,10 +1,11 @@ -| tst.js:5:26:5:42 | keypair.secretKey | -| tst.js:19:42:19:51 | 'a secret' | -| tst.js:29:36:29:51 | 'secret key 123' | -| tst.js:32:26:32:30 | "Key" | -| tst.js:35:30:35:34 | "Key" | -| tst.js:37:48:37:63 | 'secret key 123' | -| tst.js:39:38:39:42 | "Key" | -| tst.js:57:45:57:47 | key | -| tst.js:59:50:59:52 | key | -| tst.js:73:32:73:39 | "secret" | +| tst.js:7:26:7:42 | keypair.secretKey | +| tst.js:21:42:21:51 | 'a secret' | +| tst.js:36:36:36:51 | 'secret key 123' | +| tst.js:39:26:39:30 | "Key" | +| tst.js:42:30:42:34 | "Key" | +| tst.js:44:48:44:63 | 'secret key 123' | +| tst.js:46:38:46:42 | "Key" | +| tst.js:50:29:50:33 | "key" | +| tst.js:68:45:68:47 | key | +| tst.js:70:50:70:52 | key | +| tst.js:84:32:84:39 | "secret" | From e17b3d975d985cf6c6fd95495aa3aa269f91a2e1 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 3 Feb 2023 12:16:25 +0000 Subject: [PATCH 168/415] JS: pick up CryptographicKeys used in asmCrypto encrypt/decrypt calls --- .../semmle/javascript/frameworks/CryptoLibraries.qll | 12 +++++++++++- .../CryptoLibraries/CryptographicKey.expected | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll index 8d2921e48cb..2356e82ec95 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll @@ -51,6 +51,7 @@ private module AsmCrypto { DataFlow::Node input; CryptographicAlgorithm algorithm; // non-functional private string algorithmName; + private string methodName; Apply() { /* @@ -66,7 +67,7 @@ private module AsmCrypto { exists(DataFlow::SourceNode asmCrypto | asmCrypto = DataFlow::globalVarRef("asmCrypto") and algorithm.matchesName(algorithmName) and - this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(_) and + this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(methodName) and input = this.getArgument(0) ) } @@ -79,6 +80,15 @@ private module AsmCrypto { isBlockEncryptionAlgorithm(this.getAlgorithm()) and result.matchesString(algorithmName) } + + DataFlow::Node getKey() { + methodName = ["encrypt", "decrypt"] and + result = super.getArgument(1) + } + } + + private class Key extends CryptographicKey { + Key() { this = any(Apply apply).getKey() } } } diff --git a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected index 55b59cb16ad..1b714e688df 100644 --- a/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected +++ b/javascript/ql/test/library-tests/CryptoLibraries/CryptographicKey.expected @@ -1,3 +1,4 @@ +| tst.js:3:34:3:36 | key | | tst.js:7:26:7:42 | keypair.secretKey | | tst.js:21:42:21:51 | 'a secret' | | tst.js:36:36:36:51 | 'secret key 123' | From b968b59afc07bf64043c368645bd1cb2c5ce2f70 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 3 Feb 2023 14:15:32 +0000 Subject: [PATCH 169/415] CryptoAlgorithms: make CryptographicAlgorithm#matchesName hold only if that algorithm is the most specific match --- .../javascript/security/CryptoAlgorithms.qll | 30 ++++++++++++++----- .../python/concepts/CryptoAlgorithms.qll | 30 ++++++++++++++----- .../codeql/ruby/security/CryptoAlgorithms.qll | 30 ++++++++++++++----- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll index 766f99c61da..79dd19dd972 100644 --- a/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll +++ b/javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll @@ -26,6 +26,26 @@ private newtype TCryptographicAlgorithm = isWeakPasswordHashingAlgorithm(name) and isWeak = true } +/** + * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. + * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. + * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. + */ +bindingset[name] +private CryptographicAlgorithm getBestAlgorithmForName(string name) { + result = + max(CryptographicAlgorithm algorithm | + algorithm.getName() = + [ + name.toUpperCase(), // the full name + name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces + name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores + ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces + | + algorithm order by algorithm.getName().length() + ) +} + /** * A cryptographic algorithm. */ @@ -39,15 +59,11 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { abstract string getName(); /** - * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes, underscores, and anything after a dash or underscore in the name - * (to ignore modes of operation, such as CBC or ECB). + * Holds if the name of this algorithm is the most specific match for `name`. + * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. */ bindingset[name] - predicate matchesName(string name) { - [name.toUpperCase(), name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1)] - .regexpReplaceAll("[-_ ]", "") = getName() - } + predicate matchesName(string name) { this = getBestAlgorithmForName(name) } /** * Holds if this algorithm is weak. diff --git a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll index 766f99c61da..79dd19dd972 100644 --- a/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll +++ b/python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll @@ -26,6 +26,26 @@ private newtype TCryptographicAlgorithm = isWeakPasswordHashingAlgorithm(name) and isWeak = true } +/** + * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. + * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. + * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. + */ +bindingset[name] +private CryptographicAlgorithm getBestAlgorithmForName(string name) { + result = + max(CryptographicAlgorithm algorithm | + algorithm.getName() = + [ + name.toUpperCase(), // the full name + name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces + name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores + ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces + | + algorithm order by algorithm.getName().length() + ) +} + /** * A cryptographic algorithm. */ @@ -39,15 +59,11 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { abstract string getName(); /** - * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes, underscores, and anything after a dash or underscore in the name - * (to ignore modes of operation, such as CBC or ECB). + * Holds if the name of this algorithm is the most specific match for `name`. + * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. */ bindingset[name] - predicate matchesName(string name) { - [name.toUpperCase(), name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1)] - .regexpReplaceAll("[-_ ]", "") = getName() - } + predicate matchesName(string name) { this = getBestAlgorithmForName(name) } /** * Holds if this algorithm is weak. diff --git a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll index 766f99c61da..79dd19dd972 100644 --- a/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll +++ b/ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll @@ -26,6 +26,26 @@ private newtype TCryptographicAlgorithm = isWeakPasswordHashingAlgorithm(name) and isWeak = true } +/** + * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. + * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. + * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. + */ +bindingset[name] +private CryptographicAlgorithm getBestAlgorithmForName(string name) { + result = + max(CryptographicAlgorithm algorithm | + algorithm.getName() = + [ + name.toUpperCase(), // the full name + name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces + name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores + ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces + | + algorithm order by algorithm.getName().length() + ) +} + /** * A cryptographic algorithm. */ @@ -39,15 +59,11 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { abstract string getName(); /** - * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes, underscores, and anything after a dash or underscore in the name - * (to ignore modes of operation, such as CBC or ECB). + * Holds if the name of this algorithm is the most specific match for `name`. + * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. */ bindingset[name] - predicate matchesName(string name) { - [name.toUpperCase(), name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1)] - .regexpReplaceAll("[-_ ]", "") = getName() - } + predicate matchesName(string name) { this = getBestAlgorithmForName(name) } /** * Holds if this algorithm is weak. From 6c35feaa984d070765ef621733b31d40a17a6e54 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Fri, 3 Feb 2023 14:39:32 +0000 Subject: [PATCH 170/415] ConceptsShared: add a default implementation of BlockMode CryptographicOperation#getBlockMode() for compatibility with external code --- javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll | 2 +- python/ql/lib/semmle/python/internal/ConceptsShared.qll | 2 +- ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 23b34592852..522c883e0b4 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -78,7 +78,7 @@ module Cryptography { * This may have no result - for example if the `CryptographicAlgorithm` used * is a stream cipher rather than a block cipher. */ - abstract BlockMode getBlockMode(); + BlockMode getBlockMode() { none() } } } diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 23b34592852..522c883e0b4 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -78,7 +78,7 @@ module Cryptography { * This may have no result - for example if the `CryptographicAlgorithm` used * is a stream cipher rather than a block cipher. */ - abstract BlockMode getBlockMode(); + BlockMode getBlockMode() { none() } } } diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 23b34592852..522c883e0b4 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -78,7 +78,7 @@ module Cryptography { * This may have no result - for example if the `CryptographicAlgorithm` used * is a stream cipher rather than a block cipher. */ - abstract BlockMode getBlockMode(); + BlockMode getBlockMode() { none() } } } From 7d8b624a71d454a155e852c2eacfd08f748d11a4 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 27 Jan 2023 18:49:14 +0000 Subject: [PATCH 171/415] Basic script to generate shared code metrics --- misc/scripts/shared-code-metrics.py | 329 ++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 misc/scripts/shared-code-metrics.py diff --git a/misc/scripts/shared-code-metrics.py b/misc/scripts/shared-code-metrics.py new file mode 100644 index 00000000000..78970b4542b --- /dev/null +++ b/misc/scripts/shared-code-metrics.py @@ -0,0 +1,329 @@ +# Generates a report on the amount of code sharing in this repo +# +# The purpose of this is +# a) To be able to understand the structure and dependencies +# b) To provide a metric that measures the amount of shared vs non-shared code + +import datetime +from pathlib import Path +import json +import yaml + +# To add more languages, add them to this list: +languages = ['cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ql', 'ruby', 'swift'] + +repo_location = Path(__file__).parent.parent.parent + +# Gets the total number of lines in a file +def linecount(file): + with open(file, 'r') as fp: return len(fp.readlines()) + +# Gets the language name from the path +def get_language(path): + return path.parts[len(repo_location.parts)] + +# Is this path a CodeQL query file +def is_query(path): + return path.suffix == '.ql' + +# Is this path a CodeQL library file +def is_library(path): + return path.suffix == '.qll' + +# Is this path a relevant CodeQL file +def is_ql(path): + return is_query(path) or is_library(path) + +# Is this file a CodeQL package file +def is_package(path): + return path.name == 'qlpack.yml' + +# A CodeQL source file +class QlFile: + def __init__(self, path): + self.path = path + self.lines = linecount(path) + shared = False + + def language(self): + return get_language(self.path) + + def query(self): + return is_query(self.path) + + def library(self): + return is_library(self.path) + + # Returns if this qlfile is not shared, and is in a pack that is only in one language + def isOnlyInLanguage(self, language): + return not self.shared and (self.package is None or self.package.languages == {language}) and self.language() == language + +# Represents a language folder +class Language: + def __init__(self, name): + self.name = name + self.packs = [] + self.nonshared_files = 0 + self.nonshared_lines = 0 + self.imported_files = 0 + self.imported_lines = 0 + + def addQlFile(self, qlfile): + if not qlfile.shared: + self.nonshared_files += 1 + self.nonshared_lines += qlfile.lines + + def addSharedAsset(self, package): + self.imported_files += package.files + self.imported_lines += package.lines + +# A shared package or file +class SharedAsset: + def __init__(self, name): + self.name = name + +# A file shared using identical-files.json +class IdenticalFileSet(SharedAsset): + def __init__(self, name, ql_files): + self.name = name + self.languages = set() + self.files = 0 + self.lines = 0 + for file in ql_files: + file.package = self + file.shared = True + self.files = 1 + self.lines = file.lines + self.languages.add(file.language()) + + # Gets a pretty-printed markdown link + def link(self): + return self.name + +# Represents all files shared in `identical-files.json` +# Reads the file and builds a list of assets +class IdenticalFiles: + def __init__(self, repo_location, ql_file_index): + identical_files = repo_location/'config'/'identical-files.json' + with open(identical_files, "r") as fp: + identical_files_json = json.load(fp) + # Create a list of assets + self.assets = [] + for group in identical_files_json: + paths = [] + for file in identical_files_json[group]: + path = repo_location / file + if is_ql(path): + ql_file_index[path].shared = True + paths.append(ql_file_index[path]) + self.assets.append(IdenticalFileSet(group, paths)) + +# A package created from a `qlpack.yml`` file +class Package(SharedAsset): + def __init__(self, path, ql_file_index): + self.path = path + self.language = get_language(path) + self.lines = 0 + self.files = 0 + self.languages = set() + self.languages.add(self.language) + self.identical_files_dependencies = set() + with open(path, 'r') as fp: + y = yaml.safe_load(fp) + if 'name' in y: + self.name = y['name'] + else: + self.name = path.parent.name + if 'dependencies' in y: + self.deps = y['dependencies'] + if self.deps is None: + self.deps = {} + else: + self.deps = {} + # Mark all relevant files with their package + for file in ql_file_index: + if self.containsDirectory(file): + file = ql_file_index[file] + if not file.shared: + file.package = self + self.lines += file.lines + self.files += 1 + else: + self.identical_files_dependencies.add(file.package) + self.url = "https://github.com/github/codeql/blob/main/" + str(path.relative_to(repo_location)) + + # Gets a pretty-printed markdown link + def link(self): + return '[' + self.name + '](' + self.url + ')' + + def containsDirectory(self, dir): + return self.path.parent.parts == dir.parts[:len(self.path.parent.parts)] + # dir.startsWith(self.path.parent) + + # Constructs a list of transitive depedencies of this package. + def calculateDependencies(self, packageNameMap): + self.transitive_dependencies = set(self.deps) + queue = list(self.deps) + while len(queue): + item = queue.pop() + for dep2 in packageNameMap[item].deps: + if dep2 not in self.transitive_dependencies: + self.transitive_dependencies.add(dep2) + queue.append(dep2) + # Calculate the amount of imported code + self.total_imported_files = 0 + self.total_imported_lines = 0 + self.all_dependencies = set(self.identical_files_dependencies) + for dep in self.transitive_dependencies: + self.all_dependencies.add(packageNameMap[dep]) + for dep in self.all_dependencies: + self.total_imported_files += dep.files + self.total_imported_lines += dep.lines + dep.languages.add(self.language) + +# Create a big index of all files and their line counts. + +# Map from path to line count +ql_file_index = {} +package_files = [] + +# Queue of directories to read +directories_to_scan = [repo_location] + +while len(directories_to_scan)!=0: + dir = directories_to_scan.pop() + for p in dir.iterdir(): + if p.is_dir(): + directories_to_scan.append(p) + elif is_ql(p): + ql_file_index[p] = QlFile(p) + elif is_package(p): + package_files.append(p) + +# Create identical_files_json +identical_files = IdenticalFiles(repo_location, ql_file_index) + +# Create packages +# Do this after identical_files so that we can figure out the package sizes +# Do this after getting the ql_file_index fully built +packages = [] +for file in package_files: + packages.append(Package(file, ql_file_index)) + +# List all shared assets +shared_assets = packages + identical_files.assets + +# Construct statistics for each language +language_info = {} +for l in languages: + language_info[l] = Language(l) + +for qlfile in ql_file_index.values(): + lang = qlfile.language() + if lang in language_info: + info = language_info[lang] + if qlfile.isOnlyInLanguage(lang): + info.addQlFile(qlfile) + +# Determine all package dependencies + +packageNameMap = {} + +for package in packages: + packageNameMap[package.name] = package + +for package in packages: + package.calculateDependencies(packageNameMap) + +for asset in shared_assets: + if len(asset.languages)>1: + for lang in asset.languages: + if lang in language_info: + language_info[lang].addSharedAsset(asset) + + +# Functions to output the results + +def list_assets(shared_assets, language_info): + print('| Asset | Files | Lines |', end='') + for lang in language_info: + print('', lang, '|', end='') + print() + print('| ----- | ----- | ----- |', end='') + for lang in language_info: + print(' ---- |', end='') + print() + for asset in shared_assets: + print('|', asset.link(), '|', asset.files ,'|', asset.lines, '|', end=' ') + for lang in language_info: + if lang in asset.languages: + print('yes |', end=' ') + else: + print(' |', end=' '); + print() + print() + +def list_package_dependencies(package): + print("Package", package.path, package.name, package.files, package.lines, package.total_imported_files, package.total_imported_lines) + for dep in package.all_dependencies: + print(" ", dep.name, dep.files, dep.lines) + +def print_package_dependencies(packages): + print('| Package name | Non-shared files | Non-shared lines of code | Imported files | Imported lines of code | Shared code % |') + print('| ------------ | ---------------- | ------------------------ | -------------- | ---------------------- | ------------- |') + for package in packages: + nlines = package.lines + package.total_imported_lines + shared_percentage = 100 * package.total_imported_lines / nlines if nlines>0 else 0 + print('|', package.link(), '|', package.files, '|', package.lines, '|', package.total_imported_files, '|', package.total_imported_lines, '|', + # ','.join([p.name for p in package.all_dependencies]), + "%.2f" % shared_percentage, '|') + print() + +def print_language_dependencies(packages): + print_package_dependencies([p for p in packages if p.name.endswith('-all') and p.name.count('-')==1]) + +def list_shared_code_by_language(language_info): + # For each language directory, list the files that are (1) inside the directory and not shared, + # (2) packages from outside the directory, plus identical files + print('| Language | Non-shared files | Non-shared lines of code | Imported files | Imported lines of code | Shared code % |') + print('| -------- | ---------------- | ------------------------ | -------------- | ---------------------- | ------------- |') + for lang in language_info: + info = language_info[lang] + total = info.imported_lines + info.nonshared_lines + shared_percentage = 100 * info.imported_lines / total if total>0 else 0 + print('|', lang, '|', info.nonshared_files, '|', info.nonshared_lines, '|', info.imported_files, '|', info.imported_lines, '|', "%.2f" % shared_percentage, '|') + print() + + +# Output reports + +print('# Report on CodeQL code sharing\n') +print('Generated on', datetime.datetime.now()) +print() + +print('## Shared code by language\n') + +list_shared_code_by_language(language_info) + +print(''' +* *Non-shared files*: The number of CodeQL files (`.ql`/`.qll`) that are only used within this language folder. Excludes `identical-files.json` that are shared between multiple languages. +* *Non-shared lines of code*: The number of lines of code in the non-shared files. +* *Imported files*: All CodeQL files (`.ql`/`.qll`) files that are transitively used in this language folder, either via packages or `identical-files.json` +* *Imported lines of code*: The number of lines of code in the imported files +* *Shared code %*: The proportion of imported lines / total lines (nonshared + imported). + +## Shared packages use by language + +A package is *used* if it is a direct or indirect dependency, or a file shared via `identical-files.json`. + +''') + +list_assets(shared_assets, language_info) + +print('## Shared code by language pack\n') + +print_language_dependencies(packages) + +print('## Shared code by package\n') + +print_package_dependencies(packages) From ecafce81914e8d77599ba7a66463711f2e43d3a2 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Fri, 3 Feb 2023 21:44:23 +0100 Subject: [PATCH 172/415] improve the CryptoJS model by using API::Node --- .../javascript/frameworks/CryptoLibraries.qll | 46 ++++++++----------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll index 2356e82ec95..8ebae47d840 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll @@ -279,23 +279,18 @@ private module CryptoJS { /** * Matches `CryptoJS.` and `require("crypto-js/")` */ - private DataFlow::SourceNode getAlgorithmNode(CryptographicAlgorithm algorithm) { + private API::Node getAlgorithmNode(CryptographicAlgorithm algorithm) { exists(string algorithmName | algorithm.matchesName(algorithmName) | - exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("crypto-js") | - result = mod.getAPropertyRead(algorithmName) or - result = mod.getAPropertyRead("Hmac" + algorithmName) // they prefix Hmac + exists(API::Node mod | mod = API::moduleImport("crypto-js") | + result = mod.getMember(algorithmName) or + result = mod.getMember("Hmac" + algorithmName) // they prefix Hmac ) or - exists(DataFlow::SourceNode mod | - mod = DataFlow::moduleImport("crypto-js/" + algorithmName) and - result = mod - ) + result = API::moduleImport("crypto-js/" + algorithmName) ) } - private DataFlow::CallNode getEncryptionApplication( - DataFlow::Node input, CryptographicAlgorithm algorithm - ) { + private API::CallNode getEncryptionApplication(API::Node input, CryptographicAlgorithm algorithm) { /* * ``` * var CryptoJS = require("crypto-js"); @@ -309,13 +304,11 @@ private module CryptoJS { * Also matches where `CryptoJS.` has been replaced by `require("crypto-js/")` */ - result = getAlgorithmNode(algorithm).getAMemberCall("encrypt") and - input = result.getArgument(0) + result = getAlgorithmNode(algorithm).getMember("encrypt").getACall() and + input = result.getParameter(0) } - private DataFlow::CallNode getDirectApplication( - DataFlow::Node input, CryptographicAlgorithm algorithm - ) { + private API::CallNode getDirectApplication(API::Node input, CryptographicAlgorithm algorithm) { /* * ``` * var CryptoJS = require("crypto-js"); @@ -331,11 +324,11 @@ private module CryptoJS { */ result = getAlgorithmNode(algorithm).getACall() and - input = result.getArgument(0) + input = result.getParameter(0) } - private class Apply extends CryptographicOperation::Range, DataFlow::CallNode { - DataFlow::Node input; + private class Apply extends CryptographicOperation::Range instanceof API::CallNode { + API::Node input; CryptographicAlgorithm algorithm; // non-functional Apply() { @@ -343,16 +336,15 @@ private module CryptoJS { this = getDirectApplication(input, algorithm) } - override DataFlow::Node getAnInput() { result = input } + override DataFlow::Node getAnInput() { result = input.asSink() } override CryptographicAlgorithm getAlgorithm() { result = algorithm } // e.g. CryptoJS.AES.encrypt("msg", "key", { mode: CryptoJS.mode. }) private BlockMode getExplicitBlockMode() { - exists(DataFlow::ObjectLiteralNode o, DataFlow::SourceNode modeNode, string modeString | - modeNode = API::moduleImport("crypto-js").getMember("mode").getMember(modeString).asSource() and - o.flowsTo(this.getArgument(2)) and - modeNode = o.getAPropertySource("mode") + exists(string modeString | + API::moduleImport("crypto-js").getMember("mode").getMember(modeString).asSource() = + super.getParameter(2).getMember("mode").asSink() | result.matchesString(modeString) ) @@ -372,15 +364,13 @@ private module CryptoJS { private class Key extends CryptographicKey { Key() { - exists(DataFlow::SourceNode e, CryptographicAlgorithm algorithm | - e = getAlgorithmNode(algorithm) - | + exists(API::Node e, CryptographicAlgorithm algorithm | e = getAlgorithmNode(algorithm) | exists(string name | name = "encrypt" or name = "decrypt" | algorithm instanceof EncryptionAlgorithm and - this = e.getAMemberCall(name).getArgument(1) + this = e.getMember(name).getACall().getArgument(1) ) or algorithm instanceof HashingAlgorithm and From 2d7e71dfcec201fd5b2a3258df1126ee8e19d078 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Fri, 3 Feb 2023 17:28:46 -0500 Subject: [PATCH 173/415] Java: add read-file sink kind for first arg of copy --- java/ql/lib/ext/java.nio.file.model.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml index 8532cc423f3..9536f85d303 100644 --- a/java/ql/lib/ext/java.nio.file.model.yml +++ b/java/ql/lib/ext/java.nio.file.model.yml @@ -3,7 +3,8 @@ extensions: pack: codeql/java-all extensible: sinkModel data: - - ["java.nio.file", "Files", False, "copy", "", "", "Argument[0..1]", "create-file", "manual"] + - ["java.nio.file", "Files", False, "copy", "", "", "Argument[0]", "read-file", "manual"] + - ["java.nio.file", "Files", False, "copy", "", "", "Argument[1]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createDirectories", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createDirectory", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createFile", "", "", "Argument[0]", "create-file", "manual"] From 58d7af4018a5eaf551a5b05a18ba8b19f91acf01 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Wed, 1 Feb 2023 16:10:22 +1300 Subject: [PATCH 174/415] Ruby: Move ActionView tests into their own dir This ensures that changes to unrelated test files don't affect these tests. --- .../frameworks/ActionView.expected | 58 ------------------- .../library-tests/frameworks/ActionView.ql | 21 ------- .../action_view/ActionView.expected | 43 ++++++++++++++ .../frameworks/action_view/ActionView.ql | 24 +++++++- .../app/components/DummyComponent.rb | 2 + .../action_view/app/config/routes.rb | 52 +++++++++++++++++ .../app/controllers/comments_controller.rb | 40 +++++++++++++ .../app/controllers/foo/bars_controller.rb | 46 +++++++++++++++ .../app/controllers/photos_controller.rb | 4 ++ .../app/controllers/posts_controller.rb | 10 ++++ .../app/controllers/tags_controller.rb | 2 + .../users/notifications_controller.rb | 6 ++ .../app/graphql/mutations/base_mutation.rb | 8 +++ .../app/graphql/mutations/dummy.rb | 14 +++++ .../action_view/app/graphql/resolvers/base.rb | 4 ++ .../app/graphql/resolvers/dummy_resolver.rb | 15 +++++ .../app/graphql/types/base_argument.rb | 4 ++ .../app/graphql/types/base_field.rb | 5 ++ .../app/graphql/types/base_input_object.rb | 5 ++ .../app/graphql/types/base_interface.rb | 7 +++ .../app/graphql/types/base_object.rb | 5 ++ .../app/graphql/types/mutation_type.rb | 5 ++ .../app/graphql/types/query_type.rb | 46 +++++++++++++++ .../app/views/foo/bars/_widget.html.erb | 4 ++ .../app/views/foo/bars/show.html.erb | 33 +++++++++++ 25 files changed, 382 insertions(+), 81 deletions(-) delete mode 100644 ruby/ql/test/library-tests/frameworks/ActionView.expected delete mode 100644 ruby/ql/test/library-tests/frameworks/ActionView.ql create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/components/DummyComponent.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/config/routes.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/controllers/comments_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/controllers/foo/bars_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/controllers/photos_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/controllers/posts_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/controllers/tags_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/controllers/users/notifications_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/base_mutation.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/dummy.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/base.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/dummy_resolver.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_argument.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_field.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_input_object.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_interface.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_object.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/mutation_type.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/query_type.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/_widget.html.erb create mode 100644 ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/show.html.erb diff --git a/ruby/ql/test/library-tests/frameworks/ActionView.expected b/ruby/ql/test/library-tests/frameworks/ActionView.expected deleted file mode 100644 index 07fb6264633..00000000000 --- a/ruby/ql/test/library-tests/frameworks/ActionView.expected +++ /dev/null @@ -1,58 +0,0 @@ -rawCalls -| app/views/foo/bars/_widget.html.erb:1:5:1:21 | call to raw | -| app/views/foo/bars/_widget.html.erb:2:5:2:20 | call to raw | -| app/views/foo/bars/_widget.html.erb:3:5:3:29 | call to raw | -| app/views/foo/bars/show.html.erb:1:14:1:29 | call to raw | -| app/views/foo/bars/show.html.erb:2:5:2:21 | call to raw | -| app/views/foo/bars/show.html.erb:3:5:3:20 | call to raw | -| app/views/foo/bars/show.html.erb:4:5:4:29 | call to raw | -| app/views/foo/bars/show.html.erb:5:5:5:21 | call to raw | -| app/views/foo/bars/show.html.erb:7:5:7:19 | call to raw | -renderCalls -| action_controller/controllers/comments_controller.rb:60:21:60:64 | call to render | -| action_controller/controllers/comments_controller.rb:76:5:76:68 | call to render | -| action_controller/controllers/foo/bars_controller.rb:6:5:6:37 | call to render | -| action_controller/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | -| action_controller/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | -| action_controller/controllers/foo/bars_controller.rb:38:5:38:50 | call to render | -| action_controller/controllers/foo/bars_controller.rb:44:5:44:17 | call to render | -| app/controllers/foo/bars_controller.rb:6:5:6:37 | call to render | -| app/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | -| app/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | -| app/controllers/foo/bars_controller.rb:38:5:38:50 | call to render | -| app/controllers/foo/bars_controller.rb:44:5:44:17 | call to render | -| app/views/foo/bars/show.html.erb:31:5:31:89 | call to render | -renderToCalls -| action_controller/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | -| action_controller/controllers/foo/bars_controller.rb:36:12:36:67 | call to render_to_string | -| app/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | -| app/controllers/foo/bars_controller.rb:36:12:36:67 | call to render_to_string | -linkToCalls -| app/views/foo/bars/show.html.erb:33:5:33:41 | call to link_to | -httpResponses -| action_controller/controllers/comments_controller.rb:26:5:26:17 | call to body= | action_controller/controllers/comments_controller.rb:26:21:26:34 | ... = ... | text/http | -| action_controller/controllers/comments_controller.rb:36:5:36:37 | call to send_file | action_controller/controllers/comments_controller.rb:36:24:36:36 | "my-file.ext" | application/octet-stream | -| action_controller/controllers/comments_controller.rb:65:5:65:20 | call to send_data | action_controller/controllers/comments_controller.rb:65:15:65:20 | @photo | application/octet-stream | -| action_controller/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | action_controller/controllers/foo/bars_controller.rb:15:33:15:47 | "foo/bars/show" | text/html | -| action_controller/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | action_controller/controllers/foo/bars_controller.rb:23:12:23:26 | "foo/bars/show" | text/html | -| action_controller/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | action_controller/controllers/foo/bars_controller.rb:35:18:35:33 | call to [] | application/json | -| action_controller/controllers/foo/bars_controller.rb:36:12:36:67 | call to render_to_string | action_controller/controllers/foo/bars_controller.rb:36:29:36:33 | @user | application/json | -| action_controller/controllers/foo/bars_controller.rb:38:5:38:50 | call to render | action_controller/controllers/foo/bars_controller.rb:38:12:38:22 | call to backtrace | text/plain | -| action_controller/controllers/foo/bars_controller.rb:44:5:44:17 | call to render | action_controller/controllers/foo/bars_controller.rb:44:12:44:17 | "show" | text/html | -| app/controllers/comments_controller.rb:11:5:11:17 | call to body= | app/controllers/comments_controller.rb:11:21:11:34 | ... = ... | text/http | -| app/controllers/comments_controller.rb:21:5:21:37 | call to send_file | app/controllers/comments_controller.rb:21:24:21:36 | "my-file.ext" | application/octet-stream | -| app/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | app/controllers/foo/bars_controller.rb:15:33:15:47 | "foo/bars/show" | text/html | -| app/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | app/controllers/foo/bars_controller.rb:23:12:23:26 | "foo/bars/show" | text/html | -| app/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | app/controllers/foo/bars_controller.rb:35:18:35:33 | call to [] | application/json | -| app/controllers/foo/bars_controller.rb:36:12:36:67 | call to render_to_string | app/controllers/foo/bars_controller.rb:36:29:36:33 | @user | application/json | -| app/controllers/foo/bars_controller.rb:38:5:38:50 | call to render | app/controllers/foo/bars_controller.rb:38:12:38:22 | call to backtrace | text/plain | -| app/controllers/foo/bars_controller.rb:44:5:44:17 | call to render | app/controllers/foo/bars_controller.rb:44:12:44:17 | "show" | text/html | -rawHelperCalls -| action_view/helpers.erb:4:1:4:36 | call to simple_format | action_view/helpers.erb:4:15:4:15 | call to x | -| action_view/helpers.erb:7:1:7:26 | call to truncate | action_view/helpers.erb:7:10:7:10 | call to x | -| action_view/helpers.erb:10:1:10:29 | call to highlight | action_view/helpers.erb:10:11:10:11 | call to x | -| action_view/helpers.erb:12:1:12:17 | call to javascript_tag | action_view/helpers.erb:12:16:12:16 | call to x | -| action_view/helpers.erb:15:1:15:27 | call to content_tag | action_view/helpers.erb:15:16:15:16 | call to y | -| action_view/helpers.erb:18:1:18:19 | call to tag | action_view/helpers.erb:18:5:18:5 | call to x | -| action_view/helpers.erb:21:1:21:24 | call to h1 | action_view/helpers.erb:21:8:21:8 | call to x | -| action_view/helpers.erb:24:1:24:23 | call to p | action_view/helpers.erb:24:7:24:7 | call to x | diff --git a/ruby/ql/test/library-tests/frameworks/ActionView.ql b/ruby/ql/test/library-tests/frameworks/ActionView.ql deleted file mode 100644 index 124cf0722a1..00000000000 --- a/ruby/ql/test/library-tests/frameworks/ActionView.ql +++ /dev/null @@ -1,21 +0,0 @@ -private import ruby -private import codeql.ruby.AST -private import codeql.ruby.frameworks.ActionView -private import codeql.ruby.frameworks.Rails -private import codeql.ruby.Concepts - -query predicate rawCalls(RawCall c) { any() } - -query predicate renderCalls(Rails::RenderCall c) { any() } - -query predicate renderToCalls(Rails::RenderToCall c) { any() } - -query predicate linkToCalls(LinkToCall c) { any() } - -query predicate httpResponses(Http::Server::HttpResponse r, DataFlow::Node body, string mimeType) { - r.getBody() = body and r.getMimetype() = mimeType -} - -query predicate rawHelperCalls(ActionView::Helpers::RawHelperCall c, Expr arg) { - arg = c.getRawArgument() -} diff --git a/ruby/ql/test/library-tests/frameworks/action_view/ActionView.expected b/ruby/ql/test/library-tests/frameworks/action_view/ActionView.expected index 6b228de4219..b0512da2e84 100644 --- a/ruby/ql/test/library-tests/frameworks/action_view/ActionView.expected +++ b/ruby/ql/test/library-tests/frameworks/action_view/ActionView.expected @@ -1 +1,44 @@ +fileSystemResolverAccesses | ActionView.rb:5:39:5:92 | call to new | ActionView.rb:5:74:5:82 | view_path | +| app/controllers/comments_controller.rb:21:5:21:37 | call to send_file | app/controllers/comments_controller.rb:21:24:21:36 | "my-file.ext" | +| app/controllers/foo/bars_controller.rb:1:1:1:14 | call to require | app/controllers/foo/bars_controller.rb:1:9:1:14 | "json" | +rawCalls +| app/views/foo/bars/_widget.html.erb:1:5:1:21 | call to raw | +| app/views/foo/bars/_widget.html.erb:2:5:2:20 | call to raw | +| app/views/foo/bars/_widget.html.erb:3:5:3:29 | call to raw | +| app/views/foo/bars/show.html.erb:1:14:1:29 | call to raw | +| app/views/foo/bars/show.html.erb:2:5:2:21 | call to raw | +| app/views/foo/bars/show.html.erb:3:5:3:20 | call to raw | +| app/views/foo/bars/show.html.erb:4:5:4:29 | call to raw | +| app/views/foo/bars/show.html.erb:5:5:5:21 | call to raw | +| app/views/foo/bars/show.html.erb:7:5:7:19 | call to raw | +renderCalls +| app/controllers/foo/bars_controller.rb:6:5:6:37 | call to render | +| app/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | +| app/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | +| app/controllers/foo/bars_controller.rb:38:5:38:50 | call to render | +| app/controllers/foo/bars_controller.rb:44:5:44:17 | call to render | +| app/views/foo/bars/show.html.erb:31:5:31:89 | call to render | +renderToCalls +| app/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | +| app/controllers/foo/bars_controller.rb:36:12:36:67 | call to render_to_string | +linkToCalls +| app/views/foo/bars/show.html.erb:33:5:33:41 | call to link_to | +httpResponses +| app/controllers/comments_controller.rb:11:5:11:17 | call to body= | app/controllers/comments_controller.rb:11:21:11:34 | ... = ... | text/http | +| app/controllers/comments_controller.rb:21:5:21:37 | call to send_file | app/controllers/comments_controller.rb:21:24:21:36 | "my-file.ext" | application/octet-stream | +| app/controllers/foo/bars_controller.rb:15:16:15:97 | call to render_to_string | app/controllers/foo/bars_controller.rb:15:33:15:47 | "foo/bars/show" | text/html | +| app/controllers/foo/bars_controller.rb:23:5:23:76 | call to render | app/controllers/foo/bars_controller.rb:23:12:23:26 | "foo/bars/show" | text/html | +| app/controllers/foo/bars_controller.rb:35:5:35:33 | call to render | app/controllers/foo/bars_controller.rb:35:18:35:33 | call to [] | application/json | +| app/controllers/foo/bars_controller.rb:36:12:36:67 | call to render_to_string | app/controllers/foo/bars_controller.rb:36:29:36:33 | @user | application/json | +| app/controllers/foo/bars_controller.rb:38:5:38:50 | call to render | app/controllers/foo/bars_controller.rb:38:12:38:22 | call to backtrace | text/plain | +| app/controllers/foo/bars_controller.rb:44:5:44:17 | call to render | app/controllers/foo/bars_controller.rb:44:12:44:17 | "show" | text/html | +rawHelperCalls +| helpers.erb:4:1:4:36 | call to simple_format | helpers.erb:4:15:4:15 | call to x | +| helpers.erb:7:1:7:26 | call to truncate | helpers.erb:7:10:7:10 | call to x | +| helpers.erb:10:1:10:29 | call to highlight | helpers.erb:10:11:10:11 | call to x | +| helpers.erb:12:1:12:17 | call to javascript_tag | helpers.erb:12:16:12:16 | call to x | +| helpers.erb:15:1:15:27 | call to content_tag | helpers.erb:15:16:15:16 | call to y | +| helpers.erb:18:1:18:19 | call to tag | helpers.erb:18:5:18:5 | call to x | +| helpers.erb:21:1:21:24 | call to h1 | helpers.erb:21:8:21:8 | call to x | +| helpers.erb:24:1:24:23 | call to p | helpers.erb:24:7:24:7 | call to x | diff --git a/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql b/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql index 578f975b8e2..6543efcef02 100644 --- a/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql +++ b/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql @@ -1,6 +1,26 @@ -import codeql.ruby.Concepts -import codeql.ruby.DataFlow +private import ruby +private import codeql.ruby.AST +private import codeql.ruby.frameworks.ActionView +private import codeql.ruby.frameworks.Rails +private import codeql.ruby.Concepts +private import codeql.ruby.DataFlow query predicate fileSystemResolverAccesses(FileSystemAccess a, DataFlow::Node path) { a.getAPathArgument() = path } + +query predicate rawCalls(RawCall c) { any() } + +query predicate renderCalls(Rails::RenderCall c) { any() } + +query predicate renderToCalls(Rails::RenderToCall c) { any() } + +query predicate linkToCalls(LinkToCall c) { any() } + +query predicate httpResponses(Http::Server::HttpResponse r, DataFlow::Node body, string mimeType) { + r.getBody() = body and r.getMimetype() = mimeType +} + +query predicate rawHelperCalls(ActionView::Helpers::RawHelperCall c, Expr arg) { + arg = c.getRawArgument() +} diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/components/DummyComponent.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/components/DummyComponent.rb new file mode 100644 index 00000000000..80d6a602d68 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/components/DummyComponent.rb @@ -0,0 +1,2 @@ +class DummyComponent < ViewComponent::Base +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/config/routes.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/config/routes.rb new file mode 100644 index 00000000000..9c33071aa50 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/config/routes.rb @@ -0,0 +1,52 @@ +Rails.application.routes.draw do + resources :posts, only: [:show, :index] do + resources :comments do + resources :replies, only: [:create] + post "flag", to: :flag + end + post "upvote", to: "posts#upvote" + end + + if Rails.env.test? + post "destroy_all_posts", to: "posts#destroy_alll" + end + + constraints(number: /[0-9]+/) do + get "/numbers/:number", to: "numbers#show" + end + + scope path: "/admin" do + get "/jobs", to: "background_jobs#index" + end + + scope "/admin" do + get "secrets", controller: "secrets", action: "view_secrets" + delete ":user_id", to: "users#destroy" + end + + match "photos/:id" => "photos#show", via: :get + match "photos/:id", to: "photos#show", via: :get + match "photos/:id", controller: "photos", action: "show", via: :get + match "photos/:id", to: "photos#show", via: :all + + scope controller: "users" do + post "upgrade", action: "start_upgrade" + end + + scope module: "enterprise", controller: "billing" do + get "current_billing_cycle" + end + + resource :global_config, only: [:show] + + namespace :foo do + resources :bar, only: [:index, :show] do + get "show_debug", to: :show_debug + end + end + + scope "/users/:user" do + delete "/notifications", to: "users/notifications#destroy", as: :user_destroy_notifications + post "notifications/:notification_id/mark_as_read", to: "users/notifications#mark_as_read" + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/comments_controller.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/comments_controller.rb new file mode 100644 index 00000000000..57fac7797bd --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/comments_controller.rb @@ -0,0 +1,40 @@ +class CommentsController < ApplicationController + def index + request.params + request.parameters + request.GET + request.POST + request.query_parameters + request.request_parameters + request.filtered_parameters + + response.body = "some content" + + response.status = 200 + + response.header["Content-Type"] = "text/html" + response.set_header("Content-Length", 100) + response.headers["X-Custom-Header"] = "hi" + response["X-Another-Custom-Header"] = "yes" + response.add_header "X-Yet-Another", "indeed" + + response.send_file("my-file.ext") + + response.request + + response.location = "http://..." # relevant for url redirect query + response.cache_control = "value" + response._cache_control = "value" + response.etag = "value" + response.charset = "value" # sets the charset part of the content-type header + response.content_type = "value" # sets the main part of the content-type header + + response.date = Date.today + response.last_modified = Date.yesterday + response.weak_etag = "value" + response.strong_etag = "value" + end + + def show + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/foo/bars_controller.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/foo/bars_controller.rb new file mode 100644 index 00000000000..9778b8d5bcc --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/foo/bars_controller.rb @@ -0,0 +1,46 @@ +require 'json' + +class BarsController < ApplicationController + + def index + render template: "foo/bars/index" + end + + def show_debug + user_info = JSON.load cookies[:user_info] + puts "User: #{user_info['name']}" + + @user_website = params[:website] + dt = params[:text] + rendered = render_to_string "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } + puts rendered + redirect_to action: "show" + end + + def show + @user_website = params[:website] + dt = params[:text] + render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } + end + + def go_back + redirect_back_or_to action: "index" + end + + def go_back_2 + redirect_back fallback_location: { action: "index" } + end + + def show_2 + render json: { some: "data" } + body = render_to_string @user, content_type: "application/json" + rescue => e + render e.backtrace, content_type: "text/plain" + end + + private + + def unreachable_action + render "show" + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/photos_controller.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/photos_controller.rb new file mode 100644 index 00000000000..0de193b9029 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/photos_controller.rb @@ -0,0 +1,4 @@ +class PhotosController < ApplicationController + def show + end +end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/posts_controller.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/posts_controller.rb new file mode 100644 index 00000000000..9760219cdf2 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/posts_controller.rb @@ -0,0 +1,10 @@ +class PostsController < ApplicationController + def index + end + + def show + end + + def upvote + end +end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/tags_controller.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/tags_controller.rb new file mode 100644 index 00000000000..ba10ea8ea2e --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/tags_controller.rb @@ -0,0 +1,2 @@ +class TagsController < ActionController::Metal +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/users/notifications_controller.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/users/notifications_controller.rb new file mode 100644 index 00000000000..c5ff9cd3f5f --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/controllers/users/notifications_controller.rb @@ -0,0 +1,6 @@ +module Users + class NotificationsController < ApplicationController + def mark_as_read + end + end +end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/base_mutation.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/base_mutation.rb new file mode 100644 index 00000000000..0749ec0313f --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/base_mutation.rb @@ -0,0 +1,8 @@ +module Mutations + class BaseMutation < GraphQL::Schema::RelayClassicMutation + argument_class Types::BaseArgument + field_class Types::BaseField + input_object_class Types::BaseInputObject + object_class Types::BaseObject + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/dummy.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/dummy.rb new file mode 100644 index 00000000000..52f01c3d6eb --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/mutations/dummy.rb @@ -0,0 +1,14 @@ +module Mutations + class Dummy < BaseMutation + argument :something_id, ID, required: false + + def load_something(id) + "Something number #{id}" + end + + def resolve(something:) + system("echo #{something}") + { success: true } + end + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/base.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/base.rb new file mode 100644 index 00000000000..a51595c00a7 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/base.rb @@ -0,0 +1,4 @@ +module Resolvers + class Base < GraphQL::Schema::Resolver + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/dummy_resolver.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/dummy_resolver.rb new file mode 100644 index 00000000000..1fbc927c816 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/resolvers/dummy_resolver.rb @@ -0,0 +1,15 @@ +module Resolvers + class DummyResolver < Resolvers::Base + type String, null: false + argument :something_id, ID, required: true + + def load_something(id) + "Something number #{id}" + end + + def resolve(something:) + system("echo #{something}") + "true" + end + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_argument.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_argument.rb new file mode 100644 index 00000000000..c1bfdabbfee --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_argument.rb @@ -0,0 +1,4 @@ +module Types + class BaseArgument < GraphQL::Schema::Argument + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_field.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_field.rb new file mode 100644 index 00000000000..7142ef7ddb4 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_field.rb @@ -0,0 +1,5 @@ +module Types + class BaseField < GraphQL::Schema::Field + argument_class Types::BaseArgument + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_input_object.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_input_object.rb new file mode 100644 index 00000000000..c97c4796373 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_input_object.rb @@ -0,0 +1,5 @@ +module Types + class BaseInputObject < GraphQL::Schema::InputObject + argument_class Types::BaseArgument + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_interface.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_interface.rb new file mode 100644 index 00000000000..f25c9650044 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_interface.rb @@ -0,0 +1,7 @@ +module Types + module BaseInterface + include GraphQL::Schema::Interface + + field_class Types::BaseField + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_object.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_object.rb new file mode 100644 index 00000000000..1f918414d98 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/base_object.rb @@ -0,0 +1,5 @@ +module Types + class BaseObject < GraphQL::Schema::Object + field_class Types::BaseField + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/mutation_type.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/mutation_type.rb new file mode 100644 index 00000000000..5ef19f95ae6 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/mutation_type.rb @@ -0,0 +1,5 @@ +module Types + class MutationType < Types::BaseObject + field :dummy, mutation: Mutations::Dummy + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/query_type.rb b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/query_type.rb new file mode 100644 index 00000000000..e0bc578a911 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/graphql/types/query_type.rb @@ -0,0 +1,46 @@ +module Types + class QueryType < Types::BaseObject + field :test_field, String, null: false, + description: "An example field added by the generator", + resolver: Resolvers::DummyResolver + + field :with_arg, String, null: false, description: "A field with an argument" do + argument :number, Int, "A number", required: true + end + def with_arg(number:) + system("echo #{number}") + number.to_s + end + + field :with_method, String, null: false, description: "A field with a custom resolver method", resolver_method: :custom_method do + argument :blah_number, Int, "A number", required: true + end + def custom_method(blah_number:, number: nil) + system("echo #{blah_number}") + system("echo #{number}") + blah_number.to_s + end + + field :with_splat, String, null: false, description: "A field with a double-splatted argument" do + argument :something, Int, "A number", required: true + end + def with_splat(**args) + system("echo #{args[:something]}") + args[:something].to_s + end + + field :with_splat_and_named_arg, String, null: false, description: "A field with two named arguments, where the method captures the second via a hash splat param" do + argument :arg1, Int, "A number", required: true + argument :arg2, Int, "Another number", required: true + end + def with_splat_and_named_arg(arg1:, **rest) + system("echo #{arg1}") + system("echo #{rest[:arg2]}") + arg1.to_s + end + + def foo(arg) + system("echo #{arg}") + end + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/_widget.html.erb b/ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/_widget.html.erb new file mode 100644 index 00000000000..dda3813363a --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/_widget.html.erb @@ -0,0 +1,4 @@ +<%= raw @display_text %> +<%= raw display_text %> +<%= raw locals[:display_text] %> +<%= @display_text %> diff --git a/ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/show.html.erb b/ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/show.html.erb new file mode 100644 index 00000000000..a86fabf719c --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_view/app/views/foo/bars/show.html.erb @@ -0,0 +1,33 @@ +website +<%= raw @display_text %> +<%= raw display_text %> +<%= raw locals[:display_text] %> +<%= raw params[:text] %> +<% key = :display_text %> +<%= raw locals[key] %> + +
      +<% key = [:display_text, :safe_text] do +
    • <%= raw locals[key] %>
    • +<% end %> +
    + +<%= @display_text %> + +<%= + full_text = prefix + locals[:display_text] + full_text +%> + +<%= + @display_text.html_safe +%> + +<%= + @display_text.html_safe + @display_text +%> + +<%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %> + +<%= link_to "some website", @user_website %> From 6c816d56023b771c5635b81dc5962a085d45d041 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Wed, 1 Feb 2023 16:18:10 +1300 Subject: [PATCH 175/415] Ruby: Move ActionDispatch tests to own directory --- .../frameworks/ActionDispatch.expected | 139 ------------------ .../action_dispatch/ActionDispatch.expected | 68 +++++++++ .../{ => action_dispatch}/ActionDispatch.ql | 0 .../action_dispatch/app/config/routes.rb | 52 +++++++ .../app/controllers/comments_controller.rb | 40 +++++ .../app/controllers/foo/bars_controller.rb | 46 ++++++ .../app/controllers/photos_controller.rb | 4 + .../app/controllers/posts_controller.rb | 10 ++ .../app/controllers/tags_controller.rb | 2 + .../users/notifications_controller.rb | 6 + .../frameworks/action_view/ActionView.ql | 1 - 11 files changed, 228 insertions(+), 140 deletions(-) delete mode 100644 ruby/ql/test/library-tests/frameworks/ActionDispatch.expected create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected rename ruby/ql/test/library-tests/frameworks/{ => action_dispatch}/ActionDispatch.ql (100%) create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/app/config/routes.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/foo/bars_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/photos_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/posts_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/tags_controller.rb create mode 100644 ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/users/notifications_controller.rb diff --git a/ruby/ql/test/library-tests/frameworks/ActionDispatch.expected b/ruby/ql/test/library-tests/frameworks/ActionDispatch.expected deleted file mode 100644 index f09706f05fe..00000000000 --- a/ruby/ql/test/library-tests/frameworks/ActionDispatch.expected +++ /dev/null @@ -1,139 +0,0 @@ -actionDispatchRoutes -| action_controller/routes.rb:2:5:2:20 | call to resources | delete | users/:id | users | destroy | -| action_controller/routes.rb:2:5:2:20 | call to resources | get | users | users | index | -| action_controller/routes.rb:2:5:2:20 | call to resources | get | users/:id | users | show | -| action_controller/routes.rb:2:5:2:20 | call to resources | get | users/new | users | new | -| action_controller/routes.rb:2:5:2:20 | call to resources | get | users:id/edit | users | edit | -| action_controller/routes.rb:2:5:2:20 | call to resources | patch | users/:id | users | update | -| action_controller/routes.rb:2:5:2:20 | call to resources | post | users | users | create | -| action_controller/routes.rb:2:5:2:20 | call to resources | put | users/:id | users | update | -| action_controller/routes.rb:3:5:5:7 | call to resources | delete | comments/:id | comments | destroy | -| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments | comments | index | -| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments/:id | comments | show | -| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments/new | comments | new | -| action_controller/routes.rb:3:5:5:7 | call to resources | get | comments:id/edit | comments | edit | -| action_controller/routes.rb:3:5:5:7 | call to resources | patch | comments/:id | comments | update | -| action_controller/routes.rb:3:5:5:7 | call to resources | post | comments | comments | create | -| action_controller/routes.rb:3:5:5:7 | call to resources | put | comments/:id | comments | update | -| action_controller/routes.rb:4:9:4:32 | call to get | get | comments/:comment_id/photo | comments | photo | -| action_controller/routes.rb:6:5:6:21 | call to resources | delete | photos/:id | photos | destroy | -| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos | photos | index | -| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos/:id | photos | show | -| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos/new | photos | new | -| action_controller/routes.rb:6:5:6:21 | call to resources | get | photos:id/edit | photos | edit | -| action_controller/routes.rb:6:5:6:21 | call to resources | patch | photos/:id | photos | update | -| action_controller/routes.rb:6:5:6:21 | call to resources | post | photos | photos | create | -| action_controller/routes.rb:6:5:6:21 | call to resources | put | photos/:id | photos | update | -| action_controller/routes.rb:7:5:9:7 | call to resources | delete | posts/:id | posts | destroy | -| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts | posts | index | -| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts/:id | posts | show | -| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts/new | posts | new | -| action_controller/routes.rb:7:5:9:7 | call to resources | get | posts:id/edit | posts | edit | -| action_controller/routes.rb:7:5:9:7 | call to resources | patch | posts/:id | posts | update | -| action_controller/routes.rb:7:5:9:7 | call to resources | post | posts | posts | create | -| action_controller/routes.rb:7:5:9:7 | call to resources | put | posts/:id | posts | update | -| action_controller/routes.rb:8:9:8:34 | call to post | post | posts/:post_id/upvote | posts | upvote | -| action_controller/routes.rb:10:5:10:19 | call to resources | delete | tags/:id | tags | destroy | -| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags | tags | index | -| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags/:id | tags | show | -| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags/new | tags | new | -| action_controller/routes.rb:10:5:10:19 | call to resources | get | tags:id/edit | tags | edit | -| action_controller/routes.rb:10:5:10:19 | call to resources | patch | tags/:id | tags | update | -| action_controller/routes.rb:10:5:10:19 | call to resources | post | tags | tags | create | -| action_controller/routes.rb:10:5:10:19 | call to resources | put | tags/:id | tags | update | -| app/config/routes.rb:2:3:8:5 | call to resources | get | posts | posts | index | -| app/config/routes.rb:2:3:8:5 | call to resources | get | posts/:id | posts | show | -| app/config/routes.rb:3:5:6:7 | call to resources | delete | posts/:post_id/comments/:id | comments | destroy | -| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments | comments | index | -| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments/:id | comments | show | -| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments/new | comments | new | -| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments:id/edit | comments | edit | -| app/config/routes.rb:3:5:6:7 | call to resources | patch | posts/:post_id/comments/:id | comments | update | -| app/config/routes.rb:3:5:6:7 | call to resources | post | posts/:post_id/comments | comments | create | -| app/config/routes.rb:3:5:6:7 | call to resources | put | posts/:post_id/comments/:id | comments | update | -| app/config/routes.rb:4:7:4:41 | call to resources | post | posts/:post_id/comments/:comment_id/replies | replies | create | -| app/config/routes.rb:5:7:5:28 | call to post | post | posts/:post_id/comments/:comment_id/flag | comments | flag | -| app/config/routes.rb:7:5:7:37 | call to post | post | posts/:post_id/upvote | posts | upvote | -| app/config/routes.rb:11:5:11:54 | call to post | post | destroy_all_posts | posts | destroy_alll | -| app/config/routes.rb:15:5:15:46 | call to get | get | numbers/:number | numbers | show | -| app/config/routes.rb:19:5:19:44 | call to get | get | admin/jobs | background_jobs | index | -| app/config/routes.rb:23:5:23:64 | call to get | get | admin/secrets | secrets | view_secrets | -| app/config/routes.rb:24:5:24:42 | call to delete | delete | admin/:user_id | users | destroy | -| app/config/routes.rb:27:3:27:48 | call to match | get | photos/:id | photos | show | -| app/config/routes.rb:28:3:28:50 | call to match | get | photos/:id | photos | show | -| app/config/routes.rb:29:3:29:69 | call to match | get | photos/:id | photos | show | -| app/config/routes.rb:30:3:30:50 | call to match | delete | photos/:id | photos | show | -| app/config/routes.rb:30:3:30:50 | call to match | get | photos/:id | photos | show | -| app/config/routes.rb:30:3:30:50 | call to match | patch | photos/:id | photos | show | -| app/config/routes.rb:30:3:30:50 | call to match | post | photos/:id | photos | show | -| app/config/routes.rb:30:3:30:50 | call to match | put | photos/:id | photos | show | -| app/config/routes.rb:33:5:33:43 | call to post | post | upgrade | users | start_upgrade | -| app/config/routes.rb:37:5:37:31 | call to get | get | current_billing_cycle | billing/enterprise | current_billing_cycle | -| app/config/routes.rb:40:3:40:40 | call to resource | get | global_config | global_config | show | -| app/config/routes.rb:43:5:45:7 | call to resources | get | foo/bar | foo/bar | index | -| app/config/routes.rb:43:5:45:7 | call to resources | get | foo/bar/:id | foo/bar | show | -| app/config/routes.rb:44:7:44:39 | call to get | get | foo/bar/:bar_id/show_debug | foo/bar | show_debug | -| app/config/routes.rb:49:5:49:95 | call to delete | delete | users/:user/notifications | users/notifications | destroy | -| app/config/routes.rb:50:5:50:94 | call to post | post | users/:user/notifications/:notification_id/mark_as_read | users/notifications | mark_as_read | -actionDispatchControllerMethods -| action_controller/routes.rb:2:5:2:20 | call to resources | action_controller/input_access.rb:2:3:49:5 | index | -| action_controller/routes.rb:2:5:2:20 | call to resources | action_controller/logging.rb:2:5:8:7 | index | -| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:17:3:51:5 | index | -| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:53:3:54:5 | create | -| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:56:3:62:5 | show | -| action_controller/routes.rb:3:5:5:7 | call to resources | action_controller/controllers/comments_controller.rb:68:3:70:5 | destroy | -| action_controller/routes.rb:3:5:5:7 | call to resources | app/controllers/comments_controller.rb:2:3:36:5 | index | -| action_controller/routes.rb:3:5:5:7 | call to resources | app/controllers/comments_controller.rb:38:3:39:5 | show | -| action_controller/routes.rb:4:9:4:32 | call to get | action_controller/controllers/comments_controller.rb:64:3:66:5 | photo | -| action_controller/routes.rb:6:5:6:21 | call to resources | action_controller/controllers/photos_controller.rb:3:3:6:5 | show | -| action_controller/routes.rb:6:5:6:21 | call to resources | app/controllers/photos_controller.rb:2:3:3:5 | show | -| action_controller/routes.rb:7:5:9:7 | call to resources | action_controller/controllers/posts_controller.rb:12:3:13:5 | index | -| action_controller/routes.rb:7:5:9:7 | call to resources | action_controller/controllers/posts_controller.rb:15:3:16:5 | show | -| action_controller/routes.rb:7:5:9:7 | call to resources | app/controllers/posts_controller.rb:2:3:3:5 | index | -| action_controller/routes.rb:7:5:9:7 | call to resources | app/controllers/posts_controller.rb:5:3:6:5 | show | -| action_controller/routes.rb:8:9:8:34 | call to post | action_controller/controllers/posts_controller.rb:18:3:19:5 | upvote | -| action_controller/routes.rb:8:9:8:34 | call to post | app/controllers/posts_controller.rb:8:3:9:5 | upvote | -| app/config/routes.rb:2:3:8:5 | call to resources | action_controller/controllers/posts_controller.rb:12:3:13:5 | index | -| app/config/routes.rb:2:3:8:5 | call to resources | action_controller/controllers/posts_controller.rb:15:3:16:5 | show | -| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:2:3:3:5 | index | -| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:5:3:6:5 | show | -| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:17:3:51:5 | index | -| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:53:3:54:5 | create | -| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:56:3:62:5 | show | -| app/config/routes.rb:3:5:6:7 | call to resources | action_controller/controllers/comments_controller.rb:68:3:70:5 | destroy | -| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:2:3:36:5 | index | -| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:38:3:39:5 | show | -| app/config/routes.rb:7:5:7:37 | call to post | action_controller/controllers/posts_controller.rb:18:3:19:5 | upvote | -| app/config/routes.rb:7:5:7:37 | call to post | app/controllers/posts_controller.rb:8:3:9:5 | upvote | -| app/config/routes.rb:27:3:27:48 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show | -| app/config/routes.rb:27:3:27:48 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | -| app/config/routes.rb:28:3:28:50 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show | -| app/config/routes.rb:28:3:28:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | -| app/config/routes.rb:29:3:29:69 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show | -| app/config/routes.rb:29:3:29:69 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | -| app/config/routes.rb:30:3:30:50 | call to match | action_controller/controllers/photos_controller.rb:3:3:6:5 | show | -| app/config/routes.rb:30:3:30:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | -| app/config/routes.rb:50:5:50:94 | call to post | action_controller/controllers/users/notifications_controller.rb:3:5:4:7 | mark_as_read | -| app/config/routes.rb:50:5:50:94 | call to post | app/controllers/users/notifications_controller.rb:3:5:4:7 | mark_as_read | -underscore -| Foo | foo | -| Foo::Bar | foo/bar | -| Foo::Bar::Baz | foo/bar/baz | -| Foo::Bar::BazQuux | foo/bar/baz_quux | -| FooBar | foo_bar | -| FooBar::Baz | foo_bar/baz | -| HTTPServerRequest | httpserver_request | -| LotsOfCapitalLetters | lots_of_capital_letters | -| invalid | invalid | -mimeTypeInstances -| action_dispatch/mime_type.rb:2:6:2:28 | Use getMember("Mime").getContent(element_text/html) | -| action_dispatch/mime_type.rb:3:6:3:32 | Use getMember("Mime").getMember("Type").getMethod("new").getReturn() | -| action_dispatch/mime_type.rb:4:6:4:35 | Use getMember("Mime").getMember("Type").getMethod("lookup").getReturn() | -| action_dispatch/mime_type.rb:5:6:5:43 | Use getMember("Mime").getMember("Type").getMethod("lookup_by_extension").getReturn() | -| action_dispatch/mime_type.rb:6:6:6:47 | Use getMember("Mime").getMember("Type").getMethod("register").getReturn() | -| action_dispatch/mime_type.rb:7:6:7:64 | Use getMember("Mime").getMember("Type").getMethod("register_alias").getReturn() | -mimeTypeMatchRegExpInterpretations -| action_dispatch/mime_type.rb:11:11:11:19 | "foo/bar" | -| action_dispatch/mime_type.rb:12:7:12:15 | "foo/bar" | -| action_dispatch/mime_type.rb:13:11:13:11 | s | -| action_dispatch/mime_type.rb:14:7:14:7 | s | diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected new file mode 100644 index 00000000000..4524e715d4f --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.expected @@ -0,0 +1,68 @@ +actionDispatchRoutes +| app/config/routes.rb:2:3:8:5 | call to resources | get | posts | posts | index | +| app/config/routes.rb:2:3:8:5 | call to resources | get | posts/:id | posts | show | +| app/config/routes.rb:3:5:6:7 | call to resources | delete | posts/:post_id/comments/:id | comments | destroy | +| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments | comments | index | +| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments/:id | comments | show | +| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments/new | comments | new | +| app/config/routes.rb:3:5:6:7 | call to resources | get | posts/:post_id/comments:id/edit | comments | edit | +| app/config/routes.rb:3:5:6:7 | call to resources | patch | posts/:post_id/comments/:id | comments | update | +| app/config/routes.rb:3:5:6:7 | call to resources | post | posts/:post_id/comments | comments | create | +| app/config/routes.rb:3:5:6:7 | call to resources | put | posts/:post_id/comments/:id | comments | update | +| app/config/routes.rb:4:7:4:41 | call to resources | post | posts/:post_id/comments/:comment_id/replies | replies | create | +| app/config/routes.rb:5:7:5:28 | call to post | post | posts/:post_id/comments/:comment_id/flag | comments | flag | +| app/config/routes.rb:7:5:7:37 | call to post | post | posts/:post_id/upvote | posts | upvote | +| app/config/routes.rb:11:5:11:54 | call to post | post | destroy_all_posts | posts | destroy_alll | +| app/config/routes.rb:15:5:15:46 | call to get | get | numbers/:number | numbers | show | +| app/config/routes.rb:19:5:19:44 | call to get | get | admin/jobs | background_jobs | index | +| app/config/routes.rb:23:5:23:64 | call to get | get | admin/secrets | secrets | view_secrets | +| app/config/routes.rb:24:5:24:42 | call to delete | delete | admin/:user_id | users | destroy | +| app/config/routes.rb:27:3:27:48 | call to match | get | photos/:id | photos | show | +| app/config/routes.rb:28:3:28:50 | call to match | get | photos/:id | photos | show | +| app/config/routes.rb:29:3:29:69 | call to match | get | photos/:id | photos | show | +| app/config/routes.rb:30:3:30:50 | call to match | delete | photos/:id | photos | show | +| app/config/routes.rb:30:3:30:50 | call to match | get | photos/:id | photos | show | +| app/config/routes.rb:30:3:30:50 | call to match | patch | photos/:id | photos | show | +| app/config/routes.rb:30:3:30:50 | call to match | post | photos/:id | photos | show | +| app/config/routes.rb:30:3:30:50 | call to match | put | photos/:id | photos | show | +| app/config/routes.rb:33:5:33:43 | call to post | post | upgrade | users | start_upgrade | +| app/config/routes.rb:37:5:37:31 | call to get | get | current_billing_cycle | billing/enterprise | current_billing_cycle | +| app/config/routes.rb:40:3:40:40 | call to resource | get | global_config | global_config | show | +| app/config/routes.rb:43:5:45:7 | call to resources | get | foo/bar | foo/bar | index | +| app/config/routes.rb:43:5:45:7 | call to resources | get | foo/bar/:id | foo/bar | show | +| app/config/routes.rb:44:7:44:39 | call to get | get | foo/bar/:bar_id/show_debug | foo/bar | show_debug | +| app/config/routes.rb:49:5:49:95 | call to delete | delete | users/:user/notifications | users/notifications | destroy | +| app/config/routes.rb:50:5:50:94 | call to post | post | users/:user/notifications/:notification_id/mark_as_read | users/notifications | mark_as_read | +actionDispatchControllerMethods +| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:2:3:3:5 | index | +| app/config/routes.rb:2:3:8:5 | call to resources | app/controllers/posts_controller.rb:5:3:6:5 | show | +| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:2:3:36:5 | index | +| app/config/routes.rb:3:5:6:7 | call to resources | app/controllers/comments_controller.rb:38:3:39:5 | show | +| app/config/routes.rb:7:5:7:37 | call to post | app/controllers/posts_controller.rb:8:3:9:5 | upvote | +| app/config/routes.rb:27:3:27:48 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | +| app/config/routes.rb:28:3:28:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | +| app/config/routes.rb:29:3:29:69 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | +| app/config/routes.rb:30:3:30:50 | call to match | app/controllers/photos_controller.rb:2:3:3:5 | show | +| app/config/routes.rb:50:5:50:94 | call to post | app/controllers/users/notifications_controller.rb:3:5:4:7 | mark_as_read | +underscore +| Foo | foo | +| Foo::Bar | foo/bar | +| Foo::Bar::Baz | foo/bar/baz | +| Foo::Bar::BazQuux | foo/bar/baz_quux | +| FooBar | foo_bar | +| FooBar::Baz | foo_bar/baz | +| HTTPServerRequest | httpserver_request | +| LotsOfCapitalLetters | lots_of_capital_letters | +| invalid | invalid | +mimeTypeInstances +| mime_type.rb:2:6:2:28 | Use getMember("Mime").getContent(element_text/html) | +| mime_type.rb:3:6:3:32 | Use getMember("Mime").getMember("Type").getMethod("new").getReturn() | +| mime_type.rb:4:6:4:35 | Use getMember("Mime").getMember("Type").getMethod("lookup").getReturn() | +| mime_type.rb:5:6:5:43 | Use getMember("Mime").getMember("Type").getMethod("lookup_by_extension").getReturn() | +| mime_type.rb:6:6:6:47 | Use getMember("Mime").getMember("Type").getMethod("register").getReturn() | +| mime_type.rb:7:6:7:64 | Use getMember("Mime").getMember("Type").getMethod("register_alias").getReturn() | +mimeTypeMatchRegExpInterpretations +| mime_type.rb:11:11:11:19 | "foo/bar" | +| mime_type.rb:12:7:12:15 | "foo/bar" | +| mime_type.rb:13:11:13:11 | s | +| mime_type.rb:14:7:14:7 | s | diff --git a/ruby/ql/test/library-tests/frameworks/ActionDispatch.ql b/ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.ql similarity index 100% rename from ruby/ql/test/library-tests/frameworks/ActionDispatch.ql rename to ruby/ql/test/library-tests/frameworks/action_dispatch/ActionDispatch.ql diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/config/routes.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/config/routes.rb new file mode 100644 index 00000000000..9c33071aa50 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/config/routes.rb @@ -0,0 +1,52 @@ +Rails.application.routes.draw do + resources :posts, only: [:show, :index] do + resources :comments do + resources :replies, only: [:create] + post "flag", to: :flag + end + post "upvote", to: "posts#upvote" + end + + if Rails.env.test? + post "destroy_all_posts", to: "posts#destroy_alll" + end + + constraints(number: /[0-9]+/) do + get "/numbers/:number", to: "numbers#show" + end + + scope path: "/admin" do + get "/jobs", to: "background_jobs#index" + end + + scope "/admin" do + get "secrets", controller: "secrets", action: "view_secrets" + delete ":user_id", to: "users#destroy" + end + + match "photos/:id" => "photos#show", via: :get + match "photos/:id", to: "photos#show", via: :get + match "photos/:id", controller: "photos", action: "show", via: :get + match "photos/:id", to: "photos#show", via: :all + + scope controller: "users" do + post "upgrade", action: "start_upgrade" + end + + scope module: "enterprise", controller: "billing" do + get "current_billing_cycle" + end + + resource :global_config, only: [:show] + + namespace :foo do + resources :bar, only: [:index, :show] do + get "show_debug", to: :show_debug + end + end + + scope "/users/:user" do + delete "/notifications", to: "users/notifications#destroy", as: :user_destroy_notifications + post "notifications/:notification_id/mark_as_read", to: "users/notifications#mark_as_read" + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb new file mode 100644 index 00000000000..57fac7797bd --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/comments_controller.rb @@ -0,0 +1,40 @@ +class CommentsController < ApplicationController + def index + request.params + request.parameters + request.GET + request.POST + request.query_parameters + request.request_parameters + request.filtered_parameters + + response.body = "some content" + + response.status = 200 + + response.header["Content-Type"] = "text/html" + response.set_header("Content-Length", 100) + response.headers["X-Custom-Header"] = "hi" + response["X-Another-Custom-Header"] = "yes" + response.add_header "X-Yet-Another", "indeed" + + response.send_file("my-file.ext") + + response.request + + response.location = "http://..." # relevant for url redirect query + response.cache_control = "value" + response._cache_control = "value" + response.etag = "value" + response.charset = "value" # sets the charset part of the content-type header + response.content_type = "value" # sets the main part of the content-type header + + response.date = Date.today + response.last_modified = Date.yesterday + response.weak_etag = "value" + response.strong_etag = "value" + end + + def show + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/foo/bars_controller.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/foo/bars_controller.rb new file mode 100644 index 00000000000..9778b8d5bcc --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/foo/bars_controller.rb @@ -0,0 +1,46 @@ +require 'json' + +class BarsController < ApplicationController + + def index + render template: "foo/bars/index" + end + + def show_debug + user_info = JSON.load cookies[:user_info] + puts "User: #{user_info['name']}" + + @user_website = params[:website] + dt = params[:text] + rendered = render_to_string "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } + puts rendered + redirect_to action: "show" + end + + def show + @user_website = params[:website] + dt = params[:text] + render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } + end + + def go_back + redirect_back_or_to action: "index" + end + + def go_back_2 + redirect_back fallback_location: { action: "index" } + end + + def show_2 + render json: { some: "data" } + body = render_to_string @user, content_type: "application/json" + rescue => e + render e.backtrace, content_type: "text/plain" + end + + private + + def unreachable_action + render "show" + end +end diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/photos_controller.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/photos_controller.rb new file mode 100644 index 00000000000..0de193b9029 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/photos_controller.rb @@ -0,0 +1,4 @@ +class PhotosController < ApplicationController + def show + end +end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/posts_controller.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/posts_controller.rb new file mode 100644 index 00000000000..9760219cdf2 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/posts_controller.rb @@ -0,0 +1,10 @@ +class PostsController < ApplicationController + def index + end + + def show + end + + def upvote + end +end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/tags_controller.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/tags_controller.rb new file mode 100644 index 00000000000..ba10ea8ea2e --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/tags_controller.rb @@ -0,0 +1,2 @@ +class TagsController < ActionController::Metal +end diff --git a/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/users/notifications_controller.rb b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/users/notifications_controller.rb new file mode 100644 index 00000000000..c5ff9cd3f5f --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/action_dispatch/app/controllers/users/notifications_controller.rb @@ -0,0 +1,6 @@ +module Users + class NotificationsController < ApplicationController + def mark_as_read + end + end +end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql b/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql index 6543efcef02..a0c9a1fd299 100644 --- a/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql +++ b/ruby/ql/test/library-tests/frameworks/action_view/ActionView.ql @@ -3,7 +3,6 @@ private import codeql.ruby.AST private import codeql.ruby.frameworks.ActionView private import codeql.ruby.frameworks.Rails private import codeql.ruby.Concepts -private import codeql.ruby.DataFlow query predicate fileSystemResolverAccesses(FileSystemAccess a, DataFlow::Node path) { a.getAPathArgument() = path From b5d98d90117ec7dd0f7cfbd8a8267483ab46fcdd Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Sat, 4 Feb 2023 14:25:38 +1300 Subject: [PATCH 176/415] Ruby: Move GraphQL test to their own directory --- .../frameworks/{ => graphql}/GraphQL.expected | 0 .../frameworks/{ => graphql}/GraphQL.ql | 0 .../app/graphql/mutations/base_mutation.rb | 8 ++++ .../graphql/app/graphql/mutations/dummy.rb | 14 ++++++ .../graphql/app/graphql/resolvers/base.rb | 4 ++ .../app/graphql/resolvers/dummy_resolver.rb | 15 ++++++ .../app/graphql/types/base_argument.rb | 4 ++ .../graphql/app/graphql/types/base_field.rb | 5 ++ .../app/graphql/types/base_input_object.rb | 5 ++ .../app/graphql/types/base_interface.rb | 7 +++ .../graphql/app/graphql/types/base_object.rb | 5 ++ .../app/graphql/types/mutation_type.rb | 5 ++ .../graphql/app/graphql/types/query_type.rb | 46 +++++++++++++++++++ 13 files changed, 118 insertions(+) rename ruby/ql/test/library-tests/frameworks/{ => graphql}/GraphQL.expected (100%) rename ruby/ql/test/library-tests/frameworks/{ => graphql}/GraphQL.ql (100%) create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/base_mutation.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/dummy.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/base.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/dummy_resolver.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_argument.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_field.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_input_object.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_interface.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_object.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/mutation_type.rb create mode 100644 ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/query_type.rb diff --git a/ruby/ql/test/library-tests/frameworks/GraphQL.expected b/ruby/ql/test/library-tests/frameworks/graphql/GraphQL.expected similarity index 100% rename from ruby/ql/test/library-tests/frameworks/GraphQL.expected rename to ruby/ql/test/library-tests/frameworks/graphql/GraphQL.expected diff --git a/ruby/ql/test/library-tests/frameworks/GraphQL.ql b/ruby/ql/test/library-tests/frameworks/graphql/GraphQL.ql similarity index 100% rename from ruby/ql/test/library-tests/frameworks/GraphQL.ql rename to ruby/ql/test/library-tests/frameworks/graphql/GraphQL.ql diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/base_mutation.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/base_mutation.rb new file mode 100644 index 00000000000..0749ec0313f --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/base_mutation.rb @@ -0,0 +1,8 @@ +module Mutations + class BaseMutation < GraphQL::Schema::RelayClassicMutation + argument_class Types::BaseArgument + field_class Types::BaseField + input_object_class Types::BaseInputObject + object_class Types::BaseObject + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/dummy.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/dummy.rb new file mode 100644 index 00000000000..52f01c3d6eb --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/mutations/dummy.rb @@ -0,0 +1,14 @@ +module Mutations + class Dummy < BaseMutation + argument :something_id, ID, required: false + + def load_something(id) + "Something number #{id}" + end + + def resolve(something:) + system("echo #{something}") + { success: true } + end + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/base.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/base.rb new file mode 100644 index 00000000000..a51595c00a7 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/base.rb @@ -0,0 +1,4 @@ +module Resolvers + class Base < GraphQL::Schema::Resolver + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/dummy_resolver.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/dummy_resolver.rb new file mode 100644 index 00000000000..1fbc927c816 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/resolvers/dummy_resolver.rb @@ -0,0 +1,15 @@ +module Resolvers + class DummyResolver < Resolvers::Base + type String, null: false + argument :something_id, ID, required: true + + def load_something(id) + "Something number #{id}" + end + + def resolve(something:) + system("echo #{something}") + "true" + end + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_argument.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_argument.rb new file mode 100644 index 00000000000..c1bfdabbfee --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_argument.rb @@ -0,0 +1,4 @@ +module Types + class BaseArgument < GraphQL::Schema::Argument + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_field.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_field.rb new file mode 100644 index 00000000000..7142ef7ddb4 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_field.rb @@ -0,0 +1,5 @@ +module Types + class BaseField < GraphQL::Schema::Field + argument_class Types::BaseArgument + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_input_object.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_input_object.rb new file mode 100644 index 00000000000..c97c4796373 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_input_object.rb @@ -0,0 +1,5 @@ +module Types + class BaseInputObject < GraphQL::Schema::InputObject + argument_class Types::BaseArgument + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_interface.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_interface.rb new file mode 100644 index 00000000000..f25c9650044 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_interface.rb @@ -0,0 +1,7 @@ +module Types + module BaseInterface + include GraphQL::Schema::Interface + + field_class Types::BaseField + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_object.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_object.rb new file mode 100644 index 00000000000..1f918414d98 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/base_object.rb @@ -0,0 +1,5 @@ +module Types + class BaseObject < GraphQL::Schema::Object + field_class Types::BaseField + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/mutation_type.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/mutation_type.rb new file mode 100644 index 00000000000..5ef19f95ae6 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/mutation_type.rb @@ -0,0 +1,5 @@ +module Types + class MutationType < Types::BaseObject + field :dummy, mutation: Mutations::Dummy + end +end diff --git a/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/query_type.rb b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/query_type.rb new file mode 100644 index 00000000000..e0bc578a911 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/graphql/app/graphql/types/query_type.rb @@ -0,0 +1,46 @@ +module Types + class QueryType < Types::BaseObject + field :test_field, String, null: false, + description: "An example field added by the generator", + resolver: Resolvers::DummyResolver + + field :with_arg, String, null: false, description: "A field with an argument" do + argument :number, Int, "A number", required: true + end + def with_arg(number:) + system("echo #{number}") + number.to_s + end + + field :with_method, String, null: false, description: "A field with a custom resolver method", resolver_method: :custom_method do + argument :blah_number, Int, "A number", required: true + end + def custom_method(blah_number:, number: nil) + system("echo #{blah_number}") + system("echo #{number}") + blah_number.to_s + end + + field :with_splat, String, null: false, description: "A field with a double-splatted argument" do + argument :something, Int, "A number", required: true + end + def with_splat(**args) + system("echo #{args[:something]}") + args[:something].to_s + end + + field :with_splat_and_named_arg, String, null: false, description: "A field with two named arguments, where the method captures the second via a hash splat param" do + argument :arg1, Int, "A number", required: true + argument :arg2, Int, "Another number", required: true + end + def with_splat_and_named_arg(arg1:, **rest) + system("echo #{arg1}") + system("echo #{rest[:arg2]}") + arg1.to_s + end + + def foo(arg) + system("echo #{arg}") + end + end +end From dbbef0534bcac67d087d98354c32fef5427cbadc Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Sat, 4 Feb 2023 14:28:25 +1300 Subject: [PATCH 177/415] Ruby: Move Core tests into core directory --- ruby/ql/test/library-tests/frameworks/{ => core}/Core.expected | 0 ruby/ql/test/library-tests/frameworks/{ => core}/Core.ql | 0 ruby/ql/test/library-tests/frameworks/{ => core}/Stdlib.rb | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename ruby/ql/test/library-tests/frameworks/{ => core}/Core.expected (100%) rename ruby/ql/test/library-tests/frameworks/{ => core}/Core.ql (100%) rename ruby/ql/test/library-tests/frameworks/{ => core}/Stdlib.rb (100%) diff --git a/ruby/ql/test/library-tests/frameworks/Core.expected b/ruby/ql/test/library-tests/frameworks/core/Core.expected similarity index 100% rename from ruby/ql/test/library-tests/frameworks/Core.expected rename to ruby/ql/test/library-tests/frameworks/core/Core.expected diff --git a/ruby/ql/test/library-tests/frameworks/Core.ql b/ruby/ql/test/library-tests/frameworks/core/Core.ql similarity index 100% rename from ruby/ql/test/library-tests/frameworks/Core.ql rename to ruby/ql/test/library-tests/frameworks/core/Core.ql diff --git a/ruby/ql/test/library-tests/frameworks/Stdlib.rb b/ruby/ql/test/library-tests/frameworks/core/Stdlib.rb similarity index 100% rename from ruby/ql/test/library-tests/frameworks/Stdlib.rb rename to ruby/ql/test/library-tests/frameworks/core/Stdlib.rb From 071132661923472834de9547ab0cb8efda8db40c Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Sat, 4 Feb 2023 14:30:23 +1300 Subject: [PATCH 178/415] Ruby: Move PosixSpawn tests to their own directory --- .../frameworks/{ => posix-spawn}/PosixSpawn.expected | 0 .../test/library-tests/frameworks/{ => posix-spawn}/PosixSpawn.ql | 0 .../test/library-tests/frameworks/{ => posix-spawn}/PosixSpawn.rb | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename ruby/ql/test/library-tests/frameworks/{ => posix-spawn}/PosixSpawn.expected (100%) rename ruby/ql/test/library-tests/frameworks/{ => posix-spawn}/PosixSpawn.ql (100%) rename ruby/ql/test/library-tests/frameworks/{ => posix-spawn}/PosixSpawn.rb (100%) diff --git a/ruby/ql/test/library-tests/frameworks/PosixSpawn.expected b/ruby/ql/test/library-tests/frameworks/posix-spawn/PosixSpawn.expected similarity index 100% rename from ruby/ql/test/library-tests/frameworks/PosixSpawn.expected rename to ruby/ql/test/library-tests/frameworks/posix-spawn/PosixSpawn.expected diff --git a/ruby/ql/test/library-tests/frameworks/PosixSpawn.ql b/ruby/ql/test/library-tests/frameworks/posix-spawn/PosixSpawn.ql similarity index 100% rename from ruby/ql/test/library-tests/frameworks/PosixSpawn.ql rename to ruby/ql/test/library-tests/frameworks/posix-spawn/PosixSpawn.ql diff --git a/ruby/ql/test/library-tests/frameworks/PosixSpawn.rb b/ruby/ql/test/library-tests/frameworks/posix-spawn/PosixSpawn.rb similarity index 100% rename from ruby/ql/test/library-tests/frameworks/PosixSpawn.rb rename to ruby/ql/test/library-tests/frameworks/posix-spawn/PosixSpawn.rb From cfb3bc9dce8510858326a5751df626c84ae93e72 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Sat, 4 Feb 2023 14:30:56 +1300 Subject: [PATCH 179/415] Ruby: Remove unused test file --- ruby/ql/test/library-tests/frameworks/Eval.rb | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 ruby/ql/test/library-tests/frameworks/Eval.rb diff --git a/ruby/ql/test/library-tests/frameworks/Eval.rb b/ruby/ql/test/library-tests/frameworks/Eval.rb deleted file mode 100644 index 676dc61d1b6..00000000000 --- a/ruby/ql/test/library-tests/frameworks/Eval.rb +++ /dev/null @@ -1,24 +0,0 @@ -# Uses of eval and send - -eval("raise \"error\"", binding, "file", 1) -send("raise", "error") - -a = [] -a.send("push", "1") - -class Foo - def eval(x) - x + 1 - end - - def send(*args) - 2 - end - - def run - eval("exit 1") - end -end - -Foo.new.send("exit", 1) -Foo.module_eval("def bar; 1; end", "other_file.rb", 2) \ No newline at end of file From 02b09ca9f710281fe7d57f6d2474b68dd89ca225 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Sat, 4 Feb 2023 14:42:59 +1300 Subject: [PATCH 180/415] Ruby: Remove unused test files --- .../app/components/DummyComponent.rb | 2 - .../frameworks/app/config/routes.rb | 52 ------------------- .../app/controllers/comments_controller.rb | 40 -------------- .../app/controllers/foo/bars_controller.rb | 46 ---------------- .../app/controllers/photos_controller.rb | 4 -- .../app/controllers/posts_controller.rb | 10 ---- .../app/controllers/tags_controller.rb | 2 - .../users/notifications_controller.rb | 6 --- .../app/graphql/mutations/base_mutation.rb | 8 --- .../frameworks/app/graphql/mutations/dummy.rb | 14 ----- .../frameworks/app/graphql/resolvers/base.rb | 4 -- .../app/graphql/resolvers/dummy_resolver.rb | 15 ------ .../app/graphql/types/base_argument.rb | 4 -- .../app/graphql/types/base_field.rb | 5 -- .../app/graphql/types/base_input_object.rb | 5 -- .../app/graphql/types/base_interface.rb | 7 --- .../app/graphql/types/base_object.rb | 5 -- .../app/graphql/types/mutation_type.rb | 5 -- .../app/graphql/types/query_type.rb | 46 ---------------- .../app/views/foo/bars/_widget.html.erb | 4 -- .../app/views/foo/bars/show.html.erb | 33 ------------ 21 files changed, 317 deletions(-) delete mode 100644 ruby/ql/test/library-tests/frameworks/app/components/DummyComponent.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/config/routes.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/controllers/comments_controller.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/controllers/foo/bars_controller.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/controllers/photos_controller.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/controllers/posts_controller.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/controllers/tags_controller.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/controllers/users/notifications_controller.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/mutations/base_mutation.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/mutations/dummy.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/base.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/dummy_resolver.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/types/base_argument.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/types/base_field.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/types/base_input_object.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/types/base_interface.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/types/base_object.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/types/mutation_type.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/graphql/types/query_type.rb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/views/foo/bars/_widget.html.erb delete mode 100644 ruby/ql/test/library-tests/frameworks/app/views/foo/bars/show.html.erb diff --git a/ruby/ql/test/library-tests/frameworks/app/components/DummyComponent.rb b/ruby/ql/test/library-tests/frameworks/app/components/DummyComponent.rb deleted file mode 100644 index 80d6a602d68..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/components/DummyComponent.rb +++ /dev/null @@ -1,2 +0,0 @@ -class DummyComponent < ViewComponent::Base -end diff --git a/ruby/ql/test/library-tests/frameworks/app/config/routes.rb b/ruby/ql/test/library-tests/frameworks/app/config/routes.rb deleted file mode 100644 index 9c33071aa50..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/config/routes.rb +++ /dev/null @@ -1,52 +0,0 @@ -Rails.application.routes.draw do - resources :posts, only: [:show, :index] do - resources :comments do - resources :replies, only: [:create] - post "flag", to: :flag - end - post "upvote", to: "posts#upvote" - end - - if Rails.env.test? - post "destroy_all_posts", to: "posts#destroy_alll" - end - - constraints(number: /[0-9]+/) do - get "/numbers/:number", to: "numbers#show" - end - - scope path: "/admin" do - get "/jobs", to: "background_jobs#index" - end - - scope "/admin" do - get "secrets", controller: "secrets", action: "view_secrets" - delete ":user_id", to: "users#destroy" - end - - match "photos/:id" => "photos#show", via: :get - match "photos/:id", to: "photos#show", via: :get - match "photos/:id", controller: "photos", action: "show", via: :get - match "photos/:id", to: "photos#show", via: :all - - scope controller: "users" do - post "upgrade", action: "start_upgrade" - end - - scope module: "enterprise", controller: "billing" do - get "current_billing_cycle" - end - - resource :global_config, only: [:show] - - namespace :foo do - resources :bar, only: [:index, :show] do - get "show_debug", to: :show_debug - end - end - - scope "/users/:user" do - delete "/notifications", to: "users/notifications#destroy", as: :user_destroy_notifications - post "notifications/:notification_id/mark_as_read", to: "users/notifications#mark_as_read" - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/controllers/comments_controller.rb b/ruby/ql/test/library-tests/frameworks/app/controllers/comments_controller.rb deleted file mode 100644 index 57fac7797bd..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/controllers/comments_controller.rb +++ /dev/null @@ -1,40 +0,0 @@ -class CommentsController < ApplicationController - def index - request.params - request.parameters - request.GET - request.POST - request.query_parameters - request.request_parameters - request.filtered_parameters - - response.body = "some content" - - response.status = 200 - - response.header["Content-Type"] = "text/html" - response.set_header("Content-Length", 100) - response.headers["X-Custom-Header"] = "hi" - response["X-Another-Custom-Header"] = "yes" - response.add_header "X-Yet-Another", "indeed" - - response.send_file("my-file.ext") - - response.request - - response.location = "http://..." # relevant for url redirect query - response.cache_control = "value" - response._cache_control = "value" - response.etag = "value" - response.charset = "value" # sets the charset part of the content-type header - response.content_type = "value" # sets the main part of the content-type header - - response.date = Date.today - response.last_modified = Date.yesterday - response.weak_etag = "value" - response.strong_etag = "value" - end - - def show - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/controllers/foo/bars_controller.rb b/ruby/ql/test/library-tests/frameworks/app/controllers/foo/bars_controller.rb deleted file mode 100644 index 9778b8d5bcc..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/controllers/foo/bars_controller.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'json' - -class BarsController < ApplicationController - - def index - render template: "foo/bars/index" - end - - def show_debug - user_info = JSON.load cookies[:user_info] - puts "User: #{user_info['name']}" - - @user_website = params[:website] - dt = params[:text] - rendered = render_to_string "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } - puts rendered - redirect_to action: "show" - end - - def show - @user_website = params[:website] - dt = params[:text] - render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } - end - - def go_back - redirect_back_or_to action: "index" - end - - def go_back_2 - redirect_back fallback_location: { action: "index" } - end - - def show_2 - render json: { some: "data" } - body = render_to_string @user, content_type: "application/json" - rescue => e - render e.backtrace, content_type: "text/plain" - end - - private - - def unreachable_action - render "show" - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/controllers/photos_controller.rb b/ruby/ql/test/library-tests/frameworks/app/controllers/photos_controller.rb deleted file mode 100644 index 0de193b9029..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/controllers/photos_controller.rb +++ /dev/null @@ -1,4 +0,0 @@ -class PhotosController < ApplicationController - def show - end -end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/app/controllers/posts_controller.rb b/ruby/ql/test/library-tests/frameworks/app/controllers/posts_controller.rb deleted file mode 100644 index 9760219cdf2..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/controllers/posts_controller.rb +++ /dev/null @@ -1,10 +0,0 @@ -class PostsController < ApplicationController - def index - end - - def show - end - - def upvote - end -end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/app/controllers/tags_controller.rb b/ruby/ql/test/library-tests/frameworks/app/controllers/tags_controller.rb deleted file mode 100644 index ba10ea8ea2e..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/controllers/tags_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class TagsController < ActionController::Metal -end diff --git a/ruby/ql/test/library-tests/frameworks/app/controllers/users/notifications_controller.rb b/ruby/ql/test/library-tests/frameworks/app/controllers/users/notifications_controller.rb deleted file mode 100644 index c5ff9cd3f5f..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/controllers/users/notifications_controller.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Users - class NotificationsController < ApplicationController - def mark_as_read - end - end -end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/mutations/base_mutation.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/mutations/base_mutation.rb deleted file mode 100644 index 0749ec0313f..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/mutations/base_mutation.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Mutations - class BaseMutation < GraphQL::Schema::RelayClassicMutation - argument_class Types::BaseArgument - field_class Types::BaseField - input_object_class Types::BaseInputObject - object_class Types::BaseObject - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/mutations/dummy.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/mutations/dummy.rb deleted file mode 100644 index 52f01c3d6eb..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/mutations/dummy.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Mutations - class Dummy < BaseMutation - argument :something_id, ID, required: false - - def load_something(id) - "Something number #{id}" - end - - def resolve(something:) - system("echo #{something}") - { success: true } - end - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/base.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/base.rb deleted file mode 100644 index a51595c00a7..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/base.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Resolvers - class Base < GraphQL::Schema::Resolver - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/dummy_resolver.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/dummy_resolver.rb deleted file mode 100644 index 1fbc927c816..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/resolvers/dummy_resolver.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Resolvers - class DummyResolver < Resolvers::Base - type String, null: false - argument :something_id, ID, required: true - - def load_something(id) - "Something number #{id}" - end - - def resolve(something:) - system("echo #{something}") - "true" - end - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_argument.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_argument.rb deleted file mode 100644 index c1bfdabbfee..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_argument.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Types - class BaseArgument < GraphQL::Schema::Argument - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_field.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_field.rb deleted file mode 100644 index 7142ef7ddb4..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_field.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Types - class BaseField < GraphQL::Schema::Field - argument_class Types::BaseArgument - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_input_object.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_input_object.rb deleted file mode 100644 index c97c4796373..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_input_object.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Types - class BaseInputObject < GraphQL::Schema::InputObject - argument_class Types::BaseArgument - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_interface.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_interface.rb deleted file mode 100644 index f25c9650044..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_interface.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Types - module BaseInterface - include GraphQL::Schema::Interface - - field_class Types::BaseField - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_object.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_object.rb deleted file mode 100644 index 1f918414d98..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/types/base_object.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Types - class BaseObject < GraphQL::Schema::Object - field_class Types::BaseField - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/types/mutation_type.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/types/mutation_type.rb deleted file mode 100644 index 5ef19f95ae6..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/types/mutation_type.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Types - class MutationType < Types::BaseObject - field :dummy, mutation: Mutations::Dummy - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/graphql/types/query_type.rb b/ruby/ql/test/library-tests/frameworks/app/graphql/types/query_type.rb deleted file mode 100644 index e0bc578a911..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/graphql/types/query_type.rb +++ /dev/null @@ -1,46 +0,0 @@ -module Types - class QueryType < Types::BaseObject - field :test_field, String, null: false, - description: "An example field added by the generator", - resolver: Resolvers::DummyResolver - - field :with_arg, String, null: false, description: "A field with an argument" do - argument :number, Int, "A number", required: true - end - def with_arg(number:) - system("echo #{number}") - number.to_s - end - - field :with_method, String, null: false, description: "A field with a custom resolver method", resolver_method: :custom_method do - argument :blah_number, Int, "A number", required: true - end - def custom_method(blah_number:, number: nil) - system("echo #{blah_number}") - system("echo #{number}") - blah_number.to_s - end - - field :with_splat, String, null: false, description: "A field with a double-splatted argument" do - argument :something, Int, "A number", required: true - end - def with_splat(**args) - system("echo #{args[:something]}") - args[:something].to_s - end - - field :with_splat_and_named_arg, String, null: false, description: "A field with two named arguments, where the method captures the second via a hash splat param" do - argument :arg1, Int, "A number", required: true - argument :arg2, Int, "Another number", required: true - end - def with_splat_and_named_arg(arg1:, **rest) - system("echo #{arg1}") - system("echo #{rest[:arg2]}") - arg1.to_s - end - - def foo(arg) - system("echo #{arg}") - end - end -end diff --git a/ruby/ql/test/library-tests/frameworks/app/views/foo/bars/_widget.html.erb b/ruby/ql/test/library-tests/frameworks/app/views/foo/bars/_widget.html.erb deleted file mode 100644 index dda3813363a..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/views/foo/bars/_widget.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%= raw @display_text %> -<%= raw display_text %> -<%= raw locals[:display_text] %> -<%= @display_text %> diff --git a/ruby/ql/test/library-tests/frameworks/app/views/foo/bars/show.html.erb b/ruby/ql/test/library-tests/frameworks/app/views/foo/bars/show.html.erb deleted file mode 100644 index a86fabf719c..00000000000 --- a/ruby/ql/test/library-tests/frameworks/app/views/foo/bars/show.html.erb +++ /dev/null @@ -1,33 +0,0 @@ -website -<%= raw @display_text %> -<%= raw display_text %> -<%= raw locals[:display_text] %> -<%= raw params[:text] %> -<% key = :display_text %> -<%= raw locals[key] %> - -
      -<% key = [:display_text, :safe_text] do -
    • <%= raw locals[key] %>
    • -<% end %> -
    - -<%= @display_text %> - -<%= - full_text = prefix + locals[:display_text] - full_text -%> - -<%= - @display_text.html_safe -%> - -<%= - @display_text.html_safe - @display_text -%> - -<%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %> - -<%= link_to "some website", @user_website %> From ec82d61991f205bdb43681a82c2fe7dff19d0d37 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Sun, 5 Feb 2023 14:36:17 +0100 Subject: [PATCH 181/415] Add another frequently used step --- .../experimental/Security/UnsafeUnpackQuery.qll | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index b43410b14ad..bc8682f9e35 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -190,7 +190,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { or // Go through an Open for a Tarfile nodeTo = tarfileOpen().getACall() and nodeFrom = nodeTo.(MethodCallNode).getArg(0) - or + or // Handle the case where the getmembers is used. nodeTo.(MethodCallNode).calls(nodeFrom, "getmembers") and nodeFrom instanceof AllTarfileOpens @@ -201,5 +201,17 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { nodeTo = API::moduleImport("contextlib").getMember("closing").getACall() and nodeFrom = nodeTo.(API::CallNode).getArg(0) and nodeFrom = tarfileOpen().getReturn().getAValueReachableFromSource() + or + // see Path : https://docs.python.org/3/library/pathlib.html#pathlib.Path + nodeTo = API::moduleImport("pathlib").getMember("Path").getACall() and + nodeFrom = nodeTo.(API::CallNode).getArg(0) + or + // Use of absolutepath + // see absolute : https://docs.python.org/3/library/pathlib.html#pathlib.Path.absolute + exists(API::CallNode mcn | + mcn = API::moduleImport("pathlib").getMember("Path").getACall() and + nodeTo = mcn.getAMethodCall("absolute") and + nodeFrom = mcn.getArg(0) + ) } } From 43ce26e4d001a2932bfcf94df9fdefbb82ce9f33 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Tue, 7 Feb 2023 09:37:26 +1300 Subject: [PATCH 182/415] Ruby: re-add Eval.rb --- .../library-tests/frameworks/core/Eval.rb | 24 +++++++++++++++++++ .../frameworks/core/Kernel.expected | 3 +++ .../frameworks/core/Module.expected | 1 + 3 files changed, 28 insertions(+) create mode 100644 ruby/ql/test/library-tests/frameworks/core/Eval.rb diff --git a/ruby/ql/test/library-tests/frameworks/core/Eval.rb b/ruby/ql/test/library-tests/frameworks/core/Eval.rb new file mode 100644 index 00000000000..676dc61d1b6 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/core/Eval.rb @@ -0,0 +1,24 @@ +# Uses of eval and send + +eval("raise \"error\"", binding, "file", 1) +send("raise", "error") + +a = [] +a.send("push", "1") + +class Foo + def eval(x) + x + 1 + end + + def send(*args) + 2 + end + + def run + eval("exit 1") + end +end + +Foo.new.send("exit", 1) +Foo.module_eval("def bar; 1; end", "other_file.rb", 2) \ No newline at end of file diff --git a/ruby/ql/test/library-tests/frameworks/core/Kernel.expected b/ruby/ql/test/library-tests/frameworks/core/Kernel.expected index e2bf37ada74..3d35933fbf6 100644 --- a/ruby/ql/test/library-tests/frameworks/core/Kernel.expected +++ b/ruby/ql/test/library-tests/frameworks/core/Kernel.expected @@ -38,7 +38,10 @@ kernelSpawnCallExecutions | Kernel.rb:68:1:68:61 | call to spawn | | Kernel.rb:69:1:69:71 | call to spawn | sendCallCodeExecutions +| Eval.rb:4:1:4:22 | call to send | Eval.rb:4:6:4:12 | "raise" | +| Eval.rb:7:1:7:19 | call to send | Eval.rb:7:8:7:13 | "push" | | Kernel.rb:2:1:2:22 | call to send | Kernel.rb:2:6:2:12 | "raise" | | Kernel.rb:5:1:5:19 | call to send | Kernel.rb:5:8:5:13 | "push" | evalCallCodeExecutions +| Eval.rb:3:1:3:43 | call to eval | Eval.rb:3:6:3:22 | "raise \\"error\\"" | | Kernel.rb:1:1:1:43 | call to eval | Kernel.rb:1:6:1:22 | "raise \\"error\\"" | diff --git a/ruby/ql/test/library-tests/frameworks/core/Module.expected b/ruby/ql/test/library-tests/frameworks/core/Module.expected index 3e509c94739..615e38bcec1 100644 --- a/ruby/ql/test/library-tests/frameworks/core/Module.expected +++ b/ruby/ql/test/library-tests/frameworks/core/Module.expected @@ -1,6 +1,7 @@ classEvalCallCodeExecutions | Module.rb:29:1:29:47 | call to class_eval | Module.rb:29:16:29:32 | "def foo; 1; end" | moduleEvalCallCodeExecutions +| Eval.rb:24:1:24:54 | call to module_eval | Eval.rb:24:17:24:33 | "def bar; 1; end" | | Module.rb:30:1:30:54 | call to module_eval | Module.rb:30:17:30:33 | "def bar; 1; end" | moduleConstGetCallCodeExecutions | Module.rb:1:1:1:24 | call to const_get | Module.rb:1:18:1:23 | "Math" | From 642a138eaa0ce3b99bf93536369f746cadf3c68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Tue, 7 Feb 2023 10:44:48 +0100 Subject: [PATCH 183/415] Update Twirp.qll --- ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll index f6de8c85d3a..821e3486f8a 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll @@ -51,6 +51,9 @@ module Twirp { .getModule() } + /** + * Gets a handler's method. + */ Ast::Method getHandlerMethod() { result = this.getHandlerClassAstNode().getAnInstanceMethod() } } From 49a3dd61312ad63c75e158815425e265394dc330 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 27 Jan 2023 22:20:29 +0000 Subject: [PATCH 184/415] Python: Clean up version handling Depends on an internal PR. --- python/ql/lib/semmle/python/Constants.qll | 44 ++++++++++--------- .../ql/lib/semmle/python/types/Builtins.qll | 6 +-- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/python/ql/lib/semmle/python/Constants.qll b/python/ql/lib/semmle/python/Constants.qll index 19e3e757989..03254a4bfd0 100644 --- a/python/ql/lib/semmle/python/Constants.qll +++ b/python/ql/lib/semmle/python/Constants.qll @@ -3,32 +3,34 @@ import python /** the Python major version number */ -int major_version() { - explicit_major_version(result) - or - not explicit_major_version(_) and - /* If there is more than one version, prefer 2 for backwards compatibility */ - (if py_flags_versioned("version.major", "2", "2") then result = 2 else result = 3) -} +int major_version() { full_python_analysis_version(result, _, _) } /** the Python minor version number */ -int minor_version() { - exists(string v | py_flags_versioned("version.minor", v, major_version().toString()) | - result = v.toInt() - ) -} +int minor_version() { full_python_analysis_version(_, result, _) } /** the Python micro version number */ -int micro_version() { - exists(string v | py_flags_versioned("version.micro", v, major_version().toString()) | - result = v.toInt() - ) +int micro_version() { full_python_analysis_version(_, _, result) } + +/** Gets the latest supported minor version for the given major version. */ +private int latest_supported_minor_version(int major) { + major = 2 and result = 7 + or + major = 3 and result = 11 } -private predicate explicit_major_version(int v) { - exists(string version | py_flags_versioned("language.version", version, _) | - version.charAt(0) = "2" and v = 2 - or - version.charAt(0) = "3" and v = 3 +private predicate full_python_analysis_version(int major, int minor, int micro) { + exists(string version_string | py_flags_versioned("language.version", version_string, _) | + major = version_string.regexpFind("\\d+", 0, _).toInt() and + ( + minor = version_string.regexpFind("\\d+", 1, _).toInt() + or + not exists(version_string.regexpFind("\\d+", 1, _)) and + minor = latest_supported_minor_version(major) + ) and + ( + micro = version_string.regexpFind("\\d+", 2, _).toInt() + or + not exists(version_string.regexpFind("\\d+", 2, _)) and micro = 0 + ) ) } diff --git a/python/ql/lib/semmle/python/types/Builtins.qll b/python/ql/lib/semmle/python/types/Builtins.qll index 066b496b80e..e6a21e1b717 100644 --- a/python/ql/lib/semmle/python/types/Builtins.qll +++ b/python/ql/lib/semmle/python/types/Builtins.qll @@ -111,11 +111,7 @@ class Builtin extends @py_cobject { } module Builtin { - Builtin builtinModule() { - py_special_objects(result, "builtin_module_2") and major_version() = 2 - or - py_special_objects(result, "builtin_module_3") and major_version() = 3 - } + Builtin builtinModule() { py_special_objects(result, "builtin_module") } Builtin builtin(string name) { result = builtinModule().getMember(name) } From 8dea993f41d848fcc5bfa70c0d69156e59ed6ffb Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 30 Jan 2023 17:20:49 +0000 Subject: [PATCH 185/415] Python: Update failing test Seems the name for the codec changed between Python 2 and 3. :) --- .../2/query-tests/Imports/syntax_error/EncodingError.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.expected b/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.expected index 9c06cae162e..32fa7b97bf1 100644 --- a/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.expected +++ b/python/ql/test/2/query-tests/Imports/syntax_error/EncodingError.expected @@ -1 +1 @@ -| bad_encoding.py:11:19:11:19 | Encoding Error | 'utf8' codec can't decode byte 0x82 in position 82: invalid start byte | +| bad_encoding.py:11:19:11:19 | Encoding Error | 'utf-8' codec can't decode byte 0x82 in position 82: invalid start byte | From 080ce09bd7a938d040fb1f2084a1407a8951afa5 Mon Sep 17 00:00:00 2001 From: Taus Date: Sat, 4 Feb 2023 13:19:28 +0000 Subject: [PATCH 186/415] Python: Update `six` test expectations --- python/ql/test/2/library-tests/six/pointsto.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/2/library-tests/six/pointsto.expected b/python/ql/test/2/library-tests/six/pointsto.expected index 0e0d568caf3..b2ad9ae96f4 100644 --- a/python/ql/test/2/library-tests/six/pointsto.expected +++ b/python/ql/test/2/library-tests/six/pointsto.expected @@ -6,4 +6,4 @@ | six.moves.urllib | Package six.moves.urllib | | six.moves.urllib.parse | Module six.moves.urllib_parse | | six.moves.urllib.parse.urlsplit | Function urlsplit | -| six.moves.zip | builtin-class itertools.izip | +| six.moves.zip | Builtin-function zip | From 8bb1d8631af605164b286dd4ec2069fae1a1a0fa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 8 Feb 2023 16:19:29 +0100 Subject: [PATCH 187/415] Python: Add call-graph hotfix for `sympy` --- .../new/internal/DataFlowDispatch.qll | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 4641ae4a912..d5a5c04493b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -460,10 +460,26 @@ private CallCfgNode getSuperCall() { ) } +/** + * Holds if the file `f` should be ignored when computing the call-graph. + * + * We currently see a performance problem when analyzing the `sympy` PyPI package, + * which can be part of the database when dependencies are installed and extracted. + * From what we can understand, SymPy is using Python in a exotic way, so the fact that + * our analysis currently does not handle this project has nothing to say about our + * ability to handle normal Python code. Furthermore, SymPy does not look to be relevant + * in a security context, so we should not loose out on any security results by doing + * this. + */ +private predicate ignoreForCallGraph(File f) { + f.getAbsolutePath().matches("%/site-packages/sympy/%") +} + /** * Gets a reference to the function `func`. */ private TypeTrackingNode functionTracker(TypeTracker t, Function func) { + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and ( result.asExpr() = func.getDefinition() @@ -473,6 +489,7 @@ private TypeTrackingNode functionTracker(TypeTracker t, Function func) { result.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall() ) or + not ignoreForCallGraph(result.getLocation().getFile()) and exists(TypeTracker t2 | result = functionTracker(t2, func).track(t2, t)) } @@ -485,6 +502,7 @@ Node functionTracker(Function func) { functionTracker(TypeTracker::end(), func). * Gets a reference to the class `cls`. */ private TypeTrackingNode classTracker(TypeTracker t, Class cls) { + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and ( result.asExpr() = cls.getParent() @@ -498,6 +516,7 @@ private TypeTrackingNode classTracker(TypeTracker t, Class cls) { result.(CallCfgNode).getArg(0) = classInstanceTracker(cls) ) or + not ignoreForCallGraph(result.getLocation().getFile()) and exists(TypeTracker t2 | result = classTracker(t2, cls).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } @@ -511,16 +530,19 @@ Node classTracker(Class cls) { classTracker(TypeTracker::end(), cls).flowsTo(res * Gets a reference to an instance of the class `cls`. */ private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) { + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and resolveClassCall(result.(CallCfgNode).asCfgNode(), cls) or // result of `super().__new__` as used in a `__new__` method implementation + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and exists(Class classUsedInSuper | fromSuperNewCall(result.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and classUsedInSuper = getADirectSuperclass*(cls) ) or + not ignoreForCallGraph(result.getLocation().getFile()) and exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } @@ -537,6 +559,7 @@ Node classInstanceTracker(Class cls) { * The method cannot be a `staticmethod` or `classmethod`. */ private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) { + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and exists(Function func | func = classWithMethod.getAMethod() and @@ -546,6 +569,7 @@ private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) { result.asExpr() = func.getArg(0) ) or + not ignoreForCallGraph(result.getLocation().getFile()) and exists(TypeTracker t2 | result = selfTracker(t2, classWithMethod).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } @@ -564,6 +588,7 @@ Node selfTracker(Class classWithMethod) { * from a normal method. */ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod) { + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and ( exists(Function func | @@ -578,6 +603,7 @@ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod) ) or + not ignoreForCallGraph(result.getLocation().getFile()) and exists(TypeTracker t2 | result = clsArgumentTracker(t2, classWithMethod).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } @@ -596,6 +622,7 @@ Node clsArgumentTracker(Class classWithMethod) { * call happened in the method `func` (either a method or a classmethod). */ private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func) { + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and not isStaticmethod(func) and exists(CallCfgNode call | result = call | @@ -604,6 +631,7 @@ private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func call.getScope() = func ) or + not ignoreForCallGraph(result.getLocation().getFile()) and exists(TypeTracker t2 | result = superCallNoArgumentTracker(t2, func).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } @@ -621,6 +649,7 @@ Node superCallNoArgumentTracker(Function func) { * first is a reference to the class `cls`, and the second argument is `obj`. */ private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, Node obj) { + not ignoreForCallGraph(result.getLocation().getFile()) and t.start() and exists(CallCfgNode call | result = call | call = getSuperCall() and @@ -628,6 +657,7 @@ private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, N call.getArg(1) = obj ) or + not ignoreForCallGraph(result.getLocation().getFile()) and exists(TypeTracker t2 | result = superCallTwoArgumentTracker(t2, cls, obj).track(t2, t)) and not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf())) } From 5c23b47ef4935668ebe5a3583fd82289e710de5f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 8 Feb 2023 16:27:06 +0100 Subject: [PATCH 188/415] Python: Fix typo in QLDoc Co-authored-by: Taus --- .../semmle/python/dataflow/new/internal/DataFlowDispatch.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index d5a5c04493b..864642deb69 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -468,7 +468,7 @@ private CallCfgNode getSuperCall() { * From what we can understand, SymPy is using Python in a exotic way, so the fact that * our analysis currently does not handle this project has nothing to say about our * ability to handle normal Python code. Furthermore, SymPy does not look to be relevant - * in a security context, so we should not loose out on any security results by doing + * in a security context, so we should not lose out on any security results by doing * this. */ private predicate ignoreForCallGraph(File f) { From 9e285020a10c493052a9c87a031294c71d32378c Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Wed, 8 Feb 2023 21:14:53 +0100 Subject: [PATCH 189/415] Comment modif + remove redundant cast --- python/ql/src/experimental/Security/UnsafeUnpackQuery.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index bc8682f9e35..e2972b44662 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -24,7 +24,7 @@ API::Node tarfileOpen() { } /** - * Handle the previous three cases, plus the use of `closing` in the previous cases + * A class for handling the previous three cases, plus the use of `closing` in with the previous cases */ class AllTarfileOpens extends API::CallNode { AllTarfileOpens() { @@ -153,7 +153,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // Open a file for access using builtin exists(API::CallNode cn | cn = API::builtin("open").getACall() and - nodeTo = cn.(API::CallNode).getArg(0) and + nodeTo = cn.getArg(0) and cn.flowsTo(nodeFrom) ) or From 4196230a8a10d83bdad088de13cfa56538576aac Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Wed, 8 Feb 2023 21:46:50 +0100 Subject: [PATCH 190/415] use if-then-else rather than nested exists --- python/ql/src/experimental/Security/UnsafeUnpackQuery.qll | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index e2972b44662..a1f028134d3 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -84,11 +84,9 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // see wget: https://pypi.org/project/wget/ exists(API::CallNode mcn | mcn = API::moduleImport("wget").getMember("download").getACall() and - ( - source = mcn.getArg(1) - or - source = mcn.getReturn().asSource() and not exists(Node arg | arg = mcn.getArg(1)) - ) + if exists(Node arg | arg = mcn.getArg(1)) + then source = mcn.getArg(1) + else source = mcn.getReturn().asSource() ) or // catch the Django uploaded files as a source From 16ef50401ba251df3898c9acad92916e632bd2e9 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 9 Feb 2023 14:59:28 +0100 Subject: [PATCH 191/415] Update python/ql/src/experimental/Security/UnsafeUnpackQuery.qll Co-authored-by: yoff --- python/ql/src/experimental/Security/UnsafeUnpackQuery.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index a1f028134d3..a92a2cf2f84 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -103,7 +103,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // For a call to `file.extractall` without `members` argument, `file` is considered a sink. exists(MethodCallNode call, AllTarfileOpens atfo | call = atfo.getReturn().getMember("extractall").getACall() and - not exists(Node arg | arg = call.getArgByName("members")) and + not exists(call.getArgByName("members")) and sink = call.getObject() ) or From b04d5684fbabd791ec636f223e03b656279e8aea Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 9 Feb 2023 15:23:58 +0100 Subject: [PATCH 192/415] add a blank line at the end of the file --- .../query-tests/Security/CWE-022/DataflowQueryTest.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql index df70ff9fe51..f02f8529c96 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql +++ b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql @@ -1,3 +1,3 @@ import python import experimental.dataflow.TestUtil.DataflowQueryTest -import experimental.Security.UnsafeUnpackQuery \ No newline at end of file +import experimental.Security.UnsafeUnpackQuery From 09df055d86b54b0e1df6facca925dd9f0b8a04be Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Thu, 9 Feb 2023 15:25:54 +0100 Subject: [PATCH 193/415] Fix the exists cast warning --- python/ql/src/experimental/Security/UnsafeUnpackQuery.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index a92a2cf2f84..022a0fb2645 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -84,7 +84,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // see wget: https://pypi.org/project/wget/ exists(API::CallNode mcn | mcn = API::moduleImport("wget").getMember("download").getACall() and - if exists(Node arg | arg = mcn.getArg(1)) + if exists(mcn.getArg(1)) then source = mcn.getArg(1) else source = mcn.getReturn().asSource() ) From 82f09b8511e661731a4510897cbe1cd8fd4c67b4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 10 Feb 2023 17:30:44 +0000 Subject: [PATCH 194/415] Swift: More path injection test cases. --- .../Security/CWE-022/testPathInjection.swift | 171 ++++++++++-------- 1 file changed, 99 insertions(+), 72 deletions(-) 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 fbca64d0652..94f4c98e175 100644 --- a/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift @@ -9,13 +9,32 @@ class NSURL { } extension String { + struct Encoding { + static let utf8 = Encoding() + } + init(contentsOf: URL) { let data = "" self.init(data) } + + init(contentsOfFile path: String) throws { + self.init("") + } + + init(contentsOfFile path: String, encoding enc: String.Encoding) throws { + self.init("") + } + + init(contentsOfFile path: String, usedEncoding: inout String.Encoding) throws { + self.init("") + } } class NSString { + convenience init(contentsOfFile path: String, encoding enc: UInt) throws { self.init() } + convenience init(contentsOfFile path: String, usedEncoding enc: UnsafeMutablePointer?) throws { self.init() } + func write(toFile: String, atomically: Bool, encoding: UInt) {} func write(to: URL, atomically: Bool, encoding: UInt) {} } @@ -166,91 +185,99 @@ func test() { let safeUrl = URL(string: "")! let safeNsUrl = NSURL(string: "")! - Data("").write(to: remoteUrl, options: []) // $ hasPathInjection=163 + Data("").write(to: remoteUrl, options: []) // $ hasPathInjection=182 let nsData = NSData() - 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 _ = nsData.write(to: remoteUrl, atomically: false) // $ hasPathInjection=182 + nsData.write(to: remoteUrl, options: []) // $ hasPathInjection=182 + let _ = nsData.write(toFile: remoteString, atomically: false) // $ hasPathInjection=182 + nsData.write(toFile: remoteString, options: []) // $ hasPathInjection=182 let fm = FileManager() - 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 + let _ = fm.contentsOfDirectory(at: remoteUrl, includingPropertiesForKeys: [], options: []) // $ hasPathInjection=182 + let _ = fm.contentsOfDirectory(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.enumerator(at: remoteUrl, includingPropertiesForKeys: [], options: [], errorHandler: nil) // $ hasPathInjection=182 + let _ = fm.enumerator(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.subpathsOfDirectory(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.subpaths(atPath: remoteString) // $ hasPathInjection=182 + fm.createDirectory(at: remoteUrl, withIntermediateDirectories: false, attributes: [:]) // $ hasPathInjection=182 + let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=182 + let _ = fm.createFile(atPath: remoteString, contents: nil, attributes: [:]) // $ hasPathInjection=182 + fm.removeItem(at: remoteUrl) // $ hasPathInjection=182 + fm.removeItem(atPath: remoteString) // $ hasPathInjection=182 + fm.trashItem(at: remoteUrl, resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=182 + let _ = fm.replaceItemAt(remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: []) // $ hasPathInjection=182 + let _ = fm.replaceItemAt(safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: []) // $ hasPathInjection=182 + fm.replaceItem(at: remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=182 + fm.replaceItem(at: safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=182 + fm.copyItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=182 + fm.copyItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=182 + fm.copyItem(atPath: remoteString, toPath: "") // $ hasPathInjection=182 + fm.copyItem(atPath: "", toPath: remoteString) // $ hasPathInjection=182 + fm.moveItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=182 + fm.moveItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=182 + fm.moveItem(atPath: remoteString, toPath: "") // $ hasPathInjection=182 + fm.moveItem(atPath: "", toPath: remoteString) // $ hasPathInjection=182 + fm.createSymbolicLink(at: remoteUrl, withDestinationURL: safeUrl) // $ hasPathInjection=182 + fm.createSymbolicLink(at: safeUrl, withDestinationURL: remoteUrl) // $ hasPathInjection=182 + fm.createSymbolicLink(atPath: remoteString, withDestinationPath: "") // $ hasPathInjection=182 + fm.createSymbolicLink(atPath: "", withDestinationPath: remoteString) // $ hasPathInjection=182 + fm.linkItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=182 + fm.linkItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=182 + fm.linkItem(atPath: remoteString, toPath: "") // $ hasPathInjection=182 + fm.linkItem(atPath: "", toPath: remoteString) // $ hasPathInjection=182 + let _ = fm.destinationOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.fileExists(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.fileExists(atPath: remoteString, isDirectory: UnsafeMutablePointer.init(bitPattern: 0)) // $ hasPathInjection=182 + fm.setAttributes([:], ofItemAtPath: remoteString) // $ hasPathInjection=182 + let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.contentsEqual(atPath: remoteString, andPath: "") // $ hasPathInjection=182 + let _ = fm.contentsEqual(atPath: "", andPath: remoteString) // $ hasPathInjection=182 + let _ = fm.changeCurrentDirectoryPath(remoteString) // $ hasPathInjection=182 + let _ = fm.unmountVolume(at: remoteUrl, options: [], completionHandler: { _ in }) // $ hasPathInjection=182 // Deprecated methods - 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 _ = fm.changeFileAttributes([:], atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.directoryContents(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=182 + let _ = fm.createSymbolicLink(atPath: remoteString, pathContent: "") // $ hasPathInjection=182 + let _ = fm.createSymbolicLink(atPath: "", pathContent: remoteString) // $ hasPathInjection=182 + let _ = fm.pathContentOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=182 + let _ = fm.replaceItemAtURL(originalItemURL: remoteNsUrl, withItemAtURL: safeNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=182 + let _ = fm.replaceItemAtURL(originalItemURL: safeNsUrl, withItemAtURL: remoteNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=182 - 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 + var encoding = String.Encoding.utf8 + let _ = try! String(contentsOfFile: remoteString) // $ MISSING: hasPathInjection=232 + let _ = try! String(contentsOfFile: remoteString, encoding: String.Encoding.utf8) // $ MISSING: hasPathInjection=234 + let _ = try! String(contentsOfFile: remoteString, usedEncoding: &encoding) // $ MISSING: hasPathInjection=235 - let _ = Database(path: remoteString, description: "", configuration: Configuration()) // $ hasPathInjection=163 + let _ = try! NSString(contentsOfFile: remoteString, encoding: 0) // $ MISSING: hasPathInjection=237 + let _ = try! NSString(contentsOfFile: remoteString, usedEncoding: nil) // $ MISSING: hasPathInjection=238 + NSString().write(to: remoteUrl, atomically: true, encoding: 0) // $ hasPathInjection=182 + NSString().write(toFile: remoteString, atomically: true, encoding: 0) // $ hasPathInjection=182 + + let _ = NSKeyedUnarchiver().unarchiveObject(withFile: remoteString) // $ hasPathInjection=182 + let _ = ArchiveByteStream.fileStream(fd: remoteString as! FileDescriptor, automaticClose: true) // $ hasPathInjection=182 + ArchiveByteStream.withFileStream(fd: remoteString as! FileDescriptor, automaticClose: true) { _ in } // $ hasPathInjection=182 + let _ = ArchiveByteStream.fileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) // $ hasPathInjection=182 + ArchiveByteStream.withFileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) { _ in } // $ hasPathInjection=182 + let _ = Bundle(url: remoteUrl) // $ hasPathInjection=182 + let _ = Bundle(path: remoteString) // $ hasPathInjection=182 + + let _ = Database(path: remoteString, description: "", configuration: Configuration()) // $ hasPathInjection=182 let _ = Database(path: "", description: "", configuration: Configuration()) // Safe - let _ = DatabasePool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=163 + let _ = DatabasePool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=182 let _ = DatabasePool(path: "", configuration: Configuration()) // Safe - let _ = DatabaseQueue(path: remoteString, configuration: Configuration()) // $ hasPathInjection=163 + let _ = DatabaseQueue(path: remoteString, configuration: Configuration()) // $ hasPathInjection=182 let _ = DatabaseQueue(path: "", configuration: Configuration()) // Safe - let _ = DatabaseSnapshotPool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=163 + let _ = DatabaseSnapshotPool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=182 let _ = DatabaseSnapshotPool(path: "", configuration: Configuration()) // Safe - let _ = SerializedDatabase(path: remoteString, defaultLabel: "") // $ hasPathInjection=163 + let _ = SerializedDatabase(path: remoteString, defaultLabel: "") // $ hasPathInjection=182 let _ = SerializedDatabase(path: "", defaultLabel: "") // Safe - let _ = SerializedDatabase(path: remoteString, defaultLabel: "", purpose: nil) // $ hasPathInjection=163 + let _ = SerializedDatabase(path: remoteString, defaultLabel: "", purpose: nil) // $ hasPathInjection=182 let _ = SerializedDatabase(path: "", defaultLabel: "", purpose: nil) // Safe - let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "") // $ hasPathInjection=163 + let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "") // $ hasPathInjection=182 let _ = SerializedDatabase(path: "", configuration: Configuration(), defaultLabel: "") // Safe - let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "", purpose: nil) // $ hasPathInjection=163 + let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "", purpose: nil) // $ hasPathInjection=182 let _ = SerializedDatabase(path: "", configuration: Configuration(), defaultLabel: "", purpose: nil) // Safe } @@ -263,5 +290,5 @@ func testSanitizers() { if (filePath.lexicallyNormalized().starts(with: "/safe")) { let _ = fm.contents(atPath: remoteString) // Safe } - let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=258 + let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=285 } From d0efbbf5b86a45e8b1ce435bf25dd3da2aa9c94e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 10 Feb 2023 18:00:36 +0000 Subject: [PATCH 195/415] Swift: More path injection models. --- .../codeql/swift/security/PathInjectionExtensions.qll | 5 +++++ .../Security/CWE-022/testPathInjection.swift | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/PathInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/PathInjectionExtensions.qll index 916c2fa9c94..4a78cfbf867 100644 --- a/swift/ql/lib/codeql/swift/security/PathInjectionExtensions.qll +++ b/swift/ql/lib/codeql/swift/security/PathInjectionExtensions.qll @@ -108,6 +108,11 @@ 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", + ";String;true;init(contentsOfFile:);;;Argument[0];path-injection", + ";String;true;init(contentsOfFile:encoding:);;;Argument[0];path-injection", + ";String;true;init(contentsOfFile:usedEncoding:);;;Argument[0];path-injection", + ";NSString;true;init(contentsOfFile:encoding:);;;Argument[0];path-injection", + ";NSString;true;init(contentsOfFile:usedEncoding:);;;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", 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 94f4c98e175..f9f69354d68 100644 --- a/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift @@ -246,12 +246,12 @@ func test() { let _ = fm.replaceItemAtURL(originalItemURL: safeNsUrl, withItemAtURL: remoteNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=182 var encoding = String.Encoding.utf8 - let _ = try! String(contentsOfFile: remoteString) // $ MISSING: hasPathInjection=232 - let _ = try! String(contentsOfFile: remoteString, encoding: String.Encoding.utf8) // $ MISSING: hasPathInjection=234 - let _ = try! String(contentsOfFile: remoteString, usedEncoding: &encoding) // $ MISSING: hasPathInjection=235 + let _ = try! String(contentsOfFile: remoteString) // $ hasPathInjection=182 + let _ = try! String(contentsOfFile: remoteString, encoding: String.Encoding.utf8) // $ hasPathInjection=182 + let _ = try! String(contentsOfFile: remoteString, usedEncoding: &encoding) // $ hasPathInjection=182 - let _ = try! NSString(contentsOfFile: remoteString, encoding: 0) // $ MISSING: hasPathInjection=237 - let _ = try! NSString(contentsOfFile: remoteString, usedEncoding: nil) // $ MISSING: hasPathInjection=238 + let _ = try! NSString(contentsOfFile: remoteString, encoding: 0) // $ hasPathInjection=182 + let _ = try! NSString(contentsOfFile: remoteString, usedEncoding: nil) // $ hasPathInjection=182 NSString().write(to: remoteUrl, atomically: true, encoding: 0) // $ hasPathInjection=182 NSString().write(toFile: remoteString, atomically: true, encoding: 0) // $ hasPathInjection=182 From ad85b37585aa2402766c9c6c47a77480272f9cb2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 10 Feb 2023 18:06:56 +0000 Subject: [PATCH 196/415] Swift: Tidy up indenting. --- .../Security/CWE-022/testPathInjection.swift | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) 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 f9f69354d68..bceeaf1a1ed 100644 --- a/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift @@ -10,25 +10,25 @@ class NSURL { extension String { struct Encoding { - static let utf8 = Encoding() - } + static let utf8 = Encoding() + } - init(contentsOf: URL) { + init(contentsOf: URL) { let data = "" self.init(data) } - init(contentsOfFile path: String) throws { - self.init("") - } + init(contentsOfFile path: String) throws { + self.init("") + } - init(contentsOfFile path: String, encoding enc: String.Encoding) throws { - self.init("") - } + init(contentsOfFile path: String, encoding enc: String.Encoding) throws { + self.init("") + } - init(contentsOfFile path: String, usedEncoding: inout String.Encoding) throws { - self.init("") - } + init(contentsOfFile path: String, usedEncoding: inout String.Encoding) throws { + self.init("") + } } class NSString { From eed19a3e15be8e5970f7a62e8f8fc60fca2e2321 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Fri, 10 Feb 2023 21:58:29 +0100 Subject: [PATCH 197/415] Fix autoformatting issues --- python/ql/src/experimental/Security/UnsafeUnpackQuery.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll index 022a0fb2645..ba359ee32f3 100644 --- a/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll +++ b/python/ql/src/experimental/Security/UnsafeUnpackQuery.qll @@ -84,9 +84,7 @@ class UnsafeUnpackingConfig extends TaintTracking::Configuration { // see wget: https://pypi.org/project/wget/ exists(API::CallNode mcn | mcn = API::moduleImport("wget").getMember("download").getACall() and - if exists(mcn.getArg(1)) - then source = mcn.getArg(1) - else source = mcn.getReturn().asSource() + if exists(mcn.getArg(1)) then source = mcn.getArg(1) else source = mcn.getReturn().asSource() ) or // catch the Django uploaded files as a source From c87c3e30c7e5550e2b2a37888c4fb1bbaaa3937c Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Sat, 11 Feb 2023 17:07:25 -0500 Subject: [PATCH 198/415] Java: update getInvalidModelKind with 'read-file' kind --- java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index ab3d24cd23e..f6007b497ca 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -261,9 +261,9 @@ module ModelValidation { [ "open-url", "jndi-injection", "ldap", "sql", "jdbc-url", "logging", "mvel", "xpath", "groovy", "xss", "ognl-injection", "intent-start", "pending-intent-sent", - "url-open-stream", "url-redirect", "create-file", "write-file", "set-hostname-verifier", - "header-splitting", "information-leak", "xslt", "jexl", "bean-validation", "ssti", - "fragment-injection" + "url-open-stream", "url-redirect", "create-file", "read-file", "write-file", + "set-hostname-verifier", "header-splitting", "information-leak", "xslt", "jexl", + "bean-validation", "ssti", "fragment-injection" ] and not kind.matches("regex-use%") and not kind.matches("qltest%") and From ce1c814daaa110af375b31efc66228cc86594f44 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Sat, 11 Feb 2023 17:10:58 -0500 Subject: [PATCH 199/415] Java: update path-injection query to use new 'read-file' sink kind --- java/ql/src/Security/CWE/CWE-022/TaintedPath.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql index aedc7fc4b2c..e64059b63d6 100644 --- a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -29,7 +29,7 @@ class TaintedPathConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(PathCreation p).getAnInput() or - sinkNode(sink, "create-file") + sinkNode(sink, ["create-file", "read-file"]) } override predicate isSanitizer(DataFlow::Node sanitizer) { From 80d4fb5e33c49499bf329e11478e3a338e1ce86b Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Sun, 12 Feb 2023 10:51:53 +0100 Subject: [PATCH 200/415] Organisation TarSlip/UnsafeUnpack into two folders --- .../TarSlip.expected | 0 .../TarSlip.qlref | 0 .../TarSlipImprov.py | 0 .../ZipSlip.expected | 0 .../ZipSlip.qlref | 0 .../zipslip_bad.py | 0 .../zipslip_good.py | 0 .../DataflowQueryTest.expected | 15 +++++++++++ .../DataflowQueryTest.ql | 0 .../UnsafeUnpack.expected | 0 .../UnsafeUnpack.py | 26 +++++++++---------- .../UnsafeUnpack.qlref | 0 .../CWE-022/DataflowQueryTest.expected | 2 -- 13 files changed, 28 insertions(+), 15 deletions(-) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-TarSlip}/TarSlip.expected (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-TarSlip}/TarSlip.qlref (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-TarSlip}/TarSlipImprov.py (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-TarSlip}/ZipSlip.expected (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-TarSlip}/ZipSlip.qlref (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-TarSlip}/zipslip_bad.py (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-TarSlip}/zipslip_good.py (100%) create mode 100644 python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-UnsafeUnpacking}/DataflowQueryTest.ql (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-UnsafeUnpacking}/UnsafeUnpack.expected (100%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-UnsafeUnpacking}/UnsafeUnpack.py (89%) rename python/ql/test/experimental/query-tests/Security/{CWE-022 => CWE-022-UnsafeUnpacking}/UnsafeUnpack.qlref (100%) delete mode 100644 python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/TarSlip.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/TarSlip.expected rename to python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/TarSlip.qlref b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/TarSlip.qlref rename to python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/TarSlipImprov.py b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlipImprov.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/TarSlipImprov.py rename to python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/TarSlipImprov.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/ZipSlip.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.expected similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/ZipSlip.expected rename to python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/ZipSlip.qlref b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.qlref similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/ZipSlip.qlref rename to python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/ZipSlip.qlref diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/zipslip_bad.py b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_bad.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/zipslip_bad.py rename to python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_bad.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/zipslip_good.py b/python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_good.py similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/zipslip_good.py rename to python/ql/test/experimental/query-tests/Security/CWE-022-TarSlip/zipslip_good.py diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected new file mode 100644 index 00000000000..5a1382ed87c --- /dev/null +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected @@ -0,0 +1,15 @@ +missingAnnotationOnSink +failures +| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | Unexpected result: result=BAD | +| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | Unexpected result: result=BAD | +| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | Unexpected result: result=BAD | +| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | Unexpected result: result=BAD | +| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | Unexpected result: result=BAD | +| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | Unexpected result: result=BAD | +| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | Unexpected result: result=BAD | +| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | Unexpected result: result=BAD | +| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | Unexpected result: result=BAD | +| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | Unexpected result: result=BAD | +| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | Unexpected result: result=BAD | +| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | Unexpected result: result=BAD | +| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | Unexpected result: result=BAD | diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.ql similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.ql rename to python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.ql diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.expected rename to python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.expected diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.py similarity index 89% rename from python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py rename to python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.py index 50574281cbd..c83714b764c 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.py @@ -16,7 +16,7 @@ def download_from_url(): with open(tarpath, "wb") as f: f.write(response.raw.read()) untarredpath = "/tmp/tmp123" - shutil.unpack_archive(tarpath, untarredpath) # $result=BAD + shutil.unpack_archive(tarpath, untarredpath) # A source catching an S3 filename download @@ -31,7 +31,7 @@ bucket_name = "mybucket" s3 = boto3.client('s3') s3.download_file(bucket_name, remote_ziped_name, local_ziped_path) -shutil.unpack_archive(local_ziped_path, base_dir) # $result=BAD +shutil.unpack_archive(local_ziped_path, base_dir) # wget @@ -45,11 +45,11 @@ base_dir = "/tmp/basedir" # download(url, out, bar) contains out parameter wget.download(url, compressed_file) -shutil.unpack_archive(compressed_file, base_dir) # $result=BAD +shutil.unpack_archive(compressed_file, base_dir) # download(url) returns filename compressed_file = wget.download(url) -shutil.unpack_archive(compressed_file, base_dir) # $result=BAD +shutil.unpack_archive(compressed_file, base_dir) # A source coming from a CLI argparse module @@ -63,7 +63,7 @@ parser.add_argument('filename', help='filename to be provided') args = parser.parse_args() compressed_file = args.filename -shutil.unpack_archive(compressed_file, base_dir) # $result=BAD +shutil.unpack_archive(compressed_file, base_dir) # A source coming from a CLI and downloaded @@ -84,7 +84,7 @@ tarpath = "/tmp/tmp456/tarball.tar.gz" with open(tarpath, "wb") as f: f.write(response.raw.read()) -shutil.unpack_archive(tarpath, base_dir) # $result=BAD +shutil.unpack_archive(tarpath, base_dir) # the django upload functionality # see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES @@ -102,14 +102,14 @@ def simple_upload(request): with open(savepath, 'wb+') as wfile: for chunk in request.FILES["ufile1"].chunks(): wfile.write(chunk) - shutil.unpack_archive(savepath, base_dir) # $result=BAD + shutil.unpack_archive(savepath, base_dir) # Write in binary the uploaded tarball myfile = request.FILES.get("ufile1") file_path = os.path.join(base_dir, "tarball.tar") with file_path.open('wb') as f: f.write(myfile.read()) - shutil.unpack_archive(file_path, base_dir) # $result=BAD + shutil.unpack_archive(file_path, base_dir) # Save uploaded files using FileSystemStorage Django API # see FileSystemStorage: https://docs.djangoproject.com/en/4.1/ref/files/storage/#django.core.files.storage.FileSystemStorage @@ -117,7 +117,7 @@ def simple_upload(request): fs = FileSystemStorage() filename = fs.save(ufile.name, ufile) uploaded_file_path = fs.path(filename) - shutil.unpack_archive(uploaded_file_path, base_dir) # $result=BAD + shutil.unpack_archive(uploaded_file_path, base_dir) return render(request, 'simple_upload.html') @@ -139,7 +139,7 @@ parser.add_argument('filename', help='filename to be provided') args = parser.parse_args() unsafe_filename_tar = args.filename with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar: - tar.extractall(path="/tmp/unpack/", members=tar) # $result=BAD + tar.extractall(path="/tmp/unpack/", members=tar) tar = tarfile.open(unsafe_filename_tar) @@ -164,7 +164,7 @@ def simple_upload(request): if member.issym(): raise ValueError("But it is a symlink") result.append(member) - tar.extractall(path=tempfile.mkdtemp(), members=result) # $result=BAD + tar.extractall(path=tempfile.mkdtemp(), members=result) tar.close() @@ -173,7 +173,7 @@ tarpath = "/tmp/tmp456/tarball.tar.gz" with open(tarpath, "wb") as f: f.write(response.raw.read()) target_dir = "/tmp/unpack" -tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) # $result=BAD +tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) from pathlib import Path @@ -198,4 +198,4 @@ with tempfile.NamedTemporaryFile(suffix=".tar.gz") as tmp: target = cache_dir else: target = Path(tempfile.mkdtemp()) - shutil.unpack_archive(tmp.name, target) # $result=BAD \ No newline at end of file + shutil.unpack_archive(tmp.name, target) \ No newline at end of file diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.qlref b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.qlref similarity index 100% rename from python/ql/test/experimental/query-tests/Security/CWE-022/UnsafeUnpack.qlref rename to python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.qlref diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected deleted file mode 100644 index 3875da4e143..00000000000 --- a/python/ql/test/experimental/query-tests/Security/CWE-022/DataflowQueryTest.expected +++ /dev/null @@ -1,2 +0,0 @@ -missingAnnotationOnSink -failures From 518684b73685f4529587de9b5af8acb2450f8046 Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Sun, 12 Feb 2023 21:26:12 +0100 Subject: [PATCH 201/415] Put back the annotation result=BAD --- .../CWE-022-UnsafeUnpacking/UnsafeUnpack.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.py b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.py index c83714b764c..6b533462d23 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.py +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/UnsafeUnpack.py @@ -16,7 +16,7 @@ def download_from_url(): with open(tarpath, "wb") as f: f.write(response.raw.read()) untarredpath = "/tmp/tmp123" - shutil.unpack_archive(tarpath, untarredpath) + shutil.unpack_archive(tarpath, untarredpath) # $result=BAD # A source catching an S3 filename download @@ -31,7 +31,7 @@ bucket_name = "mybucket" s3 = boto3.client('s3') s3.download_file(bucket_name, remote_ziped_name, local_ziped_path) -shutil.unpack_archive(local_ziped_path, base_dir) +shutil.unpack_archive(local_ziped_path, base_dir) # $result=BAD # wget @@ -45,11 +45,11 @@ base_dir = "/tmp/basedir" # download(url, out, bar) contains out parameter wget.download(url, compressed_file) -shutil.unpack_archive(compressed_file, base_dir) +shutil.unpack_archive(compressed_file, base_dir) # $result=BAD # download(url) returns filename compressed_file = wget.download(url) -shutil.unpack_archive(compressed_file, base_dir) +shutil.unpack_archive(compressed_file, base_dir) # $result=BAD # A source coming from a CLI argparse module @@ -63,7 +63,7 @@ parser.add_argument('filename', help='filename to be provided') args = parser.parse_args() compressed_file = args.filename -shutil.unpack_archive(compressed_file, base_dir) +shutil.unpack_archive(compressed_file, base_dir) # $result=BAD # A source coming from a CLI and downloaded @@ -84,7 +84,7 @@ tarpath = "/tmp/tmp456/tarball.tar.gz" with open(tarpath, "wb") as f: f.write(response.raw.read()) -shutil.unpack_archive(tarpath, base_dir) +shutil.unpack_archive(tarpath, base_dir) # $result=BAD # the django upload functionality # see HttpRequest.FILES: https://docs.djangoproject.com/en/4.1/ref/request-response/#django.http.HttpRequest.FILES @@ -102,14 +102,14 @@ def simple_upload(request): with open(savepath, 'wb+') as wfile: for chunk in request.FILES["ufile1"].chunks(): wfile.write(chunk) - shutil.unpack_archive(savepath, base_dir) + shutil.unpack_archive(savepath, base_dir) # $result=BAD # Write in binary the uploaded tarball myfile = request.FILES.get("ufile1") file_path = os.path.join(base_dir, "tarball.tar") with file_path.open('wb') as f: f.write(myfile.read()) - shutil.unpack_archive(file_path, base_dir) + shutil.unpack_archive(file_path, base_dir) # $result=BAD # Save uploaded files using FileSystemStorage Django API # see FileSystemStorage: https://docs.djangoproject.com/en/4.1/ref/files/storage/#django.core.files.storage.FileSystemStorage @@ -117,7 +117,7 @@ def simple_upload(request): fs = FileSystemStorage() filename = fs.save(ufile.name, ufile) uploaded_file_path = fs.path(filename) - shutil.unpack_archive(uploaded_file_path, base_dir) + shutil.unpack_archive(uploaded_file_path, base_dir) # $result=BAD return render(request, 'simple_upload.html') @@ -139,7 +139,7 @@ parser.add_argument('filename', help='filename to be provided') args = parser.parse_args() unsafe_filename_tar = args.filename with tarfile.TarFile(unsafe_filename_tar, mode="r") as tar: - tar.extractall(path="/tmp/unpack/", members=tar) + tar.extractall(path="/tmp/unpack/", members=tar) # $result=BAD tar = tarfile.open(unsafe_filename_tar) @@ -164,7 +164,7 @@ def simple_upload(request): if member.issym(): raise ValueError("But it is a symlink") result.append(member) - tar.extractall(path=tempfile.mkdtemp(), members=result) + tar.extractall(path=tempfile.mkdtemp(), members=result) # $result=BAD tar.close() @@ -173,7 +173,7 @@ tarpath = "/tmp/tmp456/tarball.tar.gz" with open(tarpath, "wb") as f: f.write(response.raw.read()) target_dir = "/tmp/unpack" -tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) +tarfile.TarFile(tarpath, mode="r").extractall(path=target_dir) # $result=BAD from pathlib import Path @@ -198,4 +198,4 @@ with tempfile.NamedTemporaryFile(suffix=".tar.gz") as tmp: target = cache_dir else: target = Path(tempfile.mkdtemp()) - shutil.unpack_archive(tmp.name, target) \ No newline at end of file + shutil.unpack_archive(tmp.name, target) # $result=BAD \ No newline at end of file From d7af80136e685141b9ec26286f081bd7bab2cded Mon Sep 17 00:00:00 2001 From: Sim4n6 Date: Sun, 12 Feb 2023 21:27:20 +0100 Subject: [PATCH 202/415] Fail tests when missing annotation on sink orfail --- .../DataflowQueryTest.expected | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected index 5a1382ed87c..3875da4e143 100644 --- a/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected +++ b/python/ql/test/experimental/query-tests/Security/CWE-022-UnsafeUnpacking/DataflowQueryTest.expected @@ -1,15 +1,2 @@ missingAnnotationOnSink failures -| UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath | Unexpected result: result=BAD | -| UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path | Unexpected result: result=BAD | -| UnsafeUnpack.py:48:23:48:37 | ControlFlowNode for compressed_file | Unexpected result: result=BAD | -| UnsafeUnpack.py:52:23:52:37 | ControlFlowNode for compressed_file | Unexpected result: result=BAD | -| UnsafeUnpack.py:66:23:66:37 | ControlFlowNode for compressed_file | Unexpected result: result=BAD | -| UnsafeUnpack.py:87:23:87:29 | ControlFlowNode for tarpath | Unexpected result: result=BAD | -| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | Unexpected result: result=BAD | -| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | Unexpected result: result=BAD | -| UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path | Unexpected result: result=BAD | -| UnsafeUnpack.py:142:49:142:51 | ControlFlowNode for tar | Unexpected result: result=BAD | -| UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | Unexpected result: result=BAD | -| UnsafeUnpack.py:176:1:176:34 | ControlFlowNode for Attribute() | Unexpected result: result=BAD | -| UnsafeUnpack.py:201:29:201:36 | ControlFlowNode for Attribute | Unexpected result: result=BAD | From 676e4e8461e576f86bf1e52733796c521ffd6be1 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Sun, 12 Feb 2023 16:32:31 -0500 Subject: [PATCH 203/415] Java: add change note --- .../lib/change-notes/2023-02-13-update-create-file-sinks.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md diff --git a/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md b/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md new file mode 100644 index 00000000000..2931d0ae308 --- /dev/null +++ b/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Removed the first argument of `java.nio.file.Files#createTempDirectory(String,FileAttribute[])` as a "create-file" sink. +* Added the first argument of `java.nio.file.Files#copy` as a sink for the `java/path-injection` query. From ad8849c6b86c11f663b89ae579047d8e9a447408 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Sun, 12 Feb 2023 16:33:26 -0500 Subject: [PATCH 204/415] Java: fix typo --- java/ql/lib/ext/java.nio.file.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/ext/java.nio.file.model.yml b/java/ql/lib/ext/java.nio.file.model.yml index 9536f85d303..db51d2f6686 100644 --- a/java/ql/lib/ext/java.nio.file.model.yml +++ b/java/ql/lib/ext/java.nio.file.model.yml @@ -10,7 +10,7 @@ extensions: - ["java.nio.file", "Files", False, "createFile", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createLink", "", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createSymbolicLink", "", "", "Argument[0]", "create-file", "manual"] - - ["java.nio.file", "Files", False, "createTempDirectory", "(Path,String,FileAttribute[]])", "", "Argument[0]", "create-file", "manual"] + - ["java.nio.file", "Files", False, "createTempDirectory", "(Path,String,FileAttribute[])", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "createTempFile", "(Path,String,String,FileAttribute[])", "", "Argument[0]", "create-file", "manual"] - ["java.nio.file", "Files", False, "move", "", "", "Argument[1]", "create-file", "manual"] - ["java.nio.file", "Files", False, "newBufferedWriter", "", "", "Argument[0]", "create-file", "manual"] From b2e79e2948c7595544a9ee81ba32cdf806d8ed61 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 13 Feb 2023 10:40:47 +0100 Subject: [PATCH 205/415] Python/Ruby/JS Crypto: Add a few algorithms + block modes I have tried to add a few links to support the claim that these algorithms are strong/safe. It wasn't always super easy, so in some cases I have ended up just linking to the documentation of the `cryptography` Python package. Co-authored-by: REDMOND\brodes --- .../concepts/internal/CryptoAlgorithmNames.qll | 14 +++++++++++++- .../lib/semmle/python/internal/ConceptsShared.qll | 9 ++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll b/python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll index a234ba2cc1f..8bb63d97876 100644 --- a/python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll +++ b/python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll @@ -14,8 +14,20 @@ predicate isStrongHashingAlgorithm(string name) { name = [ + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 + // and https://www.blake2.net/ + "BLAKE2", "BLAKE2B", "BLAKE2S", + // see https://github.com/BLAKE3-team/BLAKE3 + "BLAKE3", + // "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", - "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512" + "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 + "SHAKE128", "SHAKE256", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 + "SM3", + // see https://security.stackexchange.com/a/216297 + "WHIRLPOOL", ] } diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 2f6c8bb8b29..f394360c1a3 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -81,7 +81,14 @@ module Cryptography { * data of arbitrary length using a block encryption algorithm. */ class BlockMode extends string { - BlockMode() { this = ["ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP"] } + BlockMode() { + this = + [ + "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", + "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final + "EAX" // https://en.wikipedia.org/wiki/EAX_mode + ] + } /** Holds if this block mode is considered to be insecure. */ predicate isWeak() { this = "ECB" } From 5235964b079ec0f13d58c684353356c60e19918e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 13 Feb 2023 10:44:12 +0100 Subject: [PATCH 206/415] sync files --- .../semmle/javascript/internal/ConceptsShared.qll | 9 ++++++++- .../security/internal/CryptoAlgorithmNames.qll | 14 +++++++++++++- .../ql/lib/codeql/ruby/internal/ConceptsShared.qll | 9 ++++++++- .../security/internal/CryptoAlgorithmNames.qll | 14 +++++++++++++- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 2f6c8bb8b29..f394360c1a3 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -81,7 +81,14 @@ module Cryptography { * data of arbitrary length using a block encryption algorithm. */ class BlockMode extends string { - BlockMode() { this = ["ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP"] } + BlockMode() { + this = + [ + "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", + "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final + "EAX" // https://en.wikipedia.org/wiki/EAX_mode + ] + } /** Holds if this block mode is considered to be insecure. */ predicate isWeak() { this = "ECB" } diff --git a/javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll b/javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll index a234ba2cc1f..8bb63d97876 100644 --- a/javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll +++ b/javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll @@ -14,8 +14,20 @@ predicate isStrongHashingAlgorithm(string name) { name = [ + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 + // and https://www.blake2.net/ + "BLAKE2", "BLAKE2B", "BLAKE2S", + // see https://github.com/BLAKE3-team/BLAKE3 + "BLAKE3", + // "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", - "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512" + "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 + "SHAKE128", "SHAKE256", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 + "SM3", + // see https://security.stackexchange.com/a/216297 + "WHIRLPOOL", ] } diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 2f6c8bb8b29..f394360c1a3 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -81,7 +81,14 @@ module Cryptography { * data of arbitrary length using a block encryption algorithm. */ class BlockMode extends string { - BlockMode() { this = ["ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP"] } + BlockMode() { + this = + [ + "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", + "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final + "EAX" // https://en.wikipedia.org/wiki/EAX_mode + ] + } /** Holds if this block mode is considered to be insecure. */ predicate isWeak() { this = "ECB" } diff --git a/ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll b/ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll index a234ba2cc1f..8bb63d97876 100644 --- a/ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll +++ b/ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll @@ -14,8 +14,20 @@ predicate isStrongHashingAlgorithm(string name) { name = [ + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 + // and https://www.blake2.net/ + "BLAKE2", "BLAKE2B", "BLAKE2S", + // see https://github.com/BLAKE3-team/BLAKE3 + "BLAKE3", + // "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", - "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512" + "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 + "SHAKE128", "SHAKE256", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 + "SM3", + // see https://security.stackexchange.com/a/216297 + "WHIRLPOOL", ] } From b3602a5b7f3912d1638ababf51855252747f616c Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 13 Feb 2023 13:53:46 +0100 Subject: [PATCH 207/415] C#: Use functionname as stored in the database. --- csharp/ql/lib/semmle/code/csharp/Callable.qll | 64 ++----------------- 1 file changed, 7 insertions(+), 57 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index ea88f814bce..c0a299454bf 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -435,8 +435,12 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de * (`BinaryOperator`), or a conversion operator (`ConversionOperator`). */ class Operator extends Callable, Member, Attributable, @operator { - /** Gets the assembly name of this operator. */ - string getAssemblyName() { operators(this, result, _, _, _, _) } + /** + * DEPRECATED: use `getFunctionName()` instead. + * + * Gets the assembly name of this operator. + */ + deprecated string getAssemblyName() { result = this.getFunctionName() } override string getName() { operators(this, _, result, _, _, _) } @@ -445,7 +449,7 @@ class Operator extends Callable, Member, Attributable, @operator { /** * Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`. */ - string getFunctionName() { none() } + string getFunctionName() { operators(this, result, _, _, _, _) } override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) } @@ -505,8 +509,6 @@ class UnaryOperator extends Operator { class PlusOperator extends UnaryOperator { PlusOperator() { this.getName() = "+" } - override string getFunctionName() { result = "op_UnaryPlus" } - override string getAPrimaryQlClass() { result = "PlusOperator" } } @@ -522,8 +524,6 @@ class PlusOperator extends UnaryOperator { class MinusOperator extends UnaryOperator { MinusOperator() { this.getName() = "-" } - override string getFunctionName() { result = "op_UnaryNegation" } - override string getAPrimaryQlClass() { result = "MinusOperator" } } @@ -539,8 +539,6 @@ class MinusOperator extends UnaryOperator { class NotOperator extends UnaryOperator { NotOperator() { this.getName() = "!" } - override string getFunctionName() { result = "op_LogicalNot" } - override string getAPrimaryQlClass() { result = "NotOperator" } } @@ -556,8 +554,6 @@ class NotOperator extends UnaryOperator { class ComplementOperator extends UnaryOperator { ComplementOperator() { this.getName() = "~" } - override string getFunctionName() { result = "op_OnesComplement" } - override string getAPrimaryQlClass() { result = "ComplementOperator" } } @@ -573,8 +569,6 @@ class ComplementOperator extends UnaryOperator { class IncrementOperator extends UnaryOperator { IncrementOperator() { this.getName() = "++" } - override string getFunctionName() { result = "op_Increment" } - override string getAPrimaryQlClass() { result = "IncrementOperator" } } @@ -590,8 +584,6 @@ class IncrementOperator extends UnaryOperator { class DecrementOperator extends UnaryOperator { DecrementOperator() { this.getName() = "--" } - override string getFunctionName() { result = "op_Decrement" } - override string getAPrimaryQlClass() { result = "DecrementOperator" } } @@ -607,8 +599,6 @@ class DecrementOperator extends UnaryOperator { class FalseOperator extends UnaryOperator { FalseOperator() { this.getName() = "false" } - override string getFunctionName() { result = "op_False" } - override string getAPrimaryQlClass() { result = "FalseOperator" } } @@ -624,8 +614,6 @@ class FalseOperator extends UnaryOperator { class TrueOperator extends UnaryOperator { TrueOperator() { this.getName() = "true" } - override string getFunctionName() { result = "op_True" } - override string getAPrimaryQlClass() { result = "TrueOperator" } } @@ -659,8 +647,6 @@ class BinaryOperator extends Operator { class AddOperator extends BinaryOperator { AddOperator() { this.getName() = "+" } - override string getFunctionName() { result = "op_Addition" } - override string getAPrimaryQlClass() { result = "AddOperator" } } @@ -676,8 +662,6 @@ class AddOperator extends BinaryOperator { class SubOperator extends BinaryOperator { SubOperator() { this.getName() = "-" } - override string getFunctionName() { result = "op_Subtraction" } - override string getAPrimaryQlClass() { result = "SubOperator" } } @@ -693,8 +677,6 @@ class SubOperator extends BinaryOperator { class MulOperator extends BinaryOperator { MulOperator() { this.getName() = "*" } - override string getFunctionName() { result = "op_Multiply" } - override string getAPrimaryQlClass() { result = "MulOperator" } } @@ -710,8 +692,6 @@ class MulOperator extends BinaryOperator { class DivOperator extends BinaryOperator { DivOperator() { this.getName() = "/" } - override string getFunctionName() { result = "op_Division" } - override string getAPrimaryQlClass() { result = "DivOperator" } } @@ -727,8 +707,6 @@ class DivOperator extends BinaryOperator { class RemOperator extends BinaryOperator { RemOperator() { this.getName() = "%" } - override string getFunctionName() { result = "op_Modulus" } - override string getAPrimaryQlClass() { result = "RemOperator" } } @@ -744,8 +722,6 @@ class RemOperator extends BinaryOperator { class AndOperator extends BinaryOperator { AndOperator() { this.getName() = "&" } - override string getFunctionName() { result = "op_BitwiseAnd" } - override string getAPrimaryQlClass() { result = "AndOperator" } } @@ -761,8 +737,6 @@ class AndOperator extends BinaryOperator { class OrOperator extends BinaryOperator { OrOperator() { this.getName() = "|" } - override string getFunctionName() { result = "op_BitwiseOr" } - override string getAPrimaryQlClass() { result = "OrOperator" } } @@ -778,8 +752,6 @@ class OrOperator extends BinaryOperator { class XorOperator extends BinaryOperator { XorOperator() { this.getName() = "^" } - override string getFunctionName() { result = "op_ExclusiveOr" } - override string getAPrimaryQlClass() { result = "XorOperator" } } @@ -795,8 +767,6 @@ class XorOperator extends BinaryOperator { class LeftShiftOperator extends BinaryOperator { LeftShiftOperator() { this.getName() = "<<" } - override string getFunctionName() { result = "op_LeftShift" } - override string getAPrimaryQlClass() { result = "LeftShiftOperator" } } @@ -815,8 +785,6 @@ deprecated class LShiftOperator = LeftShiftOperator; class RightShiftOperator extends BinaryOperator { RightShiftOperator() { this.getName() = ">>" } - override string getFunctionName() { result = "op_RightShift" } - override string getAPrimaryQlClass() { result = "RightShiftOperator" } } @@ -835,8 +803,6 @@ deprecated class RShiftOperator = RightShiftOperator; class UnsignedRightShiftOperator extends BinaryOperator { UnsignedRightShiftOperator() { this.getName() = ">>>" } - override string getFunctionName() { result = "op_UnsignedRightShift" } - override string getAPrimaryQlClass() { result = "UnsignedRightShiftOperator" } } @@ -852,8 +818,6 @@ class UnsignedRightShiftOperator extends BinaryOperator { class EQOperator extends BinaryOperator { EQOperator() { this.getName() = "==" } - override string getFunctionName() { result = "op_Equality" } - override string getAPrimaryQlClass() { result = "EQOperator" } } @@ -869,8 +833,6 @@ class EQOperator extends BinaryOperator { class NEOperator extends BinaryOperator { NEOperator() { this.getName() = "!=" } - override string getFunctionName() { result = "op_Inequality" } - override string getAPrimaryQlClass() { result = "NEOperator" } } @@ -886,8 +848,6 @@ class NEOperator extends BinaryOperator { class LTOperator extends BinaryOperator { LTOperator() { this.getName() = "<" } - override string getFunctionName() { result = "op_LessThan" } - override string getAPrimaryQlClass() { result = "LTOperator" } } @@ -903,8 +863,6 @@ class LTOperator extends BinaryOperator { class GTOperator extends BinaryOperator { GTOperator() { this.getName() = ">" } - override string getFunctionName() { result = "op_GreaterThan" } - override string getAPrimaryQlClass() { result = "GTOperator" } } @@ -920,8 +878,6 @@ class GTOperator extends BinaryOperator { class LEOperator extends BinaryOperator { LEOperator() { this.getName() = "<=" } - override string getFunctionName() { result = "op_LessThanOrEqual" } - override string getAPrimaryQlClass() { result = "LEOperator" } } @@ -937,8 +893,6 @@ class LEOperator extends BinaryOperator { class GEOperator extends BinaryOperator { GEOperator() { this.getName() = ">=" } - override string getFunctionName() { result = "op_GreaterThanOrEqual" } - override string getAPrimaryQlClass() { result = "GEOperator" } } @@ -976,8 +930,6 @@ class ConversionOperator extends Operator { class ImplicitConversionOperator extends ConversionOperator { ImplicitConversionOperator() { this.getName() = "implicit conversion" } - override string getFunctionName() { result = "op_Implicit" } - override string getAPrimaryQlClass() { result = "ImplicitConversionOperator" } } @@ -993,8 +945,6 @@ class ImplicitConversionOperator extends ConversionOperator { class ExplicitConversionOperator extends ConversionOperator { ExplicitConversionOperator() { this.getName() = "explicit conversion" } - override string getFunctionName() { result = "op_Explicit" } - override string getAPrimaryQlClass() { result = "ExplicitConversionOperator" } } From 39e50f745d47f4cb91fec73ce883403658f317d9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 13 Feb 2023 14:21:12 +0100 Subject: [PATCH 208/415] Ruby: Fix `.expected` for CryptoAlgorithms --- .../test/library-tests/security/CryptoAlgorithms.expected | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected b/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected index 6af41869909..eedddb2df9f 100644 --- a/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected +++ b/ruby/ql/test/library-tests/security/CryptoAlgorithms.expected @@ -12,6 +12,10 @@ weakHashingAlgorithms | SHA0 | | SHA1 | strongHashingAlgorithms +| BLAKE2 | +| BLAKE2B | +| BLAKE2S | +| BLAKE3 | | DSA | | ECDSA256 | | ECDSA384 | @@ -30,6 +34,10 @@ strongHashingAlgorithms | SHA3256 | | SHA3384 | | SHA3512 | +| SHAKE128 | +| SHAKE256 | +| SM3 | +| WHIRLPOOL | weakEncryptionAlgorithms | 3DES | | ARC2 | From 191613e8bf1020bbd01c658abdf5589d2d3d3705 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 13 Feb 2023 09:11:53 -0500 Subject: [PATCH 209/415] Java: update change note --- go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md b/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md index 2931d0ae308..ad4f35a6421 100644 --- a/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md +++ b/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md @@ -2,4 +2,4 @@ category: minorAnalysis --- * Removed the first argument of `java.nio.file.Files#createTempDirectory(String,FileAttribute[])` as a "create-file" sink. -* Added the first argument of `java.nio.file.Files#copy` as a sink for the `java/path-injection` query. +* Added the first argument of `java.nio.file.Files#copy` as a "read-file" sink for the `java/path-injection` query. From 1c3d4b98c8246eb9b11d21eae122c7af33a1e439 Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 13 Feb 2023 09:15:31 -0500 Subject: [PATCH 210/415] Java: move change note --- .../ql/lib/change-notes/2023-02-13-update-create-file-sinks.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {go => java}/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md (100%) diff --git a/go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md b/java/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md similarity index 100% rename from go/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md rename to java/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md From df221819631a0d7956464afa069a0d7f346abe75 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 13 Feb 2023 14:50:02 +0100 Subject: [PATCH 211/415] Python: Add tests of `hmac` --- .../frameworks/stdlib/test_hmac.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 python/ql/test/library-tests/frameworks/stdlib/test_hmac.py diff --git a/python/ql/test/library-tests/frameworks/stdlib/test_hmac.py b/python/ql/test/library-tests/frameworks/stdlib/test_hmac.py new file mode 100644 index 00000000000..80ae7eff2e2 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/stdlib/test_hmac.py @@ -0,0 +1,33 @@ +import hmac +import hashlib + +key = b"" + +hmac_obj = hmac.new(key, b"secret message", "sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +print(hmac_obj.digest()) +print(hmac_obj.hexdigest()) + +hmac_obj = hmac.new(key, msg=b"secret message", digestmod="sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +print(hmac_obj.hexdigest()) + + +hmac_obj = hmac.new(key, digestmod="sha256") +hmac_obj.update(b"secret") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret" CryptographicOperationAlgorithm=SHA256 +hmac_obj.update(msg=b" message") # $ MISSING: CryptographicOperation CryptographicOperationInput=b" message" CryptographicOperationAlgorithm=SHA256 +print(hmac_obj.hexdigest()) + + +hmac_obj = hmac.new(key, b"secret message", hashlib.sha256) # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +print(hmac_obj.hexdigest()) + + +# like hmac.new +hmac_obj = hmac.HMAC(key, digestmod="sha256") +hmac_obj.update(b"secret message") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +print(hmac_obj.hexdigest()) + + +dig = hmac.digest(key, b"secret message", "sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +print(dig) +dig = hmac.digest(key, msg=b"secret message", digest="sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +print(dig) From 1c7fe97427b4872f5ceca9e3e625439b4a55bc12 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 13 Feb 2023 15:39:43 +0100 Subject: [PATCH 212/415] Python: Add modeling of `hmac` --- .../change-notes/2023-02-13-hmac-modeling.md | 4 + .../lib/semmle/python/frameworks/Stdlib.qll | 73 +++++++++++++++++++ .../frameworks/stdlib/test_hmac.py | 16 ++-- 3 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 python/ql/lib/change-notes/2023-02-13-hmac-modeling.md diff --git a/python/ql/lib/change-notes/2023-02-13-hmac-modeling.md b/python/ql/lib/change-notes/2023-02-13-hmac-modeling.md new file mode 100644 index 00000000000..2753c24a818 --- /dev/null +++ b/python/ql/lib/change-notes/2023-02-13-hmac-modeling.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added modeling of cryptographic operations in the `hmac` library. diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index 3fce979c147..56f817f1840 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -2669,6 +2669,7 @@ private module StdlibPrivate { HashlibNewCall() { this = hashlibNewCall(hashName) and + // we only want to consider it as an cryptographic operation if the input is available exists(this.getParameter(1, "data")) } @@ -2751,6 +2752,78 @@ private module StdlibPrivate { } } + // --------------------------------------------------------------------------- + // hmac + // --------------------------------------------------------------------------- + abstract class HmacCryptographicOperation extends Cryptography::CryptographicOperation::Range, + API::CallNode { + abstract API::Node getDigestArg(); + + override Cryptography::CryptographicAlgorithm getAlgorithm() { + exists(string algorithmName | result.matchesName(algorithmName) | + this.getDigestArg().asSink() = hashlibMember(algorithmName).asSource() + or + this.getDigestArg().getAValueReachingSink().asExpr().(StrConst).getText() = algorithmName + ) + } + + override Cryptography::BlockMode getBlockMode() { none() } + } + + API::CallNode getHmacConstructorCall(API::Node digestArg) { + result = API::moduleImport("hmac").getMember(["new", "HMAC"]).getACall() and + digestArg = result.getParameter(2, "digestmod") + } + + /** + * A call to `hmac.new`/`hmac.HMAC`. + * + * See https://docs.python.org/3.11/library/hmac.html#hmac.new + */ + class HmacNewCall extends HmacCryptographicOperation { + API::Node digestArg; + + HmacNewCall() { + this = getHmacConstructorCall(digestArg) and + // we only want to consider it as an cryptographic operation if the input is available + exists(this.getParameter(1, "msg").asSink()) + } + + override API::Node getDigestArg() { result = digestArg } + + override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() } + } + + /** + * A call to `.update` on an HMAC object. + * + * See https://docs.python.org/3.11/library/hmac.html#hmac.HMAC.update + */ + class HmacUpdateCall extends HmacCryptographicOperation { + API::Node digestArg; + + HmacUpdateCall() { + this = getHmacConstructorCall(digestArg).getReturn().getMember("update").getACall() + } + + override API::Node getDigestArg() { result = digestArg } + + override DataFlow::Node getAnInput() { result = this.getParameter(0, "msg").asSink() } + } + + /** + * A call to `hmac.digest`. + * + * See https://docs.python.org/3.11/library/hmac.html#hmac.digest + */ + class HmacDigestCall extends HmacCryptographicOperation { + HmacDigestCall() { this = API::moduleImport("hmac").getMember("digest").getACall() } + + override API::Node getDigestArg() { result = this.getParameter(2, "digest") } + + override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() } + } + // --------------------------------------------------------------------------- // logging // --------------------------------------------------------------------------- diff --git a/python/ql/test/library-tests/frameworks/stdlib/test_hmac.py b/python/ql/test/library-tests/frameworks/stdlib/test_hmac.py index 80ae7eff2e2..ff8b30329a7 100644 --- a/python/ql/test/library-tests/frameworks/stdlib/test_hmac.py +++ b/python/ql/test/library-tests/frameworks/stdlib/test_hmac.py @@ -3,31 +3,31 @@ import hashlib key = b"" -hmac_obj = hmac.new(key, b"secret message", "sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +hmac_obj = hmac.new(key, b"secret message", "sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 print(hmac_obj.digest()) print(hmac_obj.hexdigest()) -hmac_obj = hmac.new(key, msg=b"secret message", digestmod="sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +hmac_obj = hmac.new(key, msg=b"secret message", digestmod="sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 print(hmac_obj.hexdigest()) hmac_obj = hmac.new(key, digestmod="sha256") -hmac_obj.update(b"secret") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret" CryptographicOperationAlgorithm=SHA256 -hmac_obj.update(msg=b" message") # $ MISSING: CryptographicOperation CryptographicOperationInput=b" message" CryptographicOperationAlgorithm=SHA256 +hmac_obj.update(b"secret") # $ CryptographicOperation CryptographicOperationInput=b"secret" CryptographicOperationAlgorithm=SHA256 +hmac_obj.update(msg=b" message") # $ CryptographicOperation CryptographicOperationInput=b" message" CryptographicOperationAlgorithm=SHA256 print(hmac_obj.hexdigest()) -hmac_obj = hmac.new(key, b"secret message", hashlib.sha256) # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +hmac_obj = hmac.new(key, b"secret message", hashlib.sha256) # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 print(hmac_obj.hexdigest()) # like hmac.new hmac_obj = hmac.HMAC(key, digestmod="sha256") -hmac_obj.update(b"secret message") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +hmac_obj.update(b"secret message") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 print(hmac_obj.hexdigest()) -dig = hmac.digest(key, b"secret message", "sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +dig = hmac.digest(key, b"secret message", "sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 print(dig) -dig = hmac.digest(key, msg=b"secret message", digest="sha256") # $ MISSING: CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 +dig = hmac.digest(key, msg=b"secret message", digest="sha256") # $ CryptographicOperation CryptographicOperationInput=b"secret message" CryptographicOperationAlgorithm=SHA256 print(dig) From e4c8387815ae95807bf7292ab40ebcb90d580e2b Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Mon, 13 Feb 2023 11:29:30 -0500 Subject: [PATCH 213/415] Java: update CaptureSinkModels.expected with read-file sink --- .../utils/modelgenerator/dataflow/CaptureSinkModels.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected b/java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected index 79483bc24b1..8f6c51aee54 100644 --- a/java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected +++ b/java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected @@ -1,4 +1,5 @@ | p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[-1];create-file;generated | +| p;Sinks;true;copyFileToDirectory;(Path,Path,CopyOption[]);;Argument[0];read-file;generated | | p;Sinks;true;copyFileToDirectory;(Path,Path,CopyOption[]);;Argument[1];create-file;generated | | p;Sinks;true;readUrl;(URL,Charset);;Argument[0];open-url;generated | | p;Sources;true;readUrl;(URL);;Argument[0];open-url;generated | From cfe169a4f99856bab2e82748ed9c3fa920d13673 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 13 Feb 2023 19:42:28 -0500 Subject: [PATCH 214/415] Adding MSSQL to SensitiveAPI --- java/ql/lib/semmle/code/java/security/SensitiveApi.qll | 6 +++++- .../test/query-tests/security/CWE-798/semmle/tests/options | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/semmle/code/java/security/SensitiveApi.qll b/java/ql/lib/semmle/code/java/security/SensitiveApi.qll index f9ba4f41ec5..9936ab202a3 100644 --- a/java/ql/lib/semmle/code/java/security/SensitiveApi.qll +++ b/java/ql/lib/semmle/code/java/security/SensitiveApi.qll @@ -485,6 +485,10 @@ private predicate otherApiCallableCredentialParam(string s) { "com.mongodb.MongoCredential;createCredential(String, String, char[]);2", "com.mongodb.MongoCredential;createMongoCRCredential(String, String, char[]);2", "com.mongodb.MongoCredential;createPlainCredential(String, String, char[]);2", - "com.mongodb.MongoCredential;createScramSha1Credential(String, String, char[]);2" + "com.mongodb.MongoCredential;createScramSha1Credential(String, String, char[]);2", + "com.microsoft.sqlserver.jdbc.SQLServerDataSource;setUser(String);0", + "com.microsoft.sqlserver.jdbc.SQLServerDataSource;setPassword(String);0", + "com.microsoft.sqlserver.jdbc.SQLServerDataSource;getConnection(String, String);0", + "com.microsoft.sqlserver.jdbc.SQLServerDataSource;getConnection(String, String);1", ] } diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/options b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options index 1009a2fc6e8..215e0929c43 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/options +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options @@ -1 +1 @@ -// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700:${testdir}/../../../../../stubs/azure-sdk-for-java:${testdir}/../../../../../stubs/shiro-core-1.4.0:${testdir}/../../../../../stubs/jsch-0.1.55:${testdir}/../../../../../stubs/ganymed-ssh-2-260:${testdir}/../../../../../stubs/apache-mina-sshd-2.8.0:${testdir}/../../../../../stubs/sshj-0.33.0:${testdir}/../../../../../stubs/j2ssh-1.5.5:${testdir}/../../../../../stubs/trilead-ssh2-212:${testdir}/../../../../../stubs/apache-commons-net-3.8.0:${testdir}/../../../../../stubs/mongodbClient +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700:${testdir}/../../../../../stubs/azure-sdk-for-java:${testdir}/../../../../../stubs/shiro-core-1.4.0:${testdir}/../../../../../stubs/jsch-0.1.55:${testdir}/../../../../../stubs/ganymed-ssh-2-260:${testdir}/../../../../../stubs/apache-mina-sshd-2.8.0:${testdir}/../../../../../stubs/sshj-0.33.0:${testdir}/../../../../../stubs/j2ssh-1.5.5:${testdir}/../../../../../stubs/trilead-ssh2-212:${testdir}/../../../../../stubs/apache-commons-net-3.8.0:${testdir}/../../../../../stubs/mongodbClient:${testdir}/../../../../../stubs/mssql-jdbc-12.2.0 From b0c8992eef2f263197c26559716b5ea59b96e8bb Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Mon, 13 Feb 2023 19:44:02 -0500 Subject: [PATCH 215/415] Adding CWE-798 MSSQL Tests --- .../tests/HardcodedMSSQLCredentials.java | 9 + .../sqlserver/jdbc/ISQLServerDataSource.java | 166 ++++++++++++++++ .../jdbc/SQLServerAccessTokenCallback.java | 10 + .../sqlserver/jdbc/SQLServerDataSource.java | 185 ++++++++++++++++++ .../jdbc/SqlAuthenticationToken.java | 16 ++ .../javax/crypto/SecretKey.java | 11 ++ .../javax/crypto/spec/SecretKeySpec.java | 18 ++ .../javax/naming/RefAddr.java | 17 ++ .../javax/naming/Reference.java | 36 ++++ .../javax/naming/Referenceable.java | 10 + .../javax/security/auth/Destroyable.java | 10 + .../javax/sql/CommonDataSource.java | 17 ++ .../javax/sql/DataSource.java | 20 ++ .../org/ietf/jgss/GSSCredential.java | 27 +++ .../org/ietf/jgss/GSSName.java | 24 +++ .../mssql-jdbc-12.2.0/org/ietf/jgss/Oid.java | 18 ++ 16 files changed, 594 insertions(+) create mode 100644 java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerAccessTokenCallback.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SqlAuthenticationToken.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/SecretKey.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/spec/SecretKeySpec.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/RefAddr.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Reference.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Referenceable.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/security/auth/Destroyable.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/CommonDataSource.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/DataSource.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSCredential.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSName.java create mode 100644 java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/Oid.java diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java new file mode 100644 index 00000000000..476c724bdc0 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java @@ -0,0 +1,9 @@ +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; + +public class HardcodedMSSQLCredentials { + public static void main(SQLServerDataSource ds) throws Exception { + ds.setUser("Username"); // $ HardcodedCredentialsApiCall + ds.setPassword("password"); // $ HardcodedCredentialsApiCall + ds.getConnection("Username", "password"); // $ HardcodedCredentialsApiCall + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java new file mode 100644 index 00000000000..24ca455ddd0 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java @@ -0,0 +1,166 @@ +// Generated automatically from com.microsoft.sqlserver.jdbc.ISQLServerDataSource for testing purposes + +package com.microsoft.sqlserver.jdbc; + +import com.microsoft.sqlserver.jdbc.SQLServerAccessTokenCallback; +import javax.sql.CommonDataSource; +import org.ietf.jgss.GSSCredential; + +public interface ISQLServerDataSource extends CommonDataSource +{ + GSSCredential getGSSCredentials(); + SQLServerAccessTokenCallback getAccessTokenCallback(); + String getAADSecurePrincipalId(); + String getAccessToken(); + String getApplicationIntent(); + String getApplicationName(); + String getAuthentication(); + String getClientCertificate(); + String getClientKey(); + String getColumnEncryptionSetting(); + String getDatabaseName(); + String getDatetimeParameterType(); + String getDescription(); + String getDomain(); + String getEnclaveAttestationProtocol(); + String getEnclaveAttestationUrl(); + String getEncrypt(); + String getFailoverPartner(); + String getHostNameInCertificate(); + String getIPAddressPreference(); + String getInstanceName(); + String getJAASConfigurationName(); + String getJASSConfigurationName(); + String getKeyStoreAuthentication(); + String getKeyStoreLocation(); + String getKeyStorePrincipalId(); + String getKeyVaultProviderClientId(); + String getMSIClientId(); + String getMaxResultBuffer(); + String getPrepareMethod(); + String getRealm(); + String getResponseBuffering(); + String getSSLProtocol(); + String getSelectMethod(); + String getServerCertificate(); + String getServerName(); + String getServerSpn(); + String getSocketFactoryClass(); + String getSocketFactoryConstructorArg(); + String getTrustManagerClass(); + String getTrustManagerConstructorArg(); + String getTrustStore(); + String getTrustStoreType(); + String getURL(); + String getUser(); + String getWorkstationID(); + boolean getDelayLoadingLobs(); + boolean getDisableStatementPooling(); + boolean getEnablePrepareOnFirstPreparedStatementCall(); + boolean getFIPS(); + boolean getLastUpdateCount(); + boolean getMultiSubnetFailover(); + boolean getReplication(); + boolean getSendStringParametersAsUnicode(); + boolean getSendTemporalDataTypesAsStringForBulkCopy(); + boolean getSendTimeAsDatetime(); + boolean getServerNameAsACE(); + boolean getTransparentNetworkIPResolution(); + boolean getTrustServerCertificate(); + boolean getUseBulkCopyForBatchInsert(); + boolean getUseFmtOnly(); + boolean getXopenStates(); + int getCancelQueryTimeout(); + int getConnectRetryCount(); + int getConnectRetryInterval(); + int getLockTimeout(); + int getMsiTokenCacheTtl(); + int getPacketSize(); + int getPortNumber(); + int getQueryTimeout(); + int getServerPreparedStatementDiscardThreshold(); + int getSocketTimeout(); + int getStatementPoolingCacheSize(); + void setAADSecurePrincipalId(String p0); + void setAADSecurePrincipalSecret(String p0); + void setAccessToken(String p0); + void setAccessTokenCallback(SQLServerAccessTokenCallback p0); + void setApplicationIntent(String p0); + void setApplicationName(String p0); + void setAuthentication(String p0); + void setAuthenticationScheme(String p0); + void setCancelQueryTimeout(int p0); + void setClientCertificate(String p0); + void setClientKey(String p0); + void setClientKeyPassword(String p0); + void setColumnEncryptionSetting(String p0); + void setConnectRetryCount(int p0); + void setConnectRetryInterval(int p0); + void setDatabaseName(String p0); + void setDatetimeParameterType(String p0); + void setDelayLoadingLobs(boolean p0); + void setDescription(String p0); + void setDisableStatementPooling(boolean p0); + void setDomain(String p0); + void setEnablePrepareOnFirstPreparedStatementCall(boolean p0); + void setEnclaveAttestationProtocol(String p0); + void setEnclaveAttestationUrl(String p0); + void setEncrypt(String p0); + void setEncrypt(boolean p0); + void setFIPS(boolean p0); + void setFailoverPartner(String p0); + void setGSSCredentials(GSSCredential p0); + void setHostNameInCertificate(String p0); + void setIPAddressPreference(String p0); + void setInstanceName(String p0); + void setIntegratedSecurity(boolean p0); + void setJAASConfigurationName(String p0); + void setJASSConfigurationName(String p0); + void setKeyStoreAuthentication(String p0); + void setKeyStoreLocation(String p0); + void setKeyStorePrincipalId(String p0); + void setKeyStoreSecret(String p0); + void setKeyVaultProviderClientId(String p0); + void setKeyVaultProviderClientKey(String p0); + void setLastUpdateCount(boolean p0); + void setLockTimeout(int p0); + void setMSIClientId(String p0); + void setMaxResultBuffer(String p0); + void setMsiTokenCacheTtl(int p0); + void setMultiSubnetFailover(boolean p0); + void setPacketSize(int p0); + void setPassword(String p0); + void setPortNumber(int p0); + void setPrepareMethod(String p0); + void setQueryTimeout(int p0); + void setRealm(String p0); + void setReplication(boolean p0); + void setResponseBuffering(String p0); + void setSSLProtocol(String p0); + void setSelectMethod(String p0); + void setSendStringParametersAsUnicode(boolean p0); + void setSendTemporalDataTypesAsStringForBulkCopy(boolean p0); + void setSendTimeAsDatetime(boolean p0); + void setServerCertificate(String p0); + void setServerName(String p0); + void setServerNameAsACE(boolean p0); + void setServerPreparedStatementDiscardThreshold(int p0); + void setServerSpn(String p0); + void setSocketFactoryClass(String p0); + void setSocketFactoryConstructorArg(String p0); + void setSocketTimeout(int p0); + void setStatementPoolingCacheSize(int p0); + void setTransparentNetworkIPResolution(boolean p0); + void setTrustManagerClass(String p0); + void setTrustManagerConstructorArg(String p0); + void setTrustServerCertificate(boolean p0); + void setTrustStore(String p0); + void setTrustStorePassword(String p0); + void setTrustStoreType(String p0); + void setURL(String p0); + void setUseBulkCopyForBatchInsert(boolean p0); + void setUseFmtOnly(boolean p0); + void setUser(String p0); + void setWorkstationID(String p0); + void setXopenStates(boolean p0); +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerAccessTokenCallback.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerAccessTokenCallback.java new file mode 100644 index 00000000000..50e38691e96 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerAccessTokenCallback.java @@ -0,0 +1,10 @@ +// Generated automatically from com.microsoft.sqlserver.jdbc.SQLServerAccessTokenCallback for testing purposes + +package com.microsoft.sqlserver.jdbc; + +import com.microsoft.sqlserver.jdbc.SqlAuthenticationToken; + +public interface SQLServerAccessTokenCallback +{ + SqlAuthenticationToken getAccessToken(String p0, String p1); +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java new file mode 100644 index 00000000000..03ba02d9ac0 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java @@ -0,0 +1,185 @@ +// Generated automatically from com.microsoft.sqlserver.jdbc.SQLServerDataSource for testing purposes + +package com.microsoft.sqlserver.jdbc; + +import com.microsoft.sqlserver.jdbc.ISQLServerDataSource; +import com.microsoft.sqlserver.jdbc.SQLServerAccessTokenCallback; +import java.io.PrintWriter; +import java.io.Serializable; +import java.sql.Connection; +import java.util.logging.Logger; +import javax.naming.Reference; +import javax.naming.Referenceable; +import javax.sql.DataSource; +import org.ietf.jgss.GSSCredential; + +public class SQLServerDataSource implements DataSource, ISQLServerDataSource, Referenceable, Serializable +{ + public T unwrap(Class p0){ return null; } + public Connection getConnection(){ return null; } + public Connection getConnection(String p0, String p1){ return null; } + public GSSCredential getGSSCredentials(){ return null; } + public Logger getParentLogger(){ return null; } + public PrintWriter getLogWriter(){ return null; } + public Reference getReference(){ return null; } + public SQLServerAccessTokenCallback getAccessTokenCallback(){ return null; } + public SQLServerDataSource(){} + public String getAADSecurePrincipalId(){ return null; } + public String getAccessToken(){ return null; } + public String getApplicationIntent(){ return null; } + public String getApplicationName(){ return null; } + public String getAuthentication(){ return null; } + public String getClientCertificate(){ return null; } + public String getClientKey(){ return null; } + public String getColumnEncryptionSetting(){ return null; } + public String getDatabaseName(){ return null; } + public String getDatetimeParameterType(){ return null; } + public String getDescription(){ return null; } + public String getDomain(){ return null; } + public String getEnclaveAttestationProtocol(){ return null; } + public String getEnclaveAttestationUrl(){ return null; } + public String getEncrypt(){ return null; } + public String getFailoverPartner(){ return null; } + public String getHostNameInCertificate(){ return null; } + public String getIPAddressPreference(){ return null; } + public String getInstanceName(){ return null; } + public String getJAASConfigurationName(){ return null; } + public String getJASSConfigurationName(){ return null; } + public String getKeyStoreAuthentication(){ return null; } + public String getKeyStoreLocation(){ return null; } + public String getKeyStorePrincipalId(){ return null; } + public String getKeyVaultProviderClientId(){ return null; } + public String getMSIClientId(){ return null; } + public String getMaxResultBuffer(){ return null; } + public String getPrepareMethod(){ return null; } + public String getRealm(){ return null; } + public String getResponseBuffering(){ return null; } + public String getSSLProtocol(){ return null; } + public String getSelectMethod(){ return null; } + public String getServerCertificate(){ return null; } + public String getServerName(){ return null; } + public String getServerSpn(){ return null; } + public String getSocketFactoryClass(){ return null; } + public String getSocketFactoryConstructorArg(){ return null; } + public String getTrustManagerClass(){ return null; } + public String getTrustManagerConstructorArg(){ return null; } + public String getTrustStore(){ return null; } + public String getTrustStoreType(){ return null; } + public String getURL(){ return null; } + public String getUser(){ return null; } + public String getWorkstationID(){ return null; } + public String toString(){ return null; } + public boolean getDelayLoadingLobs(){ return false; } + public boolean getDisableStatementPooling(){ return false; } + public boolean getEnablePrepareOnFirstPreparedStatementCall(){ return false; } + public boolean getFIPS(){ return false; } + public boolean getLastUpdateCount(){ return false; } + public boolean getMultiSubnetFailover(){ return false; } + public boolean getReplication(){ return false; } + public boolean getSendStringParametersAsUnicode(){ return false; } + public boolean getSendTemporalDataTypesAsStringForBulkCopy(){ return false; } + public boolean getSendTimeAsDatetime(){ return false; } + public boolean getServerNameAsACE(){ return false; } + public boolean getTransparentNetworkIPResolution(){ return false; } + public boolean getTrustServerCertificate(){ return false; } + public boolean getUseBulkCopyForBatchInsert(){ return false; } + public boolean getUseFmtOnly(){ return false; } + public boolean getXopenStates(){ return false; } + public boolean isWrapperFor(Class p0){ return false; } + public int getCancelQueryTimeout(){ return 0; } + public int getConnectRetryCount(){ return 0; } + public int getConnectRetryInterval(){ return 0; } + public int getLockTimeout(){ return 0; } + public int getLoginTimeout(){ return 0; } + public int getMsiTokenCacheTtl(){ return 0; } + public int getPacketSize(){ return 0; } + public int getPortNumber(){ return 0; } + public int getQueryTimeout(){ return 0; } + public int getServerPreparedStatementDiscardThreshold(){ return 0; } + public int getSocketTimeout(){ return 0; } + public int getStatementPoolingCacheSize(){ return 0; } + public void setAADSecurePrincipalId(String p0){} + public void setAADSecurePrincipalSecret(String p0){} + public void setAccessToken(String p0){} + public void setAccessTokenCallback(SQLServerAccessTokenCallback p0){} + public void setApplicationIntent(String p0){} + public void setApplicationName(String p0){} + public void setAuthentication(String p0){} + public void setAuthenticationScheme(String p0){} + public void setCancelQueryTimeout(int p0){} + public void setClientCertificate(String p0){} + public void setClientKey(String p0){} + public void setClientKeyPassword(String p0){} + public void setColumnEncryptionSetting(String p0){} + public void setConnectRetryCount(int p0){} + public void setConnectRetryInterval(int p0){} + public void setDatabaseName(String p0){} + public void setDatetimeParameterType(String p0){} + public void setDelayLoadingLobs(boolean p0){} + public void setDescription(String p0){} + public void setDisableStatementPooling(boolean p0){} + public void setDomain(String p0){} + public void setEnablePrepareOnFirstPreparedStatementCall(boolean p0){} + public void setEnclaveAttestationProtocol(String p0){} + public void setEnclaveAttestationUrl(String p0){} + public void setEncrypt(String p0){} + public void setEncrypt(boolean p0){} + public void setFIPS(boolean p0){} + public void setFailoverPartner(String p0){} + public void setGSSCredentials(GSSCredential p0){} + public void setHostNameInCertificate(String p0){} + public void setIPAddressPreference(String p0){} + public void setInstanceName(String p0){} + public void setIntegratedSecurity(boolean p0){} + public void setJAASConfigurationName(String p0){} + public void setJASSConfigurationName(String p0){} + public void setKeyStoreAuthentication(String p0){} + public void setKeyStoreLocation(String p0){} + public void setKeyStorePrincipalId(String p0){} + public void setKeyStoreSecret(String p0){} + public void setKeyVaultProviderClientId(String p0){} + public void setKeyVaultProviderClientKey(String p0){} + public void setLastUpdateCount(boolean p0){} + public void setLockTimeout(int p0){} + public void setLogWriter(PrintWriter p0){} + public void setLoginTimeout(int p0){} + public void setMSIClientId(String p0){} + public void setMaxResultBuffer(String p0){} + public void setMsiTokenCacheTtl(int p0){} + public void setMultiSubnetFailover(boolean p0){} + public void setPacketSize(int p0){} + public void setPassword(String p0){} + public void setPortNumber(int p0){} + public void setPrepareMethod(String p0){} + public void setQueryTimeout(int p0){} + public void setRealm(String p0){} + public void setReplication(boolean p0){} + public void setResponseBuffering(String p0){} + public void setSSLProtocol(String p0){} + public void setSelectMethod(String p0){} + public void setSendStringParametersAsUnicode(boolean p0){} + public void setSendTemporalDataTypesAsStringForBulkCopy(boolean p0){} + public void setSendTimeAsDatetime(boolean p0){} + public void setServerCertificate(String p0){} + public void setServerName(String p0){} + public void setServerNameAsACE(boolean p0){} + public void setServerPreparedStatementDiscardThreshold(int p0){} + public void setServerSpn(String p0){} + public void setSocketFactoryClass(String p0){} + public void setSocketFactoryConstructorArg(String p0){} + public void setSocketTimeout(int p0){} + public void setStatementPoolingCacheSize(int p0){} + public void setTransparentNetworkIPResolution(boolean p0){} + public void setTrustManagerClass(String p0){} + public void setTrustManagerConstructorArg(String p0){} + public void setTrustServerCertificate(boolean p0){} + public void setTrustStore(String p0){} + public void setTrustStorePassword(String p0){} + public void setTrustStoreType(String p0){} + public void setURL(String p0){} + public void setUseBulkCopyForBatchInsert(boolean p0){} + public void setUseFmtOnly(boolean p0){} + public void setUser(String p0){} + public void setWorkstationID(String p0){} + public void setXopenStates(boolean p0){} +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SqlAuthenticationToken.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SqlAuthenticationToken.java new file mode 100644 index 00000000000..454119f9225 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/com/microsoft/sqlserver/jdbc/SqlAuthenticationToken.java @@ -0,0 +1,16 @@ +// Generated automatically from com.microsoft.sqlserver.jdbc.SqlAuthenticationToken for testing purposes + +package com.microsoft.sqlserver.jdbc; + +import java.io.Serializable; +import java.util.Date; + +public class SqlAuthenticationToken implements Serializable +{ + protected SqlAuthenticationToken() {} + public Date getExpiresOn(){ return null; } + public SqlAuthenticationToken(String p0, Date p1){} + public SqlAuthenticationToken(String p0, long p1){} + public String getAccessToken(){ return null; } + public String toString(){ return null; } +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/SecretKey.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/SecretKey.java new file mode 100644 index 00000000000..88c9e4539ba --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/SecretKey.java @@ -0,0 +1,11 @@ +// Generated automatically from javax.crypto.SecretKey for testing purposes + +package javax.crypto; + +import java.security.Key; +import javax.security.auth.Destroyable; + +public interface SecretKey extends Destroyable, Key +{ + static long serialVersionUID = 0; +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/spec/SecretKeySpec.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/spec/SecretKeySpec.java new file mode 100644 index 00000000000..d90b6b2baca --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/crypto/spec/SecretKeySpec.java @@ -0,0 +1,18 @@ +// Generated automatically from javax.crypto.spec.SecretKeySpec for testing purposes + +package javax.crypto.spec; + +import java.security.spec.KeySpec; +import javax.crypto.SecretKey; + +public class SecretKeySpec implements KeySpec, SecretKey +{ + protected SecretKeySpec() {} + public SecretKeySpec(byte[] p0, String p1){} + public SecretKeySpec(byte[] p0, int p1, int p2, String p3){} + public String getAlgorithm(){ return null; } + public String getFormat(){ return null; } + public boolean equals(Object p0){ return false; } + public byte[] getEncoded(){ return null; } + public int hashCode(){ return 0; } +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/RefAddr.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/RefAddr.java new file mode 100644 index 00000000000..77d0a07406a --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/RefAddr.java @@ -0,0 +1,17 @@ +// Generated automatically from javax.naming.RefAddr for testing purposes + +package javax.naming; + +import java.io.Serializable; + +abstract public class RefAddr implements Serializable +{ + protected RefAddr() {} + protected RefAddr(String p0){} + protected String addrType = null; + public String getType(){ return null; } + public String toString(){ return null; } + public abstract Object getContent(); + public boolean equals(Object p0){ return false; } + public int hashCode(){ return 0; } +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Reference.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Reference.java new file mode 100644 index 00000000000..5dbfa520ead --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Reference.java @@ -0,0 +1,36 @@ +// Generated automatically from javax.naming.Reference for testing purposes + +package javax.naming; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Vector; +import javax.naming.RefAddr; + +public class Reference implements Cloneable, Serializable +{ + protected Reference() {} + protected String classFactory = null; + protected String classFactoryLocation = null; + protected String className = null; + protected Vector addrs = null; + public Enumeration getAll(){ return null; } + public Object clone(){ return null; } + public Object remove(int p0){ return null; } + public RefAddr get(String p0){ return null; } + public RefAddr get(int p0){ return null; } + public Reference(String p0){} + public Reference(String p0, RefAddr p1){} + public Reference(String p0, RefAddr p1, String p2, String p3){} + public Reference(String p0, String p1, String p2){} + public String getClassName(){ return null; } + public String getFactoryClassLocation(){ return null; } + public String getFactoryClassName(){ return null; } + public String toString(){ return null; } + public boolean equals(Object p0){ return false; } + public int hashCode(){ return 0; } + public int size(){ return 0; } + public void add(RefAddr p0){} + public void add(int p0, RefAddr p1){} + public void clear(){} +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Referenceable.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Referenceable.java new file mode 100644 index 00000000000..d3cc3ca087d --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/naming/Referenceable.java @@ -0,0 +1,10 @@ +// Generated automatically from javax.naming.Referenceable for testing purposes + +package javax.naming; + +import javax.naming.Reference; + +public interface Referenceable +{ + Reference getReference(); +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/security/auth/Destroyable.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/security/auth/Destroyable.java new file mode 100644 index 00000000000..979ca409ba6 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/security/auth/Destroyable.java @@ -0,0 +1,10 @@ +// Generated automatically from javax.security.auth.Destroyable for testing purposes + +package javax.security.auth; + + +public interface Destroyable +{ + default boolean isDestroyed(){ return false; } + default void destroy(){} +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/CommonDataSource.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/CommonDataSource.java new file mode 100644 index 00000000000..cdc814157ce --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/CommonDataSource.java @@ -0,0 +1,17 @@ +// Generated automatically from javax.sql.CommonDataSource for testing purposes + +package javax.sql; + +import java.io.PrintWriter; +import java.sql.ShardingKeyBuilder; +import java.util.logging.Logger; + +public interface CommonDataSource +{ + Logger getParentLogger(); + PrintWriter getLogWriter(); + default ShardingKeyBuilder createShardingKeyBuilder(){ return null; } + int getLoginTimeout(); + void setLogWriter(PrintWriter p0); + void setLoginTimeout(int p0); +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/DataSource.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/DataSource.java new file mode 100644 index 00000000000..d28d63d6e0a --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/javax/sql/DataSource.java @@ -0,0 +1,20 @@ +// Generated automatically from javax.sql.DataSource for testing purposes + +package javax.sql; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.ConnectionBuilder; +import java.sql.Wrapper; +import javax.sql.CommonDataSource; + +public interface DataSource extends CommonDataSource, Wrapper +{ + Connection getConnection(); + Connection getConnection(String p0, String p1); + PrintWriter getLogWriter(); + default ConnectionBuilder createConnectionBuilder(){ return null; } + int getLoginTimeout(); + void setLogWriter(PrintWriter p0); + void setLoginTimeout(int p0); +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSCredential.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSCredential.java new file mode 100644 index 00000000000..120a67f30c7 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSCredential.java @@ -0,0 +1,27 @@ +// Generated automatically from org.ietf.jgss.GSSCredential for testing purposes + +package org.ietf.jgss; + +import org.ietf.jgss.GSSName; +import org.ietf.jgss.Oid; + +public interface GSSCredential extends Cloneable +{ + GSSName getName(); + GSSName getName(Oid p0); + Oid[] getMechs(); + boolean equals(Object p0); + int getRemainingAcceptLifetime(Oid p0); + int getRemainingInitLifetime(Oid p0); + int getRemainingLifetime(); + int getUsage(); + int getUsage(Oid p0); + int hashCode(); + static int ACCEPT_ONLY = 0; + static int DEFAULT_LIFETIME = 0; + static int INDEFINITE_LIFETIME = 0; + static int INITIATE_AND_ACCEPT = 0; + static int INITIATE_ONLY = 0; + void add(GSSName p0, int p1, int p2, Oid p3, int p4); + void dispose(); +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSName.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSName.java new file mode 100644 index 00000000000..3ca10408640 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/GSSName.java @@ -0,0 +1,24 @@ +// Generated automatically from org.ietf.jgss.GSSName for testing purposes + +package org.ietf.jgss; + +import org.ietf.jgss.Oid; + +public interface GSSName +{ + GSSName canonicalize(Oid p0); + Oid getStringNameType(); + String toString(); + boolean equals(GSSName p0); + boolean equals(Object p0); + boolean isAnonymous(); + boolean isMN(); + byte[] export(); + int hashCode(); + static Oid NT_ANONYMOUS = null; + static Oid NT_EXPORT_NAME = null; + static Oid NT_HOSTBASED_SERVICE = null; + static Oid NT_MACHINE_UID_NAME = null; + static Oid NT_STRING_UID_NAME = null; + static Oid NT_USER_NAME = null; +} diff --git a/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/Oid.java b/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/Oid.java new file mode 100644 index 00000000000..151f60ed841 --- /dev/null +++ b/java/ql/test/stubs/mssql-jdbc-12.2.0/org/ietf/jgss/Oid.java @@ -0,0 +1,18 @@ +// Generated automatically from org.ietf.jgss.Oid for testing purposes + +package org.ietf.jgss; + +import java.io.InputStream; + +public class Oid +{ + protected Oid() {} + public Oid(InputStream p0){} + public Oid(String p0){} + public Oid(byte[] p0){} + public String toString(){ return null; } + public boolean containedIn(Oid[] p0){ return false; } + public boolean equals(Object p0){ return false; } + public byte[] getDER(){ return null; } + public int hashCode(){ return 0; } +} From 8e079320f3614371d40d261ecf10dd2ab8b3bb4c Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Tue, 14 Feb 2023 09:51:01 +0100 Subject: [PATCH 216/415] Swift: some restructuring of codegen Loading of the schema and dbscheme has been moved to a separate `loaders` package for better separation of concerns. --- swift/codegen/generators/BUILD.bazel | 2 +- swift/codegen/generators/cppgen.py | 3 +- swift/codegen/generators/dbschemegen.py | 4 +- swift/codegen/generators/qlgen.py | 3 +- swift/codegen/generators/trapgen.py | 3 +- swift/codegen/lib/BUILD.bazel | 3 +- swift/codegen/lib/dbscheme.py | 51 ------ swift/codegen/lib/{schema => }/schema.py | 130 +-------------- swift/codegen/lib/schema/__init__.py | 1 - .../lib/{schema/defs.py => schemadefs.py} | 0 swift/codegen/loaders/BUILD.bazel | 11 ++ swift/codegen/loaders/dbschemeloader.py | 54 +++++++ swift/codegen/loaders/schemaloader.py | 133 ++++++++++++++++ swift/codegen/schemadefs.py/defs.py | 149 ++++++++++++++++++ swift/codegen/test/test_dbscheme.py | 114 -------------- swift/codegen/test/test_dbschemelaoder.py | 123 +++++++++++++++ .../{test_schema.py => test_schemaloader.py} | 93 +++++------ swift/codegen/test/utils.py | 4 +- swift/schema.py | 2 +- 19 files changed, 531 insertions(+), 352 deletions(-) rename swift/codegen/lib/{schema => }/schema.py (53%) delete mode 100644 swift/codegen/lib/schema/__init__.py rename swift/codegen/lib/{schema/defs.py => schemadefs.py} (100%) create mode 100644 swift/codegen/loaders/BUILD.bazel create mode 100644 swift/codegen/loaders/dbschemeloader.py create mode 100644 swift/codegen/loaders/schemaloader.py create mode 100644 swift/codegen/schemadefs.py/defs.py create mode 100644 swift/codegen/test/test_dbschemelaoder.py rename swift/codegen/test/{test_schema.py => test_schemaloader.py} (94%) diff --git a/swift/codegen/generators/BUILD.bazel b/swift/codegen/generators/BUILD.bazel index 94285e24015..dbcf529037c 100644 --- a/swift/codegen/generators/BUILD.bazel +++ b/swift/codegen/generators/BUILD.bazel @@ -6,6 +6,6 @@ py_library( visibility = ["//swift/codegen:__subpackages__"], deps = [ "//swift/codegen/lib", - requirement("toposort"), + "//swift/codegen/loaders", ], ) diff --git a/swift/codegen/generators/cppgen.py b/swift/codegen/generators/cppgen.py index 16f997efacb..82f41bdc3a5 100644 --- a/swift/codegen/generators/cppgen.py +++ b/swift/codegen/generators/cppgen.py @@ -17,6 +17,7 @@ import typing import inflection from swift.codegen.lib import cpp, schema +from swift.codegen.loaders import schemaloader def _get_type(t: str, add_or_none_except: typing.Optional[str] = None) -> str: @@ -90,7 +91,7 @@ class Processor: def generate(opts, renderer): assert opts.cpp_output - processor = Processor(schema.load_file(opts.schema)) + processor = Processor(schemaloader.load_file(opts.schema)) out = opts.cpp_output for dir, classes in processor.get_classes().items(): renderer.render(cpp.ClassList(classes, opts.schema, diff --git a/swift/codegen/generators/dbschemegen.py b/swift/codegen/generators/dbschemegen.py index 58cb40a3335..fe7681b3b47 100755 --- a/swift/codegen/generators/dbschemegen.py +++ b/swift/codegen/generators/dbschemegen.py @@ -18,8 +18,8 @@ import typing import inflection from swift.codegen.lib import schema +from swift.codegen.loaders import schemaloader from swift.codegen.lib.dbscheme import * -from typing import Set, List log = logging.getLogger(__name__) @@ -123,7 +123,7 @@ def generate(opts, renderer): input = opts.schema out = opts.dbscheme - data = schema.load_file(input) + data = schemaloader.load_file(input) dbscheme = Scheme(src=input.relative_to(opts.swift_dir), includes=get_includes(data, include_dir=input.parent, swift_dir=opts.swift_dir), diff --git a/swift/codegen/generators/qlgen.py b/swift/codegen/generators/qlgen.py index 1d86518696a..d7a6436a0a1 100755 --- a/swift/codegen/generators/qlgen.py +++ b/swift/codegen/generators/qlgen.py @@ -30,6 +30,7 @@ import itertools import inflection from swift.codegen.lib import schema, ql +from swift.codegen.loaders import schemaloader log = logging.getLogger(__name__) @@ -297,7 +298,7 @@ def generate(opts, renderer): stubs = {q for q in stub_out.rglob("*.qll")} - data = schema.load_file(input) + data = schemaloader.load_file(input) classes = {name: get_ql_class(cls) for name, cls in data.classes.items()} if not classes: diff --git a/swift/codegen/generators/trapgen.py b/swift/codegen/generators/trapgen.py index f01203e9272..87ee104a972 100755 --- a/swift/codegen/generators/trapgen.py +++ b/swift/codegen/generators/trapgen.py @@ -18,6 +18,7 @@ import inflection from toposort import toposort_flatten from swift.codegen.lib import dbscheme, cpp +from swift.codegen.loaders import dbschemeloader log = logging.getLogger(__name__) @@ -73,7 +74,7 @@ def generate(opts, renderer): out = opts.cpp_output traps = {pathlib.Path(): []} - for e in dbscheme.iterload(opts.dbscheme): + for e in dbschemeloader.iterload(opts.dbscheme): if e.is_table: traps.setdefault(e.dir, []).append(get_trap(e)) elif e.is_union: diff --git a/swift/codegen/lib/BUILD.bazel b/swift/codegen/lib/BUILD.bazel index 6298b6d195e..fd2607448b4 100644 --- a/swift/codegen/lib/BUILD.bazel +++ b/swift/codegen/lib/BUILD.bazel @@ -2,11 +2,10 @@ load("@swift_codegen_deps//:requirements.bzl", "requirement") py_library( name = "lib", - srcs = glob(["**/*.py"]), + srcs = glob(["*.py"]), visibility = ["//swift/codegen:__subpackages__"], deps = [ requirement("pystache"), - requirement("pyyaml"), requirement("inflection"), ], ) diff --git a/swift/codegen/lib/dbscheme.py b/swift/codegen/lib/dbscheme.py index 4883b0deaf5..eee0191b678 100644 --- a/swift/codegen/lib/dbscheme.py +++ b/swift/codegen/lib/dbscheme.py @@ -105,54 +105,3 @@ class Scheme: src: str includes: List[SchemeInclude] declarations: List[Decl] - - -class Re: - entity = re.compile( - "(?m)" - r"(?:^#keyset\[(?P[\w\s,]+)\][\s\n]*)?^(?P\w+)\(" - r"(?:\s*//dir=(?P\S*))?(?P[^\)]*)" - r"\);?" - "|" - r"^(?P@\w+)\s*=\s*(?P@\w+(?:\s*\|\s*@\w+)*)\s*;?" - ) - field = re.compile(r"(?m)[\w\s]*\s(?P\w+)\s*:\s*(?P@?\w+)(?P\s+ref)?") - key = re.compile(r"@\w+") - comment = re.compile(r"(?m)(?s)/\*.*?\*/|//(?!dir=)[^\n]*$") # lookahead avoid ignoring metadata like //dir=foo - - -def get_column(match): - return Column( - schema_name=match["field"].rstrip("_"), - type=match["type"], - binding=not match["ref"], - ) - - -def get_table(match): - keyset = None - if match["tablekeys"]: - keyset = KeySet(k.strip() for k in match["tablekeys"].split(",")) - return Table( - name=match["table"], - columns=[get_column(f) for f in Re.field.finditer(match["tablebody"])], - keyset=keyset, - dir=pathlib.PosixPath(match["tabledir"]) if match["tabledir"] else None, - ) - - -def get_union(match): - return Union( - lhs=match["union"], - rhs=(d[0] for d in Re.key.finditer(match["unionbody"])), - ) - - -def iterload(file): - with open(file) as file: - data = Re.comment.sub("", file.read()) - for e in Re.entity.finditer(data): - if e["table"]: - yield get_table(e) - elif e["union"]: - yield get_union(e) diff --git a/swift/codegen/lib/schema/schema.py b/swift/codegen/lib/schema.py similarity index 53% rename from swift/codegen/lib/schema/schema.py rename to swift/codegen/lib/schema.py index a2a1de0c05a..5e2974ae87d 100644 --- a/swift/codegen/lib/schema/schema.py +++ b/swift/codegen/lib/schema.py @@ -1,15 +1,9 @@ -""" schema.yml format representation """ -import pathlib -import re -import types +""" schema format representation """ import typing from dataclasses import dataclass, field from typing import List, Set, Union, Dict, Optional from enum import Enum, auto import functools -import importlib.util -from toposort import toposort_flatten -import inflection class Error(Exception): @@ -198,125 +192,3 @@ def split_doc(doc): while trimmed and not trimmed[0]: trimmed.pop(0) return trimmed - - -@dataclass -class _PropertyNamer(PropertyModifier): - name: str - - def modify(self, prop: Property): - prop.name = self.name.rstrip("_") - - -def _get_class(cls: type) -> Class: - if not isinstance(cls, type): - raise Error(f"Only class definitions allowed in schema, found {cls}") - # we must check that going to dbscheme names and back is preserved - # In particular this will not happen if uppercase acronyms are included in the name - to_underscore_and_back = inflection.camelize(inflection.underscore(cls.__name__), uppercase_first_letter=True) - if cls.__name__ != to_underscore_and_back: - raise Error(f"Class name must be upper camel-case, without capitalized acronyms, found {cls.__name__} " - f"instead of {to_underscore_and_back}") - if len({b._group for b in cls.__bases__ if hasattr(b, "_group")}) > 1: - raise Error(f"Bases with mixed groups for {cls.__name__}") - if any(getattr(b, "_null", False) for b in cls.__bases__): - raise Error(f"Null class cannot be derived") - return Class(name=cls.__name__, - bases=[b.__name__ for b in cls.__bases__ if b is not object], - derived={d.__name__ for d in cls.__subclasses__()}, - # getattr to inherit from bases - group=getattr(cls, "_group", ""), - # in the following we don't use `getattr` to avoid inheriting - pragmas=cls.__dict__.get("_pragmas", []), - ipa=cls.__dict__.get("_ipa", None), - properties=[ - a | _PropertyNamer(n) - for n, a in cls.__dict__.get("__annotations__", {}).items() - ], - doc=split_doc(cls.__doc__), - default_doc_name=cls.__dict__.get("_doc_name"), - ) - - -def _toposort_classes_by_group(classes: typing.Dict[str, Class]) -> typing.Dict[str, Class]: - groups = {} - ret = {} - - for name, cls in classes.items(): - groups.setdefault(cls.group, []).append(name) - - for group, grouped in sorted(groups.items()): - inheritance = {name: classes[name].bases for name in grouped} - for name in toposort_flatten(inheritance): - ret[name] = classes[name] - - return ret - - -def _fill_ipa_information(classes: typing.Dict[str, Class]): - """ Take a dictionary where the `ipa` field is filled for all explicitly synthesized classes - and update it so that all non-final classes that have only synthesized final descendants - get `True` as` value for the `ipa` field - """ - if not classes: - return - - is_ipa: typing.Dict[str, bool] = {} - - def fill_is_ipa(name: str): - if name not in is_ipa: - cls = classes[name] - for d in cls.derived: - fill_is_ipa(d) - if cls.ipa is not None: - is_ipa[name] = True - elif not cls.derived: - is_ipa[name] = False - else: - is_ipa[name] = all(is_ipa[d] for d in cls.derived) - - root = next(iter(classes)) - fill_is_ipa(root) - - for name, cls in classes.items(): - if cls.ipa is None and is_ipa[name]: - cls.ipa = True - - -def load(m: types.ModuleType) -> Schema: - includes = set() - classes = {} - known = {"int", "string", "boolean"} - known.update(n for n in m.__dict__ if not n.startswith("__")) - import swift.codegen.lib.schema.defs as defs - null = None - for name, data in m.__dict__.items(): - if hasattr(defs, name): - continue - if name == "__includes": - includes = set(data) - continue - if name.startswith("__"): - continue - cls = _get_class(data) - if classes and not cls.bases: - raise Error( - f"Only one root class allowed, found second root {name}") - cls.check_types(known) - classes[name] = cls - if getattr(data, "_null", False): - if null is not None: - raise Error(f"Null class {null} already defined, second null class {name} not allowed") - null = name - cls.is_null_class = True - - _fill_ipa_information(classes) - - return Schema(includes=includes, classes=_toposort_classes_by_group(classes), null=null) - - -def load_file(path: pathlib.Path) -> Schema: - spec = importlib.util.spec_from_file_location("schema", path) - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return load(module) diff --git a/swift/codegen/lib/schema/__init__.py b/swift/codegen/lib/schema/__init__.py deleted file mode 100644 index 23e80ae8195..00000000000 --- a/swift/codegen/lib/schema/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .schema import * diff --git a/swift/codegen/lib/schema/defs.py b/swift/codegen/lib/schemadefs.py similarity index 100% rename from swift/codegen/lib/schema/defs.py rename to swift/codegen/lib/schemadefs.py diff --git a/swift/codegen/loaders/BUILD.bazel b/swift/codegen/loaders/BUILD.bazel new file mode 100644 index 00000000000..de1d8dfe5db --- /dev/null +++ b/swift/codegen/loaders/BUILD.bazel @@ -0,0 +1,11 @@ +load("@swift_codegen_deps//:requirements.bzl", "requirement") + +py_library( + name = "loaders", + srcs = glob(["*.py"]), + visibility = ["//swift/codegen:__subpackages__"], + deps = [ + requirement("toposort"), + requirement("inflection"), + ], +) diff --git a/swift/codegen/loaders/dbschemeloader.py b/swift/codegen/loaders/dbschemeloader.py new file mode 100644 index 00000000000..eda299c77b1 --- /dev/null +++ b/swift/codegen/loaders/dbschemeloader.py @@ -0,0 +1,54 @@ +import pathlib +import re +from swift.codegen.lib import dbscheme + + +class _Re: + entity = re.compile( + "(?m)" + r"(?:^#keyset\[(?P[\w\s,]+)\][\s\n]*)?^(?P
    \w+)\(" + r"(?:\s*//dir=(?P\S*))?(?P[^\)]*)" + r"\);?" + "|" + r"^(?P@\w+)\s*=\s*(?P@\w+(?:\s*\|\s*@\w+)*)\s*;?" + ) + field = re.compile(r"(?m)[\w\s]*\s(?P\w+)\s*:\s*(?P@?\w+)(?P\s+ref)?") + key = re.compile(r"@\w+") + comment = re.compile(r"(?m)(?s)/\*.*?\*/|//(?!dir=)[^\n]*$") # lookahead avoid ignoring metadata like //dir=foo + + +def _get_column(match): + return dbscheme.Column( + schema_name=match["field"].rstrip("_"), + type=match["type"], + binding=not match["ref"], + ) + + +def _get_table(match): + keyset = None + if match["tablekeys"]: + keyset = dbscheme.KeySet(k.strip() for k in match["tablekeys"].split(",")) + return dbscheme.Table( + name=match["table"], + columns=[_get_column(f) for f in _Re.field.finditer(match["tablebody"])], + keyset=keyset, + dir=pathlib.PosixPath(match["tabledir"]) if match["tabledir"] else None, + ) + + +def _get_union(match): + return dbscheme.Union( + lhs=match["union"], + rhs=(d[0] for d in _Re.key.finditer(match["unionbody"])), + ) + + +def iterload(file): + with open(file) as file: + data = _Re.comment.sub("", file.read()) + for e in _Re.entity.finditer(data): + if e["table"]: + yield _get_table(e) + elif e["union"]: + yield _get_union(e) diff --git a/swift/codegen/loaders/schemaloader.py b/swift/codegen/loaders/schemaloader.py new file mode 100644 index 00000000000..a8531b5ecd3 --- /dev/null +++ b/swift/codegen/loaders/schemaloader.py @@ -0,0 +1,133 @@ +""" schema loader """ + +import inflection +import typing +import types +import pathlib +import importlib +from dataclasses import dataclass +from toposort import toposort_flatten + +from swift.codegen.lib import schema, schemadefs + + +@dataclass +class _PropertyNamer(schema.PropertyModifier): + name: str + + def modify(self, prop: schema.Property): + prop.name = self.name.rstrip("_") + + +def _get_class(cls: type) -> schema.Class: + if not isinstance(cls, type): + raise schema.Error(f"Only class definitions allowed in schema, found {cls}") + # we must check that going to dbscheme names and back is preserved + # In particular this will not happen if uppercase acronyms are included in the name + to_underscore_and_back = inflection.camelize(inflection.underscore(cls.__name__), uppercase_first_letter=True) + if cls.__name__ != to_underscore_and_back: + raise schema.Error(f"Class name must be upper camel-case, without capitalized acronyms, found {cls.__name__} " + f"instead of {to_underscore_and_back}") + if len({b._group for b in cls.__bases__ if hasattr(b, "_group")}) > 1: + raise schema.Error(f"Bases with mixed groups for {cls.__name__}") + if any(getattr(b, "_null", False) for b in cls.__bases__): + raise schema.Error(f"Null class cannot be derived") + return schema.Class(name=cls.__name__, + bases=[b.__name__ for b in cls.__bases__ if b is not object], + derived={d.__name__ for d in cls.__subclasses__()}, + # getattr to inherit from bases + group=getattr(cls, "_group", ""), + # in the following we don't use `getattr` to avoid inheriting + pragmas=cls.__dict__.get("_pragmas", []), + ipa=cls.__dict__.get("_ipa", None), + properties=[ + a | _PropertyNamer(n) + for n, a in cls.__dict__.get("__annotations__", {}).items() + ], + doc=schema.split_doc(cls.__doc__), + default_doc_name=cls.__dict__.get("_doc_name"), + ) + + +def _toposort_classes_by_group(classes: typing.Dict[str, schema.Class]) -> typing.Dict[str, schema.Class]: + groups = {} + ret = {} + + for name, cls in classes.items(): + groups.setdefault(cls.group, []).append(name) + + for group, grouped in sorted(groups.items()): + inheritance = {name: classes[name].bases for name in grouped} + for name in toposort_flatten(inheritance): + ret[name] = classes[name] + + return ret + + +def _fill_ipa_information(classes: typing.Dict[str, schema.Class]): + """ Take a dictionary where the `ipa` field is filled for all explicitly synthesized classes + and update it so that all non-final classes that have only synthesized final descendants + get `True` as` value for the `ipa` field + """ + if not classes: + return + + is_ipa: typing.Dict[str, bool] = {} + + def fill_is_ipa(name: str): + if name not in is_ipa: + cls = classes[name] + for d in cls.derived: + fill_is_ipa(d) + if cls.ipa is not None: + is_ipa[name] = True + elif not cls.derived: + is_ipa[name] = False + else: + is_ipa[name] = all(is_ipa[d] for d in cls.derived) + + root = next(iter(classes)) + fill_is_ipa(root) + + for name, cls in classes.items(): + if cls.ipa is None and is_ipa[name]: + cls.ipa = True + + +def load(m: types.ModuleType) -> schema.Schema: + includes = set() + classes = {} + known = {"int", "string", "boolean"} + known.update(n for n in m.__dict__ if not n.startswith("__")) + import swift.codegen.lib.schemadefs as defs + null = None + for name, data in m.__dict__.items(): + if hasattr(defs, name): + continue + if name == "__includes": + includes = set(data) + continue + if name.startswith("__"): + continue + cls = _get_class(data) + if classes and not cls.bases: + raise schema.Error( + f"Only one root class allowed, found second root {name}") + cls.check_types(known) + classes[name] = cls + if getattr(data, "_null", False): + if null is not None: + raise schema.Error(f"Null class {null} already defined, second null class {name} not allowed") + null = name + cls.is_null_class = True + + _fill_ipa_information(classes) + + return schema.Schema(includes=includes, classes=_toposort_classes_by_group(classes), null=null) + + +def load_file(path: pathlib.Path) -> schema.Schema: + spec = importlib.util.spec_from_file_location("schema", path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return load(module) diff --git a/swift/codegen/schemadefs.py/defs.py b/swift/codegen/schemadefs.py/defs.py new file mode 100644 index 00000000000..d972e5a63e5 --- /dev/null +++ b/swift/codegen/schemadefs.py/defs.py @@ -0,0 +1,149 @@ +from typing import Callable as _Callable +from swift.codegen.lib import schema as _schema +import inspect as _inspect +from dataclasses import dataclass as _dataclass + + +class _ChildModifier(_schema.PropertyModifier): + def modify(self, prop: _schema.Property): + if prop.type is None or prop.type[0].islower(): + raise _schema.Error("Non-class properties cannot be children") + prop.is_child = True + + +@_dataclass +class _DocModifier(_schema.PropertyModifier): + doc: str + + def modify(self, prop: _schema.Property): + if "\n" in self.doc or self.doc[-1] == ".": + raise _schema.Error("No newlines or trailing dots are allowed in doc, did you intend to use desc?") + prop.doc = self.doc + + +@_dataclass +class _DescModifier(_schema.PropertyModifier): + description: str + + def modify(self, prop: _schema.Property): + prop.description = _schema.split_doc(self.description) + + +def include(source: str): + # add to `includes` variable in calling context + _inspect.currentframe().f_back.f_locals.setdefault( + "__includes", []).append(source) + + +class _Namespace: + """ simple namespacing mechanism """ + + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + +qltest = _Namespace() +ql = _Namespace() +cpp = _Namespace() +synth = _Namespace() + + +@_dataclass +class _Pragma(_schema.PropertyModifier): + """ A class or property pragma. + For properties, it functions similarly to a `_PropertyModifier` with `|`, adding the pragma. + For schema classes it acts as a python decorator with `@`. + """ + pragma: str + + def __post_init__(self): + namespace, _, name = self.pragma.partition('_') + setattr(globals()[namespace], name, self) + + def modify(self, prop: _schema.Property): + prop.pragmas.append(self.pragma) + + def __call__(self, cls: type) -> type: + """ use this pragma as a decorator on classes """ + if "_pragmas" in cls.__dict__: # not using hasattr as we don't want to land on inherited pragmas + cls._pragmas.append(self.pragma) + else: + cls._pragmas = [self.pragma] + return cls + + +class _Optionalizer(_schema.PropertyModifier): + def modify(self, prop: _schema.Property): + K = _schema.Property.Kind + if prop.kind != K.SINGLE: + raise _schema.Error( + "Optional should only be applied to simple property types") + prop.kind = K.OPTIONAL + + +class _Listifier(_schema.PropertyModifier): + def modify(self, prop: _schema.Property): + K = _schema.Property.Kind + if prop.kind == K.SINGLE: + prop.kind = K.REPEATED + elif prop.kind == K.OPTIONAL: + prop.kind = K.REPEATED_OPTIONAL + else: + raise _schema.Error( + "Repeated should only be applied to simple or optional property types") + + +class _TypeModifier: + """ Modifies types using get item notation """ + + def __init__(self, modifier: _schema.PropertyModifier): + self.modifier = modifier + + def __getitem__(self, item): + return item | self.modifier + + +_ClassDecorator = _Callable[[type], type] + + +def _annotate(**kwargs) -> _ClassDecorator: + def f(cls: type) -> type: + for k, v in kwargs.items(): + setattr(cls, f"_{k}", v) + return cls + + return f + + +boolean = "boolean" +int = "int" +string = "string" + +predicate = _schema.predicate_marker +optional = _TypeModifier(_Optionalizer()) +list = _TypeModifier(_Listifier()) + +child = _ChildModifier() +doc = _DocModifier +desc = _DescModifier + +use_for_null = _annotate(null=True) + +_Pragma("qltest_skip") +_Pragma("qltest_collapse_hierarchy") +_Pragma("qltest_uncollapse_hierarchy") + +ql.default_doc_name = lambda doc: _annotate(doc_name=doc) +_Pragma("ql_internal") + +_Pragma("cpp_skip") + + +def group(name: str = "") -> _ClassDecorator: + return _annotate(group=name) + + +synth.from_class = lambda ref: _annotate(ipa=_schema.IpaInfo( + from_class=_schema.get_type_name(ref))) +synth.on_arguments = lambda **kwargs: _annotate( + ipa=_schema.IpaInfo(on_arguments={k: _schema.get_type_name(t) for k, t in kwargs.items()})) diff --git a/swift/codegen/test/test_dbscheme.py b/swift/codegen/test/test_dbscheme.py index 9d9184ea954..a520cc2b66b 100644 --- a/swift/codegen/test/test_dbscheme.py +++ b/swift/codegen/test/test_dbscheme.py @@ -48,119 +48,5 @@ def test_union_has_first_case_marked(): assert [c.type for c in u.rhs] == rhs -# load tests -@pytest.fixture -def load(tmp_path): - file = tmp_path / "test.dbscheme" - - def ret(yml): - write(file, yml) - return list(dbscheme.iterload(file)) - - return ret - - -def test_load_empty(load): - assert load("") == [] - - -def test_load_one_empty_table(load): - assert load(""" -test_foos(); -""") == [ - dbscheme.Table(name="test_foos", columns=[]) - ] - - -def test_load_table_with_keyset(load): - assert load(""" -#keyset[x, y,z] -test_foos(); -""") == [ - dbscheme.Table(name="test_foos", columns=[], keyset=dbscheme.KeySet(["x", "y", "z"])) - ] - - -expected_columns = [ - ("int foo: int ref", dbscheme.Column(schema_name="foo", type="int", binding=False)), - (" int bar : int ref", dbscheme.Column(schema_name="bar", type="int", binding=False)), - ("str baz_: str ref", dbscheme.Column(schema_name="baz", type="str", binding=False)), - ("int x: @foo ref", dbscheme.Column(schema_name="x", type="@foo", binding=False)), - ("int y: @foo", dbscheme.Column(schema_name="y", type="@foo", binding=True)), - ("unique int z: @foo", dbscheme.Column(schema_name="z", type="@foo", binding=True)), -] - - -@pytest.mark.parametrize("column,expected", expected_columns) -def test_load_table_with_column(load, column, expected): - assert load(f""" -foos( - {column} -); -""") == [ - dbscheme.Table(name="foos", columns=[deepcopy(expected)]) - ] - - -def test_load_table_with_multiple_columns(load): - columns = ",\n".join(c for c, _ in expected_columns) - expected = [deepcopy(e) for _, e in expected_columns] - assert load(f""" -foos( -{columns} -); -""") == [ - dbscheme.Table(name="foos", columns=expected) - ] - - -def test_load_table_with_multiple_columns_and_dir(load): - columns = ",\n".join(c for c, _ in expected_columns) - expected = [deepcopy(e) for _, e in expected_columns] - assert load(f""" -foos( //dir=foo/bar/baz -{columns} -); -""") == [ - dbscheme.Table(name="foos", columns=expected, dir=pathlib.Path("foo/bar/baz")) - ] - - -def test_load_multiple_table_with_columns(load): - tables = [f"table{i}({col});" for i, (col, _) in enumerate(expected_columns)] - expected = [dbscheme.Table(name=f"table{i}", columns=[deepcopy(e)]) for i, (_, e) in enumerate(expected_columns)] - assert load("\n".join(tables)) == expected - - -def test_union(load): - assert load("@foo = @bar | @baz | @bla;") == [ - dbscheme.Union(lhs="@foo", rhs=["@bar", "@baz", "@bla"]), - ] - - -def test_table_and_union(load): - assert load(""" -foos(); - -@foo = @bar | @baz | @bla;""") == [ - dbscheme.Table(name="foos", columns=[]), - dbscheme.Union(lhs="@foo", rhs=["@bar", "@baz", "@bla"]), - ] - - -def test_comments_ignored(load): - assert load(""" -// fake_table(); -foos(/* x */unique /*y*/int/* -z -*/ id/* */: /* * */ @bar/*, -int ignored: int ref*/); - -@foo = @bar | @baz | @bla; // | @xxx""") == [ - dbscheme.Table(name="foos", columns=[dbscheme.Column(schema_name="id", type="@bar", binding=True)]), - dbscheme.Union(lhs="@foo", rhs=["@bar", "@baz", "@bla"]), - ] - - if __name__ == '__main__': sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_dbschemelaoder.py b/swift/codegen/test/test_dbschemelaoder.py new file mode 100644 index 00000000000..6212b860cbb --- /dev/null +++ b/swift/codegen/test/test_dbschemelaoder.py @@ -0,0 +1,123 @@ +import sys +from copy import deepcopy + +from swift.codegen.lib import dbscheme +from swift.codegen.loaders.dbschemeloader import iterload +from swift.codegen.test.utils import * + + +@pytest.fixture +def load(tmp_path): + file = tmp_path / "test.dbscheme" + + def ret(yml): + write(file, yml) + return list(iterload(file)) + + return ret + + +def test_load_empty(load): + assert load("") == [] + + +def test_load_one_empty_table(load): + assert load(""" +test_foos(); +""") == [ + dbscheme.Table(name="test_foos", columns=[]) + ] + + +def test_load_table_with_keyset(load): + assert load(""" +#keyset[x, y,z] +test_foos(); +""") == [ + dbscheme.Table(name="test_foos", columns=[], keyset=dbscheme.KeySet(["x", "y", "z"])) + ] + + +expected_columns = [ + ("int foo: int ref", dbscheme.Column(schema_name="foo", type="int", binding=False)), + (" int bar : int ref", dbscheme.Column(schema_name="bar", type="int", binding=False)), + ("str baz_: str ref", dbscheme.Column(schema_name="baz", type="str", binding=False)), + ("int x: @foo ref", dbscheme.Column(schema_name="x", type="@foo", binding=False)), + ("int y: @foo", dbscheme.Column(schema_name="y", type="@foo", binding=True)), + ("unique int z: @foo", dbscheme.Column(schema_name="z", type="@foo", binding=True)), +] + + +@pytest.mark.parametrize("column,expected", expected_columns) +def test_load_table_with_column(load, column, expected): + assert load(f""" +foos( + {column} +); +""") == [ + dbscheme.Table(name="foos", columns=[deepcopy(expected)]) + ] + + +def test_load_table_with_multiple_columns(load): + columns = ",\n".join(c for c, _ in expected_columns) + expected = [deepcopy(e) for _, e in expected_columns] + assert load(f""" +foos( +{columns} +); +""") == [ + dbscheme.Table(name="foos", columns=expected) + ] + + +def test_load_table_with_multiple_columns_and_dir(load): + columns = ",\n".join(c for c, _ in expected_columns) + expected = [deepcopy(e) for _, e in expected_columns] + assert load(f""" +foos( //dir=foo/bar/baz +{columns} +); +""") == [ + dbscheme.Table(name="foos", columns=expected, dir=pathlib.Path("foo/bar/baz")) + ] + + +def test_load_multiple_table_with_columns(load): + tables = [f"table{i}({col});" for i, (col, _) in enumerate(expected_columns)] + expected = [dbscheme.Table(name=f"table{i}", columns=[deepcopy(e)]) for i, (_, e) in enumerate(expected_columns)] + assert load("\n".join(tables)) == expected + + +def test_union(load): + assert load("@foo = @bar | @baz | @bla;") == [ + dbscheme.Union(lhs="@foo", rhs=["@bar", "@baz", "@bla"]), + ] + + +def test_table_and_union(load): + assert load(""" +foos(); + +@foo = @bar | @baz | @bla;""") == [ + dbscheme.Table(name="foos", columns=[]), + dbscheme.Union(lhs="@foo", rhs=["@bar", "@baz", "@bla"]), + ] + + +def test_comments_ignored(load): + assert load(""" +// fake_table(); +foos(/* x */unique /*y*/int/* +z +*/ id/* */: /* * */ @bar/*, +int ignored: int ref*/); + +@foo = @bar | @baz | @bla; // | @xxx""") == [ + dbscheme.Table(name="foos", columns=[dbscheme.Column(schema_name="id", type="@bar", binding=True)]), + dbscheme.Union(lhs="@foo", rhs=["@bar", "@baz", "@bla"]), + ] + + +if __name__ == '__main__': + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_schema.py b/swift/codegen/test/test_schemaloader.py similarity index 94% rename from swift/codegen/test/test_schema.py rename to swift/codegen/test/test_schemaloader.py index b5f5f7d1c1a..2428636609e 100644 --- a/swift/codegen/test/test_schema.py +++ b/swift/codegen/test/test_schemaloader.py @@ -3,11 +3,12 @@ import sys import pytest from swift.codegen.test.utils import * -from swift.codegen.lib.schema import defs +from swift.codegen.lib import schemadefs as defs +from swift.codegen.loaders.schemaloader import load def test_empty_schema(): - @schema.load + @load class data: pass @@ -18,7 +19,7 @@ def test_empty_schema(): def test_one_empty_class(): - @schema.load + @load class data: class MyClass: pass @@ -30,7 +31,7 @@ def test_one_empty_class(): def test_two_empty_classes(): - @schema.load + @load class data: class MyClass1: pass @@ -50,7 +51,7 @@ def test_no_external_bases(): pass with pytest.raises(schema.Error): - @schema.load + @load class data: class MyClass(A): pass @@ -58,7 +59,7 @@ def test_no_external_bases(): def test_no_multiple_roots(): with pytest.raises(schema.Error): - @schema.load + @load class data: class MyClass1: pass @@ -68,7 +69,7 @@ def test_no_multiple_roots(): def test_empty_classes_diamond(): - @schema.load + @load class data: class A: pass @@ -92,7 +93,7 @@ def test_empty_classes_diamond(): # def test_group(): - @schema.load + @load class data: @defs.group("xxx") class A: @@ -104,7 +105,7 @@ def test_group(): def test_group_is_inherited(): - @schema.load + @load class data: class A: pass @@ -129,7 +130,7 @@ def test_group_is_inherited(): def test_no_mixed_groups_in_bases(): with pytest.raises(schema.Error): - @schema.load + @load class data: class A: pass @@ -151,14 +152,14 @@ def test_no_mixed_groups_in_bases(): def test_lowercase_rejected(): with pytest.raises(schema.Error): - @schema.load + @load class data: class aLowerCase: pass def test_properties(): - @schema.load + @load class data: class A: one: defs.string @@ -182,7 +183,7 @@ def test_class_properties(): class A: pass - @schema.load + @load class data: class A: pass @@ -205,7 +206,7 @@ def test_class_properties(): def test_string_reference_class_properties(): - @schema.load + @load class data: class A: one: "A" @@ -227,14 +228,14 @@ def test_string_reference_class_properties(): lambda t: defs.list[defs.optional[t]]]) def test_string_reference_dangling(spec): with pytest.raises(schema.Error): - @schema.load + @load class data: class A: x: spec("B") def test_children(): - @schema.load + @load class data: class A: one: "A" | defs.child @@ -255,7 +256,7 @@ def test_children(): @pytest.mark.parametrize("spec", [defs.string, defs.int, defs.boolean, defs.predicate]) def test_builtin_and_predicate_children_not_allowed(spec): with pytest.raises(schema.Error): - @schema.load + @load class data: class A: x: spec | defs.child @@ -271,7 +272,7 @@ _pragmas = [(defs.qltest.skip, "qltest_skip"), @pytest.mark.parametrize("pragma,expected", _pragmas) def test_property_with_pragma(pragma, expected): - @schema.load + @load class data: class A: x: defs.string | pragma @@ -288,7 +289,7 @@ def test_property_with_pragmas(): for pragma, _ in _pragmas: spec |= pragma - @schema.load + @load class data: class A: x: spec @@ -302,7 +303,7 @@ def test_property_with_pragmas(): @pytest.mark.parametrize("pragma,expected", _pragmas) def test_class_with_pragma(pragma, expected): - @schema.load + @load class data: @pragma class A: @@ -318,7 +319,7 @@ def test_class_with_pragmas(): for p, _ in _pragmas: p(cls) - @schema.load + @load class data: class A: pass @@ -331,7 +332,7 @@ def test_class_with_pragmas(): def test_ipa_from_class(): - @schema.load + @load class data: class A: pass @@ -347,7 +348,7 @@ def test_ipa_from_class(): def test_ipa_from_class_ref(): - @schema.load + @load class data: @defs.synth.from_class("B") class A: @@ -364,7 +365,7 @@ def test_ipa_from_class_ref(): def test_ipa_from_class_dangling(): with pytest.raises(schema.Error): - @schema.load + @load class data: @defs.synth.from_class("X") class A: @@ -372,7 +373,7 @@ def test_ipa_from_class_dangling(): def test_ipa_class_on(): - @schema.load + @load class data: class A: pass @@ -391,7 +392,7 @@ def test_ipa_class_on_ref(): class A: pass - @schema.load + @load class data: @defs.synth.on_arguments(b="B", i=defs.int) class A: @@ -408,7 +409,7 @@ def test_ipa_class_on_ref(): def test_ipa_class_on_dangling(): with pytest.raises(schema.Error): - @schema.load + @load class data: @defs.synth.on_arguments(s=defs.string, a="A", i=defs.int) class B: @@ -416,7 +417,7 @@ def test_ipa_class_on_dangling(): def test_ipa_class_hierarchy(): - @schema.load + @load class data: class Root: pass @@ -449,7 +450,7 @@ def test_ipa_class_hierarchy(): def test_class_docstring(): - @schema.load + @load class data: class A: """Very important class.""" @@ -460,7 +461,7 @@ def test_class_docstring(): def test_property_docstring(): - @schema.load + @load class data: class A: x: int | defs.desc("very important property.") @@ -471,7 +472,7 @@ def test_property_docstring(): def test_class_docstring_newline(): - @schema.load + @load class data: class A: """Very important @@ -483,7 +484,7 @@ def test_class_docstring_newline(): def test_property_docstring_newline(): - @schema.load + @load class data: class A: x: int | defs.desc("""very important @@ -496,7 +497,7 @@ def test_property_docstring_newline(): def test_class_docstring_stripped(): - @schema.load + @load class data: class A: """ @@ -511,7 +512,7 @@ def test_class_docstring_stripped(): def test_property_docstring_stripped(): - @schema.load + @load class data: class A: x: int | defs.desc(""" @@ -526,7 +527,7 @@ def test_property_docstring_stripped(): def test_class_docstring_split(): - @schema.load + @load class data: class A: """Very important class. @@ -539,7 +540,7 @@ def test_class_docstring_split(): def test_property_docstring_split(): - @schema.load + @load class data: class A: x: int | defs.desc("""very important property. @@ -553,7 +554,7 @@ def test_property_docstring_split(): def test_class_docstring_indent(): - @schema.load + @load class data: class A: """ @@ -567,7 +568,7 @@ def test_class_docstring_indent(): def test_property_docstring_indent(): - @schema.load + @load class data: class A: x: int | defs.desc(""" @@ -582,7 +583,7 @@ def test_property_docstring_indent(): def test_property_doc_override(): - @schema.load + @load class data: class A: x: int | defs.doc("y") @@ -595,7 +596,7 @@ def test_property_doc_override(): def test_property_doc_override_no_newlines(): with pytest.raises(schema.Error): - @schema.load + @load class data: class A: x: int | defs.doc("no multiple\nlines") @@ -603,14 +604,14 @@ def test_property_doc_override_no_newlines(): def test_property_doc_override_no_trailing_dot(): with pytest.raises(schema.Error): - @schema.load + @load class data: class A: x: int | defs.doc("no dots please.") def test_class_default_doc_name(): - @schema.load + @load class data: @defs.ql.default_doc_name("b") class A: @@ -622,7 +623,7 @@ def test_class_default_doc_name(): def test_null_class(): - @schema.load + @load class data: class Root: pass @@ -641,7 +642,7 @@ def test_null_class(): def test_null_class_cannot_be_derived(): with pytest.raises(schema.Error): - @schema.load + @load class data: class Root: pass @@ -656,7 +657,7 @@ def test_null_class_cannot_be_derived(): def test_null_class_cannot_be_defined_multiple_times(): with pytest.raises(schema.Error): - @schema.load + @load class data: class Root: pass @@ -672,7 +673,7 @@ def test_null_class_cannot_be_defined_multiple_times(): def test_uppercase_acronyms_are_rejected(): with pytest.raises(schema.Error): - @schema.load + @load class data: class Root: pass diff --git a/swift/codegen/test/utils.py b/swift/codegen/test/utils.py index 3911206bfa5..cf686bbf599 100644 --- a/swift/codegen/test/utils.py +++ b/swift/codegen/test/utils.py @@ -47,7 +47,7 @@ def override_paths(tmp_path): @pytest.fixture def input(opts, tmp_path): opts.schema = tmp_path / schema_file - with mock.patch("swift.codegen.lib.schema.load_file") as load_mock: + with mock.patch("swift.codegen.loaders.schemaloader.load_file") as load_mock: load_mock.return_value = schema.Schema([]) yield load_mock.return_value assert load_mock.mock_calls == [ @@ -58,7 +58,7 @@ def input(opts, tmp_path): @pytest.fixture def dbscheme_input(opts, tmp_path): opts.dbscheme = tmp_path / dbscheme_file - with mock.patch("swift.codegen.lib.dbscheme.iterload") as load_mock: + with mock.patch("swift.codegen.loaders.dbschemeloader.iterload") as load_mock: load_mock.entities = [] load_mock.side_effect = lambda _: load_mock.entities yield load_mock diff --git a/swift/schema.py b/swift/schema.py index 251db0f242f..82eab1b4119 100644 --- a/swift/schema.py +++ b/swift/schema.py @@ -9,7 +9,7 @@ This file should be kept simple: For how documentation of generated QL code works, please read schema_documentation.md. """ -from swift.codegen.lib.schema.defs import * +from swift.codegen.lib.schemadefs import * include("prefix.dbscheme") From 81de500301a9765c3611195257db0db738e85dc6 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Tue, 14 Feb 2023 10:39:15 +0100 Subject: [PATCH 217/415] Swift: fix import not working in all python versions --- swift/codegen/loaders/schemaloader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/codegen/loaders/schemaloader.py b/swift/codegen/loaders/schemaloader.py index a8531b5ecd3..cb276ed11c2 100644 --- a/swift/codegen/loaders/schemaloader.py +++ b/swift/codegen/loaders/schemaloader.py @@ -4,7 +4,7 @@ import inflection import typing import types import pathlib -import importlib +import importlib.util from dataclasses import dataclass from toposort import toposort_flatten From dc5bb4fb7712c3d4442e6bf802f8dc95ac249bbf Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 14 Feb 2023 11:54:18 +0100 Subject: [PATCH 218/415] Python: Update a few examples so queries work on them Fixes problem highlighted in https://github.com/github/codeql/issues/12156 --- .../Security/CWE-022/examples/tainted_path.py | 36 ++++++++----------- .../Security/CWE-022/examples/tarslip_bad.py | 4 +-- .../Security/CWE-022/examples/tarslip_good.py | 4 +-- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/python/ql/src/Security/CWE-022/examples/tainted_path.py b/python/ql/src/Security/CWE-022/examples/tainted_path.py index 31dfafc9309..b3d402874d5 100644 --- a/python/ql/src/Security/CWE-022/examples/tainted_path.py +++ b/python/ql/src/Security/CWE-022/examples/tainted_path.py @@ -1,36 +1,30 @@ import os.path +from flask import Flask, request, abort +app = Flask(__name__) -urlpatterns = [ - # Route to user_picture - url(r'^user-pic1$', user_picture1, name='user-picture1'), - url(r'^user-pic2$', user_picture2, name='user-picture2'), - url(r'^user-pic3$', user_picture3, name='user-picture3') -] - - -def user_picture1(request): - """A view that is vulnerable to malicious file access.""" - filename = request.GET.get('p') +@app.route("/user_picture1") +def user_picture1(): + filename = request.args.get('p') # BAD: This could read any file on the file system data = open(filename, 'rb').read() - return HttpResponse(data) + return data -def user_picture2(request): - """A view that is vulnerable to malicious file access.""" +@app.route("/user_picture2") +def user_picture2(): base_path = '/server/static/images' - filename = request.GET.get('p') + filename = request.args.get('p') # BAD: This could still read any file on the file system data = open(os.path.join(base_path, filename), 'rb').read() - return HttpResponse(data) + return data -def user_picture3(request): - """A view that is not vulnerable to malicious file access.""" +@app.route("/user_picture3") +def user_picture3(): base_path = '/server/static/images' - filename = request.GET.get('p') + filename = request.args.get('p') #GOOD -- Verify with normalised version of path fullpath = os.path.normpath(os.path.join(base_path, filename)) if not fullpath.startswith(base_path): - raise SecurityException() + raise Exception("not allowed") data = open(fullpath, 'rb').read() - return HttpResponse(data) + return data diff --git a/python/ql/src/Security/CWE-022/examples/tarslip_bad.py b/python/ql/src/Security/CWE-022/examples/tarslip_bad.py index d0a233e2c4b..d7976e97b5b 100644 --- a/python/ql/src/Security/CWE-022/examples/tarslip_bad.py +++ b/python/ql/src/Security/CWE-022/examples/tarslip_bad.py @@ -1,7 +1,7 @@ - +import sys import tarfile -with tarfile.open('archive.zip') as tar: +with tarfile.open(sys.argv[1]) as tar: #BAD : This could write any file on the filesystem. for entry in tar: tar.extract(entry, "/tmp/unpack/") diff --git a/python/ql/src/Security/CWE-022/examples/tarslip_good.py b/python/ql/src/Security/CWE-022/examples/tarslip_good.py index 59be338d212..0791ab9d3e8 100644 --- a/python/ql/src/Security/CWE-022/examples/tarslip_good.py +++ b/python/ql/src/Security/CWE-022/examples/tarslip_good.py @@ -1,8 +1,8 @@ - +import sys import tarfile import os.path -with tarfile.open('archive.zip') as tar: +with tarfile.open(sys.argv[1]) as tar: for entry in tar: #GOOD: Check that entry is safe if os.path.isabs(entry.name) or ".." in entry.name: From b7123aaa89c739f696bca48410674563b693fb14 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 13 Feb 2023 17:01:16 +0100 Subject: [PATCH 219/415] C#: Add viable callable testcases for regular and checked operators. --- .../library-tests/dispatch/CallGraph.expected | 4 ++++ .../dispatch/GetADynamicTarget.expected | 4 ++++ .../library-tests/dispatch/ViableCallable.cs | 23 +++++++++++++++++++ .../dispatch/viableCallable.expected | 4 ++++ 4 files changed, 35 insertions(+) diff --git a/csharp/ql/test/library-tests/dispatch/CallGraph.expected b/csharp/ql/test/library-tests/dispatch/CallGraph.expected index 213fc0eb4cf..0e52045cbdf 100644 --- a/csharp/ql/test/library-tests/dispatch/CallGraph.expected +++ b/csharp/ql/test/library-tests/dispatch/CallGraph.expected @@ -238,3 +238,7 @@ | ViableCallable.cs:458:10:458:14 | M5<> | ViableCallable.cs:444:23:444:27 | M2<> | | ViableCallable.cs:475:10:475:12 | Run | ViableCallable.cs:468:10:468:11 | M2 | | ViableCallable.cs:475:10:475:12 | Run | ViableCallable.cs:473:17:473:18 | M1 | +| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:487:32:487:32 | + | +| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:488:40:488:40 | checked + | +| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:489:28:489:35 | explicit conversion | +| ViableCallable.cs:492:10:492:12 | Run | ViableCallable.cs:490:28:490:35 | checked explicit conversion | diff --git a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected index fb0547dffcd..074deaf9dff 100644 --- a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected +++ b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected @@ -471,3 +471,7 @@ | ViableCallable.cs:461:9:461:30 | call to method M2 | C17.M2(Func) | | ViableCallable.cs:478:9:478:14 | call to method M1 | C18.M1() | | ViableCallable.cs:481:9:481:14 | call to method M2 | I2.M2() | +| ViableCallable.cs:495:18:495:22 | call to operator + | C19.+(C19, C19) | +| ViableCallable.cs:498:26:498:30 | call to operator checked + | C19.checked +(C19, C19) | +| ViableCallable.cs:501:18:501:23 | call to operator explicit conversion | C19.explicit conversion(C19) | +| ViableCallable.cs:504:26:504:31 | call to operator checked explicit conversion | C19.checked explicit conversion(C19) | diff --git a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs index c742789fef3..6345bb3510e 100644 --- a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs +++ b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs @@ -480,4 +480,27 @@ class C18 : I2 // Viable callables: I2.M2() i.M2(); } +} + +class C19 +{ + public static C19 operator +(C19 x, C19 y) => throw null; + public static C19 operator checked +(C19 x, C19 y) => throw null; + public static explicit operator int(C19 x) => throw null; + public static explicit operator checked int(C19 x) => throw null; + + void Run(C19 c) + { + // Viable callables: C19.op_Addition() + var c1 = c + c; + + // Viable callables: C19.op_CheckedAddition() + var c2 = checked(c + c); + + // Viable callables: C19.op_Explicit() + var n1 = (int)c; + + // Viable callables: C19.op_CheckedExplicit() + var n2 = checked((int)c); + } } \ No newline at end of file diff --git a/csharp/ql/test/library-tests/dispatch/viableCallable.expected b/csharp/ql/test/library-tests/dispatch/viableCallable.expected index 2de575c5291..d752fb824da 100644 --- a/csharp/ql/test/library-tests/dispatch/viableCallable.expected +++ b/csharp/ql/test/library-tests/dispatch/viableCallable.expected @@ -268,3 +268,7 @@ | ViableCallable.cs:423:9:423:21 | call to method M | M<> | A5 | | ViableCallable.cs:478:9:478:14 | call to method M1 | M1 | C18 | | ViableCallable.cs:481:9:481:14 | call to method M2 | M2 | I2 | +| ViableCallable.cs:495:18:495:22 | call to operator + | + | C19 | +| ViableCallable.cs:498:26:498:30 | call to operator checked + | checked + | C19 | +| ViableCallable.cs:501:18:501:23 | call to operator explicit conversion | explicit conversion | C19 | +| ViableCallable.cs:504:26:504:31 | call to operator checked explicit conversion | checked explicit conversion | C19 | From 238a70fc5598c438773a3ed59a19fcb68f42aeed Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 14 Feb 2023 12:50:48 +0100 Subject: [PATCH 220/415] C#: Add library support for checked operators. --- csharp/ql/lib/semmle/code/csharp/Callable.qll | 141 +++++++++++++++++- 1 file changed, 133 insertions(+), 8 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index c0a299454bf..82ffbfa6a06 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -485,10 +485,11 @@ class RecordCloneMethod extends Method, DotNet::RecordCloneCallable { * A user-defined unary operator - an operator taking one operand. * * Either a plus operator (`PlusOperator`), minus operator (`MinusOperator`), - * not operator (`NotOperator`), complement operator (`ComplementOperator`), - * true operator (`TrueOperator`), false operator (`FalseOperator`), - * increment operator (`IncrementOperator`), or decrement operator - * (`DecrementOperator`). + * checked minus operator (`CheckedMinusOperator`), not operator (`NotOperator`), + * complement operator (`ComplementOperator`), true operator (`TrueOperator`), + * false operator (`FalseOperator`), increment operator (`IncrementOperator`), + * checked increment operator (`CheckedIncrementOperator`), decrement operator + * (`DecrementOperator`) or checked decrement operator (`CheckedDecrementOperator`). */ class UnaryOperator extends Operator { UnaryOperator() { @@ -527,6 +528,21 @@ class MinusOperator extends UnaryOperator { override string getAPrimaryQlClass() { result = "MinusOperator" } } +/** + * A user-defined checked minus operator (`-`), for example + * + * ```csharp + * public static Widget operator checked -(Widget w) { + * ... + * } + * ``` + */ +class CheckedMinusOperator extends UnaryOperator { + CheckedMinusOperator() { this.getName() = "checked -" } + + override string getAPrimaryQlClass() { result = "CheckedMinusOperator" } +} + /** * A user-defined not operator (`!`), for example * @@ -572,6 +588,21 @@ class IncrementOperator extends UnaryOperator { override string getAPrimaryQlClass() { result = "IncrementOperator" } } +/** + * A user-defined checked increment operator (`++`), for example + * + * ```csharp + * public static Widget operator checked ++(Widget w) { + * ... + * } + * ``` + */ +class CheckedIncrementOperator extends UnaryOperator { + CheckedIncrementOperator() { this.getName() = "checked ++" } + + override string getAPrimaryQlClass() { result = "CheckedIncrementOperator" } +} + /** * A user-defined decrement operator (`--`), for example * @@ -587,6 +618,21 @@ class DecrementOperator extends UnaryOperator { override string getAPrimaryQlClass() { result = "DecrementOperator" } } +/** + * A user-defined checked decrement operator (`--`), for example + * + * ```csharp + * public static Widget operator checked --(Widget w) { + * ... + * } + * ``` + */ +class CheckedDecrementOperator extends UnaryOperator { + CheckedDecrementOperator() { this.getName() = "checked --" } + + override string getAPrimaryQlClass() { result = "CheckedDecrementOperator" } +} + /** * A user-defined false operator (`false`), for example * @@ -620,9 +666,12 @@ class TrueOperator extends UnaryOperator { /** * A user-defined binary operator. * - * Either an addition operator (`AddOperator`), a subtraction operator - * (`SubOperator`), a multiplication operator (`MulOperator`), a division - * operator (`DivOperator`), a remainder operator (`RemOperator`), an and + * Either an addition operator (`AddOperator`), a checked addition operator + * (`CheckedAddOperator`) a subtraction operator (`SubOperator`), a checked + * substraction operator (`CheckedSubOperator`), a multiplication operator + * (`MulOperator`), a checked multiplication operator (`CheckedMulOperator`), + * a division operator (`DivOperator`), a checked division operator + * (`CheckedDivOperator`), 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 unsigned right shift @@ -650,6 +699,21 @@ class AddOperator extends BinaryOperator { override string getAPrimaryQlClass() { result = "AddOperator" } } +/** + * A user-defined checked addition operator (`+`), for example + * + * ```csharp + * public static Widget operator checked +(Widget lhs, Widget rhs) { + * ... + * } + * ``` + */ +class CheckedAddOperator extends BinaryOperator { + CheckedAddOperator() { this.getName() = "checked +" } + + override string getAPrimaryQlClass() { result = "CheckedAddOperator" } +} + /** * A user-defined subtraction operator (`-`), for example * @@ -665,6 +729,21 @@ class SubOperator extends BinaryOperator { override string getAPrimaryQlClass() { result = "SubOperator" } } +/** + * A user-defined checked subtraction operator (`-`), for example + * + * ```csharp + * public static Widget operator checked -(Widget lhs, Widget rhs) { + * ... + * } + * ``` + */ +class CheckedSubOperator extends BinaryOperator { + CheckedSubOperator() { this.getName() = "checked -" } + + override string getAPrimaryQlClass() { result = "CheckedSubOperator" } +} + /** * A user-defined multiplication operator (`*`), for example * @@ -680,6 +759,21 @@ class MulOperator extends BinaryOperator { override string getAPrimaryQlClass() { result = "MulOperator" } } +/** + * A user-defined checked multiplication operator (`*`), for example + * + * ```csharp + * public static Widget operator checked *(Widget lhs, Widget rhs) { + * ... + * } + * ``` + */ +class CheckedMulOperator extends BinaryOperator { + CheckedMulOperator() { this.getName() = "checked *" } + + override string getAPrimaryQlClass() { result = "CheckedMulOperator" } +} + /** * A user-defined division operator (`/`), for example * @@ -695,6 +789,21 @@ class DivOperator extends BinaryOperator { override string getAPrimaryQlClass() { result = "DivOperator" } } +/** + * A user-defined checked division operator (`/`), for example + * + * ```csharp + * public static Widget operator checked /(Widget lhs, Widget rhs) { + * ... + * } + * ``` + */ +class CheckedDivOperator extends BinaryOperator { + CheckedDivOperator() { this.getName() = "checked /" } + + override string getAPrimaryQlClass() { result = "CheckedDivOperator" } +} + /** * A user-defined remainder operator (`%`), for example * @@ -908,7 +1017,8 @@ class GEOperator extends BinaryOperator { class ConversionOperator extends Operator { ConversionOperator() { this.getName() = "implicit conversion" or - this.getName() = "explicit conversion" + this.getName() = "explicit conversion" or + this.getName() = "checked explicit conversion" } /** Gets the source type of the conversion. */ @@ -948,6 +1058,21 @@ class ExplicitConversionOperator extends ConversionOperator { override string getAPrimaryQlClass() { result = "ExplicitConversionOperator" } } +/** + * A user-defined checked explicit conversion operator, for example + * + * ```csharp + * public static explicit operator checked int(BigInteger i) { + * ... + * } + * ``` + */ +class CheckedExplicitConversionOperator extends ConversionOperator { + CheckedExplicitConversionOperator() { this.getName() = "checked explicit conversion" } + + override string getAPrimaryQlClass() { result = "CheckedExplicitConversionOperator" } +} + /** * A local function, defined within the scope of another callable. * For example, `Fac` on lines 2--4 in From b3c234d0205626d80e4f0f8a46218bbe16a075c9 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 14 Feb 2023 12:52:04 +0100 Subject: [PATCH 221/415] C#: Add testcases for checked operators. --- .../csharp11/CheckedOperators.cs | 56 +++++ .../library-tests/csharp11/PrintAst.expected | 218 ++++++++++++++++++ .../csharp11/checkedOperators.expected | 16 ++ .../csharp11/checkedOperators.ql | 5 + 4 files changed, 295 insertions(+) create mode 100644 csharp/ql/test/library-tests/csharp11/CheckedOperators.cs create mode 100644 csharp/ql/test/library-tests/csharp11/checkedOperators.expected create mode 100644 csharp/ql/test/library-tests/csharp11/checkedOperators.ql diff --git a/csharp/ql/test/library-tests/csharp11/CheckedOperators.cs b/csharp/ql/test/library-tests/csharp11/CheckedOperators.cs new file mode 100644 index 00000000000..a61be485b15 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp11/CheckedOperators.cs @@ -0,0 +1,56 @@ +namespace CheckedOperators; + +public class Number +{ + public int Value { get; } + + public Number(int n) => this.Value = n; + + public static Number operator checked +(Number n1, Number n2) => + new Number(checked(n1.Value + n2.Value)); + + public static Number operator +(Number n1, Number n2) => + new Number(n1.Value + n2.Value); + + public static Number operator checked -(Number n1, Number n2) => + new Number(checked(n1.Value - n2.Value)); + + public static Number operator -(Number n1, Number n2) => + new Number(n1.Value - n2.Value); + + public static Number operator checked *(Number n1, Number n2) => + new Number(checked(n1.Value * n2.Value)); + + public static Number operator *(Number n1, Number n2) => + new Number(n1.Value * n2.Value); + + public static Number operator checked /(Number n1, Number n2) => + new Number(checked(n1.Value / n2.Value)); + + public static Number operator /(Number n1, Number n2) => + new Number(n1.Value / n2.Value); + + public static Number operator checked -(Number n) => + new Number(checked(-n.Value)); + + public static Number operator -(Number n) => + new Number(-n.Value); + + public static Number operator checked ++(Number n) => + new Number(checked(n.Value + 1)); + + public static Number operator ++(Number n) => + new Number(n.Value + 1); + + public static Number operator checked --(Number n) => + new Number(checked(n.Value - 1)); + + public static Number operator --(Number n) => + new Number(n.Value - 1); + + public static explicit operator short(Number n) => + (short)n.Value; + + public static explicit operator checked short(Number n) => + checked((short)n.Value); +} diff --git a/csharp/ql/test/library-tests/csharp11/PrintAst.expected b/csharp/ql/test/library-tests/csharp11/PrintAst.expected index b03c5b6a9e3..c9ebe7cc05e 100644 --- a/csharp/ql/test/library-tests/csharp11/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp11/PrintAst.expected @@ -1,3 +1,221 @@ +CheckedOperators.cs: +# 1| [NamespaceDeclaration] namespace ... { ... } +# 3| 1: [Class] Number +# 5| 4: [Property] Value +# 5| -1: [TypeMention] int +# 5| 3: [Getter] get_Value +# 7| 5: [InstanceConstructor] Number +#-----| 2: (Parameters) +# 7| 0: [Parameter] n +# 7| -1: [TypeMention] int +# 7| 4: [AssignExpr] ... = ... +# 7| 0: [PropertyCall] access to property Value +# 7| -1: [ThisAccess] this access +# 7| 1: [ParameterAccess] access to parameter n +# 9| 6: [CheckedAddOperator] checked + +# 9| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 9| 0: [Parameter] n1 +# 9| -1: [TypeMention] Number +# 9| 1: [Parameter] n2 +# 9| -1: [TypeMention] Number +# 10| 4: [ObjectCreation] object creation of type Number +# 10| -1: [TypeMention] Number +# 10| 0: [CheckedExpr] checked (...) +# 10| 0: [AddExpr] ... + ... +# 10| 0: [PropertyCall] access to property Value +# 10| -1: [ParameterAccess] access to parameter n1 +# 10| 1: [PropertyCall] access to property Value +# 10| -1: [ParameterAccess] access to parameter n2 +# 12| 7: [AddOperator] + +# 12| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 12| 0: [Parameter] n1 +# 12| -1: [TypeMention] Number +# 12| 1: [Parameter] n2 +# 12| -1: [TypeMention] Number +# 13| 4: [ObjectCreation] object creation of type Number +# 13| -1: [TypeMention] Number +# 13| 0: [AddExpr] ... + ... +# 13| 0: [PropertyCall] access to property Value +# 13| -1: [ParameterAccess] access to parameter n1 +# 13| 1: [PropertyCall] access to property Value +# 13| -1: [ParameterAccess] access to parameter n2 +# 15| 8: [CheckedSubOperator] checked - +# 15| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 15| 0: [Parameter] n1 +# 15| -1: [TypeMention] Number +# 15| 1: [Parameter] n2 +# 15| -1: [TypeMention] Number +# 16| 4: [ObjectCreation] object creation of type Number +# 16| -1: [TypeMention] Number +# 16| 0: [CheckedExpr] checked (...) +# 16| 0: [SubExpr] ... - ... +# 16| 0: [PropertyCall] access to property Value +# 16| -1: [ParameterAccess] access to parameter n1 +# 16| 1: [PropertyCall] access to property Value +# 16| -1: [ParameterAccess] access to parameter n2 +# 18| 9: [SubOperator] - +# 18| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 18| 0: [Parameter] n1 +# 18| -1: [TypeMention] Number +# 18| 1: [Parameter] n2 +# 18| -1: [TypeMention] Number +# 19| 4: [ObjectCreation] object creation of type Number +# 19| -1: [TypeMention] Number +# 19| 0: [SubExpr] ... - ... +# 19| 0: [PropertyCall] access to property Value +# 19| -1: [ParameterAccess] access to parameter n1 +# 19| 1: [PropertyCall] access to property Value +# 19| -1: [ParameterAccess] access to parameter n2 +# 21| 10: [CheckedMulOperator] checked * +# 21| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 21| 0: [Parameter] n1 +# 21| -1: [TypeMention] Number +# 21| 1: [Parameter] n2 +# 21| -1: [TypeMention] Number +# 22| 4: [ObjectCreation] object creation of type Number +# 22| -1: [TypeMention] Number +# 22| 0: [CheckedExpr] checked (...) +# 22| 0: [MulExpr] ... * ... +# 22| 0: [PropertyCall] access to property Value +# 22| -1: [ParameterAccess] access to parameter n1 +# 22| 1: [PropertyCall] access to property Value +# 22| -1: [ParameterAccess] access to parameter n2 +# 24| 11: [MulOperator] * +# 24| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 24| 0: [Parameter] n1 +# 24| -1: [TypeMention] Number +# 24| 1: [Parameter] n2 +# 24| -1: [TypeMention] Number +# 25| 4: [ObjectCreation] object creation of type Number +# 25| -1: [TypeMention] Number +# 25| 0: [MulExpr] ... * ... +# 25| 0: [PropertyCall] access to property Value +# 25| -1: [ParameterAccess] access to parameter n1 +# 25| 1: [PropertyCall] access to property Value +# 25| -1: [ParameterAccess] access to parameter n2 +# 27| 12: [CheckedDivOperator] checked / +# 27| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 27| 0: [Parameter] n1 +# 27| -1: [TypeMention] Number +# 27| 1: [Parameter] n2 +# 27| -1: [TypeMention] Number +# 28| 4: [ObjectCreation] object creation of type Number +# 28| -1: [TypeMention] Number +# 28| 0: [CheckedExpr] checked (...) +# 28| 0: [DivExpr] ... / ... +# 28| 0: [PropertyCall] access to property Value +# 28| -1: [ParameterAccess] access to parameter n1 +# 28| 1: [PropertyCall] access to property Value +# 28| -1: [ParameterAccess] access to parameter n2 +# 30| 13: [DivOperator] / +# 30| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 30| 0: [Parameter] n1 +# 30| -1: [TypeMention] Number +# 30| 1: [Parameter] n2 +# 30| -1: [TypeMention] Number +# 31| 4: [ObjectCreation] object creation of type Number +# 31| -1: [TypeMention] Number +# 31| 0: [DivExpr] ... / ... +# 31| 0: [PropertyCall] access to property Value +# 31| -1: [ParameterAccess] access to parameter n1 +# 31| 1: [PropertyCall] access to property Value +# 31| -1: [ParameterAccess] access to parameter n2 +# 33| 14: [CheckedMinusOperator] checked - +# 33| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 33| 0: [Parameter] n +# 33| -1: [TypeMention] Number +# 34| 4: [ObjectCreation] object creation of type Number +# 34| -1: [TypeMention] Number +# 34| 0: [CheckedExpr] checked (...) +# 34| 0: [UnaryMinusExpr] -... +# 34| 0: [PropertyCall] access to property Value +# 34| -1: [ParameterAccess] access to parameter n +# 36| 15: [MinusOperator] - +# 36| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 36| 0: [Parameter] n +# 36| -1: [TypeMention] Number +# 37| 4: [ObjectCreation] object creation of type Number +# 37| -1: [TypeMention] Number +# 37| 0: [UnaryMinusExpr] -... +# 37| 0: [PropertyCall] access to property Value +# 37| -1: [ParameterAccess] access to parameter n +# 39| 16: [CheckedIncrementOperator] checked ++ +# 39| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 39| 0: [Parameter] n +# 39| -1: [TypeMention] Number +# 40| 4: [ObjectCreation] object creation of type Number +# 40| -1: [TypeMention] Number +# 40| 0: [CheckedExpr] checked (...) +# 40| 0: [AddExpr] ... + ... +# 40| 0: [PropertyCall] access to property Value +# 40| -1: [ParameterAccess] access to parameter n +# 40| 1: [IntLiteral] 1 +# 42| 17: [IncrementOperator] ++ +# 42| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 42| 0: [Parameter] n +# 42| -1: [TypeMention] Number +# 43| 4: [ObjectCreation] object creation of type Number +# 43| -1: [TypeMention] Number +# 43| 0: [AddExpr] ... + ... +# 43| 0: [PropertyCall] access to property Value +# 43| -1: [ParameterAccess] access to parameter n +# 43| 1: [IntLiteral] 1 +# 45| 18: [CheckedDecrementOperator] checked -- +# 45| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 45| 0: [Parameter] n +# 45| -1: [TypeMention] Number +# 46| 4: [ObjectCreation] object creation of type Number +# 46| -1: [TypeMention] Number +# 46| 0: [CheckedExpr] checked (...) +# 46| 0: [SubExpr] ... - ... +# 46| 0: [PropertyCall] access to property Value +# 46| -1: [ParameterAccess] access to parameter n +# 46| 1: [IntLiteral] 1 +# 48| 19: [DecrementOperator] -- +# 48| -1: [TypeMention] Number +#-----| 2: (Parameters) +# 48| 0: [Parameter] n +# 48| -1: [TypeMention] Number +# 49| 4: [ObjectCreation] object creation of type Number +# 49| -1: [TypeMention] Number +# 49| 0: [SubExpr] ... - ... +# 49| 0: [PropertyCall] access to property Value +# 49| -1: [ParameterAccess] access to parameter n +# 49| 1: [IntLiteral] 1 +# 51| 20: [ExplicitConversionOperator] explicit conversion +# 51| -1: [TypeMention] short +#-----| 2: (Parameters) +# 51| 0: [Parameter] n +# 51| -1: [TypeMention] Number +# 52| 4: [CastExpr] (...) ... +# 52| 0: [TypeAccess] access to type Int16 +# 52| 0: [TypeMention] short +# 52| 1: [PropertyCall] access to property Value +# 52| -1: [ParameterAccess] access to parameter n +# 54| 21: [CheckedExplicitConversionOperator] checked explicit conversion +# 54| -1: [TypeMention] short +#-----| 2: (Parameters) +# 54| 0: [Parameter] n +# 54| -1: [TypeMention] Number +# 55| 4: [CheckedExpr] checked (...) +# 55| 0: [CastExpr] (...) ... +# 55| 0: [TypeAccess] access to type Int16 +# 55| 0: [TypeMention] short +# 55| 1: [PropertyCall] access to property Value +# 55| -1: [ParameterAccess] access to parameter n GenericAttribute.cs: # 3| [GenericAssemblyAttribute] [assembly: MyGeneric(...)] # 3| 0: [TypeMention] MyGenericAttribute diff --git a/csharp/ql/test/library-tests/csharp11/checkedOperators.expected b/csharp/ql/test/library-tests/csharp11/checkedOperators.expected new file mode 100644 index 00000000000..bbd509e36d9 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp11/checkedOperators.expected @@ -0,0 +1,16 @@ +| CheckedOperators.cs:9:43:9:43 | checked + | op_CheckedAddition | CheckedAddOperator | +| CheckedOperators.cs:12:35:12:35 | + | op_Addition | AddOperator | +| CheckedOperators.cs:15:43:15:43 | checked - | op_CheckedSubtraction | CheckedSubOperator | +| CheckedOperators.cs:18:35:18:35 | - | op_Subtraction | SubOperator | +| CheckedOperators.cs:21:43:21:43 | checked * | op_CheckedMultiply | CheckedMulOperator | +| CheckedOperators.cs:24:35:24:35 | * | op_Multiply | MulOperator | +| CheckedOperators.cs:27:43:27:43 | checked / | op_CheckedDivision | CheckedDivOperator | +| CheckedOperators.cs:30:35:30:35 | / | op_Division | DivOperator | +| CheckedOperators.cs:33:43:33:43 | checked - | op_CheckedUnaryNegation | CheckedMinusOperator | +| CheckedOperators.cs:36:35:36:35 | - | op_UnaryNegation | MinusOperator | +| CheckedOperators.cs:39:43:39:44 | checked ++ | op_CheckedIncrement | CheckedIncrementOperator | +| CheckedOperators.cs:42:35:42:36 | ++ | op_Increment | IncrementOperator | +| CheckedOperators.cs:45:43:45:44 | checked -- | op_CheckedDecrement | CheckedDecrementOperator | +| CheckedOperators.cs:48:35:48:36 | -- | op_Decrement | DecrementOperator | +| CheckedOperators.cs:51:28:51:35 | explicit conversion | op_Explicit | ExplicitConversionOperator | +| CheckedOperators.cs:54:28:54:35 | checked explicit conversion | op_CheckedExplicit | CheckedExplicitConversionOperator | diff --git a/csharp/ql/test/library-tests/csharp11/checkedOperators.ql b/csharp/ql/test/library-tests/csharp11/checkedOperators.ql new file mode 100644 index 00000000000..c7ad15aa625 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp11/checkedOperators.ql @@ -0,0 +1,5 @@ +import csharp + +from Operator o +where o.getFile().getStem() = "CheckedOperators" +select o, o.getFunctionName(), o.getAPrimaryQlClass() From 469b289db9d2bae30fedcc798451ed2afe1cd825 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 14 Feb 2023 13:14:45 +0100 Subject: [PATCH 222/415] C#: Add change note. --- csharp/ql/lib/change-notes/2023-02-14-checked-operators.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2023-02-14-checked-operators.md diff --git a/csharp/ql/lib/change-notes/2023-02-14-checked-operators.md b/csharp/ql/lib/change-notes/2023-02-14-checked-operators.md new file mode 100644 index 00000000000..19d4a7f3f66 --- /dev/null +++ b/csharp/ql/lib/change-notes/2023-02-14-checked-operators.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C# 11: Added library support for `checked` operators. \ No newline at end of file From 3f0fe96f856b37eae62342f7d0010d2ecaa13dda Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Tue, 20 Dec 2022 21:23:29 +0100 Subject: [PATCH 223/415] add `getBoolValue()` as a utility predicate on `BooleanLiteral` --- javascript/ql/lib/semmle/javascript/Expr.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/Expr.qll b/javascript/ql/lib/semmle/javascript/Expr.qll index 11fe4739f7b..925352cacad 100644 --- a/javascript/ql/lib/semmle/javascript/Expr.qll +++ b/javascript/ql/lib/semmle/javascript/Expr.qll @@ -379,7 +379,10 @@ class NullLiteral extends @null_literal, Literal { } * false * ``` */ -class BooleanLiteral extends @boolean_literal, Literal { } +class BooleanLiteral extends @boolean_literal, Literal { + /** Gets the value of this literal. */ + boolean getBoolValue() { if this.getRawValue() = "true" then result = true else result = false } +} /** * A numeric literal. From c355a266572e2b5c2fb2449e747ec6bb957e7051 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Wed, 21 Dec 2022 10:32:17 +0100 Subject: [PATCH 224/415] add failing test --- .../CWE-089/untyped/SqlInjection.expected | 22 ++++++++++++++++++ .../Security/CWE-089/untyped/koarouter.js | 23 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index f752ea6427f..dd11457f520 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -68,6 +68,17 @@ nodes | json-schema-validator.js:59:22:59:26 | query | | json-schema-validator.js:61:22:61:26 | query | | json-schema-validator.js:61:22:61:26 | query | +| koarouter.js:5:11:5:33 | version | +| koarouter.js:5:13:5:19 | version | +| koarouter.js:5:13:5:19 | version | +| koarouter.js:11:11:11:28 | conditions | +| koarouter.js:11:24:11:28 | ['1'] | +| koarouter.js:14:25:14:46 | `versio ... rsion}` | +| koarouter.js:14:38:14:44 | version | +| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | +| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | +| koarouter.js:17:52:17:61 | conditions | +| koarouter.js:17:52:17:75 | conditi ... and ') | | ldap.js:20:7:20:34 | q | | ldap.js:20:11:20:34 | url.par ... , true) | | ldap.js:20:21:20:27 | req.url | @@ -482,6 +493,16 @@ edges | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | json-schema-validator.js:50:15:50:48 | query | | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | +| koarouter.js:5:11:5:33 | version | koarouter.js:14:38:14:44 | version | +| koarouter.js:5:13:5:19 | version | koarouter.js:5:11:5:33 | version | +| koarouter.js:5:13:5:19 | version | koarouter.js:5:11:5:33 | version | +| koarouter.js:11:11:11:28 | conditions | koarouter.js:17:52:17:61 | conditions | +| koarouter.js:11:24:11:28 | ['1'] | koarouter.js:11:11:11:28 | conditions | +| koarouter.js:14:25:14:46 | `versio ... rsion}` | koarouter.js:11:24:11:28 | ['1'] | +| koarouter.js:14:38:14:44 | version | koarouter.js:14:25:14:46 | `versio ... rsion}` | +| koarouter.js:17:52:17:61 | conditions | koarouter.js:17:52:17:75 | conditi ... and ') | +| koarouter.js:17:52:17:75 | conditi ... and ') | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | +| koarouter.js:17:52:17:75 | conditi ... and ') | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | | ldap.js:20:7:20:34 | q | ldap.js:22:18:22:18 | q | | ldap.js:20:11:20:34 | url.par ... , true) | ldap.js:20:7:20:34 | q | | ldap.js:20:21:20:27 | req.url | ldap.js:20:11:20:34 | url.par ... , true) | @@ -929,6 +950,7 @@ edges | json-schema-validator.js:55:22:55:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:55:22:55:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | | json-schema-validator.js:59:22:59:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:59:22:59:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | | json-schema-validator.js:61:22:61:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:61:22:61:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | +| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | koarouter.js:5:13:5:19 | version | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | This query depends on a $@. | koarouter.js:5:13:5:19 | version | user-provided value | | ldap.js:28:30:28:34 | opts1 | ldap.js:20:21:20:27 | req.url | ldap.js:28:30:28:34 | opts1 | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | | ldap.js:32:5:32:61 | { filte ... e}))` } | ldap.js:20:21:20:27 | req.url | ldap.js:32:5:32:61 | { filte ... e}))` } | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | | ldap.js:66:30:66:53 | { filte ... ilter } | ldap.js:20:21:20:27 | req.url | ldap.js:66:30:66:53 | { filte ... ilter } | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js new file mode 100644 index 00000000000..6331d15d7e6 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js @@ -0,0 +1,23 @@ +const Router = require('koa-router') +const {Sequelize} = require("sequelize"); + +new Router().get("/hello", (ctx) => { + const { version } = ctx.query; + + if (version && validVersion(version) === false) { + throw new Error(`invalid version ${version}`); + } + + const conditions = ['1']; + + if (version) { + conditions.push(`version = ${version}`) + } + + new Sequelize().query(`SELECT * FROM t WHERE ${conditions.join(' and ')}`, null); // OK - but still flagged [INCONSISTENCY] +}); + +function validVersion(version) { + const pattern = /^[a-zA-Z0-9]+$/; + return pattern.test(version); +} From 9549cac3e549b0f1a1092012342e5b15330ee774 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Wed, 21 Dec 2022 10:35:05 +0100 Subject: [PATCH 225/415] add an additional barrier guard that finds "=== true" versions of previous barrier guards --- .../javascript/dataflow/Configuration.qll | 38 +++++++++++++++++++ .../UnsafeShellCommandConstruction.expected | 30 +++++++++++++++ .../UnsafeShellCommandConstruction/lib/lib.js | 24 ++++++++++++ .../CWE-089/untyped/SqlInjection.expected | 22 ----------- .../Security/CWE-089/untyped/koarouter.js | 2 +- 5 files changed, 93 insertions(+), 23 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll index f4a91834ad4..b741d756037 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll @@ -368,6 +368,8 @@ private predicate barrierGuardBlocksExpr( // Handle labelled barrier guard functions specially, to avoid negative recursion // through the non-abstract 3-argument version of blocks(). guard.(AdditionalBarrierGuardCall).internalBlocksLabel(outcome, test, label) + or + guard.(CallAgainstEqualityCheck).internalBlocksLabel(outcome, test, label) } /** @@ -1999,6 +2001,42 @@ private class AdditionalBarrierGuardCall extends AdditionalBarrierGuardNode, Dat override predicate appliesTo(Configuration cfg) { f.appliesTo(cfg) } } +/** + * A sanitizer where an inner sanitizer is compared against a boolean. + * E.g. (assuming `sanitizes(e)` is an existing sanitizer): + * ```javascript + * if (sanitizes(e) === true) { + * // e is sanitized + * } + * ``` + */ +private class CallAgainstEqualityCheck extends AdditionalBarrierGuardNode { + DataFlow::BarrierGuardNode prev; + boolean polarity; + + CallAgainstEqualityCheck() { + prev instanceof DataFlow::CallNode and + exists(EqualityTest test, BooleanLiteral bool | + this.asExpr() = test and + test.hasOperands(prev.asExpr(), bool) and + polarity = test.getPolarity().booleanXor(bool.getBoolValue()) + ) + } + + override predicate blocks(boolean outcome, Expr e) { + none() // handled by internalBlocksLabel + } + + predicate internalBlocksLabel(boolean outcome, Expr e, DataFlow::FlowLabel lbl) { + exists(boolean prevOutcome | + barrierGuardBlocksExpr(prev, prevOutcome, e, lbl) and + outcome = prevOutcome.booleanXor(polarity) + ) + } + + override predicate appliesTo(Configuration cfg) { cfg.isBarrierGuard(prev) } +} + /** * A guard node for a variable in a negative condition, such as `x` in `if(!x)`. * Can be added to a `isBarrier` in a data-flow configuration to block flow through such checks. 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 2b7a9927826..eaeb896cbc8 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 @@ -301,6 +301,16 @@ nodes | lib/lib.js:562:26:562:29 | name | | lib/lib.js:566:26:566:29 | name | | lib/lib.js:566:26:566:29 | name | +| lib/lib.js:572:41:572:44 | name | +| lib/lib.js:572:41:572:44 | name | +| lib/lib.js:573:22:573:25 | name | +| lib/lib.js:573:22:573:25 | name | +| lib/lib.js:579:25:579:28 | name | +| lib/lib.js:579:25:579:28 | name | +| lib/lib.js:590:29:590:32 | name | +| lib/lib.js:590:29:590:32 | name | +| lib/lib.js:593:25:593:28 | name | +| lib/lib.js:593:25:593:28 | 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 | @@ -703,6 +713,22 @@ edges | lib/lib.js:558:41:558:44 | name | lib/lib.js:566:26:566:29 | name | | lib/lib.js:558:41:558:44 | name | lib/lib.js:566:26:566:29 | name | | lib/lib.js:558:41:558:44 | name | lib/lib.js:566:26:566:29 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:573:22:573:25 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:573:22:573:25 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:573:22:573:25 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:573:22:573:25 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:579:25:579:28 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:579:25:579:28 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:579:25:579:28 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:579:25:579:28 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:590:29:590:32 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:590:29:590:32 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:590:29:590:32 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:590:29:590:32 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | +| lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593: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 | | lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name | @@ -826,6 +852,10 @@ edges | lib/lib.js:560:14:560:29 | "rm -rf " + name | lib/lib.js:558:41:558:44 | name | lib/lib.js:560:26:560:29 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:558:41:558:44 | name | library input | lib/lib.js:560:9:560:30 | exec("r ... + name) | shell command | | lib/lib.js:562:14:562:29 | "rm -rf " + name | lib/lib.js:558:41:558:44 | name | lib/lib.js:562:26:562:29 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:558:41:558:44 | name | library input | lib/lib.js:562:9:562:30 | exec("r ... + name) | shell command | | lib/lib.js:566:14:566:29 | "rm -rf " + name | lib/lib.js:558:41:558:44 | name | lib/lib.js:566:26:566:29 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:558:41:558:44 | name | library input | lib/lib.js:566:9:566:30 | exec("r ... + name) | shell command | +| lib/lib.js:573:10:573:25 | "rm -rf " + name | lib/lib.js:572:41:572:44 | name | lib/lib.js:573:22:573:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:572:41:572:44 | name | library input | lib/lib.js:573:2:573:26 | cp.exec ... + name) | shell command | +| lib/lib.js:579:13:579:28 | "rm -rf " + name | lib/lib.js:572:41:572:44 | name | lib/lib.js:579:25:579:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:572:41:572:44 | name | library input | lib/lib.js:579:5:579:29 | cp.exec ... + name) | shell command | +| lib/lib.js:590:17:590:32 | "rm -rf " + name | lib/lib.js:572:41:572:44 | name | lib/lib.js:590:29:590:32 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:572:41:572:44 | name | library input | lib/lib.js:590:9:590:33 | cp.exec ... + name) | shell command | +| lib/lib.js:593:13:593:28 | "rm -rf " + name | lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:572:41:572:44 | name | library input | lib/lib.js:593:5:593:29 | cp.exec ... + name) | 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 eb528e59450..c45a616e6bb 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 @@ -568,3 +568,27 @@ module.exports.badSanitizer = function (name) { exec("rm -rf " + name); // OK } } + +module.exports.safeWithBool = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (isSafeName(name)) { + cp.exec("rm -rf " + name); // OK + } + + cp.exec("rm -rf " + name); // NOT OK + + if (isSafeName(name) === true) { + cp.exec("rm -rf " + name); // OK + } + + if (isSafeName(name) !== false) { + cp.exec("rm -rf " + name); // OK + } + + if (isSafeName(name) == false) { + cp.exec("rm -rf " + name); // NOT OK + } + + cp.exec("rm -rf " + name); // NOT OK +} diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index dd11457f520..f752ea6427f 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -68,17 +68,6 @@ nodes | json-schema-validator.js:59:22:59:26 | query | | json-schema-validator.js:61:22:61:26 | query | | json-schema-validator.js:61:22:61:26 | query | -| koarouter.js:5:11:5:33 | version | -| koarouter.js:5:13:5:19 | version | -| koarouter.js:5:13:5:19 | version | -| koarouter.js:11:11:11:28 | conditions | -| koarouter.js:11:24:11:28 | ['1'] | -| koarouter.js:14:25:14:46 | `versio ... rsion}` | -| koarouter.js:14:38:14:44 | version | -| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | -| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | -| koarouter.js:17:52:17:61 | conditions | -| koarouter.js:17:52:17:75 | conditi ... and ') | | ldap.js:20:7:20:34 | q | | ldap.js:20:11:20:34 | url.par ... , true) | | ldap.js:20:21:20:27 | req.url | @@ -493,16 +482,6 @@ edges | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | json-schema-validator.js:50:15:50:48 | query | | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:50:23:50:48 | JSON.pa ... y.data) | -| koarouter.js:5:11:5:33 | version | koarouter.js:14:38:14:44 | version | -| koarouter.js:5:13:5:19 | version | koarouter.js:5:11:5:33 | version | -| koarouter.js:5:13:5:19 | version | koarouter.js:5:11:5:33 | version | -| koarouter.js:11:11:11:28 | conditions | koarouter.js:17:52:17:61 | conditions | -| koarouter.js:11:24:11:28 | ['1'] | koarouter.js:11:11:11:28 | conditions | -| koarouter.js:14:25:14:46 | `versio ... rsion}` | koarouter.js:11:24:11:28 | ['1'] | -| koarouter.js:14:38:14:44 | version | koarouter.js:14:25:14:46 | `versio ... rsion}` | -| koarouter.js:17:52:17:61 | conditions | koarouter.js:17:52:17:75 | conditi ... and ') | -| koarouter.js:17:52:17:75 | conditi ... and ') | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | -| koarouter.js:17:52:17:75 | conditi ... and ') | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | | ldap.js:20:7:20:34 | q | ldap.js:22:18:22:18 | q | | ldap.js:20:11:20:34 | url.par ... , true) | ldap.js:20:7:20:34 | q | | ldap.js:20:21:20:27 | req.url | ldap.js:20:11:20:34 | url.par ... , true) | @@ -950,7 +929,6 @@ edges | json-schema-validator.js:55:22:55:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:55:22:55:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | | json-schema-validator.js:59:22:59:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:59:22:59:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | | json-schema-validator.js:61:22:61:26 | query | json-schema-validator.js:50:34:50:47 | req.query.data | json-schema-validator.js:61:22:61:26 | query | This query depends on a $@. | json-schema-validator.js:50:34:50:47 | req.query.data | user-provided value | -| koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | koarouter.js:5:13:5:19 | version | koarouter.js:17:27:17:77 | `SELECT ... nd ')}` | This query depends on a $@. | koarouter.js:5:13:5:19 | version | user-provided value | | ldap.js:28:30:28:34 | opts1 | ldap.js:20:21:20:27 | req.url | ldap.js:28:30:28:34 | opts1 | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | | ldap.js:32:5:32:61 | { filte ... e}))` } | ldap.js:20:21:20:27 | req.url | ldap.js:32:5:32:61 | { filte ... e}))` } | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | | ldap.js:66:30:66:53 | { filte ... ilter } | ldap.js:20:21:20:27 | req.url | ldap.js:66:30:66:53 | { filte ... ilter } | This query depends on a $@. | ldap.js:20:21:20:27 | req.url | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js index 6331d15d7e6..bc21bb58f4a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/koarouter.js @@ -14,7 +14,7 @@ new Router().get("/hello", (ctx) => { conditions.push(`version = ${version}`) } - new Sequelize().query(`SELECT * FROM t WHERE ${conditions.join(' and ')}`, null); // OK - but still flagged [INCONSISTENCY] + new Sequelize().query(`SELECT * FROM t WHERE ${conditions.join(' and ')}`, null); // OK }); function validVersion(version) { From 943bdeca6d74dac8eb3bd2eff7d76ed8b820d0f3 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Wed, 21 Dec 2022 10:46:43 +0100 Subject: [PATCH 226/415] make `appliesTo` recursive --- .../javascript/dataflow/Configuration.qll | 30 ++++++++-------- .../UnsafeShellCommandConstruction.expected | 23 ++++++++++++ .../UnsafeShellCommandConstruction/lib/lib.js | 36 +++++++++++++++++++ 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll index b741d756037..86309cb1a6c 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Configuration.qll @@ -161,7 +161,7 @@ abstract class Configuration extends string { */ predicate isBarrier(DataFlow::Node node) { exists(BarrierGuardNode guard | - isBarrierGuardInternal(guard) and + isBarrierGuardInternal(this, guard) and barrierGuardBlocksNode(guard, node, "") ) } @@ -181,7 +181,7 @@ abstract class Configuration extends string { */ predicate isLabeledBarrier(DataFlow::Node node, FlowLabel lbl) { exists(BarrierGuardNode guard | - isBarrierGuardInternal(guard) and + isBarrierGuardInternal(this, guard) and barrierGuardBlocksNode(guard, node, lbl) ) or @@ -198,17 +198,6 @@ abstract class Configuration extends string { */ predicate isBarrierGuard(BarrierGuardNode guard) { none() } - /** - * Holds if `guard` is a barrier guard for this configuration, added through - * `isBarrierGuard` or `AdditionalBarrierGuardNode`. - */ - pragma[nomagic] - private predicate isBarrierGuardInternal(BarrierGuardNode guard) { - isBarrierGuard(guard) - or - guard.(AdditionalBarrierGuardNode).appliesTo(this) - } - /** * Holds if data may flow from `source` to `sink` for this configuration. */ @@ -267,6 +256,17 @@ abstract class Configuration extends string { } } +/** + * Holds if `guard` is a barrier guard for this configuration, added through + * `isBarrierGuard` or `AdditionalBarrierGuardNode`. + */ +pragma[nomagic] +private predicate isBarrierGuardInternal(Configuration cfg, BarrierGuardNode guard) { + cfg.isBarrierGuard(guard) + or + guard.(AdditionalBarrierGuardNode).appliesTo(cfg) +} + /** * A label describing the kind of information tracked by a flow configuration. * @@ -1981,7 +1981,7 @@ private class BarrierGuardFunction extends Function { /** * Holds if this function applies to the flow in `cfg`. */ - predicate appliesTo(Configuration cfg) { cfg.isBarrierGuard(guard) } + predicate appliesTo(Configuration cfg) { isBarrierGuardInternal(cfg, guard) } } /** @@ -2034,7 +2034,7 @@ private class CallAgainstEqualityCheck extends AdditionalBarrierGuardNode { ) } - override predicate appliesTo(Configuration cfg) { cfg.isBarrierGuard(prev) } + override predicate appliesTo(Configuration cfg) { isBarrierGuardInternal(cfg, prev) } } /** 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 eaeb896cbc8..b4022c8550c 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 @@ -311,6 +311,14 @@ nodes | lib/lib.js:590:29:590:32 | name | | lib/lib.js:593:25:593:28 | name | | lib/lib.js:593:25:593:28 | name | +| lib/lib.js:608:42:608:45 | name | +| lib/lib.js:608:42:608:45 | name | +| lib/lib.js:609:22:609:25 | name | +| lib/lib.js:609:22:609:25 | name | +| lib/lib.js:626:29:626:32 | name | +| lib/lib.js:626:29:626:32 | name | +| lib/lib.js:629:25:629:28 | name | +| lib/lib.js:629:25:629:28 | 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 | @@ -729,6 +737,18 @@ edges | lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | | lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | | lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:609:22:609:25 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:609:22:609:25 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:609:22:609:25 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:609:22:609:25 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:626:29:626:32 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:626:29:626:32 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:626:29:626:32 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:626:29:626:32 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | +| lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629: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 | | lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name | @@ -856,6 +876,9 @@ edges | lib/lib.js:579:13:579:28 | "rm -rf " + name | lib/lib.js:572:41:572:44 | name | lib/lib.js:579:25:579:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:572:41:572:44 | name | library input | lib/lib.js:579:5:579:29 | cp.exec ... + name) | shell command | | lib/lib.js:590:17:590:32 | "rm -rf " + name | lib/lib.js:572:41:572:44 | name | lib/lib.js:590:29:590:32 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:572:41:572:44 | name | library input | lib/lib.js:590:9:590:33 | cp.exec ... + name) | shell command | | lib/lib.js:593:13:593:28 | "rm -rf " + name | lib/lib.js:572:41:572:44 | name | lib/lib.js:593:25:593:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:572:41:572:44 | name | library input | lib/lib.js:593:5:593:29 | cp.exec ... + name) | shell command | +| lib/lib.js:609:10:609:25 | "rm -rf " + name | lib/lib.js:608:42:608:45 | name | lib/lib.js:609:22:609:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:608:42:608:45 | name | library input | lib/lib.js:609:2:609:26 | cp.exec ... + name) | shell command | +| lib/lib.js:626:17:626:32 | "rm -rf " + name | lib/lib.js:608:42:608:45 | name | lib/lib.js:626:29:626:32 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:608:42:608:45 | name | library input | lib/lib.js:626:9:626:33 | cp.exec ... + name) | shell command | +| lib/lib.js:629:13:629:28 | "rm -rf " + name | lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:608:42:608:45 | name | library input | lib/lib.js:629:5:629:29 | cp.exec ... + name) | 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 c45a616e6bb..504de998c1c 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 @@ -592,3 +592,39 @@ module.exports.safeWithBool = function (name) { cp.exec("rm -rf " + name); // NOT OK } + +function indirectThing(name) { + return isSafeName(name); +} + +function indirectThing2(name) { + return isSafeName(name) === true; +} + +function moreIndirect(name) { + return indirectThing2(name) !== false; +} + +module.exports.veryIndeirect = function (name) { + cp.exec("rm -rf " + name); // NOT OK + + if (indirectThing(name)) { + cp.exec("rm -rf " + name); // OK + } + + if (indirectThing2(name)) { + cp.exec("rm -rf " + name); // OK + } + + if (moreIndirect(name)) { + cp.exec("rm -rf " + name); // OK + } + + if (moreIndirect(name) !== false) { + cp.exec("rm -rf " + name); // OK + } else { + cp.exec("rm -rf " + name); // NOT OK + } + + cp.exec("rm -rf " + name); // NOT OK +} From 36478124ae3488e9291ff213de3d063608b5cefb Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 13 Feb 2023 21:13:44 +0100 Subject: [PATCH 227/415] add process.env and process.argv etc. as source for `js/regex-injection` --- ...IndirectCommandInjectionCustomizations.qll | 7 +++++++ .../RegExpInjectionCustomizations.qll | 15 +++++++++++++- .../src/Security/CWE-730/RegExpInjection.ql | 2 +- .../Security/CWE-730/RegExpInjection.expected | 20 +++++++++++++++++++ .../Security/CWE-730/RegExpInjection.js | 6 ++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll index eed346d8d0b..814df3949a5 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll @@ -37,6 +37,13 @@ module IndirectCommandInjection { } } + /** + * A read of `process.env`, considered as a flow source for command injection. + */ + private class ProcessEnvAsSource extends Source { + ProcessEnvAsSource() { this = NodeJSLib::process().getAPropertyRead("env") } + } + /** * An object containing parsed command-line arguments, considered as a flow source for command injection. */ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll index ab9f3d90e02..f33956a4bd3 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll @@ -10,7 +10,10 @@ module RegExpInjection { /** * A data flow source for untrusted user input used to construct regular expressions. */ - abstract class Source extends DataFlow::Node { } + abstract class Source extends DataFlow::Node { + /** Gets a description of this source. */ + string describe() { result = "user-provided value" } + } /** * A data flow sink for untrusted user input used to construct regular expressions. @@ -30,6 +33,16 @@ module RegExpInjection { RemoteFlowSourceAsSource() { not this instanceof ClientSideRemoteFlowSource } } + private import IndirectCommandInjectionCustomizations + + /** + * A read of `process.env`, `process.argv`, and similar, considered as a flow source for regular + * expression injection. + */ + class ArgvAsSource extends Source instanceof IndirectCommandInjection::Source { + override string describe() { result = "command-line argument" } + } + /** * The source string of a regular expression. */ diff --git a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql index 8da2080d167..5b679cf1dcf 100644 --- a/javascript/ql/src/Security/CWE-730/RegExpInjection.ql +++ b/javascript/ql/src/Security/CWE-730/RegExpInjection.ql @@ -20,4 +20,4 @@ import DataFlow::PathGraph from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "This regular expression is constructed from a $@.", - source.getNode(), "user-provided value" + source.getNode(), source.getNode().(Source).describe() diff --git a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected index 7d24e94a590..1fb30b0dd3b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected @@ -56,6 +56,16 @@ nodes | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | | RegExpInjection.js:87:25:87:29 | input | | RegExpInjection.js:87:25:87:48 | input.r ... g, "\|") | +| RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | +| RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | +| RegExpInjection.js:91:20:91:30 | process.env | +| RegExpInjection.js:91:20:91:30 | process.env | +| RegExpInjection.js:91:20:91:35 | process.env.HOME | +| RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | +| RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | +| RegExpInjection.js:93:20:93:31 | process.argv | +| RegExpInjection.js:93:20:93:31 | process.argv | +| RegExpInjection.js:93:20:93:34 | process.argv[1] | | tst.js:1:46:1:46 | e | | tst.js:1:46:1:46 | e | | tst.js:2:9:2:21 | data | @@ -121,6 +131,14 @@ edges | RegExpInjection.js:87:25:87:29 | input | RegExpInjection.js:87:25:87:48 | input.r ... g, "\|") | | RegExpInjection.js:87:25:87:48 | input.r ... g, "\|") | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | | RegExpInjection.js:87:25:87:48 | input.r ... g, "\|") | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | +| RegExpInjection.js:91:20:91:30 | process.env | RegExpInjection.js:91:20:91:35 | process.env.HOME | +| RegExpInjection.js:91:20:91:30 | process.env | RegExpInjection.js:91:20:91:35 | process.env.HOME | +| RegExpInjection.js:91:20:91:35 | process.env.HOME | RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | +| RegExpInjection.js:91:20:91:35 | process.env.HOME | RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | +| RegExpInjection.js:93:20:93:31 | process.argv | RegExpInjection.js:93:20:93:34 | process.argv[1] | +| RegExpInjection.js:93:20:93:31 | process.argv | RegExpInjection.js:93:20:93:34 | process.argv[1] | +| RegExpInjection.js:93:20:93:34 | process.argv[1] | RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | +| RegExpInjection.js:93:20:93:34 | process.argv[1] | RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | | tst.js:1:46:1:46 | e | tst.js:2:16:2:16 | e | | tst.js:1:46:1:46 | e | tst.js:2:16:2:16 | e | | tst.js:2:9:2:21 | data | tst.js:3:21:3:24 | data | @@ -146,4 +164,6 @@ edges | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | | RegExpInjection.js:64:14:64:18 | input | RegExpInjection.js:60:39:60:56 | req.param("input") | RegExpInjection.js:64:14:64:18 | input | This regular expression is constructed from a $@. | RegExpInjection.js:60:39:60:56 | req.param("input") | user-provided value | | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | RegExpInjection.js:82:15:82:32 | req.param("input") | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | This regular expression is constructed from a $@. | RegExpInjection.js:82:15:82:32 | req.param("input") | user-provided value | +| RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | RegExpInjection.js:91:20:91:30 | process.env | RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:91:20:91:30 | process.env | command-line argument | +| RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | RegExpInjection.js:93:20:93:31 | process.argv | RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:93:20:93:31 | process.argv | command-line argument | | tst.js:3:16:3:35 | "^"+ data.name + "$" | tst.js:1:46:1:46 | e | tst.js:3:16:3:35 | "^"+ data.name + "$" | This regular expression is constructed from a $@. | tst.js:1:46:1:46 | e | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js index 3551a1ff72a..1f8113f7d75 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js +++ b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js @@ -86,3 +86,9 @@ app.get('/has-sanitizer', function(req, res) { new RegExp("^.*\.(" + input.replace(/,/g, "|") + ")$"); // NOT OK }); + +app.get("argv", function(req, res) { + new RegExp(`^${process.env.HOME}/Foo/bar.app$`); // NOT OK + + new RegExp(`^${process.argv[1]}/Foo/bar.app$`); // NOT OK +}); From 4f7c598ffcfdb20981b371cd5793e3208de6405f Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 14 Feb 2023 13:22:48 +0000 Subject: [PATCH 228/415] Python: Add change note --- .../released/2023-02-14-python-2-no-longer-supported.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 python/ql/lib/change-notes/released/2023-02-14-python-2-no-longer-supported.md diff --git a/python/ql/lib/change-notes/released/2023-02-14-python-2-no-longer-supported.md b/python/ql/lib/change-notes/released/2023-02-14-python-2-no-longer-supported.md new file mode 100644 index 00000000000..a15dda02da9 --- /dev/null +++ b/python/ql/lib/change-notes/released/2023-02-14-python-2-no-longer-supported.md @@ -0,0 +1,7 @@ +--- +category: breaking +--- +- Python 2 is no longer supported for extracting databases using the CodeQL CLI. As a consequence, + the previously deprecated support for `pyxl` and `spitfire` templates has also been removed. When + extracting Python 2 code, having Python 2 installed is still recommended, as this ensures the + correct version of the Python standard library is extracted. From 4644a88b89da9c61364cb9485527d29a28025aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Tue, 14 Feb 2023 14:27:17 +0100 Subject: [PATCH 229/415] address code review comments --- ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll | 29 +++++++++---------- .../library-tests/frameworks/Twirp/Twirp.ql | 8 ++--- .../frameworks/Twirp/tests.expected | 1 - 3 files changed, 17 insertions(+), 21 deletions(-) delete mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/tests.expected diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll index 821e3486f8a..30141b76961 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Twirp.qll @@ -19,32 +19,30 @@ module Twirp { class ServiceInstantiation extends DataFlow::CallNode { ServiceInstantiation() { this = - API::getTopLevelMember("Twirp").getMember("Service").getASubclass*().getAnInstantiation() + API::getTopLevelMember("Twirp").getMember("Service").getASubclass().getAnInstantiation() } /** * Gets a local source node for the Service instantiation argument (the service handler). */ - DataFlow::LocalSourceNode getHandlerSource() { result = this.getArgument(0).getALocalSource() } + private DataFlow::LocalSourceNode getHandlerSource() { + result = this.getArgument(0).getALocalSource() + } /** * Gets the API::Node for the service handler's class. */ - API::Node getHandlerClassApiNode() { result.getAnInstantiation() = this.getHandlerSource() } - - /** - * Gets the local source node for the service handler's class. - */ - DataFlow::LocalSourceNode getHandlerClassDataFlowNode() { - result = this.getHandlerClassApiNode().asSource() + private API::Node getAHandlerClassApiNode() { + result.getAnInstantiation() = this.getHandlerSource() } /** * Gets the AST module for the service handler's class. */ - Ast::Module getHandlerClassAstNode() { + private Ast::Module getAHandlerClassAstNode() { result = - this.getHandlerClassDataFlowNode() + this.getAHandlerClassApiNode() + .asSource() .asExpr() .(CfgNodes::ExprNodes::ConstantReadAccessCfgNode) .getExpr() @@ -54,7 +52,9 @@ module Twirp { /** * Gets a handler's method. */ - Ast::Method getHandlerMethod() { result = this.getHandlerClassAstNode().getAnInstanceMethod() } + Ast::Method getAHandlerMethod() { + result = this.getAHandlerClassAstNode().getAnInstanceMethod() + } } /** @@ -62,8 +62,7 @@ module Twirp { */ class ClientInstantiation extends DataFlow::CallNode { ClientInstantiation() { - this = - API::getTopLevelMember("Twirp").getMember("Client").getASubclass*().getAnInstantiation() + this = API::getTopLevelMember("Twirp").getMember("Client").getASubclass().getAnInstantiation() } } @@ -76,7 +75,7 @@ module Twirp { class UnmarshaledParameter extends Http::Server::RequestInputAccess::Range, DataFlow::ParameterNode { UnmarshaledParameter() { - exists(ServiceInstantiation i | i.getHandlerMethod().getParameter(0) = this.asParameter()) + exists(ServiceInstantiation i | i.getAHandlerMethod().getParameter(0) = this.asParameter()) } override string getSourceType() { result = "Twirp Unmarhaled Parameter" } diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql index e6b1c36bde4..4c0494f9100 100644 --- a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql +++ b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.ql @@ -1,10 +1,8 @@ private import codeql.ruby.frameworks.Twirp private import codeql.ruby.DataFlow -query predicate sourceTest(DataFlow::Node s) { s instanceof Twirp::UnmarshaledParameter } +query predicate sourceTest(Twirp::UnmarshaledParameter source) { any() } -query predicate ssrfSinkTest(DataFlow::Node n) { n instanceof Twirp::ServiceUrlAsSsrfSink } +query predicate ssrfSinkTest(Twirp::ServiceUrlAsSsrfSink sink) { any() } -query predicate serviceInstantiationTest(DataFlow::Node n) { - n instanceof Twirp::ServiceInstantiation -} +query predicate serviceInstantiationTest(Twirp::ServiceInstantiation si) { any() } diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/tests.expected b/ruby/ql/test/library-tests/frameworks/Twirp/tests.expected deleted file mode 100644 index 429c96f804a..00000000000 --- a/ruby/ql/test/library-tests/frameworks/Twirp/tests.expected +++ /dev/null @@ -1 +0,0 @@ -The query depends on an extensional predicate sinkModel which has not been defined. From 393649b7ce258ea8c3bfde7bec267102af1f0285 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Tue, 14 Feb 2023 14:27:41 +0100 Subject: [PATCH 230/415] don't call environment variables for command-line arguments --- .../dataflow/IndirectCommandInjectionCustomizations.qll | 7 ++++++- .../security/dataflow/RegExpInjectionCustomizations.qll | 2 +- .../ql/src/Security/CWE-078/IndirectCommandInjection.ql | 2 +- .../query-tests/Security/CWE-730/RegExpInjection.expected | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll index 814df3949a5..14fbcd4f400 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll @@ -10,7 +10,10 @@ module IndirectCommandInjection { /** * A data flow source for command-injection vulnerabilities. */ - abstract class Source extends DataFlow::Node { } + abstract class Source extends DataFlow::Node { + /** Gets a description of this source. */ + string describe() { result = "command-line argument" } + } /** * A data flow sink for command-injection vulnerabilities. @@ -42,6 +45,8 @@ module IndirectCommandInjection { */ private class ProcessEnvAsSource extends Source { ProcessEnvAsSource() { this = NodeJSLib::process().getAPropertyRead("env") } + + override string describe() { result = "environment variable" } } /** diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll index f33956a4bd3..6f2499c7fe4 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll @@ -40,7 +40,7 @@ module RegExpInjection { * expression injection. */ class ArgvAsSource extends Source instanceof IndirectCommandInjection::Source { - override string describe() { result = "command-line argument" } + override string describe() { result = IndirectCommandInjection::Source.super.describe() } } /** diff --git a/javascript/ql/src/Security/CWE-078/IndirectCommandInjection.ql b/javascript/ql/src/Security/CWE-078/IndirectCommandInjection.ql index 7520a95ed9c..34f89023441 100644 --- a/javascript/ql/src/Security/CWE-078/IndirectCommandInjection.ql +++ b/javascript/ql/src/Security/CWE-078/IndirectCommandInjection.ql @@ -25,4 +25,4 @@ where then cfg.isSinkWithHighlight(sink.getNode(), highlight) else highlight = sink.getNode() select highlight, source, sink, "This command depends on an unsanitized $@.", source.getNode(), - "command-line argument" + source.getNode().(Source).describe() diff --git a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected index 1fb30b0dd3b..693ef9e5e95 100644 --- a/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.expected @@ -164,6 +164,6 @@ edges | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | RegExpInjection.js:5:13:5:28 | req.param("key") | RegExpInjection.js:54:14:54:52 | key.spl ... in("-") | This regular expression is constructed from a $@. | RegExpInjection.js:5:13:5:28 | req.param("key") | user-provided value | | RegExpInjection.js:64:14:64:18 | input | RegExpInjection.js:60:39:60:56 | req.param("input") | RegExpInjection.js:64:14:64:18 | input | This regular expression is constructed from a $@. | RegExpInjection.js:60:39:60:56 | req.param("input") | user-provided value | | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | RegExpInjection.js:82:15:82:32 | req.param("input") | RegExpInjection.js:87:14:87:55 | "^.*\\.( ... + ")$" | This regular expression is constructed from a $@. | RegExpInjection.js:82:15:82:32 | req.param("input") | user-provided value | -| RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | RegExpInjection.js:91:20:91:30 | process.env | RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:91:20:91:30 | process.env | command-line argument | +| RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | RegExpInjection.js:91:20:91:30 | process.env | RegExpInjection.js:91:16:91:50 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:91:20:91:30 | process.env | environment variable | | RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | RegExpInjection.js:93:20:93:31 | process.argv | RegExpInjection.js:93:16:93:49 | `^${pro ... r.app$` | This regular expression is constructed from a $@. | RegExpInjection.js:93:20:93:31 | process.argv | command-line argument | | tst.js:3:16:3:35 | "^"+ data.name + "$" | tst.js:1:46:1:46 | e | tst.js:3:16:3:35 | "^"+ data.name + "$" | This regular expression is constructed from a $@. | tst.js:1:46:1:46 | e | user-provided value | From 1b30043422b70e55ad8ae876e7df672ff9c7a4c5 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 14 Feb 2023 13:48:55 +0000 Subject: [PATCH 231/415] Python: Move change note to correct directory --- .../{released => }/2023-02-14-python-2-no-longer-supported.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/ql/lib/change-notes/{released => }/2023-02-14-python-2-no-longer-supported.md (100%) diff --git a/python/ql/lib/change-notes/released/2023-02-14-python-2-no-longer-supported.md b/python/ql/lib/change-notes/2023-02-14-python-2-no-longer-supported.md similarity index 100% rename from python/ql/lib/change-notes/released/2023-02-14-python-2-no-longer-supported.md rename to python/ql/lib/change-notes/2023-02-14-python-2-no-longer-supported.md From 8d90c02a6726bf7c05a21fce12f7258838153e96 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 14 Feb 2023 15:24:22 +0000 Subject: [PATCH 232/415] JS: remove unused field --- .../ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll index 8ebae47d840..21d23f517f3 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/CryptoLibraries.qll @@ -149,7 +149,6 @@ private module BrowserIdCrypto { */ private module NodeJSCrypto { private class InstantiatedAlgorithm extends DataFlow::CallNode { - CryptographicAlgorithm algorithm; // non-functional private string algorithmName; InstantiatedAlgorithm() { @@ -169,12 +168,11 @@ private module NodeJSCrypto { exists(DataFlow::SourceNode mod | mod = DataFlow::moduleImport("crypto") and this = mod.getAMemberCall("create" + ["Hash", "Hmac", "Sign", "Cipher"]) and - algorithmName = this.getArgument(0).getStringValue() and - algorithm.matchesName(algorithmName) + algorithmName = this.getArgument(0).getStringValue() ) } - CryptographicAlgorithm getAlgorithm() { result = algorithm } + CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) } private BlockMode getExplicitBlockMode() { result.matchesString(algorithmName) } From 3514dd1e4dc6f165855cac34f2d594cc685bda31 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 6 Feb 2023 21:08:27 +0000 Subject: [PATCH 233/415] Java: merge the @class and @interface database types and tables This will allow the extractor to emit class(id, ...) when all it knows about a class is its name, due to not having it available on the classpath. Previously it would have had to guess whether it belonged to @class or @interface, possibly introducing an inconsistency. --- .../classes.ql | 11 + .../interfaces.ql | 11 + .../old.dbscheme | 1242 + .../semmlecode.dbscheme | 1246 + .../upgrade.properties | 5 + .../src/main/kotlin/KotlinFileExtractor.kt | 52 +- .../src/main/kotlin/KotlinUsesExtractor.kt | 20 +- java/ql/lib/config/semmlecode.dbscheme | 42 +- java/ql/lib/semmle/code/Location.qll | 4 +- java/ql/lib/semmle/code/java/Type.qll | 21 +- .../classes_or_interfaces.ql | 11 + .../isInterface.ql | 6 + .../old.dbscheme | 1246 + .../semmlecode.dbscheme | 1242 + .../semmlecode.dbscheme.stats | 26852 ++++++++++++++++ .../upgrade.properties | 4 + .../library-tests/qlengine/selectAtType.ql | 2 +- 17 files changed, 31939 insertions(+), 78 deletions(-) create mode 100644 java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/classes.ql create mode 100644 java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/interfaces.ql create mode 100644 java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/old.dbscheme create mode 100644 java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/semmlecode.dbscheme create mode 100644 java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties create mode 100644 java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/classes_or_interfaces.ql create mode 100644 java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/isInterface.ql create mode 100644 java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/old.dbscheme create mode 100644 java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme create mode 100644 java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme.stats create mode 100644 java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties diff --git a/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/classes.ql b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/classes.ql new file mode 100644 index 00000000000..82123848cb7 --- /dev/null +++ b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/classes.ql @@ -0,0 +1,11 @@ +class ClassOrInterface extends @classorinterface { + string toString() { result = "class-or-interface" } +} + +class Package extends @package { + string toString() { result = "package" } +} + +from ClassOrInterface id, string nodeName, Package parentId, ClassOrInterface sourceId +where classes_or_interfaces(id, nodeName, parentId, sourceId) and not isInterface(id) +select id, nodeName, parentId, sourceId diff --git a/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/interfaces.ql b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/interfaces.ql new file mode 100644 index 00000000000..83d804fcf80 --- /dev/null +++ b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/interfaces.ql @@ -0,0 +1,11 @@ +class ClassOrInterface extends @classorinterface { + string toString() { result = "class-or-interface" } +} + +class Package extends @package { + string toString() { result = "package" } +} + +from ClassOrInterface id, string nodeName, Package parentId, ClassOrInterface sourceId +where classes_or_interfaces(id, nodeName, parentId, sourceId) and isInterface(id) +select id, nodeName, parentId, sourceId diff --git a/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/old.dbscheme b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/old.dbscheme new file mode 100644 index 00000000000..934bf10b4bd --- /dev/null +++ b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/old.dbscheme @@ -0,0 +1,1242 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#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 + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +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 +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int 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 +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * 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; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/semmlecode.dbscheme b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/semmlecode.dbscheme new file mode 100644 index 00000000000..44d61b266be --- /dev/null +++ b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/semmlecode.dbscheme @@ -0,0 +1,1246 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#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 + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +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 +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int 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 +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes( + unique int id: @class, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @class ref +); + +file_class( + int id: @class ref +); + +class_object( + unique int id: @class ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @class ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isRecord( + unique int id: @class ref +); + +interfaces( + unique int id: @interface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @interface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @interface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @class ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @class ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @interface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterface = @interface | @class; +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @class | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @class | @interface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @class | @interface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * 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; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @class ref +) diff --git a/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties new file mode 100644 index 00000000000..52c95780abc --- /dev/null +++ b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties @@ -0,0 +1,5 @@ +description: Seperate class and interface tables +compatibility: full +classes.rel: run classes.qlo +interfaces.rel: run interfaces.qlo +isInterface.rel: delete diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 793d7b15b6f..b93bfa369f5 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -351,18 +351,14 @@ open class KotlinFileExtractor( val pkgId = extractPackage(pkg) // TODO: There's lots of duplication between this and extractClassSource. // Can we share it? + val sourceId = useClassSource(c) + tw.writeClasses_or_interfaces(id, cls, pkgId, sourceId) if (c.isInterfaceLike) { - val interfaceId = id.cast() - val sourceInterfaceId = useClassSource(c).cast() - tw.writeInterfaces(interfaceId, cls, pkgId, sourceInterfaceId) + tw.writeIsInterface(id) } else { - val classId = id.cast() - val sourceClassId = useClassSource(c).cast() - tw.writeClasses(classId, cls, pkgId, sourceClassId) - val kind = c.kind if (kind == ClassKind.ENUM_CLASS) { - tw.writeIsEnumType(classId) + tw.writeIsEnumType(id) } else if (kind != ClassKind.CLASS && kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) { logger.errorElement("Unrecognised class kind $kind", c) } @@ -459,11 +455,11 @@ open class KotlinFileExtractor( } private fun extractLocalTypeDeclStmt(c: IrClass, callable: Label, parent: Label, idx: Int) { - val id = extractClassSource(c, extractDeclarations = true, extractStaticInitializer = true, extractPrivateMembers = true, extractFunctionBodies = true).cast() + val id = extractClassSource(c, extractDeclarations = true, extractStaticInitializer = true, extractPrivateMembers = true, extractFunctionBodies = true) extractLocalTypeDeclStmt(id, c, callable, parent, idx) } - private fun extractLocalTypeDeclStmt(id: Label, locElement: IrElement, callable: Label, parent: Label, idx: Int) { + private fun extractLocalTypeDeclStmt(id: Label, locElement: IrElement, callable: Label, parent: Label, idx: Int) { val stmtId = tw.getFreshIdLabel() tw.writeStmts_localtypedeclstmt(stmtId, parent, idx, callable) tw.writeIsLocalClassOrInterface(id, stmtId) @@ -630,26 +626,22 @@ open class KotlinFileExtractor( val pkg = c.packageFqName?.asString() ?: "" val cls = if (c.isAnonymousObject) "" else c.name.asString() val pkgId = extractPackage(pkg) + tw.writeClasses_or_interfaces(id, cls, pkgId, id) if (c.isInterfaceLike) { - val interfaceId = id.cast() - tw.writeInterfaces(interfaceId, cls, pkgId, interfaceId) - + tw.writeIsInterface(id) if (c.kind == ClassKind.ANNOTATION_CLASS) { - tw.writeIsAnnotType(interfaceId) + tw.writeIsAnnotType(id) } } else { - val classId = id.cast() - tw.writeClasses(classId, cls, pkgId, classId) - val kind = c.kind if (kind == ClassKind.ENUM_CLASS) { - tw.writeIsEnumType(classId) + tw.writeIsEnumType(id) } else if (kind != ClassKind.CLASS && kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) { logger.warnElement("Unrecognised class kind $kind", c) } if (c.isData) { - tw.writeKtDataClasses(classId) + tw.writeKtDataClasses(id) } } @@ -694,7 +686,7 @@ open class KotlinFileExtractor( tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id) tw.writeHasLocation(instance.id, locId) addModifiers(instance.id, "public", "static", "final") - tw.writeClass_object(id.cast(), instance.id) + tw.writeClass_object(id, instance.id) } if (c.isObject) { addModifiers(id, "static") @@ -830,7 +822,7 @@ open class KotlinFileExtractor( tw.writeFieldsKotlinType(instance.id, type.kotlinResult.id) tw.writeHasLocation(instance.id, innerLocId) addModifiers(instance.id, "public", "static", "final") - tw.writeType_companion_object(parentId, instance.id, innerId.cast()) + tw.writeType_companion_object(parentId, instance.id, innerId) } } @@ -4448,7 +4440,7 @@ open class KotlinFileExtractor( } private open inner class GeneratedClassHelper(protected val locId: Label, protected val ids: GeneratedClassLabels) { - protected val classId = ids.type.javaResult.id.cast() + protected val classId = ids.type.javaResult.id.cast() /** * Extract a parameter to field assignment, such as `this.field = paramName` below: @@ -4788,7 +4780,7 @@ open class KotlinFileExtractor( val locId = tw.getLocation(propertyReferenceExpr) - val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") + val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") val kotlinResult = TypeResult(tw.getFreshIdLabel(), "", "") tw.writeKt_notnull_types(kotlinResult.id, javaResult.id) val ids = GeneratedClassLabels( @@ -4980,7 +4972,7 @@ open class KotlinFileExtractor( val locId = tw.getLocation(functionReferenceExpr) - val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") + val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") val kotlinResult = TypeResult(tw.getFreshIdLabel(), "", "") tw.writeKt_notnull_types(kotlinResult.id, javaResult.id) val ids = LocallyVisibleFunctionLabels( @@ -5550,7 +5542,7 @@ open class KotlinFileExtractor( return } - val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") + val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") val kotlinResult = TypeResult(tw.getFreshIdLabel(), "", "") tw.writeKt_notnull_types(kotlinResult.id, javaResult.id) val ids = LocallyVisibleFunctionLabels( @@ -5659,7 +5651,7 @@ open class KotlinFileExtractor( val idNewexpr = extractNewExpr(ids.constructor, ids.type, locId, id, 1, callable, enclosingStmt) - tw.writeIsAnonymClass(ids.type.javaResult.id.cast(), idNewexpr) + tw.writeIsAnonymClass(ids.type.javaResult.id.cast(), idNewexpr) extractTypeAccessRecursive(e.typeOperand, locId, idNewexpr, -3, callable, enclosingStmt) @@ -5705,11 +5697,11 @@ open class KotlinFileExtractor( compilerGeneratedKindOverride: CompilerGeneratedKinds? = null, superConstructorSelector: (IrFunction) -> Boolean = { it.valueParameters.isEmpty() }, extractSuperconstructorArgs: (Label) -> Unit = {}, - ): Label { + ): Label { // Write class - val id = ids.type.javaResult.id.cast() + val id = ids.type.javaResult.id.cast() val pkgId = extractPackage("") - tw.writeClasses(id, "", pkgId, id) + tw.writeClasses_or_interfaces(id, "", pkgId, id) tw.writeCompiler_generated(id, (compilerGeneratedKindOverride ?: CompilerGeneratedKinds.CALLABLE_CLASS).kind) tw.writeHasLocation(id, locId) @@ -5761,7 +5753,7 @@ open class KotlinFileExtractor( localFunction: IrFunction, superTypes: List, compilerGeneratedKindOverride: CompilerGeneratedKinds? = null - ) : Label { + ) : Label { with("generated class", localFunction) { val ids = getLocallyVisibleFunctionLabels(localFunction) diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 92fc961dd0f..c72f094808b 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -71,16 +71,16 @@ open class KotlinUsesExtractor( TypeResult(fakeKotlinType(), "", "") ) - fun extractFileClass(f: IrFile): Label { + fun extractFileClass(f: IrFile): Label { val pkg = f.fqName.asString() val jvmName = getFileClassName(f) val qualClassName = if (pkg.isEmpty()) jvmName else "$pkg.$jvmName" val label = "@\"class;$qualClassName\"" - val id: Label = tw.getLabelFor(label) { + val id: Label = tw.getLabelFor(label) { val fileId = tw.mkFileId(f.path, false) val locId = tw.getWholeFileLocation(fileId) val pkgId = extractPackage(pkg) - tw.writeClasses(it, jvmName, pkgId, it) + tw.writeClasses_or_interfaces(it, jvmName, pkgId, it) tw.writeFile_class(it) tw.writeHasLocation(it, locId) @@ -478,7 +478,7 @@ open class KotlinUsesExtractor( private fun useAnonymousClass(c: IrClass) = tw.lm.anonymousTypeMapping.getOrPut(c) { TypeResults( - TypeResult(tw.getFreshIdLabel(), "", ""), + TypeResult(tw.getFreshIdLabel(), "", ""), TypeResult(fakeKotlinType(), "TODO", "TODO") ) } @@ -487,8 +487,8 @@ open class KotlinUsesExtractor( val fakeKotlinPackageId: Label = tw.getLabelFor("@\"FakeKotlinPackage\"", { tw.writePackages(it, "fake.kotlin") }) - val fakeKotlinClassId: Label = tw.getLabelFor("@\"FakeKotlinClass\"", { - tw.writeClasses(it, "FakeKotlinClass", fakeKotlinPackageId, it) + val fakeKotlinClassId: Label = tw.getLabelFor("@\"FakeKotlinClass\"", { + tw.writeClasses_or_interfaces(it, "FakeKotlinClass", fakeKotlinPackageId, it) }) val fakeKotlinTypeId: Label = tw.getLabelFor("@\"FakeKotlinType\"", { tw.writeKt_nullable_types(it, fakeKotlinClassId) @@ -650,11 +650,11 @@ open class KotlinUsesExtractor( // We use this when we don't actually have an IrClass for a class // we want to refer to // TODO: Eliminate the need for this if possible - fun makeClass(pkgName: String, className: String): Label { + fun makeClass(pkgName: String, className: String): Label { val pkgId = extractPackage(pkgName) val label = "@\"class;$pkgName.$className\"" - val classId: Label = tw.getLabelFor(label, { - tw.writeClasses(it, className, pkgId, it) + val classId: Label = tw.getLabelFor(label, { + tw.writeClasses_or_interfaces(it, className, pkgId, it) }) return classId } @@ -1237,7 +1237,7 @@ open class KotlinUsesExtractor( var res = tw.lm.locallyVisibleFunctionLabelMapping[f] if (res == null) { - val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") + val javaResult = TypeResult(tw.getFreshIdLabel(), "", "") val kotlinResult = TypeResult(tw.getFreshIdLabel(), "", "") tw.writeKt_notnull_types(kotlinResult.id, javaResult.id) res = LocallyVisibleFunctionLabels( diff --git a/java/ql/lib/config/semmlecode.dbscheme b/java/ql/lib/config/semmlecode.dbscheme index 44d61b266be..934bf10b4bd 100644 --- a/java/ql/lib/config/semmlecode.dbscheme +++ b/java/ql/lib/config/semmlecode.dbscheme @@ -346,26 +346,26 @@ error_type( unique int id: @errortype ); -classes( - unique int id: @class, +classes_or_interfaces( + unique int id: @classorinterface, string nodeName: string ref, int parentid: @package ref, - int sourceid: @class ref + int sourceid: @classorinterface ref ); file_class( - int id: @class ref + int id: @classorinterface ref ); class_object( - unique int id: @class ref, + unique int id: @classorinterface ref, unique int instance: @field ref ); type_companion_object( unique int id: @classorinterface ref, unique int instance: @field ref, - unique int companion_object: @class ref + unique int companion_object: @classorinterface ref ); kt_nullable_types( @@ -386,15 +386,12 @@ kt_type_alias( @kt_type = @kt_nullable_type | @kt_notnull_type -isRecord( - unique int id: @class ref +isInterface( + unique int id: @classorinterface ref ); -interfaces( - unique int id: @interface, - string nodeName: string ref, - int parentid: @package ref, - int sourceid: @interface ref +isRecord( + unique int id: @classorinterface ref ); fielddecls( @@ -480,7 +477,7 @@ exceptions( ); isAnnotType( - int interfaceid: @interface ref + int interfaceid: @classorinterface ref ); isAnnotElem( @@ -494,7 +491,7 @@ annotValue( ); isEnumType( - int classid: @class ref + int classid: @classorinterface ref ); isEnumConst( @@ -546,7 +543,7 @@ erasure( #keyset[classid] #keyset[parent] isAnonymClass( - int classid: @class ref, + int classid: @classorinterface ref, int parent: @classinstancexpr ref ); @@ -586,7 +583,7 @@ extendsReftype( implInterface( int id1: @classorarray ref, - int id2: @interface ref + int id2: @classorinterface ref ); permits( @@ -868,7 +865,7 @@ propertyRefSetBinding( int setter: @callable ref ); -@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable; +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; variableBinding( unique int expr: @varaccess ref, @@ -1022,12 +1019,11 @@ javadocText( @javadocParent = @javadoc | @javadocTag; @javadocElement = @javadocTag | @javadocText; -@classorinterface = @interface | @class; @classorinterfaceorpackage = @classorinterface | @package; @classorinterfaceorcallable = @classorinterface | @callable; @boundedtype = @typevariable | @wildcard; @reftype = @classorinterface | @array | @boundedtype | @errortype; -@classorarray = @class | @array; +@classorarray = @classorinterface | @array; @type = @primitive | @reftype; @callable = @method | @constructor; @@ -1035,13 +1031,13 @@ javadocText( @element = @package | @modifier | @annotation | @errortype | @locatableElement; -@locatableElement = @file | @primitive | @class | @interface | @method | @constructor | @param | @exception | @field | +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | @kt_property; @modifiable = @member_modifiable| @param | @localvar | @typevariable; -@member_modifiable = @class | @interface | @method | @constructor | @field | @kt_property; +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; @member = @method | @constructor | @field | @reftype ; @@ -1242,5 +1238,5 @@ ktFunctionOriginalNames( ) ktDataClasses( - unique int id: @class ref + unique int id: @classorinterface ref ) diff --git a/java/ql/lib/semmle/code/Location.qll b/java/ql/lib/semmle/code/Location.qll index 256b831a8ad..8b53254893b 100644 --- a/java/ql/lib/semmle/code/Location.qll +++ b/java/ql/lib/semmle/code/Location.qll @@ -10,9 +10,7 @@ private import semmle.code.SMAP /** Holds if element `e` has name `name`. */ predicate hasName(Element e, string name) { - classes(e, name, _, _) - or - interfaces(e, name, _, _) + classes_or_interfaces(e, name, _, _) or primitives(e, name) or diff --git a/java/ql/lib/semmle/code/java/Type.qll b/java/ql/lib/semmle/code/java/Type.qll index eff61ed0fde..f0b79ee945c 100644 --- a/java/ql/lib/semmle/code/java/Type.qll +++ b/java/ql/lib/semmle/code/java/Type.qll @@ -385,10 +385,7 @@ class Array extends RefType, @array { */ class RefType extends Type, Annotatable, Modifiable, @reftype { /** Gets the package in which this type is declared. */ - Package getPackage() { - classes(this, _, result, _) or - interfaces(this, _, result, _) - } + Package getPackage() { classes_or_interfaces(this, _, result, _) } /** Gets the type in which this reference type is enclosed, if any. */ RefType getEnclosingType() { enclInReftype(this, result) } @@ -685,12 +682,12 @@ class SrcRefType extends RefType { } /** A class declaration. */ -class Class extends ClassOrInterface, @class { +class Class extends ClassOrInterface { + Class() { not isInterface(this) } + /** Holds if this class is an anonymous class. */ predicate isAnonymous() { isAnonymClass(this.getSourceDeclaration(), _) } - override RefType getSourceDeclaration() { classes(this, _, _, result) } - /** * Gets an annotation that applies to this class. * @@ -742,10 +739,10 @@ class Record extends Class { } /** An intersection type. */ -class IntersectionType extends RefType, @class { +class IntersectionType extends RefType, @classorinterface { IntersectionType() { exists(string shortname | - classes(this, shortname, _, _) and + classes_or_interfaces(this, shortname, _, _) and shortname.matches("% & ...") ) } @@ -940,8 +937,8 @@ class InnerClass extends NestedClass { } /** An interface. */ -class Interface extends ClassOrInterface, @interface { - override RefType getSourceDeclaration() { interfaces(this, _, _, result) } +class Interface extends ClassOrInterface { + Interface() { isInterface(this) } override predicate isAbstract() { // JLS 9.1.1.1: "Every interface is implicitly abstract" @@ -953,6 +950,8 @@ class Interface extends ClassOrInterface, @interface { /** A class or interface. */ class ClassOrInterface extends RefType, @classorinterface { + override RefType getSourceDeclaration() { classes_or_interfaces(this, _, _, result) } + /** Holds if this class or interface is local. */ predicate isLocal() { isLocalClassOrInterface(this.getSourceDeclaration(), _) } diff --git a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/classes_or_interfaces.ql b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/classes_or_interfaces.ql new file mode 100644 index 00000000000..8e969327d7e --- /dev/null +++ b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/classes_or_interfaces.ql @@ -0,0 +1,11 @@ +class ClassOrInterface extends @classorinterface { + string toString() { result = "class-or-interface" } +} + +class Package extends @package { + string toString() { result = "package" } +} + +from ClassOrInterface id, string nodeName, Package parentId, ClassOrInterface sourceId +where classes(id, nodeName, parentId, sourceId) or interfaces(id, nodeName, parentId, sourceId) +select id, nodeName, parentId, sourceId diff --git a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/isInterface.ql b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/isInterface.ql new file mode 100644 index 00000000000..6c7ffac591c --- /dev/null +++ b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/isInterface.ql @@ -0,0 +1,6 @@ +class Interface extends @interface { + string toString() { result = "interface" } +} + +from Interface i +select i diff --git a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/old.dbscheme b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/old.dbscheme new file mode 100644 index 00000000000..44d61b266be --- /dev/null +++ b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/old.dbscheme @@ -0,0 +1,1246 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#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 + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +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 +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int 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 +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes( + unique int id: @class, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @class ref +); + +file_class( + int id: @class ref +); + +class_object( + unique int id: @class ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @class ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isRecord( + unique int id: @class ref +); + +interfaces( + unique int id: @interface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @interface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @interface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @class ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @class ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @interface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @class | @interface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterface = @interface | @class; +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @class | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @class | @interface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @class | @interface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * 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; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @class ref +) diff --git a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme new file mode 100644 index 00000000000..934bf10b4bd --- /dev/null +++ b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme @@ -0,0 +1,1242 @@ +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * javac A.java B.java C.java + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + /** + * An invocation of the compiler. Note that more than one file may + * be compiled per invocation. For example, this command compiles + * three source files: + * + * javac A.java B.java C.java + */ + unique int id : @compilation, + int kind: int ref, + string cwd : string ref, + string name : string ref +); + +case @compilation.kind of + 1 = @javacompilation +| 2 = @kotlincompilation +; + +compilation_started( + int id : @compilation ref +) + +compilation_info( + int id : @compilation ref, + string info_key: string ref, + string info_value: string ref +) + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * javac A.java B.java C.java + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | *path to extractor* + * 1 | `--javac-args` + * 2 | A.java + * 3 | B.java + * 4 | C.java + */ +#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 + * + * javac A.java B.java C.java + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | A.java + * 1 | B.java + * 2 | C.java + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * For each file recorded in `compilation_compiling_files`, + * there will be a corresponding row in + * `compilation_compiling_files_completed` once extraction + * of that file is complete. The `result` will indicate the + * extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +#keyset[id, num] +compilation_compiling_files_completed( + int id : @compilation ref, + int num : int ref, + int result : int 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 +); + +/** + * The `cpu_seconds` and `elapsed_seconds` are the CPU time and elapsed + * time (respectively) that the original compilation (not the extraction) + * took for compiler invocation `id`. + */ +compilation_compiler_times( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float 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`. + * The `result` will indicate the extraction result: + * + * 0: Successfully extracted + * 1: Errors were encountered, but extraction recovered + * 2: Errors were encountered, and extraction could not recover + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref, + int result : int ref +); + +diagnostics( + unique int id: @diagnostic, + string generated_by: string ref, // TODO: Sync this with the other languages? + 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 +); + +/* + * External artifacts + */ + +externalData( + int id : @externalDataElement, + string path : string ref, + int column: int ref, + string value : string ref +); + +snapshotDate( + unique date snapshotDate : date ref +); + +sourceLocationPrefix( + string prefix : string ref +); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id : @duplication, + string relativePath : string ref, + int equivClass : int ref +); + +similarCode( + unique int id : @similarity, + string relativePath : string ref, + int equivClass : int ref +); + +@duplication_or_similarity = @duplication | @similarity + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref +); + +/* + * SMAP + */ + +smap_header( + int outputFileId: @file ref, + string outputFilename: string ref, + string defaultStratum: string ref +); + +smap_files( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + string inputFileName: string ref, + int inputFileId: @file ref +); + +smap_lines( + int outputFileId: @file ref, + string stratum: string ref, + int inputFileNum: int ref, + int inputStartLine: int ref, + int inputLineCount: int ref, + int outputStartLine: int ref, + int outputLineIncrement: int ref +); + +/* + * Locations and files + */ + +@location = @location_default ; + +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 +); + +hasLocation( + int locatableid: @locatable ref, + int id: @location ref +); + +@sourceline = @locatable ; + +#keyset[element_id] +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int 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 +); + +/* + * Java + */ + +cupackage( + unique int id: @file ref, + int packageid: @package ref +); + +#keyset[fileid,keyName] +jarManifestMain( + int fileid: @file ref, + string keyName: string ref, + string value: string ref +); + +#keyset[fileid,entryName,keyName] +jarManifestEntries( + int fileid: @file ref, + string entryName: string ref, + string keyName: string ref, + string value: string ref +); + +packages( + unique int id: @package, + string nodeName: string ref +); + +primitives( + unique int id: @primitive, + string nodeName: string ref +); + +modifiers( + unique int id: @modifier, + string nodeName: string ref +); + +/** + * An errortype is used when the extractor is unable to extract a type + * correctly for some reason. + */ +error_type( + unique int id: @errortype +); + +classes_or_interfaces( + unique int id: @classorinterface, + string nodeName: string ref, + int parentid: @package ref, + int sourceid: @classorinterface ref +); + +file_class( + int id: @classorinterface ref +); + +class_object( + unique int id: @classorinterface ref, + unique int instance: @field ref +); + +type_companion_object( + unique int id: @classorinterface ref, + unique int instance: @field ref, + unique int companion_object: @classorinterface ref +); + +kt_nullable_types( + unique int id: @kt_nullable_type, + int classid: @reftype ref +) + +kt_notnull_types( + unique int id: @kt_notnull_type, + int classid: @reftype ref +) + +kt_type_alias( + unique int id: @kt_type_alias, + string name: string ref, + int kttypeid: @kt_type ref +) + +@kt_type = @kt_nullable_type | @kt_notnull_type + +isInterface( + unique int id: @classorinterface ref +); + +isRecord( + unique int id: @classorinterface ref +); + +fielddecls( + unique int id: @fielddecl, + int parentid: @reftype ref +); + +#keyset[fieldId] #keyset[fieldDeclId,pos] +fieldDeclaredIn( + int fieldId: @field ref, + int fieldDeclId: @fielddecl ref, + int pos: int ref +); + +fields( + unique int id: @field, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @field ref +); + +fieldsKotlinType( + unique int id: @field ref, + int kttypeid: @kt_type ref +); + +constrs( + unique int id: @constructor, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @constructor ref +); + +constrsKotlinType( + unique int id: @constructor ref, + int kttypeid: @kt_type ref +); + +methods( + unique int id: @method, + string nodeName: string ref, + string signature: string ref, + int typeid: @type ref, + int parentid: @reftype ref, + int sourceid: @method ref +); + +methodsKotlinType( + unique int id: @method ref, + int kttypeid: @kt_type ref +); + +#keyset[parentid,pos] +params( + unique int id: @param, + int typeid: @type ref, + int pos: int ref, + int parentid: @callable ref, + int sourceid: @param ref +); + +paramsKotlinType( + unique int id: @param ref, + int kttypeid: @kt_type ref +); + +paramName( + unique int id: @param ref, + string nodeName: string ref +); + +isVarargsParam( + int param: @param ref +); + +exceptions( + unique int id: @exception, + int typeid: @type ref, + int parentid: @callable ref +); + +isAnnotType( + int interfaceid: @classorinterface ref +); + +isAnnotElem( + int methodid: @method ref +); + +annotValue( + int parentid: @annotation ref, + int id2: @method ref, + unique int value: @expr ref +); + +isEnumType( + int classid: @classorinterface ref +); + +isEnumConst( + int fieldid: @field ref +); + +#keyset[parentid,pos] +typeVars( + unique int id: @typevariable, + string nodeName: string ref, + int pos: int ref, + int kind: int ref, // deprecated + int parentid: @classorinterfaceorcallable ref +); + +wildcards( + unique int id: @wildcard, + string nodeName: string ref, + int kind: int ref +); + +#keyset[parentid,pos] +typeBounds( + unique int id: @typebound, + int typeid: @reftype ref, + int pos: int ref, + int parentid: @boundedtype ref +); + +#keyset[parentid,pos] +typeArgs( + int argumentid: @reftype ref, + int pos: int ref, + int parentid: @classorinterfaceorcallable ref +); + +isParameterized( + int memberid: @member ref +); + +isRaw( + int memberid: @member ref +); + +erasure( + unique int memberid: @member ref, + int erasureid: @member ref +); + +#keyset[classid] #keyset[parent] +isAnonymClass( + int classid: @classorinterface ref, + int parent: @classinstancexpr ref +); + +#keyset[typeid] #keyset[parent] +isLocalClassOrInterface( + int typeid: @classorinterface ref, + int parent: @localtypedeclstmt ref +); + +isDefConstr( + int constructorid: @constructor ref +); + +#keyset[exprId] +lambdaKind( + int exprId: @lambdaexpr ref, + int bodyKind: int ref +); + +arrays( + unique int id: @array, + string nodeName: string ref, + int elementtypeid: @type ref, + int dimension: int ref, + int componenttypeid: @type ref +); + +enclInReftype( + unique int child: @reftype ref, + int parent: @reftype ref +); + +extendsReftype( + int id1: @reftype ref, + int id2: @classorinterface ref +); + +implInterface( + int id1: @classorarray ref, + int id2: @classorinterface ref +); + +permits( + int id1: @classorinterface ref, + int id2: @classorinterface ref +); + +hasModifier( + int id1: @modifiable ref, + int id2: @modifier ref +); + +imports( + unique int id: @import, + int holder: @classorinterfaceorpackage ref, + string name: string ref, + int kind: int ref +); + +#keyset[parent,idx] +stmts( + unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + int bodydecl: @callable ref +); + +@stmtparent = @callable | @stmt | @switchexpr | @whenexpr| @stmtexpr; + +case @stmt.kind of + 0 = @block +| 1 = @ifstmt +| 2 = @forstmt +| 3 = @enhancedforstmt +| 4 = @whilestmt +| 5 = @dostmt +| 6 = @trystmt +| 7 = @switchstmt +| 8 = @synchronizedstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @emptystmt +| 14 = @exprstmt +| 15 = @labeledstmt +| 16 = @assertstmt +| 17 = @localvariabledeclstmt +| 18 = @localtypedeclstmt +| 19 = @constructorinvocationstmt +| 20 = @superconstructorinvocationstmt +| 21 = @case +| 22 = @catchclause +| 23 = @yieldstmt +| 24 = @errorstmt +| 25 = @whenbranch +; + +#keyset[parent,idx] +exprs( + unique int id: @expr, + int kind: int ref, + int typeid: @type ref, + int parent: @exprparent ref, + int idx: int ref +); + +exprsKotlinType( + unique int id: @expr ref, + int kttypeid: @kt_type ref +); + +callableEnclosingExpr( + unique int id: @expr ref, + int callable_id: @callable ref +); + +statementEnclosingExpr( + unique int id: @expr ref, + int statement_id: @stmt ref +); + +isParenthesized( + unique int id: @expr ref, + int parentheses: int ref +); + +case @expr.kind of + 1 = @arrayaccess +| 2 = @arraycreationexpr +| 3 = @arrayinit +| 4 = @assignexpr +| 5 = @assignaddexpr +| 6 = @assignsubexpr +| 7 = @assignmulexpr +| 8 = @assigndivexpr +| 9 = @assignremexpr +| 10 = @assignandexpr +| 11 = @assignorexpr +| 12 = @assignxorexpr +| 13 = @assignlshiftexpr +| 14 = @assignrshiftexpr +| 15 = @assignurshiftexpr +| 16 = @booleanliteral +| 17 = @integerliteral +| 18 = @longliteral +| 19 = @floatingpointliteral +| 20 = @doubleliteral +| 21 = @characterliteral +| 22 = @stringliteral +| 23 = @nullliteral +| 24 = @mulexpr +| 25 = @divexpr +| 26 = @remexpr +| 27 = @addexpr +| 28 = @subexpr +| 29 = @lshiftexpr +| 30 = @rshiftexpr +| 31 = @urshiftexpr +| 32 = @andbitexpr +| 33 = @orbitexpr +| 34 = @xorbitexpr +| 35 = @andlogicalexpr +| 36 = @orlogicalexpr +| 37 = @ltexpr +| 38 = @gtexpr +| 39 = @leexpr +| 40 = @geexpr +| 41 = @eqexpr +| 42 = @neexpr +| 43 = @postincexpr +| 44 = @postdecexpr +| 45 = @preincexpr +| 46 = @predecexpr +| 47 = @minusexpr +| 48 = @plusexpr +| 49 = @bitnotexpr +| 50 = @lognotexpr +| 51 = @castexpr +| 52 = @newexpr +| 53 = @conditionalexpr +| 54 = @parexpr // deprecated +| 55 = @instanceofexpr +| 56 = @localvariabledeclexpr +| 57 = @typeliteral +| 58 = @thisaccess +| 59 = @superaccess +| 60 = @varaccess +| 61 = @methodaccess +| 62 = @unannotatedtypeaccess +| 63 = @arraytypeaccess +| 64 = @packageaccess +| 65 = @wildcardtypeaccess +| 66 = @declannotation +| 67 = @uniontypeaccess +| 68 = @lambdaexpr +| 69 = @memberref +| 70 = @annotatedtypeaccess +| 71 = @typeannotation +| 72 = @intersectiontypeaccess +| 73 = @switchexpr +| 74 = @errorexpr +| 75 = @whenexpr +| 76 = @getclassexpr +| 77 = @safecastexpr +| 78 = @implicitcastexpr +| 79 = @implicitnotnullexpr +| 80 = @implicitcoerciontounitexpr +| 81 = @notinstanceofexpr +| 82 = @stmtexpr +| 83 = @stringtemplateexpr +| 84 = @notnullexpr +| 85 = @unsafecoerceexpr +| 86 = @valueeqexpr +| 87 = @valueneexpr +| 88 = @propertyref +; + +/** Holds if this `when` expression was written as an `if` expression. */ +when_if(unique int id: @whenexpr ref); + +/** Holds if this `when` branch was written as an `else` branch. */ +when_branch_else(unique int id: @whenbranch ref); + +@classinstancexpr = @newexpr | @lambdaexpr | @memberref | @propertyref + +@annotation = @declannotation | @typeannotation +@typeaccess = @unannotatedtypeaccess | @annotatedtypeaccess + +@assignment = @assignexpr + | @assignop; + +@unaryassignment = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr; + +@assignop = @assignaddexpr + | @assignsubexpr + | @assignmulexpr + | @assigndivexpr + | @assignremexpr + | @assignandexpr + | @assignorexpr + | @assignxorexpr + | @assignlshiftexpr + | @assignrshiftexpr + | @assignurshiftexpr; + +@literal = @booleanliteral + | @integerliteral + | @longliteral + | @floatingpointliteral + | @doubleliteral + | @characterliteral + | @stringliteral + | @nullliteral; + +@binaryexpr = @mulexpr + | @divexpr + | @remexpr + | @addexpr + | @subexpr + | @lshiftexpr + | @rshiftexpr + | @urshiftexpr + | @andbitexpr + | @orbitexpr + | @xorbitexpr + | @andlogicalexpr + | @orlogicalexpr + | @ltexpr + | @gtexpr + | @leexpr + | @geexpr + | @eqexpr + | @neexpr + | @valueeqexpr + | @valueneexpr; + +@unaryexpr = @postincexpr + | @postdecexpr + | @preincexpr + | @predecexpr + | @minusexpr + | @plusexpr + | @bitnotexpr + | @lognotexpr + | @notnullexpr; + +@caller = @classinstancexpr + | @methodaccess + | @constructorinvocationstmt + | @superconstructorinvocationstmt; + +callableBinding( + unique int callerid: @caller ref, + int callee: @callable ref +); + +memberRefBinding( + unique int id: @expr ref, + int callable: @callable ref +); + +propertyRefGetBinding( + unique int id: @expr ref, + int getter: @callable ref +); + +propertyRefFieldBinding( + unique int id: @expr ref, + int field: @field ref +); + +propertyRefSetBinding( + unique int id: @expr ref, + int setter: @callable ref +); + +@exprparent = @stmt | @expr | @whenbranch | @callable | @field | @fielddecl | @classorinterface | @param | @localvar | @typevariable; + +variableBinding( + unique int expr: @varaccess ref, + int variable: @variable ref +); + +@variable = @localscopevariable | @field; + +@localscopevariable = @localvar | @param; + +localvars( + unique int id: @localvar, + string nodeName: string ref, + int typeid: @type ref, + int parentid: @localvariabledeclexpr ref +); + +localvarsKotlinType( + unique int id: @localvar ref, + int kttypeid: @kt_type ref +); + +@namedexprorstmt = @breakstmt + | @continuestmt + | @labeledstmt + | @literal; + +namestrings( + string name: string ref, + string value: string ref, + unique int parent: @namedexprorstmt ref +); + +/* + * Modules + */ + +#keyset[name] +modules( + unique int id: @module, + string name: string ref +); + +isOpen( + int id: @module ref +); + +#keyset[fileId] +cumodule( + int fileId: @file ref, + int moduleId: @module ref +); + +@directive = @requires + | @exports + | @opens + | @uses + | @provides + +#keyset[directive] +directives( + int id: @module ref, + int directive: @directive ref +); + +requires( + unique int id: @requires, + int target: @module ref +); + +isTransitive( + int id: @requires ref +); + +isStatic( + int id: @requires ref +); + +exports( + unique int id: @exports, + int target: @package ref +); + +exportsTo( + int id: @exports ref, + int target: @module ref +); + +opens( + unique int id: @opens, + int target: @package ref +); + +opensTo( + int id: @opens ref, + int target: @module ref +); + +uses( + unique int id: @uses, + string serviceInterface: string ref +); + +provides( + unique int id: @provides, + string serviceInterface: string ref +); + +providesWith( + int id: @provides ref, + string serviceImpl: string ref +); + +/* + * Javadoc + */ + +javadoc( + unique int id: @javadoc +); + +isNormalComment( + int commentid : @javadoc ref +); + +isEolComment( + int commentid : @javadoc ref +); + +hasJavadoc( + int documentableid: @member ref, + int javadocid: @javadoc ref +); + +#keyset[parentid,idx] +javadocTag( + unique int id: @javadocTag, + string name: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +#keyset[parentid,idx] +javadocText( + unique int id: @javadocText, + string text: string ref, + int parentid: @javadocParent ref, + int idx: int ref +); + +@javadocParent = @javadoc | @javadocTag; +@javadocElement = @javadocTag | @javadocText; + +@classorinterfaceorpackage = @classorinterface | @package; +@classorinterfaceorcallable = @classorinterface | @callable; +@boundedtype = @typevariable | @wildcard; +@reftype = @classorinterface | @array | @boundedtype | @errortype; +@classorarray = @classorinterface | @array; +@type = @primitive | @reftype; +@callable = @method | @constructor; + +/** A program element that has a name. */ +@element = @package | @modifier | @annotation | @errortype | + @locatableElement; + +@locatableElement = @file | @primitive | @classorinterface | @method | @constructor | @param | @exception | @field | + @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias | + @kt_property; + +@modifiable = @member_modifiable| @param | @localvar | @typevariable; + +@member_modifiable = @classorinterface | @method | @constructor | @field | @kt_property; + +@member = @method | @constructor | @field | @reftype ; + +/** A program element that has a location. */ +@locatable = @typebound | @javadoc | @javadocTag | @javadocText | @xmllocatable | @ktcomment | + @locatableElement; + +@top = @element | @locatable | @folder; + +/* + * 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; + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +ktComments( + unique int id: @ktcomment, + int kind: int ref, + string text : string ref +) + +ktCommentSections( + unique int id: @ktcommentsection, + int comment: @ktcomment ref, + string content : string ref +) + +ktCommentSectionNames( + unique int id: @ktcommentsection ref, + string name : string ref +) + +ktCommentSectionSubjectNames( + unique int id: @ktcommentsection ref, + string subjectname : string ref +) + +#keyset[id, owner] +ktCommentOwners( + int id: @ktcomment ref, + int owner: @top ref +) + +ktExtensionFunctions( + unique int id: @method ref, + int typeid: @type ref, + int kttypeid: @kt_type ref +) + +ktProperties( + unique int id: @kt_property, + string nodeName: string ref +) + +ktPropertyGetters( + unique int id: @kt_property ref, + int getter: @method ref +) + +ktPropertySetters( + unique int id: @kt_property ref, + int setter: @method ref +) + +ktPropertyBackingFields( + unique int id: @kt_property ref, + int backingField: @field ref +) + +ktSyntheticBody( + unique int id: @callable ref, + int kind: int ref + // 1: ENUM_VALUES + // 2: ENUM_VALUEOF +) + +ktLocalFunction( + unique int id: @method ref +) + +ktInitializerAssignment( + unique int id: @assignexpr ref +) + +ktPropertyDelegates( + unique int id: @kt_property ref, + unique int variableId: @variable ref +) + +/** + * If `id` is a compiler generated element, then the kind indicates the + * reason that the compiler generated it. + * See `Element.compilerGeneratedReason()` for an explanation of what + * each `kind` means. + */ +compiler_generated( + unique int id: @element ref, + int kind: int ref +) + +ktFunctionOriginalNames( + unique int id: @method ref, + string name: string ref +) + +ktDataClasses( + unique int id: @classorinterface ref +) diff --git a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme.stats b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme.stats new file mode 100644 index 00000000000..7ebc6e0b93e --- /dev/null +++ b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/semmlecode.dbscheme.stats @@ -0,0 +1,26852 @@ + + + + @javacompilation + 8628 + + + @kotlincompilation + 7683 + + + @diagnostic + 61632 + + + @externalDataElement + 1 + + + @duplication + 1 + + + @similarity + 1 + + + @file + 9158642 + + + @folder + 1415670 + + + @location_default + 602747369 + + + @package + 580098 + + + @primitive + 17287 + + + @modifier + 26891 + + + @errortype + 1 + + + @class + 12618104 + + + @kt_nullable_type + 1920 + + + @kt_notnull_type + 172391 + + + @kt_type_alias + 1821 + + + @interface + 23200100 + + + @fielddecl + 199475 + + + @field + 19350704 + + + @constructor + 8006128 + + + @method + 109719302 + + + @param + 120852585 + + + @exception + 1232644 + + + @typevariable + 6288883 + + + @wildcard + 3338447 + + + @typebound + 4229725 + + + @array + 1375332 + + + @import + 368550 + + + @block + 756817 + + + @ifstmt + 188285 + + + @forstmt + 52504 + + + @enhancedforstmt + 18520 + + + @whilestmt + 13266 + + + @dostmt + 2405 + + + @trystmt + 58624 + + + @switchstmt + 10546 + + + @synchronizedstmt + 18206 + + + @returnstmt + 532846 + + + @throwstmt + 35917 + + + @breakstmt + 35329 + + + @continuestmt + 3211 + + + @emptystmt + 1561 + + + @exprstmt + 942102 + + + @assertstmt + 10815 + + + @localvariabledeclstmt + 318689 + + + @localtypedeclstmt + 3841 + + + @constructorinvocationstmt + 9165 + + + @superconstructorinvocationstmt + 201354 + + + @case + 107945 + + + @catchclause + 55201 + + + @labeledstmt + 2342 + + + @yieldstmt + 36 + + + @errorstmt + 1 + + + @whenbranch + 225101 + + + @arrayaccess + 409681 + + + @arraycreationexpr + 69247 + + + @arrayinit + 405405 + + + @assignexpr + 465407 + + + @assignaddexpr + 17016 + + + @assignsubexpr + 3505 + + + @assignmulexpr + 2153 + + + @assigndivexpr + 1071 + + + @assignandexpr + 3971 + + + @assignorexpr + 14528 + + + @booleanliteral + 589912 + + + @integerliteral + 1151458 + + + @longliteral + 185904 + + + @floatingpointliteral + 2824996 + + + @doubleliteral + 486619 + + + @characterliteral + 40016 + + + @stringliteral + 1262818 + + + @nullliteral + 434113 + + + @mulexpr + 204580 + + + @divexpr + 36264 + + + @remexpr + 3904 + + + @addexpr + 176986 + + + @subexpr + 84385 + + + @lshiftexpr + 8736 + + + @rshiftexpr + 4206 + + + @urshiftexpr + 5463 + + + @andbitexpr + 110212 + + + @orbitexpr + 12590 + + + @xorbitexpr + 1925 + + + @andlogicalexpr + 36742 + + + @orlogicalexpr + 31150 + + + @ltexpr + 66249 + + + @gtexpr + 17203 + + + @leexpr + 10529 + + + @geexpr + 13411 + + + @eqexpr + 128429 + + + @neexpr + 60975 + + + @postincexpr + 29632 + + + @postdecexpr + 11683 + + + @preincexpr + 23714 + + + @predecexpr + 3781 + + + @minusexpr + 744386 + + + @plusexpr + 53007 + + + @bitnotexpr + 8186 + + + @lognotexpr + 40111 + + + @castexpr + 93187 + + + @newexpr + 252083 + + + @conditionalexpr + 16047 + + + @instanceofexpr + 29542 + + + @localvariabledeclexpr + 385272 + + + @typeliteral + 144350 + + + @thisaccess + 756915 + + + @superaccess + 99884 + + + @varaccess + 2434277 + + + @methodaccess + 1512385 + + + @unannotatedtypeaccess + 2608638 + + + @arraytypeaccess + 120727 + + + @wildcardtypeaccess + 64091 + + + @declannotation + 6740832 + + + @assignremexpr + 47 + + + @assignxorexpr + 1102 + + + @assignlshiftexpr + 916 + + + @assignrshiftexpr + 1404 + + + @assignurshiftexpr + 431 + + + @parexpr + 1 + + + @packageaccess + 1 + + + @uniontypeaccess + 917 + + + @lambdaexpr + 167982 + + + @memberref + 23859 + + + @annotatedtypeaccess + 1281 + + + @typeannotation + 1281 + + + @intersectiontypeaccess + 25 + + + @switchexpr + 591 + + + @errorexpr + 1 + + + @whenexpr + 152111 + + + @getclassexpr + 1920 + + + @safecastexpr + 6402 + + + @implicitcastexpr + 30316 + + + @implicitnotnullexpr + 216630 + + + @implicitcoerciontounitexpr + 81396 + + + @notinstanceofexpr + 17306 + + + @stmtexpr + 55704 + + + @stringtemplateexpr + 59546 + + + @notnullexpr + 18820 + + + @unsafecoerceexpr + 1 + + + @valueeqexpr + 93060 + + + @valueneexpr + 95639 + + + @propertyref + 8878 + + + @localvar + 385272 + + + @module + 7965 + + + @requires + 1991 + + + @exports + 35013 + + + @opens + 165 + + + @uses + 10786 + + + @provides + 2323 + + + @javadoc + 985091 + + + @javadocTag + 335808 + + + @javadocText + 2502848 + + + @xmldtd + 569 + + + @xmlelement + 150282022 + + + @xmlattribute + 182798274 + + + @xmlnamespace + 11525 + + + @xmlcomment + 151257816 + + + @xmlcharacters + 142938589 + + + @config + 1 + + + @configName + 1 + + + @configValue + 1 + + + @ktcomment + 188243 + + + @ktcommentsection + 52611 + + + @kt_property + 21895839 + + + + + compilations + 8628 + + + id + 8628 + + + kind + 165 + + + cwd + 165 + + + name + 8628 + + + + + id + kind + + + 12 + + + 1 + 2 + 8628 + + + + + + + id + cwd + + + 12 + + + 1 + 2 + 8628 + + + + + + + id + name + + + 12 + + + 1 + 2 + 8628 + + + + + + + kind + id + + + 12 + + + 52 + 53 + 165 + + + + + + + kind + cwd + + + 12 + + + 1 + 2 + 165 + + + + + + + kind + name + + + 12 + + + 52 + 53 + 165 + + + + + + + cwd + id + + + 12 + + + 52 + 53 + 165 + + + + + + + cwd + kind + + + 12 + + + 1 + 2 + 165 + + + + + + + cwd + name + + + 12 + + + 52 + 53 + 165 + + + + + + + name + id + + + 12 + + + 1 + 2 + 8628 + + + + + + + name + kind + + + 12 + + + 1 + 2 + 8628 + + + + + + + name + cwd + + + 12 + + + 1 + 2 + 8628 + + + + + + + + + compilation_started + 7683 + + + id + 7683 + + + + + + compilation_info + 15366 + + + id + 7683 + + + info_key + 3841 + + + info_value + 3841 + + + + + id + info_key + + + 12 + + + 2 + 3 + 7683 + + + + + + + id + info_value + + + 12 + + + 2 + 3 + 7683 + + + + + + + info_key + id + + + 12 + + + 4 + 5 + 3841 + + + + + + + info_key + info_value + + + 12 + + + 1 + 2 + 3841 + + + + + + + info_value + id + + + 12 + + + 4 + 5 + 3841 + + + + + + + info_value + info_key + + + 12 + + + 1 + 2 + 3841 + + + + + + + + + compilation_args + 169035 + + + id + 7683 + + + num + 48021 + + + arg + 90280 + + + + + id + num + + + 12 + + + 20 + 21 + 3841 + + + 23 + 24 + 1920 + + + 25 + 26 + 1920 + + + + + + + id + arg + + + 12 + + + 20 + 21 + 3841 + + + 23 + 24 + 1920 + + + 25 + 26 + 1920 + + + + + + + num + id + + + 12 + + + 1 + 2 + 3841 + + + 2 + 3 + 5762 + + + 4 + 5 + 38417 + + + + + + + num + arg + + + 12 + + + 1 + 2 + 9604 + + + 2 + 3 + 17287 + + + 3 + 4 + 11525 + + + 4 + 5 + 9604 + + + + + + + arg + id + + + 12 + + + 1 + 2 + 61467 + + + 2 + 3 + 3841 + + + 4 + 5 + 24971 + + + + + + + arg + num + + + 12 + + + 1 + 2 + 67229 + + + 2 + 3 + 19208 + + + 3 + 4 + 3841 + + + + + + + + + compilation_compiling_files + 59495 + + + id + 2275 + + + num + 17556 + + + file + 49742 + + + + + id + num + + + 12 + + + 1 + 2 + 325 + + + 2 + 3 + 650 + + + 35 + 36 + 650 + + + 54 + 55 + 650 + + + + + + + id + file + + + 12 + + + 1 + 2 + 325 + + + 2 + 3 + 650 + + + 35 + 36 + 650 + + + 54 + 55 + 650 + + + + + + + num + id + + + 12 + + + 2 + 3 + 6177 + + + 4 + 5 + 10728 + + + 6 + 8 + 650 + + + + + + + num + file + + + 12 + + + 2 + 3 + 6177 + + + 3 + 4 + 9753 + + + 4 + 8 + 1625 + + + + + + + file + id + + + 12 + + + 1 + 2 + 39989 + + + 2 + 3 + 9753 + + + + + + + file + num + + + 12 + + + 1 + 2 + 49742 + + + + + + + + + compilation_compiling_files_completed + 59495 + + + id + 2275 + + + num + 17556 + + + result + 325 + + + + + id + num + + + 12 + + + 1 + 2 + 325 + + + 2 + 3 + 650 + + + 35 + 36 + 650 + + + 54 + 55 + 650 + + + + + + + id + result + + + 12 + + + 1 + 2 + 2275 + + + + + + + num + id + + + 12 + + + 2 + 3 + 6177 + + + 4 + 5 + 10728 + + + 6 + 8 + 650 + + + + + + + num + result + + + 12 + + + 1 + 2 + 17556 + + + + + + + result + id + + + 12 + + + 7 + 8 + 325 + + + + + + + result + num + + + 12 + + + 54 + 55 + 325 + + + + + + + + + compilation_time + 196471 + + + id + 8628 + + + num + 5144 + + + kind + 663 + + + seconds + 89772 + + + + + id + num + + + 12 + + + 1 + 2 + 331 + + + 2 + 3 + 1659 + + + 3 + 4 + 1161 + + + 4 + 5 + 2157 + + + 5 + 6 + 663 + + + 6 + 7 + 497 + + + 7 + 8 + 497 + + + 8 + 12 + 663 + + + 13 + 16 + 663 + + + 20 + 32 + 331 + + + + + + + id + kind + + + 12 + + + 4 + 5 + 8628 + + + + + + + id + seconds + + + 12 + + + 2 + 3 + 331 + + + 4 + 5 + 1659 + + + 6 + 7 + 1161 + + + 8 + 9 + 2157 + + + 10 + 11 + 663 + + + 12 + 13 + 497 + + + 14 + 15 + 497 + + + 16 + 23 + 663 + + + 26 + 31 + 663 + + + 40 + 63 + 331 + + + + + + + num + id + + + 12 + + + 1 + 2 + 1825 + + + 2 + 3 + 829 + + + 3 + 5 + 331 + + + 6 + 7 + 331 + + + 7 + 8 + 331 + + + 8 + 11 + 331 + + + 13 + 17 + 331 + + + 20 + 34 + 331 + + + 40 + 51 + 331 + + + 52 + 53 + 165 + + + + + + + num + kind + + + 12 + + + 4 + 5 + 5144 + + + + + + + num + seconds + + + 12 + + + 3 + 4 + 1825 + + + 5 + 6 + 829 + + + 7 + 10 + 331 + + + 13 + 14 + 331 + + + 15 + 16 + 331 + + + 17 + 22 + 331 + + + 27 + 34 + 331 + + + 41 + 54 + 331 + + + 67 + 82 + 331 + + + 101 + 102 + 165 + + + + + + + kind + id + + + 12 + + + 52 + 53 + 663 + + + + + + + kind + num + + + 12 + + + 31 + 32 + 663 + + + + + + + kind + seconds + + + 12 + + + 1 + 2 + 331 + + + 245 + 246 + 165 + + + 296 + 297 + 165 + + + + + + + seconds + id + + + 12 + + + 1 + 2 + 89606 + + + 52 + 53 + 165 + + + + + + + seconds + num + + + 12 + + + 1 + 2 + 89606 + + + 31 + 32 + 165 + + + + + + + seconds + kind + + + 12 + + + 1 + 2 + 89606 + + + 3 + 4 + 165 + + + + + + + + + diagnostic_for + 61632 + + + diagnostic + 61632 + + + compilation + 574 + + + file_number + 14797 + + + file_number_diagnostic_number + 2154 + + + + + diagnostic + compilation + + + 12 + + + 1 + 2 + 61632 + + + + + + + diagnostic + file_number + + + 12 + + + 1 + 2 + 61632 + + + + + + + diagnostic + file_number_diagnostic_number + + + 12 + + + 1 + 2 + 61632 + + + + + + + compilation + diagnostic + + + 12 + + + 14 + 15 + 143 + + + 28 + 29 + 143 + + + 123 + 124 + 143 + + + 264 + 265 + 143 + + + + + + + compilation + file_number + + + 12 + + + 7 + 8 + 143 + + + 14 + 15 + 143 + + + 45 + 46 + 143 + + + 103 + 104 + 143 + + + + + + + compilation + file_number_diagnostic_number + + + 12 + + + 2 + 3 + 287 + + + 14 + 15 + 143 + + + 15 + 16 + 143 + + + + + + + file_number + diagnostic + + + 12 + + + 1 + 2 + 143 + + + 2 + 3 + 6464 + + + 3 + 4 + 718 + + + 4 + 5 + 3160 + + + 5 + 6 + 1292 + + + 6 + 8 + 1149 + + + 8 + 11 + 1292 + + + 12 + 21 + 574 + + + + + + + file_number + compilation + + + 12 + + + 1 + 2 + 8332 + + + 2 + 3 + 4453 + + + 3 + 4 + 1005 + + + 4 + 5 + 1005 + + + + + + + file_number + file_number_diagnostic_number + + + 12 + + + 1 + 2 + 143 + + + 2 + 3 + 10056 + + + 3 + 4 + 2011 + + + 4 + 5 + 1005 + + + 5 + 8 + 1149 + + + 10 + 16 + 430 + + + + + + + file_number_diagnostic_number + diagnostic + + + 12 + + + 1 + 2 + 143 + + + 2 + 3 + 574 + + + 3 + 4 + 430 + + + 5 + 6 + 143 + + + 7 + 8 + 143 + + + 11 + 12 + 143 + + + 18 + 19 + 143 + + + 33 + 34 + 143 + + + 168 + 169 + 143 + + + 169 + 170 + 143 + + + + + + + file_number_diagnostic_number + compilation + + + 12 + + + 1 + 2 + 143 + + + 2 + 3 + 1723 + + + 4 + 5 + 287 + + + + + + + file_number_diagnostic_number + file_number + + + 12 + + + 1 + 2 + 143 + + + 2 + 3 + 574 + + + 3 + 4 + 430 + + + 5 + 6 + 143 + + + 7 + 8 + 143 + + + 11 + 12 + 143 + + + 18 + 19 + 143 + + + 32 + 33 + 143 + + + 102 + 103 + 143 + + + 103 + 104 + 143 + + + + + + + + + compilation_compiler_times + 7683 + + + id + 7683 + + + cpu_seconds + 1920 + + + elapsed_seconds + 7683 + + + + + id + cpu_seconds + + + 12 + + + 1 + 2 + 7683 + + + + + + + id + elapsed_seconds + + + 12 + + + 1 + 2 + 7683 + + + + + + + cpu_seconds + id + + + 12 + + + 4 + 5 + 1920 + + + + + + + cpu_seconds + elapsed_seconds + + + 12 + + + 4 + 5 + 1920 + + + + + + + elapsed_seconds + id + + + 12 + + + 1 + 2 + 7683 + + + + + + + elapsed_seconds + cpu_seconds + + + 12 + + + 1 + 2 + 7683 + + + + + + + + + compilation_finished + 8628 + + + id + 8628 + + + cpu_seconds + 165 + + + elapsed_seconds + 8628 + + + result + 165 + + + + + id + cpu_seconds + + + 12 + + + 1 + 2 + 8628 + + + + + + + id + elapsed_seconds + + + 12 + + + 1 + 2 + 8628 + + + + + + + id + result + + + 12 + + + 1 + 2 + 8628 + + + + + + + cpu_seconds + id + + + 12 + + + 52 + 53 + 165 + + + + + + + cpu_seconds + elapsed_seconds + + + 12 + + + 52 + 53 + 165 + + + + + + + cpu_seconds + result + + + 12 + + + 1 + 2 + 165 + + + + + + + elapsed_seconds + id + + + 12 + + + 1 + 2 + 8628 + + + + + + + elapsed_seconds + cpu_seconds + + + 12 + + + 1 + 2 + 8628 + + + + + + + elapsed_seconds + result + + + 12 + + + 1 + 2 + 8628 + + + + + + + result + id + + + 12 + + + 52 + 53 + 165 + + + + + + + result + cpu_seconds + + + 12 + + + 1 + 2 + 165 + + + + + + + result + elapsed_seconds + + + 12 + + + 52 + 53 + 165 + + + + + + + + + diagnostics + 61632 + + + id + 61632 + + + generated_by + 143 + + + severity + 143 + + + error_tag + 143 + + + error_message + 1580 + + + full_error_message + 40944 + + + location + 143 + + + + + id + generated_by + + + 12 + + + 1 + 2 + 61632 + + + + + + + id + severity + + + 12 + + + 1 + 2 + 61632 + + + + + + + id + error_tag + + + 12 + + + 1 + 2 + 61632 + + + + + + + id + error_message + + + 12 + + + 1 + 2 + 61632 + + + + + + + id + full_error_message + + + 12 + + + 1 + 2 + 61632 + + + + + + + id + location + + + 12 + + + 1 + 2 + 61632 + + + + + + + generated_by + id + + + 12 + + + 429 + 430 + 143 + + + + + + + generated_by + severity + + + 12 + + + 1 + 2 + 143 + + + + + + + generated_by + error_tag + + + 12 + + + 1 + 2 + 143 + + + + + + + generated_by + error_message + + + 12 + + + 11 + 12 + 143 + + + + + + + generated_by + full_error_message + + + 12 + + + 285 + 286 + 143 + + + + + + + generated_by + location + + + 12 + + + 1 + 2 + 143 + + + + + + + severity + id + + + 12 + + + 429 + 430 + 143 + + + + + + + severity + generated_by + + + 12 + + + 1 + 2 + 143 + + + + + + + severity + error_tag + + + 12 + + + 1 + 2 + 143 + + + + + + + severity + error_message + + + 12 + + + 11 + 12 + 143 + + + + + + + severity + full_error_message + + + 12 + + + 285 + 286 + 143 + + + + + + + severity + location + + + 12 + + + 1 + 2 + 143 + + + + + + + error_tag + id + + + 12 + + + 429 + 430 + 143 + + + + + + + error_tag + generated_by + + + 12 + + + 1 + 2 + 143 + + + + + + + error_tag + severity + + + 12 + + + 1 + 2 + 143 + + + + + + + error_tag + error_message + + + 12 + + + 11 + 12 + 143 + + + + + + + error_tag + full_error_message + + + 12 + + + 285 + 286 + 143 + + + + + + + error_tag + location + + + 12 + + + 1 + 2 + 143 + + + + + + + error_message + id + + + 12 + + + 1 + 2 + 143 + + + 2 + 3 + 143 + + + 3 + 4 + 143 + + + 6 + 7 + 143 + + + 9 + 10 + 143 + + + 12 + 13 + 287 + + + 24 + 25 + 143 + + + 28 + 29 + 143 + + + 166 + 167 + 287 + + + + + + + error_message + generated_by + + + 12 + + + 1 + 2 + 1580 + + + + + + + error_message + severity + + + 12 + + + 1 + 2 + 1580 + + + + + + + error_message + error_tag + + + 12 + + + 1 + 2 + 1580 + + + + + + + error_message + full_error_message + + + 12 + + + 1 + 2 + 143 + + + 2 + 3 + 143 + + + 3 + 4 + 143 + + + 6 + 7 + 143 + + + 9 + 10 + 143 + + + 12 + 13 + 287 + + + 22 + 23 + 143 + + + 24 + 25 + 143 + + + 28 + 29 + 143 + + + 166 + 167 + 143 + + + + + + + error_message + location + + + 12 + + + 1 + 2 + 1580 + + + + + + + full_error_message + id + + + 12 + + + 1 + 2 + 38358 + + + 2 + 25 + 2585 + + + + + + + full_error_message + generated_by + + + 12 + + + 1 + 2 + 40944 + + + + + + + full_error_message + severity + + + 12 + + + 1 + 2 + 40944 + + + + + + + full_error_message + error_tag + + + 12 + + + 1 + 2 + 40944 + + + + + + + full_error_message + error_message + + + 12 + + + 1 + 2 + 40944 + + + + + + + full_error_message + location + + + 12 + + + 1 + 2 + 40944 + + + + + + + location + id + + + 12 + + + 429 + 430 + 143 + + + + + + + location + generated_by + + + 12 + + + 1 + 2 + 143 + + + + + + + location + severity + + + 12 + + + 1 + 2 + 143 + + + + + + + location + error_tag + + + 12 + + + 1 + 2 + 143 + + + + + + + location + error_message + + + 12 + + + 11 + 12 + 143 + + + + + + + location + full_error_message + + + 12 + + + 285 + 286 + 143 + + + + + + + + + externalData + 1 + + + id + 1 + + + path + 1 + + + column + 1 + + + value + 1 + + + + + id + path + + + 12 + + + + + + id + column + + + 12 + + + + + + id + value + + + 12 + + + + + + path + id + + + 12 + + + + + + path + column + + + 12 + + + + + + path + value + + + 12 + + + + + + column + id + + + 12 + + + + + + column + path + + + 12 + + + + + + column + value + + + 12 + + + + + + value + id + + + 12 + + + + + + value + path + + + 12 + + + + + + value + column + + + 12 + + + + + + + + snapshotDate + 1 + + + snapshotDate + 1 + + + + + + sourceLocationPrefix + 1920 + + + prefix + 1920 + + + + + + duplicateCode + 1 + + + id + 1 + + + relativePath + 1 + + + equivClass + 1 + + + + + id + relativePath + + + 12 + + + 1 + 2 + 1 + + + + + + + id + equivClass + + + 12 + + + 1 + 2 + 1 + + + + + + + relativePath + id + + + 12 + + + + + + relativePath + equivClass + + + 12 + + + + + + equivClass + id + + + 12 + + + + + + equivClass + relativePath + + + 12 + + + + + + + + similarCode + 1 + + + id + 1 + + + relativePath + 1 + + + equivClass + 1 + + + + + id + relativePath + + + 12 + + + 1 + 2 + 1 + + + + + + + id + equivClass + + + 12 + + + 1 + 2 + 1 + + + + + + + relativePath + id + + + 12 + + + + + + relativePath + equivClass + + + 12 + + + + + + equivClass + id + + + 12 + + + + + + equivClass + relativePath + + + 12 + + + + + + + + tokens + 1 + + + id + 1 + + + offset + 1 + + + beginLine + 1 + + + beginColumn + 1 + + + endLine + 1 + + + endColumn + 1 + + + + + id + offset + + + 12 + + + + + + id + beginLine + + + 12 + + + + + + id + beginColumn + + + 12 + + + + + + id + endLine + + + 12 + + + + + + id + endColumn + + + 12 + + + + + + offset + id + + + 12 + + + + + + offset + beginLine + + + 12 + + + + + + offset + beginColumn + + + 12 + + + + + + offset + endLine + + + 12 + + + + + + offset + endColumn + + + 12 + + + + + + beginLine + id + + + 12 + + + + + + beginLine + offset + + + 12 + + + + + + beginLine + beginColumn + + + 12 + + + + + + beginLine + endLine + + + 12 + + + + + + beginLine + endColumn + + + 12 + + + + + + beginColumn + id + + + 12 + + + + + + beginColumn + offset + + + 12 + + + + + + beginColumn + beginLine + + + 12 + + + + + + beginColumn + endLine + + + 12 + + + + + + beginColumn + endColumn + + + 12 + + + + + + endLine + id + + + 12 + + + + + + endLine + offset + + + 12 + + + + + + endLine + beginLine + + + 12 + + + + + + endLine + beginColumn + + + 12 + + + + + + endLine + endColumn + + + 12 + + + + + + endColumn + id + + + 12 + + + + + + endColumn + offset + + + 12 + + + + + + endColumn + beginLine + + + 12 + + + + + + endColumn + beginColumn + + + 12 + + + + + + endColumn + endLine + + + 12 + + + + + + + + smap_header + 1 + + + outputFileId + 1 + + + outputFilename + 1 + + + defaultStratum + 1 + + + + + outputFileId + outputFilename + + + 12 + + + + + + outputFileId + defaultStratum + + + 12 + + + + + + outputFilename + outputFileId + + + 12 + + + + + + outputFilename + defaultStratum + + + 12 + + + + + + defaultStratum + outputFileId + + + 12 + + + + + + defaultStratum + outputFilename + + + 12 + + + + + + + + smap_files + 1 + + + outputFileId + 1 + + + stratum + 1 + + + inputFileNum + 1 + + + inputFileName + 1 + + + inputFileId + 1 + + + + + outputFileId + stratum + + + 12 + + + + + + outputFileId + inputFileNum + + + 12 + + + + + + outputFileId + inputFileName + + + 12 + + + + + + outputFileId + inputFileId + + + 12 + + + + + + stratum + outputFileId + + + 12 + + + + + + stratum + inputFileNum + + + 12 + + + + + + stratum + inputFileName + + + 12 + + + + + + stratum + inputFileId + + + 12 + + + + + + inputFileNum + outputFileId + + + 12 + + + + + + inputFileNum + stratum + + + 12 + + + + + + inputFileNum + inputFileName + + + 12 + + + + + + inputFileNum + inputFileId + + + 12 + + + + + + inputFileName + outputFileId + + + 12 + + + + + + inputFileName + stratum + + + 12 + + + + + + inputFileName + inputFileNum + + + 12 + + + + + + inputFileName + inputFileId + + + 12 + + + + + + inputFileId + outputFileId + + + 12 + + + + + + inputFileId + stratum + + + 12 + + + + + + inputFileId + inputFileNum + + + 12 + + + + + + inputFileId + inputFileName + + + 12 + + + + + + + + smap_lines + 1 + + + outputFileId + 1 + + + stratum + 1 + + + inputFileNum + 1 + + + inputStartLine + 1 + + + inputLineCount + 1 + + + outputStartLine + 1 + + + outputLineIncrement + 1 + + + + + outputFileId + stratum + + + 12 + + + + + + outputFileId + inputFileNum + + + 12 + + + + + + outputFileId + inputStartLine + + + 12 + + + + + + outputFileId + inputLineCount + + + 12 + + + + + + outputFileId + outputStartLine + + + 12 + + + + + + outputFileId + outputLineIncrement + + + 12 + + + + + + stratum + outputFileId + + + 12 + + + + + + stratum + inputFileNum + + + 12 + + + + + + stratum + inputStartLine + + + 12 + + + + + + stratum + inputLineCount + + + 12 + + + + + + stratum + outputStartLine + + + 12 + + + + + + stratum + outputLineIncrement + + + 12 + + + + + + inputFileNum + outputFileId + + + 12 + + + + + + inputFileNum + stratum + + + 12 + + + + + + inputFileNum + inputStartLine + + + 12 + + + + + + inputFileNum + inputLineCount + + + 12 + + + + + + inputFileNum + outputStartLine + + + 12 + + + + + + inputFileNum + outputLineIncrement + + + 12 + + + + + + inputStartLine + outputFileId + + + 12 + + + + + + inputStartLine + stratum + + + 12 + + + + + + inputStartLine + inputFileNum + + + 12 + + + + + + inputStartLine + inputLineCount + + + 12 + + + + + + inputStartLine + outputStartLine + + + 12 + + + + + + inputStartLine + outputLineIncrement + + + 12 + + + + + + inputLineCount + outputFileId + + + 12 + + + + + + inputLineCount + stratum + + + 12 + + + + + + inputLineCount + inputFileNum + + + 12 + + + + + + inputLineCount + inputStartLine + + + 12 + + + + + + inputLineCount + outputStartLine + + + 12 + + + + + + inputLineCount + outputLineIncrement + + + 12 + + + + + + outputStartLine + outputFileId + + + 12 + + + + + + outputStartLine + stratum + + + 12 + + + + + + outputStartLine + inputFileNum + + + 12 + + + + + + outputStartLine + inputStartLine + + + 12 + + + + + + outputStartLine + inputLineCount + + + 12 + + + + + + outputStartLine + outputLineIncrement + + + 12 + + + + + + outputLineIncrement + outputFileId + + + 12 + + + + + + outputLineIncrement + stratum + + + 12 + + + + + + outputLineIncrement + inputFileNum + + + 12 + + + + + + outputLineIncrement + inputStartLine + + + 12 + + + + + + outputLineIncrement + inputLineCount + + + 12 + + + + + + outputLineIncrement + outputStartLine + + + 12 + + + + + + + + locations_default + 602747369 + + + id + 602747369 + + + file + 9158642 + + + beginLine + 3943517 + + + beginColumn + 247790 + + + endLine + 3945438 + + + endColumn + 873989 + + + + + id + file + + + 12 + + + 1 + 2 + 602747369 + + + + + + + id + beginLine + + + 12 + + + 1 + 2 + 602747369 + + + + + + + id + beginColumn + + + 12 + + + 1 + 2 + 602747369 + + + + + + + id + endLine + + + 12 + + + 1 + 2 + 602747369 + + + + + + + id + endColumn + + + 12 + + + 1 + 2 + 602747369 + + + + + + + file + id + + + 12 + + + 1 + 2 + 7986919 + + + 2 + 11 + 714558 + + + 11 + 3605 + 457163 + + + + + + + file + beginLine + + + 12 + + + 1 + 2 + 7986919 + + + 2 + 9 + 712637 + + + 9 + 1830 + 459084 + + + + + + + file + beginColumn + + + 12 + + + 1 + 2 + 7986919 + + + 2 + 5 + 776025 + + + 5 + 105 + 395696 + + + + + + + file + endLine + + + 12 + + + 1 + 2 + 7986919 + + + 2 + 10 + 693429 + + + 10 + 1834 + 478293 + + + + + + + file + endColumn + + + 12 + + + 1 + 2 + 7986919 + + + 2 + 9 + 695349 + + + 9 + 205 + 476372 + + + + + + + beginLine + id + + + 12 + + + 1 + 14 + 313099 + + + 14 + 125 + 301574 + + + 125 + 142 + 307336 + + + 142 + 152 + 316941 + + + 152 + 159 + 359200 + + + 159 + 164 + 272761 + + + 164 + 169 + 343833 + + + 169 + 173 + 299653 + + + 173 + 178 + 332308 + + + 178 + 184 + 347674 + + + 184 + 193 + 316941 + + + 193 + 211 + 297732 + + + 211 + 4769 + 134459 + + + + + + + beginLine + file + + + 12 + + + 1 + 7 + 322703 + + + 7 + 65 + 299653 + + + 65 + 73 + 307336 + + + 73 + 78 + 295811 + + + 78 + 81 + 265078 + + + 81 + 84 + 357279 + + + 84 + 86 + 299653 + + + 86 + 87 + 188243 + + + 87 + 89 + 357279 + + + 89 + 91 + 259315 + + + 91 + 94 + 324624 + + + 94 + 99 + 328466 + + + 99 + 141 + 295811 + + + 141 + 4769 + 42258 + + + + + + + beginLine + beginColumn + + + 12 + + + 1 + 5 + 313099 + + + 5 + 17 + 280444 + + + 17 + 19 + 251632 + + + 19 + 20 + 309257 + + + 20 + 21 + 403379 + + + 21 + 22 + 420667 + + + 22 + 23 + 476372 + + + 23 + 24 + 457163 + + + 24 + 25 + 339991 + + + 25 + 26 + 213215 + + + 26 + 29 + 361120 + + + 29 + 40 + 117172 + + + + + + + beginLine + endLine + + + 12 + + + 1 + 2 + 1273527 + + + 2 + 3 + 1265844 + + + 3 + 4 + 674220 + + + 4 + 5 + 299653 + + + 5 + 11 + 307336 + + + 11 + 97 + 122934 + + + + + + + beginLine + endColumn + + + 12 + + + 1 + 13 + 309257 + + + 13 + 60 + 307336 + + + 60 + 64 + 311178 + + + 64 + 66 + 311178 + + + 66 + 68 + 353437 + + + 68 + 69 + 194006 + + + 69 + 70 + 217056 + + + 70 + 72 + 359200 + + + 72 + 74 + 322703 + + + 74 + 76 + 245869 + + + 76 + 79 + 330387 + + + 79 + 83 + 295811 + + + 83 + 91 + 316941 + + + 91 + 103 + 69150 + + + + + + + beginColumn + id + + + 12 + + + 1 + 11 + 21129 + + + 15 + 24 + 21129 + + + 28 + 57 + 19208 + + + 57 + 79 + 19208 + + + 87 + 119 + 19208 + + + 130 + 177 + 19208 + + + 195 + 269 + 19208 + + + 270 + 436 + 19208 + + + 443 + 835 + 19208 + + + 844 + 1367 + 19208 + + + 1419 + 2155 + 19208 + + + 2252 + 2517 + 19208 + + + 2521 + 226452 + 13445 + + + + + + + beginColumn + file + + + 12 + + + 1 + 9 + 17287 + + + 9 + 11 + 21129 + + + 11 + 15 + 15366 + + + 15 + 19 + 21129 + + + 23 + 68 + 19208 + + + 69 + 78 + 19208 + + + 79 + 100 + 13445 + + + 100 + 104 + 21129 + + + 104 + 109 + 19208 + + + 109 + 112 + 13445 + + + 112 + 115 + 19208 + + + 115 + 117 + 19208 + + + 117 + 123 + 19208 + + + 145 + 4769 + 9604 + + + + + + + beginColumn + beginLine + + + 12 + + + 1 + 10 + 21129 + + + 10 + 22 + 21129 + + + 23 + 39 + 19208 + + + 41 + 58 + 19208 + + + 58 + 84 + 19208 + + + 84 + 106 + 19208 + + + 108 + 166 + 19208 + + + 167 + 225 + 19208 + + + 230 + 376 + 19208 + + + 381 + 647 + 19208 + + + 657 + 941 + 19208 + + + 941 + 1090 + 19208 + + + 1102 + 2051 + 13445 + + + + + + + beginColumn + endLine + + + 12 + + + 1 + 10 + 21129 + + + 10 + 22 + 21129 + + + 23 + 39 + 19208 + + + 41 + 59 + 19208 + + + 59 + 86 + 19208 + + + 86 + 109 + 19208 + + + 114 + 168 + 19208 + + + 170 + 224 + 19208 + + + 229 + 379 + 19208 + + + 382 + 647 + 19208 + + + 658 + 941 + 19208 + + + 941 + 1089 + 19208 + + + 1102 + 2051 + 13445 + + + + + + + beginColumn + endColumn + + + 12 + + + 1 + 8 + 21129 + + + 8 + 16 + 21129 + + + 16 + 23 + 21129 + + + 24 + 31 + 21129 + + + 32 + 37 + 21129 + + + 37 + 50 + 19208 + + + 50 + 60 + 19208 + + + 60 + 68 + 19208 + + + 68 + 80 + 19208 + + + 81 + 101 + 19208 + + + 101 + 121 + 19208 + + + 126 + 158 + 19208 + + + 159 + 393 + 7683 + + + + + + + endLine + id + + + 12 + + + 1 + 14 + 309257 + + + 14 + 124 + 305416 + + + 124 + 143 + 309257 + + + 143 + 152 + 334228 + + + 152 + 159 + 322703 + + + 159 + 164 + 299653 + + + 164 + 169 + 341912 + + + 169 + 173 + 309257 + + + 173 + 178 + 338070 + + + 178 + 184 + 305416 + + + 184 + 193 + 315020 + + + 193 + 212 + 301574 + + + 212 + 4769 + 153668 + + + + + + + endLine + file + + + 12 + + + 1 + 7 + 324624 + + + 7 + 66 + 318862 + + + 66 + 74 + 320782 + + + 74 + 80 + 355358 + + + 80 + 83 + 339991 + + + 83 + 85 + 268919 + + + 85 + 87 + 343833 + + + 87 + 89 + 355358 + + + 89 + 91 + 266999 + + + 91 + 94 + 345754 + + + 94 + 99 + 324624 + + + 99 + 130 + 301574 + + + 131 + 4769 + 78755 + + + + + + + endLine + beginLine + + + 12 + + + 1 + 2 + 1000766 + + + 2 + 3 + 1392620 + + + 3 + 4 + 908564 + + + 4 + 6 + 336149 + + + 6 + 19 + 299653 + + + 19 + 22 + 7683 + + + + + + + endLine + beginColumn + + + 12 + + + 1 + 5 + 309257 + + + 5 + 17 + 284286 + + + 17 + 19 + 232423 + + + 19 + 20 + 280444 + + + 20 + 21 + 420667 + + + 21 + 22 + 407221 + + + 22 + 23 + 482134 + + + 23 + 24 + 437955 + + + 24 + 25 + 334228 + + + 25 + 26 + 259315 + + + 26 + 29 + 363041 + + + 29 + 39 + 134459 + + + + + + + endLine + endColumn + + + 12 + + + 1 + 13 + 313099 + + + 13 + 60 + 305416 + + + 60 + 64 + 305416 + + + 64 + 66 + 303495 + + + 66 + 68 + 357279 + + + 68 + 69 + 197848 + + + 69 + 70 + 201689 + + + 70 + 71 + 218977 + + + 71 + 73 + 326545 + + + 73 + 75 + 263157 + + + 75 + 77 + 257394 + + + 77 + 80 + 299653 + + + 80 + 85 + 318862 + + + 85 + 119 + 276603 + + + + + + + endColumn + id + + + 12 + + + 1 + 2 + 205531 + + + 2 + 3 + 90280 + + + 3 + 5 + 71071 + + + 5 + 13 + 71071 + + + 13 + 53 + 67229 + + + 53 + 138 + 67229 + + + 142 + 346 + 67229 + + + 357 + 967 + 67229 + + + 1050 + 2386 + 67229 + + + 2392 + 4902 + 67229 + + + 4949 + 5933 + 32654 + + + + + + + endColumn + file + + + 12 + + + 1 + 2 + 213215 + + + 2 + 3 + 86438 + + + 3 + 5 + 74913 + + + 5 + 13 + 71071 + + + 13 + 42 + 67229 + + + 42 + 77 + 67229 + + + 77 + 102 + 69150 + + + 102 + 114 + 67229 + + + 114 + 139 + 67229 + + + 139 + 169 + 69150 + + + 173 + 4769 + 21129 + + + + + + + endColumn + beginLine + + + 12 + + + 1 + 2 + 217056 + + + 2 + 3 + 88359 + + + 3 + 5 + 69150 + + + 5 + 13 + 69150 + + + 13 + 50 + 67229 + + + 50 + 113 + 67229 + + + 114 + 266 + 67229 + + + 269 + 636 + 67229 + + + 648 + 1197 + 67229 + + + 1198 + 1635 + 69150 + + + 1639 + 1722 + 24971 + + + + + + + endColumn + beginColumn + + + 12 + + + 1 + 2 + 274682 + + + 2 + 3 + 105647 + + + 3 + 6 + 76834 + + + 6 + 14 + 76834 + + + 14 + 25 + 74913 + + + 25 + 36 + 71071 + + + 36 + 47 + 67229 + + + 47 + 54 + 67229 + + + 54 + 65 + 59546 + + + + + + + endColumn + endLine + + + 12 + + + 1 + 2 + 217056 + + + 2 + 3 + 86438 + + + 3 + 5 + 69150 + + + 5 + 13 + 69150 + + + 13 + 51 + 67229 + + + 51 + 112 + 67229 + + + 112 + 262 + 67229 + + + 262 + 630 + 67229 + + + 637 + 1186 + 67229 + + + 1197 + 1625 + 67229 + + + 1632 + 1722 + 28812 + + + + + + + + + hasLocation + 340930835 + + + locatableid + 340658074 + + + id + 12195515 + + + + + locatableid + id + + + 12 + + + 1 + 2 + 340385312 + + + 2 + 3 + 272761 + + + + + + + id + locatableid + + + 12 + + + 1 + 2 + 2091812 + + + 2 + 3 + 1333074 + + + 3 + 4 + 772184 + + + 4 + 6 + 1085283 + + + 6 + 8 + 1062233 + + + 8 + 11 + 1100650 + + + 11 + 15 + 1048787 + + + 15 + 21 + 964269 + + + 21 + 32 + 916248 + + + 32 + 64 + 920090 + + + 64 + 9549 + 900881 + + + + + + + + + numlines + 303305105 + + + element_id + 303305105 + + + num_lines + 618515 + + + num_code + 612753 + + + num_comment + 1893964 + + + + + element_id + num_lines + + + 12 + + + 1 + 2 + 303305105 + + + + + + + element_id + num_code + + + 12 + + + 1 + 2 + 303305105 + + + + + + + element_id + num_comment + + + 12 + + + 1 + 2 + 303305105 + + + + + + + num_lines + element_id + + + 12 + + + 1 + 2 + 320782 + + + 2 + 3 + 78755 + + + 3 + 4 + 61467 + + + 4 + 7 + 49942 + + + 7 + 14 + 48021 + + + 15 + 194 + 48021 + + + 320 + 149659 + 11525 + + + + + + + num_lines + num_code + + + 12 + + + 1 + 2 + 509026 + + + 2 + 3 + 69150 + + + 3 + 6 + 40337 + + + + + + + num_lines + num_comment + + + 12 + + + 1 + 2 + 380329 + + + 2 + 3 + 97963 + + + 3 + 4 + 51863 + + + 4 + 6 + 53783 + + + 6 + 987 + 34575 + + + + + + + num_code + element_id + + + 12 + + + 1 + 2 + 316941 + + + 2 + 3 + 78755 + + + 3 + 4 + 61467 + + + 4 + 7 + 51863 + + + 7 + 15 + 46100 + + + 16 + 214 + 46100 + + + 325 + 78746 + 11525 + + + + + + + num_code + num_lines + + + 12 + + + 1 + 2 + 516710 + + + 2 + 3 + 51863 + + + 3 + 8 + 44179 + + + + + + + num_code + num_comment + + + 12 + + + 1 + 2 + 370725 + + + 2 + 3 + 101805 + + + 3 + 4 + 53783 + + + 4 + 6 + 46100 + + + 6 + 987 + 40337 + + + + + + + num_comment + element_id + + + 12 + + + 1 + 7 + 153668 + + + 7 + 49 + 142143 + + + 49 + 71 + 147905 + + + 71 + 78 + 151747 + + + 78 + 83 + 145985 + + + 83 + 87 + 163272 + + + 87 + 89 + 140222 + + + 89 + 91 + 134459 + + + 91 + 92 + 80675 + + + 92 + 93 + 96042 + + + 93 + 94 + 105647 + + + 94 + 95 + 97963 + + + 95 + 97 + 151747 + + + 97 + 119 + 144064 + + + 120 + 75134 + 38417 + + + + + + + num_comment + num_lines + + + 12 + + + 1 + 2 + 1550130 + + + 2 + 3 + 165193 + + + 3 + 7 + 145985 + + + 7 + 120 + 32654 + + + + + + + num_comment + num_code + + + 12 + + + 1 + 2 + 1550130 + + + 2 + 3 + 165193 + + + 3 + 7 + 145985 + + + 7 + 122 + 32654 + + + + + + + + + files + 9158642 + + + id + 9158642 + + + name + 9158642 + + + + + id + name + + + 12 + + + 1 + 2 + 9158642 + + + + + + + name + id + + + 12 + + + 1 + 2 + 9158642 + + + + + + + + + folders + 1415670 + + + id + 1415670 + + + name + 1415670 + + + + + id + name + + + 12 + + + 1 + 2 + 1415670 + + + + + + + name + id + + + 12 + + + 1 + 2 + 1415670 + + + + + + + + + containerparent + 10570471 + + + parent + 1463692 + + + child + 10570471 + + + + + parent + child + + + 12 + + + 1 + 2 + 843255 + + + 2 + 3 + 149826 + + + 3 + 5 + 128697 + + + 5 + 11 + 124855 + + + 11 + 21 + 113330 + + + 21 + 194 + 103726 + + + + + + + child + parent + + + 12 + + + 1 + 2 + 10570471 + + + + + + + + + cupackage + 7979236 + + + id + 7979236 + + + packageid + 576256 + + + + + id + packageid + + + 12 + + + 1 + 2 + 7979236 + + + + + + + packageid + id + + + 12 + + + 1 + 2 + 121013 + + + 2 + 3 + 80675 + + + 3 + 4 + 42258 + + + 4 + 6 + 49942 + + + 6 + 9 + 49942 + + + 9 + 12 + 51863 + + + 12 + 17 + 48021 + + + 17 + 23 + 46100 + + + 24 + 43 + 44179 + + + 43 + 187 + 42258 + + + + + + + + + jarManifestMain + 172742 + + + fileid + 13275 + + + keyName + 12611 + + + value + 89772 + + + + + fileid + keyName + + + 12 + + + 1 + 4 + 995 + + + 5 + 6 + 2323 + + + 6 + 7 + 2157 + + + 9 + 13 + 1161 + + + 13 + 15 + 1161 + + + 15 + 17 + 829 + + + 17 + 18 + 829 + + + 19 + 21 + 829 + + + 21 + 24 + 1161 + + + 24 + 27 + 1161 + + + 28 + 35 + 663 + + + + + + + fileid + value + + + 12 + + + 1 + 4 + 995 + + + 5 + 6 + 2489 + + + 6 + 7 + 1991 + + + 8 + 10 + 663 + + + 10 + 12 + 995 + + + 12 + 13 + 663 + + + 14 + 15 + 995 + + + 15 + 17 + 1161 + + + 17 + 18 + 829 + + + 18 + 20 + 1161 + + + 21 + 24 + 1161 + + + 29 + 30 + 165 + + + + + + + keyName + fileid + + + 12 + + + 1 + 2 + 5144 + + + 2 + 3 + 829 + + + 3 + 4 + 829 + + + 5 + 8 + 995 + + + 10 + 20 + 995 + + + 24 + 28 + 829 + + + 28 + 31 + 995 + + + 32 + 38 + 995 + + + 39 + 81 + 995 + + + + + + + keyName + value + + + 12 + + + 1 + 2 + 5807 + + + 2 + 3 + 995 + + + 3 + 5 + 995 + + + 5 + 8 + 995 + + + 10 + 16 + 1161 + + + 17 + 26 + 1161 + + + 27 + 36 + 995 + + + 37 + 53 + 497 + + + + + + + value + fileid + + + 12 + + + 1 + 2 + 75999 + + + 2 + 3 + 4480 + + + 3 + 6 + 6969 + + + 6 + 81 + 2323 + + + + + + + value + keyName + + + 12 + + + 1 + 2 + 75668 + + + 2 + 3 + 8794 + + + 3 + 6 + 5310 + + + + + + + + + jarManifestEntries + 30201 + + + fileid + 61 + + + entryName + 30129 + + + keyName + 27 + + + value + 30163 + + + + + fileid + entryName + + + 12 + + + 1 + 2 + 4 + + + 4 + 10 + 3 + + + 10 + 12 + 4 + + + 12 + 31 + 4 + + + 65 + 82 + 4 + + + 123 + 164 + 4 + + + 178 + 240 + 4 + + + 253 + 294 + 4 + + + 307 + 357 + 4 + + + 361 + 395 + 4 + + + 433 + 461 + 4 + + + 591 + 662 + 4 + + + 957 + 2267 + 4 + + + 3647 + 3762 + 3 + + + + + + + fileid + keyName + + + 12 + + + 1 + 2 + 57 + + + 6 + 10 + 3 + + + + + + + fileid + value + + + 12 + + + 1 + 2 + 4 + + + 3 + 8 + 4 + + + 9 + 13 + 4 + + + 24 + 66 + 4 + + + 70 + 124 + 4 + + + 127 + 179 + 4 + + + 195 + 254 + 4 + + + 265 + 308 + 4 + + + 320 + 362 + 4 + + + 381 + 434 + 4 + + + 434 + 592 + 4 + + + 618 + 958 + 4 + + + 1671 + 3648 + 4 + + + 3761 + 3762 + 1 + + + + + + + entryName + fileid + + + 12 + + + 1 + 2 + 30113 + + + 2 + 26 + 16 + + + + + + + entryName + keyName + + + 12 + + + 1 + 2 + 30126 + + + 6 + 10 + 3 + + + + + + + entryName + value + + + 12 + + + 1 + 2 + 30125 + + + 3 + 26 + 4 + + + + + + + keyName + fileid + + + 12 + + + 1 + 2 + 21 + + + 2 + 3 + 3 + + + 3 + 4 + 1 + + + 32 + 33 + 1 + + + + + + + keyName + entryName + + + 12 + + + 1 + 2 + 21 + + + 2 + 3 + 1 + + + 11 + 12 + 1 + + + 369 + 370 + 1 + + + 19366 + 19367 + 1 + + + + + + + keyName + value + + + 12 + + + 1 + 2 + 22 + + + 2 + 3 + 1 + + + 369 + 370 + 1 + + + 19390 + 19391 + 1 + + + + + + + value + fileid + + + 12 + + + 1 + 2 + 30162 + + + 2 + 3 + 1 + + + + + + + value + entryName + + + 12 + + + 1 + 2 + 30162 + + + 11 + 12 + 1 + + + + + + + value + keyName + + + 12 + + + 1 + 2 + 30155 + + + 2 + 3 + 7 + + + + + + + + + packages + 580098 + + + id + 580098 + + + nodeName + 580098 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 580098 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 580098 + + + + + + + + + primitives + 17287 + + + id + 17287 + + + nodeName + 17287 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 17287 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 17287 + + + + + + + + + modifiers + 26891 + + + id + 26891 + + + nodeName + 26891 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 26891 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 26891 + + + + + + + + + error_type + 1 + + + id + 1 + + + + + + classes + 12618104 + + + id + 12618104 + + + nodeName + 6732600 + + + parentid + 455242 + + + sourceid + 5253541 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 12618104 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 12618104 + + + + + + + id + sourceid + + + 12 + + + 1 + 2 + 12618104 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 5601216 + + + 2 + 3 + 726083 + + + 3 + 204 + 405300 + + + + + + + nodeName + parentid + + + 12 + + + 1 + 2 + 5950812 + + + 2 + 3 + 731846 + + + 3 + 52 + 49942 + + + + + + + nodeName + sourceid + + + 12 + + + 1 + 2 + 5921999 + + + 2 + 3 + 714558 + + + 3 + 160 + 96042 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 94121 + + + 2 + 3 + 46100 + + + 3 + 4 + 30733 + + + 4 + 5 + 26891 + + + 5 + 6 + 24971 + + + 6 + 8 + 40337 + + + 8 + 12 + 32654 + + + 12 + 18 + 38417 + + + 18 + 23 + 34575 + + + 23 + 40 + 36496 + + + 40 + 76 + 34575 + + + 83 + 891 + 15366 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 96042 + + + 2 + 3 + 46100 + + + 3 + 4 + 34575 + + + 4 + 5 + 28812 + + + 5 + 6 + 36496 + + + 6 + 9 + 40337 + + + 9 + 13 + 40337 + + + 13 + 18 + 26891 + + + 18 + 25 + 38417 + + + 26 + 41 + 36496 + + + 41 + 479 + 30733 + + + + + + + parentid + sourceid + + + 12 + + + 1 + 2 + 99884 + + + 2 + 3 + 57625 + + + 3 + 4 + 36496 + + + 4 + 5 + 32654 + + + 5 + 6 + 32654 + + + 6 + 8 + 34575 + + + 8 + 12 + 38417 + + + 12 + 18 + 32654 + + + 18 + 25 + 34575 + + + 25 + 47 + 34575 + + + 51 + 138 + 21129 + + + + + + + sourceid + id + + + 12 + + + 1 + 2 + 4694572 + + + 2 + 11 + 407221 + + + 11 + 426 + 151747 + + + + + + + sourceid + nodeName + + + 12 + + + 1 + 2 + 4694572 + + + 2 + 6 + 426430 + + + 6 + 224 + 132539 + + + + + + + sourceid + parentid + + + 12 + + + 1 + 2 + 5253541 + + + + + + + + + file_class + 17287 + + + id + 17287 + + + + + + class_object + 163272 + + + id + 163272 + + + instance + 163272 + + + + + id + instance + + + 12 + + + 1 + 2 + 163272 + + + + + + + instance + id + + + 12 + + + 1 + 2 + 163272 + + + + + + + + + type_companion_object + 307336 + + + id + 307336 + + + instance + 307336 + + + companion_object + 307336 + + + + + id + instance + + + 12 + + + 1 + 2 + 307336 + + + + + + + id + companion_object + + + 12 + + + 1 + 2 + 307336 + + + + + + + instance + id + + + 12 + + + 1 + 2 + 307336 + + + + + + + instance + companion_object + + + 12 + + + 1 + 2 + 307336 + + + + + + + companion_object + id + + + 12 + + + 1 + 2 + 307336 + + + + + + + companion_object + instance + + + 12 + + + 1 + 2 + 307336 + + + + + + + + + kt_nullable_types + 1920 + + + id + 1920 + + + classid + 1920 + + + + + id + classid + + + 12 + + + 1 + 2 + 1920 + + + + + + + classid + id + + + 12 + + + 1 + 2 + 1920 + + + + + + + + + kt_notnull_types + 172391 + + + id + 172391 + + + classid + 172391 + + + + + id + classid + + + 12 + + + 1 + 2 + 172391 + + + + + + + classid + id + + + 12 + + + 1 + 2 + 172391 + + + + + + + + + kt_type_alias + 1821 + + + id + 1821 + + + name + 1821 + + + kttypeid + 910 + + + + + id + name + + + 12 + + + 1 + 2 + 1821 + + + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 1821 + + + + + + + name + id + + + 12 + + + 1 + 2 + 1821 + + + + + + + name + kttypeid + + + 12 + + + 1 + 2 + 1821 + + + + + + + kttypeid + id + + + 12 + + + 2 + 3 + 910 + + + + + + + kttypeid + name + + + 12 + + + 2 + 3 + 910 + + + + + + + + + isRecord + 417 + + + id + 417 + + + + + + interfaces + 23200100 + + + id + 23200100 + + + nodeName + 8705320 + + + parentid + 430271 + + + sourceid + 2787162 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 23200100 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 23200100 + + + + + + + id + sourceid + + + 12 + + + 1 + 2 + 23200100 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 6834406 + + + 2 + 3 + 1079521 + + + 3 + 25 + 655011 + + + 25 + 345 + 136380 + + + + + + + nodeName + parentid + + + 12 + + + 1 + 2 + 7996524 + + + 2 + 4 + 695349 + + + 4 + 7 + 13445 + + + + + + + nodeName + sourceid + + + 12 + + + 1 + 2 + 7967711 + + + 2 + 4 + 718400 + + + 4 + 7 + 19208 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 113330 + + + 2 + 3 + 55704 + + + 3 + 4 + 48021 + + + 4 + 5 + 26891 + + + 5 + 8 + 36496 + + + 8 + 13 + 34575 + + + 13 + 18 + 34575 + + + 18 + 41 + 32654 + + + 42 + 182 + 32654 + + + 187 + 4152 + 15366 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 113330 + + + 2 + 3 + 55704 + + + 3 + 4 + 48021 + + + 4 + 5 + 38417 + + + 5 + 7 + 24971 + + + 7 + 10 + 32654 + + + 10 + 15 + 36496 + + + 15 + 28 + 32654 + + + 30 + 94 + 32654 + + + 100 + 1213 + 15366 + + + + + + + parentid + sourceid + + + 12 + + + 1 + 2 + 140222 + + + 2 + 3 + 65309 + + + 3 + 4 + 44179 + + + 4 + 5 + 34575 + + + 5 + 7 + 28812 + + + 7 + 9 + 34575 + + + 9 + 14 + 34575 + + + 14 + 26 + 32654 + + + 26 + 160 + 15366 + + + + + + + sourceid + id + + + 12 + + + 1 + 2 + 2391465 + + + 2 + 11 + 213215 + + + 11 + 1565 + 182481 + + + + + + + sourceid + nodeName + + + 12 + + + 1 + 2 + 2391465 + + + 2 + 6 + 217056 + + + 6 + 492 + 178639 + + + + + + + sourceid + parentid + + + 12 + + + 1 + 2 + 2787162 + + + + + + + + + fielddecls + 199475 + + + id + 199475 + + + parentid + 25503 + + + + + id + parentid + + + 12 + + + 1 + 2 + 199475 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 4554 + + + 2 + 3 + 5465 + + + 3 + 4 + 1821 + + + 4 + 6 + 1821 + + + 6 + 7 + 2732 + + + 7 + 9 + 1821 + + + 9 + 10 + 910 + + + 10 + 11 + 1821 + + + 13 + 18 + 1821 + + + 19 + 20 + 1821 + + + 57 + 58 + 910 + + + + + + + + + fieldDeclaredIn + 199475 + + + fieldId + 199475 + + + fieldDeclId + 199475 + + + pos + 910 + + + + + fieldId + fieldDeclId + + + 12 + + + 1 + 2 + 199475 + + + + + + + fieldId + pos + + + 12 + + + 1 + 2 + 199475 + + + + + + + fieldDeclId + fieldId + + + 12 + + + 1 + 2 + 199475 + + + + + + + fieldDeclId + pos + + + 12 + + + 1 + 2 + 199475 + + + + + + + pos + fieldId + + + 12 + + + 219 + 220 + 910 + + + + + + + pos + fieldDeclId + + + 12 + + + 219 + 220 + 910 + + + + + + + + + fields + 19350704 + + + id + 19350704 + + + nodeName + 13628474 + + + typeid + 3038794 + + + parentid + 4089502 + + + sourceid + 19350704 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 19350704 + + + + + + + id + typeid + + + 12 + + + 1 + 2 + 19350704 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 19350704 + + + + + + + id + sourceid + + + 12 + + + 1 + 2 + 19350704 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 12016876 + + + 2 + 3 + 1123700 + + + 3 + 722 + 487897 + + + + + + + nodeName + typeid + + + 12 + + + 1 + 2 + 12416414 + + + 2 + 5 + 1085283 + + + 5 + 160 + 126776 + + + + + + + nodeName + parentid + + + 12 + + + 1 + 2 + 12016876 + + + 2 + 3 + 1123700 + + + 3 + 722 + 487897 + + + + + + + nodeName + sourceid + + + 12 + + + 1 + 2 + 12016876 + + + 2 + 3 + 1123700 + + + 3 + 722 + 487897 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 2059157 + + + 2 + 3 + 320782 + + + 3 + 4 + 213215 + + + 4 + 8 + 245869 + + + 8 + 2588 + 199769 + + + + + + + typeid + nodeName + + + 12 + + + 1 + 2 + 2120625 + + + 2 + 3 + 299653 + + + 3 + 4 + 199769 + + + 4 + 9 + 255473 + + + 9 + 2016 + 163272 + + + + + + + typeid + parentid + + + 12 + + + 1 + 2 + 2706486 + + + 2 + 4 + 251632 + + + 4 + 1014 + 80675 + + + + + + + typeid + sourceid + + + 12 + + + 1 + 2 + 2059157 + + + 2 + 3 + 320782 + + + 3 + 4 + 213215 + + + 4 + 8 + 245869 + + + 8 + 2588 + 199769 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 2427962 + + + 2 + 3 + 478293 + + + 3 + 4 + 303495 + + + 4 + 6 + 338070 + + + 6 + 13 + 330387 + + + 13 + 1610 + 211294 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 2427962 + + + 2 + 3 + 478293 + + + 3 + 4 + 303495 + + + 4 + 6 + 338070 + + + 6 + 13 + 330387 + + + 13 + 1610 + 211294 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 3031110 + + + 2 + 3 + 595465 + + + 3 + 5 + 347674 + + + 5 + 76 + 115251 + + + + + + + parentid + sourceid + + + 12 + + + 1 + 2 + 2427962 + + + 2 + 3 + 478293 + + + 3 + 4 + 303495 + + + 4 + 6 + 338070 + + + 6 + 13 + 330387 + + + 13 + 1610 + 211294 + + + + + + + sourceid + id + + + 12 + + + 1 + 2 + 19350704 + + + + + + + sourceid + nodeName + + + 12 + + + 1 + 2 + 19350704 + + + + + + + sourceid + typeid + + + 12 + + + 1 + 2 + 19350704 + + + + + + + sourceid + parentid + + + 12 + + + 1 + 2 + 19350704 + + + + + + + + + fieldsKotlinType + 19350704 + + + id + 19350704 + + + kttypeid + 1920 + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 19350704 + + + + + + + kttypeid + id + + + 12 + + + 10074 + 10075 + 1920 + + + + + + + + + constrs + 8006128 + + + id + 8006128 + + + nodeName + 4333451 + + + signature + 6803672 + + + typeid + 3841 + + + parentid + 5639633 + + + sourceid + 5720309 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 8006128 + + + + + + + id + signature + + + 12 + + + 1 + 2 + 8006128 + + + + + + + id + typeid + + + 12 + + + 1 + 2 + 8006128 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 8006128 + + + + + + + id + sourceid + + + 12 + + + 1 + 2 + 8006128 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 2623889 + + + 2 + 3 + 1085283 + + + 3 + 4 + 259315 + + + 4 + 11 + 326545 + + + 11 + 36 + 38417 + + + + + + + nodeName + signature + + + 12 + + + 1 + 2 + 2977327 + + + 2 + 3 + 868226 + + + 3 + 5 + 341912 + + + 5 + 19 + 145985 + + + + + + + nodeName + typeid + + + 12 + + + 1 + 2 + 4333451 + + + + + + + nodeName + parentid + + + 12 + + + 1 + 2 + 3764878 + + + 2 + 3 + 401458 + + + 3 + 36 + 167114 + + + + + + + nodeName + sourceid + + + 12 + + + 1 + 2 + 2737220 + + + 2 + 3 + 1083362 + + + 3 + 5 + 353437 + + + 5 + 32 + 159431 + + + + + + + signature + id + + + 12 + + + 1 + 2 + 6302329 + + + 2 + 36 + 501343 + + + + + + + signature + nodeName + + + 12 + + + 1 + 2 + 6803672 + + + + + + + signature + typeid + + + 12 + + + 1 + 2 + 6803672 + + + + + + + signature + parentid + + + 12 + + + 1 + 2 + 6302329 + + + 2 + 36 + 501343 + + + + + + + signature + sourceid + + + 12 + + + 1 + 2 + 6461760 + + + 2 + 23 + 341912 + + + + + + + typeid + id + + + 12 + + + 22 + 23 + 1920 + + + 4146 + 4147 + 1920 + + + + + + + typeid + nodeName + + + 12 + + + 1 + 2 + 1920 + + + 2255 + 2256 + 1920 + + + + + + + typeid + signature + + + 12 + + + 1 + 2 + 1920 + + + 3541 + 3542 + 1920 + + + + + + + typeid + parentid + + + 12 + + + 22 + 23 + 1920 + + + 2914 + 2915 + 1920 + + + + + + + typeid + sourceid + + + 12 + + + 22 + 23 + 1920 + + + 2956 + 2957 + 1920 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 4256617 + + + 2 + 3 + 895118 + + + 3 + 6 + 434113 + + + 6 + 19 + 53783 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 5639633 + + + + + + + parentid + signature + + + 12 + + + 1 + 2 + 4256617 + + + 2 + 3 + 895118 + + + 3 + 6 + 434113 + + + 6 + 19 + 53783 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 5639633 + + + + + + + parentid + sourceid + + + 12 + + + 1 + 2 + 4256617 + + + 2 + 3 + 895118 + + + 3 + 6 + 434113 + + + 6 + 19 + 53783 + + + + + + + sourceid + id + + + 12 + + + 1 + 2 + 5357267 + + + 2 + 209 + 363041 + + + + + + + sourceid + nodeName + + + 12 + + + 1 + 2 + 5357267 + + + 2 + 172 + 363041 + + + + + + + sourceid + signature + + + 12 + + + 1 + 2 + 5357267 + + + 2 + 172 + 363041 + + + + + + + sourceid + typeid + + + 12 + + + 1 + 2 + 5720309 + + + + + + + sourceid + parentid + + + 12 + + + 1 + 2 + 5357267 + + + 2 + 209 + 363041 + + + + + + + + + constrsKotlinType + 8006128 + + + id + 8006128 + + + kttypeid + 1920 + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 8006128 + + + + + + + kttypeid + id + + + 12 + + + 4168 + 4169 + 1920 + + + + + + + + + methods + 109719302 + + + id + 109719302 + + + nodeName + 22908130 + + + signature + 33369112 + + + typeid + 13338425 + + + parentid + 12810189 + + + sourceid + 67091663 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 109719302 + + + + + + + id + signature + + + 12 + + + 1 + 2 + 109719302 + + + + + + + id + typeid + + + 12 + + + 1 + 2 + 109719302 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 109719302 + + + + + + + id + sourceid + + + 12 + + + 1 + 2 + 109719302 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 13324979 + + + 2 + 3 + 4070294 + + + 3 + 4 + 1573181 + + + 4 + 7 + 2026503 + + + 7 + 56 + 1719166 + + + 57 + 1769 + 194006 + + + + + + + nodeName + signature + + + 12 + + + 1 + 2 + 19150935 + + + 2 + 3 + 2228193 + + + 3 + 298 + 1529001 + + + + + + + nodeName + typeid + + + 12 + + + 1 + 2 + 19179748 + + + 2 + 3 + 1872834 + + + 3 + 25 + 1726849 + + + 25 + 741 + 128697 + + + + + + + nodeName + parentid + + + 12 + + + 1 + 2 + 14028012 + + + 2 + 3 + 3889733 + + + 3 + 4 + 1502109 + + + 4 + 7 + 1817129 + + + 7 + 1099 + 1671144 + + + + + + + nodeName + sourceid + + + 12 + + + 1 + 2 + 13743725 + + + 2 + 3 + 4283509 + + + 3 + 4 + 1544368 + + + 4 + 7 + 1857467 + + + 7 + 800 + 1479059 + + + + + + + signature + id + + + 12 + + + 1 + 2 + 22735253 + + + 2 + 3 + 5434102 + + + 3 + 5 + 2635414 + + + 5 + 157 + 2502875 + + + 157 + 1096 + 61467 + + + + + + + signature + nodeName + + + 12 + + + 1 + 2 + 33369112 + + + + + + + signature + typeid + + + 12 + + + 1 + 2 + 29957672 + + + 2 + 5 + 2650781 + + + 5 + 739 + 760659 + + + + + + + signature + parentid + + + 12 + + + 1 + 2 + 22741015 + + + 2 + 3 + 5432181 + + + 3 + 5 + 2631572 + + + 5 + 157 + 2502875 + + + 157 + 1096 + 61467 + + + + + + + signature + sourceid + + + 12 + + + 1 + 2 + 23365294 + + + 2 + 3 + 5656921 + + + 3 + 6 + 2900492 + + + 6 + 795 + 1446404 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 6603903 + + + 2 + 3 + 2729536 + + + 3 + 4 + 1208218 + + + 4 + 6 + 1119859 + + + 6 + 15 + 1019974 + + + 15 + 10335 + 656932 + + + + + + + typeid + nodeName + + + 12 + + + 1 + 2 + 8714924 + + + 2 + 3 + 2620047 + + + 3 + 6 + 1167880 + + + 6 + 2888 + 835572 + + + + + + + typeid + signature + + + 12 + + + 1 + 2 + 8565097 + + + 2 + 3 + 2602760 + + + 3 + 6 + 1210139 + + + 6 + 4142 + 960428 + + + + + + + typeid + parentid + + + 12 + + + 1 + 2 + 7714158 + + + 2 + 3 + 2869759 + + + 3 + 4 + 1108333 + + + 4 + 8 + 1069916 + + + 8 + 2865 + 576256 + + + + + + + typeid + sourceid + + + 12 + + + 1 + 2 + 7166714 + + + 2 + 3 + 2524004 + + + 3 + 4 + 1096808 + + + 4 + 6 + 1094888 + + + 6 + 16 + 1016132 + + + 16 + 6435 + 439876 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 3630418 + + + 2 + 3 + 1456008 + + + 3 + 4 + 1164038 + + + 4 + 5 + 735687 + + + 5 + 7 + 1021895 + + + 7 + 10 + 1106413 + + + 10 + 13 + 1146751 + + + 13 + 21 + 1181326 + + + 21 + 40 + 1021895 + + + 40 + 319 + 345754 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 3678439 + + + 2 + 3 + 1457929 + + + 3 + 4 + 1231268 + + + 4 + 5 + 791392 + + + 5 + 7 + 960428 + + + 7 + 10 + 1183247 + + + 10 + 13 + 1102571 + + + 13 + 18 + 849018 + + + 18 + 26 + 968111 + + + 26 + 290 + 587781 + + + + + + + parentid + signature + + + 12 + + + 1 + 2 + 3630418 + + + 2 + 3 + 1456008 + + + 3 + 4 + 1164038 + + + 4 + 5 + 735687 + + + 5 + 7 + 1021895 + + + 7 + 10 + 1106413 + + + 10 + 13 + 1146751 + + + 13 + 21 + 1181326 + + + 21 + 40 + 1021895 + + + 40 + 319 + 345754 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 4348818 + + + 2 + 3 + 1757583 + + + 3 + 4 + 1436800 + + + 4 + 5 + 922010 + + + 5 + 6 + 743371 + + + 6 + 7 + 564731 + + + 7 + 8 + 879752 + + + 8 + 11 + 1160197 + + + 11 + 31 + 964269 + + + 33 + 78 + 32654 + + + + + + + parentid + sourceid + + + 12 + + + 1 + 2 + 3630418 + + + 2 + 3 + 1456008 + + + 3 + 4 + 1164038 + + + 4 + 5 + 735687 + + + 5 + 7 + 1021895 + + + 7 + 10 + 1106413 + + + 10 + 13 + 1146751 + + + 13 + 21 + 1181326 + + + 21 + 40 + 1021895 + + + 40 + 319 + 345754 + + + + + + + sourceid + id + + + 12 + + + 1 + 2 + 61836200 + + + 2 + 50 + 5032643 + + + 52 + 286 + 222819 + + + + + + + sourceid + nodeName + + + 12 + + + 1 + 2 + 67091663 + + + + + + + sourceid + signature + + + 12 + + + 1 + 2 + 66767038 + + + 2 + 284 + 324624 + + + + + + + sourceid + typeid + + + 12 + + + 1 + 2 + 65030584 + + + 2 + 209 + 2061078 + + + + + + + sourceid + parentid + + + 12 + + + 1 + 2 + 61836200 + + + 2 + 50 + 5032643 + + + 52 + 286 + 222819 + + + + + + + + + methodsKotlinType + 109719302 + + + id + 109719302 + + + kttypeid + 1920 + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 109719302 + + + + + + + kttypeid + id + + + 12 + + + 57120 + 57121 + 1920 + + + + + + + + + params + 120852585 + + + id + 120852585 + + + typeid + 12833239 + + + pos + 42258 + + + parentid + 65007534 + + + sourceid + 73639861 + + + + + id + typeid + + + 12 + + + 1 + 2 + 120852585 + + + + + + + id + pos + + + 12 + + + 1 + 2 + 120852585 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 120852585 + + + + + + + id + sourceid + + + 12 + + + 1 + 2 + 120852585 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 6763334 + + + 2 + 3 + 1945827 + + + 3 + 4 + 948902 + + + 4 + 6 + 1148671 + + + 6 + 12 + 1018053 + + + 12 + 326 + 966190 + + + 343 + 6738 + 42258 + + + + + + + typeid + pos + + + 12 + + + 1 + 2 + 10436011 + + + 2 + 3 + 1342678 + + + 3 + 8 + 964269 + + + 8 + 17 + 90280 + + + + + + + typeid + parentid + + + 12 + + + 1 + 2 + 7005362 + + + 2 + 3 + 1895885 + + + 3 + 4 + 975794 + + + 4 + 6 + 1087204 + + + 6 + 13 + 1008449 + + + 13 + 4326 + 860543 + + + + + + + typeid + sourceid + + + 12 + + + 1 + 2 + 7216656 + + + 2 + 3 + 1788317 + + + 3 + 4 + 996924 + + + 4 + 6 + 1117938 + + + 6 + 13 + 1002686 + + + 13 + 5757 + 710716 + + + + + + + pos + id + + + 12 + + + 1 + 2 + 3841 + + + 50 + 53 + 3841 + + + 104 + 106 + 3841 + + + 157 + 165 + 3841 + + + 214 + 231 + 3841 + + + 291 + 315 + 3841 + + + 485 + 606 + 3841 + + + 804 + 1067 + 3841 + + + 1445 + 2015 + 3841 + + + 3084 + 5199 + 3841 + + + 12689 + 33844 + 3841 + + + + + + + pos + typeid + + + 12 + + + 1 + 2 + 3841 + + + 2 + 5 + 3841 + + + 6 + 7 + 3841 + + + 11 + 14 + 3841 + + + 15 + 20 + 3841 + + + 27 + 37 + 3841 + + + 57 + 75 + 3841 + + + 97 + 153 + 3841 + + + 201 + 289 + 3841 + + + 403 + 777 + 3841 + + + 1979 + 5089 + 3841 + + + + + + + pos + parentid + + + 12 + + + 1 + 2 + 3841 + + + 50 + 53 + 3841 + + + 104 + 106 + 3841 + + + 157 + 165 + 3841 + + + 214 + 231 + 3841 + + + 291 + 315 + 3841 + + + 485 + 606 + 3841 + + + 804 + 1067 + 3841 + + + 1445 + 2015 + 3841 + + + 3084 + 5199 + 3841 + + + 12689 + 33844 + 3841 + + + + + + + pos + sourceid + + + 12 + + + 1 + 2 + 3841 + + + 2 + 5 + 3841 + + + 6 + 8 + 3841 + + + 11 + 15 + 3841 + + + 16 + 29 + 3841 + + + 39 + 63 + 3841 + + + 101 + 144 + 3841 + + + 210 + 386 + 3841 + + + 628 + 1069 + 3841 + + + 1955 + 3748 + 3841 + + + 8555 + 21355 + 3841 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 40633790 + + + 2 + 3 + 14389133 + + + 3 + 4 + 4060689 + + + 4 + 10 + 4992305 + + + 10 + 23 + 931615 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 45326442 + + + 2 + 3 + 14805959 + + + 3 + 23 + 4875132 + + + + + + + parentid + pos + + + 12 + + + 1 + 2 + 40633790 + + + 2 + 3 + 14389133 + + + 3 + 4 + 4060689 + + + 4 + 10 + 4992305 + + + 10 + 23 + 931615 + + + + + + + parentid + sourceid + + + 12 + + + 1 + 2 + 40633790 + + + 2 + 3 + 14389133 + + + 3 + 4 + 4060689 + + + 4 + 10 + 4992305 + + + 10 + 23 + 931615 + + + + + + + sourceid + id + + + 12 + + + 1 + 2 + 68584168 + + + 2 + 286 + 5055693 + + + + + + + sourceid + typeid + + + 12 + + + 1 + 2 + 71932220 + + + 2 + 286 + 1707641 + + + + + + + sourceid + pos + + + 12 + + + 1 + 2 + 73639861 + + + + + + + sourceid + parentid + + + 12 + + + 1 + 2 + 68584168 + + + 2 + 286 + 5055693 + + + + + + + + + paramsKotlinType + 120852585 + + + id + 120852585 + + + kttypeid + 1920 + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 120852585 + + + + + + + kttypeid + id + + + 12 + + + 62916 + 62917 + 1920 + + + + + + + + + paramName + 15639610 + + + id + 15639610 + + + nodeName + 2335761 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 15639610 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 998845 + + + 2 + 3 + 451401 + + + 3 + 4 + 249711 + + + 4 + 5 + 170956 + + + 5 + 8 + 182481 + + + 8 + 18 + 176718 + + + 18 + 769 + 105647 + + + + + + + + + isVarargsParam + 945061 + + + param + 945061 + + + + + + exceptions + 1232644 + + + id + 1232644 + + + typeid + 36990 + + + parentid + 987367 + + + + + id + typeid + + + 12 + + + 1 + 2 + 1232644 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 1232644 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 11950 + + + 2 + 3 + 3983 + + + 3 + 4 + 4552 + + + 4 + 7 + 2276 + + + 7 + 8 + 2845 + + + 9 + 13 + 3414 + + + 20 + 35 + 2845 + + + 41 + 93 + 2845 + + + 106 + 813 + 2276 + + + + + + + typeid + parentid + + + 12 + + + 1 + 2 + 11950 + + + 2 + 3 + 3983 + + + 3 + 4 + 4552 + + + 4 + 7 + 2276 + + + 7 + 8 + 2845 + + + 9 + 13 + 3414 + + + 20 + 35 + 2845 + + + 41 + 93 + 2845 + + + 106 + 813 + 2276 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 755179 + + + 2 + 3 + 224220 + + + 3 + 6 + 7967 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 755179 + + + 2 + 3 + 224220 + + + 3 + 6 + 7967 + + + + + + + + + isAnnotType + 29260 + + + interfaceid + 29260 + + + + + + isAnnotElem + 61065 + + + methodid + 61065 + + + + + + annotValue + 1574925 + + + parentid + 568174 + + + id2 + 52104 + + + value + 1574925 + + + + + parentid + id2 + + + 12 + + + 1 + 2 + 153493 + + + 2 + 3 + 252724 + + + 3 + 4 + 48951 + + + 4 + 6 + 26550 + + + 6 + 7 + 35179 + + + 7 + 9 + 46628 + + + 9 + 13 + 4646 + + + + + + + parentid + value + + + 12 + + + 1 + 2 + 138061 + + + 2 + 3 + 268157 + + + 3 + 4 + 47292 + + + 4 + 6 + 26052 + + + 6 + 8 + 39659 + + + 8 + 10 + 44139 + + + 10 + 13 + 4812 + + + + + + + id2 + parentid + + + 12 + + + 1 + 2 + 17091 + + + 2 + 3 + 5144 + + + 3 + 4 + 2655 + + + 4 + 6 + 4812 + + + 6 + 9 + 4314 + + + 9 + 15 + 4148 + + + 16 + 25 + 4314 + + + 27 + 86 + 3982 + + + 86 + 153 + 4148 + + + 164 + 1105 + 1493 + + + + + + + id2 + value + + + 12 + + + 1 + 2 + 15266 + + + 2 + 3 + 6637 + + + 3 + 4 + 2820 + + + 4 + 6 + 3816 + + + 6 + 8 + 3816 + + + 8 + 10 + 4812 + + + 10 + 25 + 4148 + + + 25 + 53 + 3982 + + + 53 + 132 + 3982 + + + 134 + 1105 + 2820 + + + + + + + value + parentid + + + 12 + + + 1 + 2 + 1574925 + + + + + + + value + id2 + + + 12 + + + 1 + 2 + 1574925 + + + + + + + + + isEnumType + 397617 + + + classid + 397617 + + + + + + isEnumConst + 3081053 + + + fieldid + 3081053 + + + + + + typeVars + 6288883 + + + id + 6288883 + + + nodeName + 86438 + + + pos + 7683 + + + kind + 1920 + + + parentid + 4444861 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 6288883 + + + + + + + id + pos + + + 12 + + + 1 + 2 + 6288883 + + + + + + + id + kind + + + 12 + + + 1 + 2 + 6288883 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 6288883 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 21129 + + + 2 + 3 + 11525 + + + 3 + 4 + 9604 + + + 4 + 7 + 7683 + + + 7 + 10 + 7683 + + + 10 + 28 + 7683 + + + 36 + 69 + 7683 + + + 71 + 412 + 7683 + + + 603 + 710 + 5762 + + + + + + + nodeName + pos + + + 12 + + + 1 + 2 + 51863 + + + 2 + 3 + 23050 + + + 3 + 4 + 9604 + + + 4 + 5 + 1920 + + + + + + + nodeName + kind + + + 12 + + + 1 + 2 + 86438 + + + + + + + nodeName + parentid + + + 12 + + + 1 + 2 + 21129 + + + 2 + 3 + 11525 + + + 3 + 4 + 9604 + + + 4 + 7 + 7683 + + + 7 + 10 + 7683 + + + 10 + 28 + 7683 + + + 36 + 69 + 7683 + + + 71 + 412 + 7683 + + + 603 + 710 + 5762 + + + + + + + pos + id + + + 12 + + + 6 + 7 + 1920 + + + 89 + 90 + 1920 + + + 865 + 866 + 1920 + + + 2314 + 2315 + 1920 + + + + + + + pos + nodeName + + + 12 + + + 2 + 3 + 1920 + + + 13 + 14 + 1920 + + + 21 + 22 + 1920 + + + 34 + 35 + 1920 + + + + + + + pos + kind + + + 12 + + + 1 + 2 + 7683 + + + + + + + pos + parentid + + + 12 + + + 6 + 7 + 1920 + + + 89 + 90 + 1920 + + + 865 + 866 + 1920 + + + 2314 + 2315 + 1920 + + + + + + + kind + id + + + 12 + + + 3274 + 3275 + 1920 + + + + + + + kind + nodeName + + + 12 + + + 45 + 46 + 1920 + + + + + + + kind + pos + + + 12 + + + 4 + 5 + 1920 + + + + + + + kind + parentid + + + 12 + + + 2314 + 2315 + 1920 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 2783320 + + + 2 + 3 + 1490584 + + + 3 + 5 + 170956 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 2783320 + + + 2 + 3 + 1490584 + + + 3 + 5 + 170956 + + + + + + + parentid + pos + + + 12 + + + 1 + 2 + 2783320 + + + 2 + 3 + 1490584 + + + 3 + 5 + 170956 + + + + + + + parentid + kind + + + 12 + + + 1 + 2 + 4444861 + + + + + + + + + wildcards + 3338447 + + + id + 3338447 + + + nodeName + 533998 + + + kind + 3841 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 3338447 + + + + + + + id + kind + + + 12 + + + 1 + 2 + 3338447 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 397617 + + + 2 + 3 + 55704 + + + 3 + 7 + 44179 + + + 7 + 170 + 36496 + + + + + + + nodeName + kind + + + 12 + + + 1 + 2 + 533998 + + + + + + + kind + id + + + 12 + + + 791 + 792 + 1920 + + + 947 + 948 + 1920 + + + + + + + kind + nodeName + + + 12 + + + 91 + 92 + 1920 + + + 187 + 188 + 1920 + + + + + + + + + typeBounds + 4229725 + + + id + 4229725 + + + typeid + 2852471 + + + pos + 1920 + + + parentid + 4229725 + + + + + id + typeid + + + 12 + + + 1 + 2 + 4229725 + + + + + + + id + pos + + + 12 + + + 1 + 2 + 4229725 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 4229725 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 2091812 + + + 2 + 3 + 695349 + + + 3 + 52 + 65309 + + + + + + + typeid + pos + + + 12 + + + 1 + 2 + 2852471 + + + + + + + typeid + parentid + + + 12 + + + 1 + 2 + 2091812 + + + 2 + 3 + 695349 + + + 3 + 52 + 65309 + + + + + + + pos + id + + + 12 + + + 2202 + 2203 + 1920 + + + + + + + pos + typeid + + + 12 + + + 1485 + 1486 + 1920 + + + + + + + pos + parentid + + + 12 + + + 2202 + 2203 + 1920 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 4229725 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 4229725 + + + + + + + parentid + pos + + + 12 + + + 1 + 2 + 4229725 + + + + + + + + + typeArgs + 53854237 + + + argumentid + 1430551 + + + pos + 57 + + + parentid + 22244248 + + + + + argumentid + pos + + + 12 + + + 1 + 2 + 865848 + + + 2 + 3 + 470615 + + + 3 + 11 + 94087 + + + + + + + argumentid + parentid + + + 12 + + + 1 + 2 + 64071 + + + 2 + 3 + 433698 + + + 3 + 5 + 100595 + + + 5 + 6 + 35547 + + + 6 + 7 + 201249 + + + 7 + 11 + 39437 + + + 11 + 12 + 218178 + + + 12 + 15 + 111421 + + + 15 + 29 + 108138 + + + 29 + 341 + 107450 + + + 341 + 757580 + 10762 + + + + + + + pos + argumentid + + + 12 + + + 4 + 5 + 5 + + + 597 + 598 + 5 + + + 887 + 888 + 5 + + + 1129 + 1130 + 5 + + + 1758 + 1759 + 5 + + + 3885 + 3886 + 5 + + + 4027 + 4028 + 5 + + + 51686 + 51687 + 5 + + + 142042 + 142043 + 5 + + + 161580 + 161581 + 5 + + + + + + + pos + parentid + + + 12 + + + 4 + 5 + 5 + + + 831 + 832 + 5 + + + 3895 + 3896 + 5 + + + 8694 + 8695 + 5 + + + 19012 + 19013 + 5 + + + 85622 + 85623 + 5 + + + 103257 + 103258 + 5 + + + 1447294 + 1447295 + 5 + + + 3800219 + 3800220 + 5 + + + 3848466 + 3848467 + 5 + + + + + + + parentid + argumentid + + + 12 + + + 1 + 2 + 296162 + + + 2 + 3 + 13666793 + + + 3 + 4 + 7750153 + + + 4 + 11 + 531138 + + + + + + + parentid + pos + + + 12 + + + 1 + 2 + 278869 + + + 2 + 3 + 13599976 + + + 3 + 4 + 7768574 + + + 4 + 11 + 596828 + + + + + + + + + isParameterized + 27045654 + + + memberid + 27045654 + + + + + + isRaw + 731846 + + + memberid + 731846 + + + + + + erasure + 27777500 + + + memberid + 27777500 + + + erasureid + 954665 + + + + + memberid + erasureid + + + 12 + + + 1 + 2 + 27777500 + + + + + + + erasureid + memberid + + + 12 + + + 1 + 2 + 142143 + + + 2 + 3 + 138301 + + + 3 + 4 + 86438 + + + 4 + 5 + 57625 + + + 5 + 6 + 65309 + + + 6 + 8 + 69150 + + + 8 + 10 + 61467 + + + 10 + 15 + 72992 + + + 15 + 22 + 76834 + + + 22 + 44 + 74913 + + + 46 + 124 + 72992 + + + 169 + 1564 + 36496 + + + + + + + + + isAnonymClass + 174213 + + + classid + 174213 + + + parent + 174213 + + + + + classid + parent + + + 12 + + + 1 + 2 + 174213 + + + + + + + parent + classid + + + 12 + + + 1 + 2 + 174213 + + + + + + + + + isLocalClassOrInterface + 3841 + + + typeid + 3841 + + + parent + 3841 + + + + + typeid + parent + + + 12 + + + 1 + 2 + 3841 + + + + + + + parent + typeid + + + 12 + + + 1 + 2 + 3841 + + + + + + + + + isDefConstr + 139383 + + + constructorid + 139383 + + + + + + lambdaKind + 167982 + + + exprId + 167982 + + + bodyKind + 13 + + + + + exprId + bodyKind + + + 12 + + + 1 + 2 + 167982 + + + + + + + bodyKind + exprId + + + 12 + + + 12267 + 12268 + 13 + + + + + + + + + arrays + 1375332 + + + id + 1375332 + + + nodeName + 831730 + + + elementtypeid + 1365728 + + + dimension + 3841 + + + componenttypeid + 1375332 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 1375332 + + + + + + + id + elementtypeid + + + 12 + + + 1 + 2 + 1375332 + + + + + + + id + dimension + + + 12 + + + 1 + 2 + 1375332 + + + + + + + id + componenttypeid + + + 12 + + + 1 + 2 + 1375332 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 664616 + + + 2 + 3 + 140222 + + + 3 + 87 + 26891 + + + + + + + nodeName + elementtypeid + + + 12 + + + 1 + 2 + 664616 + + + 2 + 3 + 140222 + + + 3 + 87 + 26891 + + + + + + + nodeName + dimension + + + 12 + + + 1 + 2 + 831730 + + + + + + + nodeName + componenttypeid + + + 12 + + + 1 + 2 + 664616 + + + 2 + 3 + 140222 + + + 3 + 87 + 26891 + + + + + + + elementtypeid + id + + + 12 + + + 1 + 2 + 1356124 + + + 2 + 3 + 9604 + + + + + + + elementtypeid + nodeName + + + 12 + + + 1 + 2 + 1356124 + + + 2 + 3 + 9604 + + + + + + + elementtypeid + dimension + + + 12 + + + 1 + 2 + 1356124 + + + 2 + 3 + 9604 + + + + + + + elementtypeid + componenttypeid + + + 12 + + + 1 + 2 + 1356124 + + + 2 + 3 + 9604 + + + + + + + dimension + id + + + 12 + + + 5 + 6 + 1920 + + + 711 + 712 + 1920 + + + + + + + dimension + nodeName + + + 12 + + + 5 + 6 + 1920 + + + 428 + 429 + 1920 + + + + + + + dimension + elementtypeid + + + 12 + + + 5 + 6 + 1920 + + + 711 + 712 + 1920 + + + + + + + dimension + componenttypeid + + + 12 + + + 5 + 6 + 1920 + + + 711 + 712 + 1920 + + + + + + + componenttypeid + id + + + 12 + + + 1 + 2 + 1375332 + + + + + + + componenttypeid + nodeName + + + 12 + + + 1 + 2 + 1375332 + + + + + + + componenttypeid + elementtypeid + + + 12 + + + 1 + 2 + 1375332 + + + + + + + componenttypeid + dimension + + + 12 + + + 1 + 2 + 1375332 + + + + + + + + + enclInReftype + 4051085 + + + child + 4051085 + + + parent + 1125621 + + + + + child + parent + + + 12 + + + 1 + 2 + 4051085 + + + + + + + parent + child + + + 12 + + + 1 + 2 + 666537 + + + 2 + 3 + 176718 + + + 3 + 4 + 86438 + + + 4 + 6 + 82596 + + + 6 + 17 + 84517 + + + 17 + 265 + 28812 + + + + + + + + + extendsReftype + 34389087 + + + id1 + 33104034 + + + id2 + 13251986 + + + + + id1 + id2 + + + 12 + + + 1 + 2 + 32118635 + + + 2 + 10 + 985399 + + + + + + + id2 + id1 + + + 12 + + + 1 + 2 + 12030322 + + + 2 + 5 + 1023816 + + + 5 + 8715 + 197848 + + + + + + + + + implInterface + 14423708 + + + id1 + 8255839 + + + id2 + 4487119 + + + + + id1 + id2 + + + 12 + + + 1 + 2 + 4223962 + + + 2 + 3 + 2829421 + + + 3 + 4 + 276603 + + + 4 + 5 + 920090 + + + 5 + 7 + 5762 + + + + + + + id2 + id1 + + + 12 + + + 1 + 2 + 4003064 + + + 2 + 4 + 366883 + + + 4 + 2275 + 117172 + + + + + + + + + permits + 129 + + + id1 + 31 + + + id2 + 129 + + + + + id1 + id2 + + + 12 + + + 1 + 2 + 2 + + + 2 + 3 + 8 + + + 3 + 4 + 6 + + + 4 + 5 + 2 + + + 5 + 6 + 2 + + + 6 + 8 + 2 + + + 8 + 9 + 2 + + + 9 + 11 + 2 + + + + + + + id2 + id1 + + + 12 + + + 1 + 2 + 129 + + + + + + + + + hasModifier + 270713939 + + + id1 + 180180147 + + + id2 + 26891 + + + + + id1 + id2 + + + 12 + + + 1 + 2 + 90230296 + + + 2 + 3 + 89365911 + + + 3 + 4 + 583940 + + + + + + + id2 + id1 + + + 12 + + + 4 + 5 + 1920 + + + 14 + 15 + 1920 + + + 20 + 21 + 1920 + + + 21 + 22 + 1920 + + + 34 + 35 + 1920 + + + 50 + 51 + 1920 + + + 109 + 110 + 1920 + + + 219 + 220 + 1920 + + + 3864 + 3865 + 1920 + + + 7193 + 7194 + 1920 + + + 9195 + 9196 + 1920 + + + 14706 + 14707 + 1920 + + + 18810 + 18811 + 1920 + + + 86695 + 86696 + 1920 + + + + + + + + + imports + 368550 + + + id + 368550 + + + holder + 58078 + + + name + 8794 + + + kind + 663 + + + + + id + holder + + + 12 + + + 1 + 2 + 368550 + + + + + + + id + name + + + 12 + + + 1 + 2 + 368550 + + + + + + + id + kind + + + 12 + + + 1 + 2 + 368550 + + + + + + + holder + id + + + 12 + + + 1 + 2 + 28375 + + + 2 + 3 + 9292 + + + 3 + 4 + 5475 + + + 4 + 6 + 4646 + + + 6 + 15 + 4480 + + + 15 + 54 + 4480 + + + 64 + 98 + 1327 + + + + + + + holder + name + + + 12 + + + 1 + 2 + 54593 + + + 2 + 7 + 3484 + + + + + + + holder + kind + + + 12 + + + 1 + 2 + 55091 + + + 2 + 3 + 2986 + + + + + + + name + id + + + 12 + + + 1 + 2 + 4148 + + + 2 + 3 + 1825 + + + 3 + 4 + 829 + + + 4 + 7 + 663 + + + 7 + 26 + 663 + + + 30 + 1962 + 663 + + + + + + + name + holder + + + 12 + + + 1 + 2 + 7301 + + + 2 + 3 + 1161 + + + 3 + 337 + 331 + + + + + + + name + kind + + + 12 + + + 1 + 2 + 8628 + + + 3 + 4 + 165 + + + + + + + kind + id + + + 12 + + + 1 + 2 + 165 + + + 6 + 7 + 165 + + + 260 + 261 + 165 + + + 1954 + 1955 + 165 + + + + + + + kind + holder + + + 12 + + + 1 + 2 + 165 + + + 3 + 4 + 165 + + + 31 + 32 + 165 + + + 333 + 334 + 165 + + + + + + + kind + name + + + 12 + + + 1 + 2 + 497 + + + 52 + 53 + 165 + + + + + + + + + stmts + 2441387 + + + id + 2441387 + + + kind + 9674 + + + parent + 1353860 + + + idx + 15934 + + + bodydecl + 367630 + + + + + id + kind + + + 12 + + + 1 + 2 + 2441387 + + + + + + + id + parent + + + 12 + + + 1 + 2 + 2441387 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 2441387 + + + + + + + id + bodydecl + + + 12 + + + 1 + 2 + 2441387 + + + + + + + kind + id + + + 12 + + + 1 + 2 + 1707 + + + 6 + 7 + 569 + + + 7 + 8 + 569 + + + 17 + 18 + 569 + + + 20 + 21 + 569 + + + 23 + 24 + 569 + + + 33 + 34 + 569 + + + 83 + 84 + 569 + + + 91 + 92 + 569 + + + 97 + 98 + 569 + + + 265 + 266 + 569 + + + 312 + 313 + 569 + + + 560 + 561 + 569 + + + 1243 + 1244 + 569 + + + 1530 + 1531 + 569 + + + + + + + kind + parent + + + 12 + + + 1 + 2 + 2276 + + + 7 + 8 + 569 + + + 12 + 13 + 569 + + + 17 + 18 + 569 + + + 21 + 22 + 569 + + + 33 + 34 + 569 + + + 71 + 72 + 569 + + + 81 + 82 + 569 + + + 91 + 92 + 569 + + + 246 + 247 + 569 + + + 265 + 266 + 569 + + + 271 + 272 + 569 + + + 716 + 717 + 569 + + + 1192 + 1193 + 569 + + + + + + + kind + idx + + + 12 + + + 1 + 2 + 2276 + + + 3 + 4 + 569 + + + 4 + 5 + 569 + + + 6 + 7 + 1138 + + + 7 + 8 + 569 + + + 8 + 9 + 1138 + + + 10 + 11 + 1138 + + + 13 + 14 + 569 + + + 17 + 18 + 569 + + + 21 + 22 + 569 + + + 26 + 27 + 569 + + + + + + + kind + bodydecl + + + 12 + + + 1 + 2 + 2276 + + + 7 + 8 + 1138 + + + 17 + 18 + 569 + + + 20 + 21 + 569 + + + 21 + 22 + 569 + + + 53 + 54 + 569 + + + 54 + 55 + 569 + + + 91 + 92 + 569 + + + 119 + 120 + 569 + + + 179 + 180 + 569 + + + 211 + 212 + 569 + + + 431 + 432 + 569 + + + 646 + 647 + 569 + + + + + + + parent + id + + + 12 + + + 1 + 2 + 989074 + + + 2 + 3 + 191782 + + + 3 + 6 + 107557 + + + 6 + 27 + 65445 + + + + + + + parent + kind + + + 12 + + + 1 + 2 + 1081267 + + + 2 + 3 + 194058 + + + 3 + 6 + 78534 + + + + + + + parent + idx + + + 12 + + + 1 + 2 + 989074 + + + 2 + 3 + 191782 + + + 3 + 6 + 107557 + + + 6 + 27 + 65445 + + + + + + + parent + bodydecl + + + 12 + + + 1 + 2 + 1353860 + + + + + + + idx + id + + + 12 + + + 3 + 5 + 1138 + + + 5 + 6 + 1138 + + + 6 + 7 + 2276 + + + 10 + 15 + 1138 + + + 15 + 16 + 1138 + + + 17 + 20 + 1138 + + + 24 + 32 + 1138 + + + 40 + 43 + 1138 + + + 55 + 72 + 1138 + + + 83 + 94 + 1138 + + + 115 + 160 + 1138 + + + 204 + 386 + 1138 + + + 939 + 1919 + 1138 + + + + + + + idx + kind + + + 12 + + + 1 + 2 + 2276 + + + 2 + 3 + 3983 + + + 3 + 5 + 1138 + + + 5 + 6 + 2276 + + + 6 + 7 + 2276 + + + 7 + 9 + 1138 + + + 9 + 10 + 1138 + + + 12 + 14 + 1138 + + + 16 + 17 + 569 + + + + + + + idx + parent + + + 12 + + + 3 + 5 + 1138 + + + 5 + 6 + 1138 + + + 6 + 7 + 2276 + + + 10 + 15 + 1138 + + + 15 + 16 + 1138 + + + 17 + 20 + 1138 + + + 24 + 32 + 1138 + + + 40 + 43 + 1138 + + + 55 + 72 + 1138 + + + 83 + 94 + 1138 + + + 115 + 160 + 1138 + + + 204 + 386 + 1138 + + + 939 + 1919 + 1138 + + + + + + + idx + bodydecl + + + 12 + + + 3 + 5 + 1138 + + + 5 + 6 + 1138 + + + 6 + 7 + 2276 + + + 10 + 15 + 1138 + + + 15 + 16 + 1138 + + + 17 + 20 + 1138 + + + 24 + 32 + 1138 + + + 40 + 43 + 1138 + + + 54 + 56 + 1138 + + + 68 + 87 + 1138 + + + 104 + 138 + 1138 + + + 167 + 226 + 1138 + + + 337 + 647 + 1138 + + + + + + + bodydecl + id + + + 12 + + + 1 + 2 + 17641 + + + 2 + 3 + 157637 + + + 3 + 4 + 38128 + + + 4 + 5 + 33576 + + + 5 + 7 + 24470 + + + 7 + 10 + 29023 + + + 10 + 16 + 30730 + + + 16 + 34 + 27885 + + + 34 + 131 + 8536 + + + + + + + bodydecl + kind + + + 12 + + + 1 + 2 + 17641 + + + 2 + 3 + 193489 + + + 3 + 4 + 77965 + + + 4 + 5 + 29592 + + + 5 + 7 + 33007 + + + 7 + 11 + 15934 + + + + + + + bodydecl + parent + + + 12 + + + 1 + 2 + 17641 + + + 2 + 3 + 261780 + + + 4 + 5 + 33576 + + + 5 + 10 + 31299 + + + 10 + 88 + 23332 + + + + + + + bodydecl + idx + + + 12 + + + 1 + 2 + 175279 + + + 2 + 3 + 63737 + + + 3 + 4 + 27885 + + + 4 + 5 + 18210 + + + 5 + 7 + 30161 + + + 7 + 11 + 29592 + + + 11 + 28 + 22763 + + + + + + + + + exprs + 7410663 + + + id + 7410663 + + + kind + 1618 + + + typeid + 115976 + + + parent + 5075638 + + + idx + 1426 + + + + + id + kind + + + 12 + + + 1 + 2 + 7410663 + + + + + + + id + typeid + + + 12 + + + 1 + 2 + 7410663 + + + + + + + id + parent + + + 12 + + + 1 + 2 + 7410663 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 7410663 + + + + + + + kind + id + + + 12 + + + 1 + 3 + 137 + + + 3 + 9 + 137 + + + 13 + 31 + 137 + + + 31 + 76 + 137 + + + 85 + 161 + 109 + + + 186 + 307 + 137 + + + 378 + 492 + 137 + + + 494 + 659 + 137 + + + 708 + 1063 + 137 + + + 1114 + 2997 + 137 + + + 3119 + 9319 + 137 + + + 10083 + 75330 + 137 + + + + + + + kind + typeid + + + 12 + + + 1 + 2 + 768 + + + 2 + 3 + 246 + + + 3 + 6 + 137 + + + 18 + 48 + 137 + + + 48 + 152 + 137 + + + 246 + 1578 + 137 + + + 2399 + 2509 + 54 + + + + + + + kind + parent + + + 12 + + + 1 + 3 + 137 + + + 3 + 9 + 137 + + + 13 + 31 + 137 + + + 31 + 76 + 137 + + + 81 + 177 + 137 + + + 183 + 357 + 137 + + + 378 + 482 + 137 + + + 572 + 708 + 137 + + + 708 + 1060 + 137 + + + 1102 + 3043 + 137 + + + 5490 + 10002 + 137 + + + 16929 + 60299 + 109 + + + + + + + kind + idx + + + 12 + + + 1 + 2 + 246 + + + 2 + 3 + 521 + + + 3 + 4 + 246 + + + 4 + 6 + 137 + + + 6 + 8 + 137 + + + 8 + 11 + 137 + + + 12 + 27 + 137 + + + 46 + 49 + 54 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 48881 + + + 2 + 3 + 13002 + + + 3 + 6 + 10697 + + + 6 + 10 + 9628 + + + 10 + 17 + 9271 + + + 17 + 32 + 8722 + + + 32 + 89 + 8750 + + + 89 + 52561 + 7022 + + + + + + + typeid + kind + + + 12 + + + 1 + 2 + 57851 + + + 2 + 3 + 18543 + + + 3 + 4 + 8914 + + + 4 + 5 + 14455 + + + 5 + 6 + 9737 + + + 6 + 32 + 6473 + + + + + + + typeid + parent + + + 12 + + + 1 + 2 + 49045 + + + 2 + 3 + 13413 + + + 3 + 5 + 8668 + + + 5 + 8 + 8530 + + + 8 + 13 + 9244 + + + 13 + 24 + 8750 + + + 24 + 57 + 8805 + + + 57 + 851 + 8722 + + + 890 + 37212 + 795 + + + + + + + typeid + idx + + + 12 + + + 1 + 2 + 58673 + + + 2 + 3 + 18378 + + + 3 + 4 + 14730 + + + 4 + 5 + 19119 + + + 5 + 50 + 5074 + + + + + + + parent + id + + + 12 + + + 1 + 2 + 3222211 + + + 2 + 3 + 1522614 + + + 3 + 48 + 330812 + + + + + + + parent + kind + + + 12 + + + 1 + 2 + 3525291 + + + 2 + 3 + 1385461 + + + 3 + 8 + 164884 + + + + + + + parent + typeid + + + 12 + + + 1 + 2 + 4085559 + + + 2 + 3 + 832078 + + + 3 + 10 + 157999 + + + + + + + parent + idx + + + 12 + + + 1 + 2 + 3222211 + + + 2 + 3 + 1522614 + + + 3 + 48 + 330812 + + + + + + + idx + id + + + 12 + + + 1 + 2 + 82 + + + 2 + 3 + 466 + + + 3 + 4 + 82 + + + 4 + 5 + 54 + + + 5 + 6 + 82 + + + 6 + 8 + 109 + + + 8 + 19 + 109 + + + 24 + 37 + 109 + + + 75 + 343 + 109 + + + 536 + 6117 + 109 + + + 7863 + 137171 + 109 + + + + + + + idx + kind + + + 12 + + + 1 + 2 + 164 + + + 2 + 3 + 521 + + + 3 + 4 + 27 + + + 4 + 5 + 246 + + + 6 + 7 + 54 + + + 7 + 8 + 109 + + + 8 + 13 + 109 + + + 13 + 26 + 109 + + + 27 + 59 + 82 + + + + + + + idx + typeid + + + 12 + + + 1 + 2 + 82 + + + 2 + 3 + 521 + + + 3 + 4 + 54 + + + 4 + 5 + 246 + + + 7 + 12 + 109 + + + 12 + 20 + 109 + + + 29 + 66 + 109 + + + 80 + 1212 + 109 + + + 1956 + 3022 + 82 + + + + + + + idx + parent + + + 12 + + + 1 + 2 + 82 + + + 2 + 3 + 466 + + + 3 + 4 + 82 + + + 4 + 5 + 54 + + + 5 + 6 + 82 + + + 6 + 8 + 109 + + + 8 + 19 + 109 + + + 24 + 37 + 109 + + + 75 + 343 + 109 + + + 536 + 6117 + 109 + + + 7863 + 137171 + 109 + + + + + + + + + exprsKotlinType + 7410663 + + + id + 7410663 + + + kttypeid + 10930 + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 7410663 + + + + + + + kttypeid + id + + + 12 + + + 1 + 2 + 8197 + + + 2 + 3 + 1821 + + + 8123 + 8124 + 910 + + + + + + + + + callableEnclosingExpr + 7299071 + + + id + 7299071 + + + callable_id + 19877 + + + + + id + callable_id + + + 12 + + + 1 + 2 + 7299071 + + + + + + + callable_id + id + + + 12 + + + 1 + 2 + 711 + + + 2 + 3 + 1691 + + + 3 + 5 + 1604 + + + 5 + 6 + 806 + + + 6 + 7 + 1955 + + + 7 + 9 + 1374 + + + 9 + 13 + 1825 + + + 13 + 18 + 1574 + + + 18 + 26 + 1530 + + + 26 + 42 + 1530 + + + 42 + 73 + 1504 + + + 73 + 177 + 1495 + + + 179 + 1146 + 1491 + + + 1148 + 37742 + 780 + + + + + + + + + statementEnclosingExpr + 7258714 + + + id + 7258714 + + + statement_id + 525778 + + + + + id + statement_id + + + 12 + + + 1 + 2 + 7258714 + + + + + + + statement_id + id + + + 12 + + + 1 + 3 + 29126 + + + 3 + 5 + 47077 + + + 5 + 7 + 48474 + + + 7 + 8 + 36042 + + + 8 + 9 + 38145 + + + 9 + 10 + 50447 + + + 10 + 11 + 29212 + + + 11 + 12 + 127049 + + + 12 + 35 + 35322 + + + 35 + 40 + 44623 + + + 40 + 81 + 40222 + + + 82 + 210 + 34 + + + + + + + + + isParenthesized + 94652 + + + id + 94652 + + + parentheses + 5 + + + + + id + parentheses + + + 12 + + + 1 + 2 + 94652 + + + + + + + parentheses + id + + + 12 + + + 58 + 59 + 2 + + + 34605 + 34606 + 2 + + + + + + + + + when_if + 74334 + + + id + 74334 + + + + + + when_branch_else + 76075 + + + id + 76075 + + + + + + callableBinding + 1832520 + + + callerid + 1832520 + + + callee + 264311 + + + + + callerid + callee + + + 12 + + + 1 + 2 + 1832520 + + + + + + + callee + callerid + + + 12 + + + 1 + 2 + 162993 + + + 2 + 3 + 33137 + + + 3 + 4 + 16271 + + + 4 + 7 + 22271 + + + 7 + 20 + 19902 + + + 20 + 46115 + 9734 + + + + + + + + + memberRefBinding + 23208 + + + id + 23208 + + + callable + 11197 + + + + + id + callable + + + 12 + + + 1 + 2 + 23208 + + + + + + + callable + id + + + 12 + + + 1 + 2 + 7862 + + + 2 + 3 + 2075 + + + 3 + 7 + 940 + + + 7 + 912 + 319 + + + + + + + + + propertyRefGetBinding + 8876 + + + id + 8876 + + + getter + 5366 + + + + + id + getter + + + 12 + + + 1 + 2 + 8876 + + + + + + + getter + id + + + 12 + + + 1 + 2 + 1951 + + + 2 + 3 + 3328 + + + 3 + 6 + 86 + + + + + + + + + propertyRefFieldBinding + 2 + + + id + 2 + + + field + 2 + + + + + id + field + + + 12 + + + 1 + 2 + 2 + + + + + + + field + id + + + 12 + + + 1 + 2 + 2 + + + + + + + + + propertyRefSetBinding + 2600 + + + id + 2600 + + + setter + 1300 + + + + + id + setter + + + 12 + + + 1 + 2 + 2600 + + + + + + + setter + id + + + 12 + + + 2 + 3 + 1300 + + + + + + + + + variableBinding + 2434277 + + + expr + 2434277 + + + variable + 572528 + + + + + expr + variable + + + 12 + + + 1 + 2 + 2434277 + + + + + + + variable + expr + + + 12 + + + 1 + 2 + 205791 + + + 2 + 3 + 120945 + + + 3 + 4 + 85022 + + + 4 + 5 + 45967 + + + 5 + 7 + 40059 + + + 7 + 14 + 43072 + + + 14 + 464 + 31669 + + + + + + + + + localvars + 385272 + + + id + 385272 + + + nodeName + 139995 + + + typeid + 49510 + + + parentid + 385272 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 385272 + + + + + + + id + typeid + + + 12 + + + 1 + 2 + 385272 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 385272 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 83655 + + + 2 + 3 + 26178 + + + 3 + 5 + 10243 + + + 5 + 9 + 11950 + + + 9 + 42 + 7967 + + + + + + + nodeName + typeid + + + 12 + + + 1 + 2 + 124630 + + + 2 + 3 + 13089 + + + 3 + 19 + 2276 + + + + + + + nodeName + parentid + + + 12 + + + 1 + 2 + 83655 + + + 2 + 3 + 26178 + + + 3 + 5 + 10243 + + + 5 + 9 + 11950 + + + 9 + 42 + 7967 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 16503 + + + 2 + 3 + 9105 + + + 3 + 5 + 2276 + + + 5 + 6 + 5121 + + + 6 + 7 + 2845 + + + 7 + 8 + 2845 + + + 8 + 12 + 4552 + + + 14 + 30 + 3983 + + + 51 + 76 + 2276 + + + + + + + typeid + nodeName + + + 12 + + + 1 + 2 + 23332 + + + 2 + 3 + 9105 + + + 3 + 4 + 6259 + + + 4 + 6 + 3983 + + + 6 + 14 + 3983 + + + 14 + 35 + 2845 + + + + + + + typeid + parentid + + + 12 + + + 1 + 2 + 16503 + + + 2 + 3 + 9105 + + + 3 + 5 + 2276 + + + 5 + 6 + 5121 + + + 6 + 7 + 2845 + + + 7 + 8 + 2845 + + + 8 + 12 + 4552 + + + 14 + 30 + 3983 + + + 51 + 76 + 2276 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 385272 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 385272 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 385272 + + + + + + + + + localvarsKotlinType + 240107 + + + id + 240107 + + + kttypeid + 1920 + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 240107 + + + + + + + kttypeid + id + + + 12 + + + 125 + 126 + 1920 + + + + + + + + + namestrings + 4022436 + + + name + 23384 + + + value + 22166 + + + parent + 4022436 + + + + + name + value + + + 12 + + + 1 + 2 + 23384 + + + + + + + name + parent + + + 12 + + + 1 + 2 + 9604 + + + 2 + 3 + 3811 + + + 3 + 5 + 2150 + + + 5 + 9 + 1769 + + + 9 + 21 + 1795 + + + 21 + 69 + 1760 + + + 69 + 385 + 1756 + + + 390 + 412517 + 737 + + + + + + + value + name + + + 12 + + + 1 + 2 + 21559 + + + 2 + 12 + 607 + + + + + + + value + parent + + + 12 + + + 1 + 2 + 9118 + + + 2 + 3 + 3594 + + + 3 + 5 + 1912 + + + 5 + 9 + 1665 + + + 9 + 21 + 1691 + + + 21 + 67 + 1678 + + + 67 + 318 + 1665 + + + 320 + 413340 + 841 + + + + + + + parent + name + + + 12 + + + 1 + 2 + 4022436 + + + + + + + parent + value + + + 12 + + + 1 + 2 + 4022436 + + + + + + + + + modules + 7965 + + + id + 7965 + + + name + 7965 + + + + + id + name + + + 12 + + + 1 + 2 + 7965 + + + + + + + name + id + + + 12 + + + 1 + 2 + 7965 + + + + + + + + + isOpen + 1 + + + id + 1 + + + + + + cumodule + 247580 + + + fileId + 247580 + + + moduleId + 1161 + + + + + fileId + moduleId + + + 12 + + + 1 + 2 + 247580 + + + + + + + moduleId + fileId + + + 12 + + + 12 + 13 + 331 + + + 39 + 40 + 165 + + + 64 + 65 + 165 + + + 71 + 72 + 165 + + + 415 + 416 + 165 + + + 879 + 880 + 165 + + + + + + + + + directives + 50279 + + + id + 1161 + + + directive + 50279 + + + + + id + directive + + + 12 + + + 3 + 4 + 165 + + + 4 + 5 + 165 + + + 7 + 8 + 165 + + + 9 + 10 + 165 + + + 43 + 44 + 165 + + + 89 + 90 + 165 + + + 148 + 149 + 165 + + + + + + + directive + id + + + 12 + + + 1 + 2 + 50279 + + + + + + + + + requires + 1991 + + + id + 1991 + + + target + 995 + + + + + id + target + + + 12 + + + 1 + 2 + 1991 + + + + + + + target + id + + + 12 + + + 1 + 2 + 663 + + + 2 + 3 + 165 + + + 6 + 7 + 165 + + + + + + + + + isTransitive + 829 + + + id + 829 + + + + + + isStatic + 1 + + + id + 1 + + + + + + exports + 35013 + + + id + 35013 + + + target + 35013 + + + + + id + target + + + 12 + + + 1 + 2 + 35013 + + + + + + + target + id + + + 12 + + + 1 + 2 + 35013 + + + + + + + + + exportsTo + 28707 + + + id + 12279 + + + target + 7467 + + + + + id + target + + + 12 + + + 1 + 2 + 7301 + + + 2 + 3 + 1825 + + + 3 + 4 + 829 + + + 4 + 5 + 829 + + + 5 + 7 + 995 + + + 9 + 18 + 497 + + + + + + + target + id + + + 12 + + + 1 + 2 + 1991 + + + 2 + 3 + 1825 + + + 3 + 4 + 663 + + + 4 + 5 + 663 + + + 5 + 6 + 663 + + + 6 + 7 + 331 + + + 8 + 10 + 663 + + + 11 + 13 + 663 + + + + + + + + + opens + 165 + + + id + 165 + + + target + 165 + + + + + id + target + + + 12 + + + 1 + 2 + 165 + + + + + + + target + id + + + 12 + + + 1 + 2 + 165 + + + + + + + + + opensTo + 165 + + + id + 165 + + + target + 165 + + + + + id + target + + + 12 + + + 1 + 2 + 165 + + + + + + + target + id + + + 12 + + + 1 + 2 + 165 + + + + + + + + + uses + 10786 + + + id + 10786 + + + serviceInterface + 10786 + + + + + id + serviceInterface + + + 12 + + + 1 + 2 + 10786 + + + + + + + serviceInterface + id + + + 12 + + + 1 + 2 + 10786 + + + + + + + + + provides + 2323 + + + id + 2323 + + + serviceInterface + 2323 + + + + + id + serviceInterface + + + 12 + + + 1 + 2 + 2323 + + + + + + + serviceInterface + id + + + 12 + + + 1 + 2 + 2323 + + + + + + + + + providesWith + 5310 + + + id + 2323 + + + serviceImpl + 5310 + + + + + id + serviceImpl + + + 12 + + + 1 + 2 + 1327 + + + 2 + 3 + 165 + + + 4 + 5 + 663 + + + 6 + 7 + 165 + + + + + + + serviceImpl + id + + + 12 + + + 1 + 2 + 5310 + + + + + + + + + javadoc + 985091 + + + id + 985091 + + + + + + isNormalComment + 649898 + + + commentid + 649898 + + + + + + isEolComment + 610062 + + + commentid + 610062 + + + + + + hasJavadoc + 435352 + + + documentableid + 368199 + + + javadocid + 435352 + + + + + documentableid + javadocid + + + 12 + + + 1 + 2 + 320396 + + + 2 + 3 + 44957 + + + 3 + 27 + 2845 + + + + + + + javadocid + documentableid + + + 12 + + + 1 + 2 + 435352 + + + + + + + + + javadocTag + 335808 + + + id + 335808 + + + name + 577 + + + parentid + 114110 + + + idx + 4789 + + + + + id + name + + + 12 + + + 1 + 2 + 335808 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 335808 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 335808 + + + + + + + name + id + + + 12 + + + 34 + 35 + 82 + + + 69 + 70 + 82 + + + 203 + 204 + 82 + + + 405 + 406 + 82 + + + 608 + 609 + 82 + + + 968 + 969 + 82 + + + 1780 + 1781 + 82 + + + + + + + name + parentid + + + 12 + + + 34 + 35 + 82 + + + 69 + 70 + 82 + + + 158 + 159 + 82 + + + 404 + 405 + 82 + + + 608 + 609 + 82 + + + 668 + 669 + 82 + + + 969 + 970 + 82 + + + + + + + name + idx + + + 12 + + + 17 + 18 + 82 + + + 21 + 22 + 82 + + + 31 + 32 + 82 + + + 35 + 36 + 165 + + + 38 + 39 + 82 + + + 41 + 42 + 82 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 33192 + + + 2 + 3 + 24935 + + + 3 + 4 + 18660 + + + 4 + 5 + 13128 + + + 5 + 6 + 9990 + + + 6 + 7 + 7678 + + + 7 + 11 + 6522 + + + + + + + parentid + name + + + 12 + + + 1 + 2 + 39963 + + + 2 + 3 + 38642 + + + 3 + 4 + 21137 + + + 4 + 5 + 12220 + + + 5 + 6 + 2146 + + + + + + + parentid + idx + + + 12 + + + 1 + 2 + 33192 + + + 2 + 3 + 24935 + + + 3 + 4 + 18660 + + + 4 + 5 + 13128 + + + 5 + 6 + 9990 + + + 6 + 7 + 7678 + + + 7 + 11 + 6522 + + + + + + + idx + id + + + 12 + + + 1 + 2 + 1238 + + + 2 + 3 + 247 + + + 4 + 5 + 330 + + + 5 + 6 + 412 + + + 6 + 8 + 330 + + + 8 + 17 + 412 + + + 21 + 34 + 412 + + + 38 + 72 + 412 + + + 76 + 152 + 412 + + + 199 + 504 + 412 + + + 603 + 713 + 165 + + + + + + + idx + name + + + 12 + + + 1 + 2 + 1321 + + + 2 + 3 + 330 + + + 3 + 4 + 743 + + + 4 + 5 + 412 + + + 5 + 6 + 412 + + + 6 + 7 + 908 + + + 7 + 8 + 660 + + + + + + + idx + parentid + + + 12 + + + 1 + 2 + 1238 + + + 2 + 3 + 247 + + + 4 + 5 + 330 + + + 5 + 6 + 412 + + + 6 + 8 + 330 + + + 8 + 17 + 412 + + + 21 + 34 + 412 + + + 38 + 72 + 412 + + + 76 + 152 + 412 + + + 199 + 504 + 412 + + + 603 + 713 + 165 + + + + + + + + + javadocText + 2502848 + + + id + 2502848 + + + text + 1370363 + + + parentid + 1169475 + + + idx + 42112 + + + + + id + text + + + 12 + + + 1 + 2 + 2502848 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 2502848 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 2502848 + + + + + + + text + id + + + 12 + + + 1 + 2 + 1139314 + + + 2 + 3 + 149670 + + + 3 + 147 + 81379 + + + + + + + text + parentid + + + 12 + + + 1 + 2 + 1140452 + + + 2 + 3 + 149101 + + + 3 + 88 + 80810 + + + + + + + text + idx + + + 12 + + + 1 + 2 + 1346462 + + + 2 + 32 + 23901 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 870135 + + + 2 + 3 + 159344 + + + 3 + 12 + 83086 + + + 12 + 75 + 56908 + + + + + + + parentid + text + + + 12 + + + 1 + 2 + 870135 + + + 2 + 3 + 159344 + + + 3 + 12 + 84225 + + + 12 + 67 + 55770 + + + + + + + parentid + idx + + + 12 + + + 1 + 2 + 870135 + + + 2 + 3 + 159344 + + + 3 + 12 + 83086 + + + 12 + 75 + 56908 + + + + + + + idx + id + + + 12 + + + 2 + 3 + 21056 + + + 3 + 5 + 2276 + + + 5 + 7 + 3414 + + + 7 + 11 + 2276 + + + 12 + 16 + 3414 + + + 19 + 102 + 3414 + + + 108 + 154 + 3414 + + + 181 + 2056 + 2845 + + + + + + + idx + text + + + 12 + + + 1 + 2 + 569 + + + 2 + 3 + 20487 + + + 3 + 5 + 2845 + + + 5 + 7 + 3414 + + + 7 + 13 + 3414 + + + 13 + 23 + 3414 + + + 27 + 47 + 3414 + + + 47 + 123 + 3414 + + + 254 + 1252 + 1138 + + + + + + + idx + parentid + + + 12 + + + 2 + 3 + 21056 + + + 3 + 5 + 2276 + + + 5 + 7 + 3414 + + + 7 + 11 + 2276 + + + 12 + 16 + 3414 + + + 19 + 102 + 3414 + + + 108 + 154 + 3414 + + + 181 + 2056 + 2845 + + + + + + + + + xmlEncoding + 1129463 + + + id + 1129463 + + + encoding + 1920 + + + + + id + encoding + + + 12 + + + 1 + 2 + 1129463 + + + + + + + encoding + id + + + 12 + + + 588 + 589 + 1920 + + + + + + + + + xmlDTDs + 569 + + + id + 569 + + + root + 569 + + + publicId + 569 + + + systemId + 569 + + + fileid + 569 + + + + + id + root + + + 12 + + + 1 + 2 + 569 + + + + + + + id + publicId + + + 12 + + + 1 + 2 + 569 + + + + + + + id + systemId + + + 12 + + + 1 + 2 + 569 + + + + + + + id + fileid + + + 12 + + + 1 + 2 + 569 + + + + + + + root + id + + + 12 + + + 1 + 2 + 569 + + + + + + + root + publicId + + + 12 + + + 1 + 2 + 569 + + + + + + + root + systemId + + + 12 + + + 1 + 2 + 569 + + + + + + + root + fileid + + + 12 + + + 1 + 2 + 569 + + + + + + + publicId + id + + + 12 + + + 1 + 2 + 569 + + + + + + + publicId + root + + + 12 + + + 1 + 2 + 569 + + + + + + + publicId + systemId + + + 12 + + + 1 + 2 + 569 + + + + + + + publicId + fileid + + + 12 + + + 1 + 2 + 569 + + + + + + + systemId + id + + + 12 + + + 1 + 2 + 569 + + + + + + + systemId + root + + + 12 + + + 1 + 2 + 569 + + + + + + + systemId + publicId + + + 12 + + + 1 + 2 + 569 + + + + + + + systemId + fileid + + + 12 + + + 1 + 2 + 569 + + + + + + + fileid + id + + + 12 + + + 1 + 2 + 569 + + + + + + + fileid + root + + + 12 + + + 1 + 2 + 569 + + + + + + + fileid + publicId + + + 12 + + + 1 + 2 + 569 + + + + + + + fileid + systemId + + + 12 + + + 1 + 2 + 569 + + + + + + + + + xmlElements + 150282022 + + + id + 150282022 + + + name + 476372 + + + parentid + 3876287 + + + idx + 1703799 + + + fileid + 1129463 + + + + + id + name + + + 12 + + + 1 + 2 + 150282022 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 150282022 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 150282022 + + + + + + + id + fileid + + + 12 + + + 1 + 2 + 150282022 + + + + + + + name + id + + + 12 + + + 1 + 2 + 149826 + + + 2 + 3 + 57625 + + + 3 + 4 + 23050 + + + 4 + 6 + 42258 + + + 6 + 8 + 34575 + + + 8 + 9 + 17287 + + + 9 + 10 + 32654 + + + 10 + 18 + 40337 + + + 18 + 48 + 36496 + + + 52 + 250 + 36496 + + + 342 + 73380 + 5762 + + + + + + + name + parentid + + + 12 + + + 1 + 2 + 174797 + + + 2 + 3 + 65309 + + + 3 + 4 + 24971 + + + 4 + 5 + 21129 + + + 5 + 6 + 26891 + + + 6 + 8 + 40337 + + + 8 + 10 + 40337 + + + 10 + 21 + 38417 + + + 22 + 128 + 36496 + + + 130 + 229 + 7683 + + + + + + + name + idx + + + 12 + + + 1 + 2 + 263157 + + + 2 + 3 + 69150 + + + 3 + 4 + 34575 + + + 4 + 6 + 28812 + + + 6 + 9 + 28812 + + + 9 + 38 + 36496 + + + 45 + 888 + 15366 + + + + + + + name + fileid + + + 12 + + + 1 + 2 + 259315 + + + 2 + 3 + 51863 + + + 3 + 4 + 24971 + + + 4 + 5 + 19208 + + + 5 + 7 + 42258 + + + 7 + 16 + 36496 + + + 17 + 114 + 38417 + + + 118 + 131 + 3841 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 2358811 + + + 2 + 3 + 605069 + + + 3 + 4 + 251632 + + + 4 + 8 + 301574 + + + 8 + 777 + 316941 + + + 777 + 888 + 42258 + + + + + + + parentid + name + + + 12 + + + 1 + 2 + 3200146 + + + 2 + 3 + 411063 + + + 3 + 17 + 265078 + + + + + + + parentid + idx + + + 12 + + + 1 + 2 + 2358811 + + + 2 + 3 + 605069 + + + 3 + 4 + 251632 + + + 4 + 8 + 301574 + + + 8 + 777 + 316941 + + + 777 + 888 + 42258 + + + + + + + parentid + fileid + + + 12 + + + 1 + 2 + 3876287 + + + + + + + idx + id + + + 12 + + + 2 + 8 + 144064 + + + 9 + 76 + 136380 + + + 76 + 82 + 128697 + + + 82 + 89 + 122934 + + + 89 + 92 + 111409 + + + 92 + 95 + 134459 + + + 95 + 97 + 149826 + + + 97 + 98 + 211294 + + + 98 + 99 + 130618 + + + 99 + 104 + 155589 + + + 104 + 106 + 130618 + + + 106 + 159 + 128697 + + + 162 + 2019 + 19208 + + + + + + + idx + name + + + 12 + + + 1 + 2 + 1381095 + + + 2 + 5 + 126776 + + + 5 + 9 + 145985 + + + 9 + 150 + 49942 + + + + + + + idx + parentid + + + 12 + + + 2 + 8 + 144064 + + + 9 + 76 + 136380 + + + 76 + 82 + 128697 + + + 82 + 89 + 122934 + + + 89 + 92 + 111409 + + + 92 + 95 + 134459 + + + 95 + 97 + 149826 + + + 97 + 98 + 211294 + + + 98 + 99 + 130618 + + + 99 + 104 + 155589 + + + 104 + 106 + 130618 + + + 106 + 159 + 128697 + + + 162 + 2019 + 19208 + + + + + + + idx + fileid + + + 12 + + + 2 + 8 + 144064 + + + 9 + 76 + 136380 + + + 76 + 82 + 128697 + + + 82 + 89 + 122934 + + + 89 + 92 + 111409 + + + 92 + 95 + 134459 + + + 95 + 97 + 149826 + + + 97 + 98 + 211294 + + + 98 + 99 + 130618 + + + 99 + 104 + 155589 + + + 104 + 106 + 130618 + + + 106 + 139 + 128697 + + + 141 + 589 + 19208 + + + + + + + fileid + id + + + 12 + + + 1 + 2 + 82596 + + + 2 + 3 + 190164 + + + 3 + 4 + 249711 + + + 4 + 5 + 105647 + + + 5 + 7 + 84517 + + + 7 + 10 + 94121 + + + 10 + 31 + 88359 + + + 35 + 694 + 86438 + + + 738 + 776 + 28812 + + + 777 + 779 + 92201 + + + 788 + 889 + 26891 + + + + + + + fileid + name + + + 12 + + + 1 + 2 + 82596 + + + 2 + 3 + 562810 + + + 3 + 4 + 195927 + + + 4 + 5 + 92201 + + + 5 + 6 + 86438 + + + 6 + 9 + 92201 + + + 9 + 69 + 17287 + + + + + + + fileid + parentid + + + 12 + + + 1 + 2 + 82596 + + + 2 + 3 + 800997 + + + 3 + 4 + 80675 + + + 4 + 6 + 82596 + + + 6 + 165 + 82596 + + + + + + + fileid + idx + + + 12 + + + 1 + 2 + 286207 + + + 2 + 3 + 309257 + + + 3 + 4 + 124855 + + + 4 + 7 + 94121 + + + 7 + 17 + 94121 + + + 18 + 763 + 86438 + + + 764 + 777 + 92201 + + + 777 + 888 + 42258 + + + + + + + + + xmlAttrs + 182798274 + + + id + 182798274 + + + elementid + 149002731 + + + name + 722241 + + + value + 11548187 + + + idx + 44179 + + + fileid + 1127542 + + + + + id + elementid + + + 12 + + + 1 + 2 + 182798274 + + + + + + + id + name + + + 12 + + + 1 + 2 + 182798274 + + + + + + + id + value + + + 12 + + + 1 + 2 + 182798274 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 182798274 + + + + + + + id + fileid + + + 12 + + + 1 + 2 + 182798274 + + + + + + + elementid + id + + + 12 + + + 1 + 2 + 136351973 + + + 2 + 6 + 11204353 + + + 6 + 24 + 1446404 + + + + + + + elementid + name + + + 12 + + + 1 + 2 + 136351973 + + + 2 + 6 + 11223562 + + + 6 + 23 + 1427196 + + + + + + + elementid + value + + + 12 + + + 1 + 2 + 136426886 + + + 2 + 6 + 11279267 + + + 6 + 21 + 1296577 + + + + + + + elementid + idx + + + 12 + + + 1 + 2 + 136351973 + + + 2 + 6 + 11204353 + + + 6 + 24 + 1446404 + + + + + + + elementid + fileid + + + 12 + + + 1 + 2 + 149002731 + + + + + + + name + id + + + 12 + + + 1 + 2 + 149826 + + + 2 + 3 + 78755 + + + 3 + 4 + 44179 + + + 4 + 5 + 24971 + + + 5 + 6 + 42258 + + + 6 + 8 + 51863 + + + 8 + 11 + 59546 + + + 11 + 22 + 55704 + + + 23 + 38 + 57625 + + + 38 + 79 + 57625 + + + 81 + 168 + 55704 + + + 168 + 74700 + 44179 + + + + + + + name + elementid + + + 12 + + + 1 + 2 + 149826 + + + 2 + 3 + 78755 + + + 3 + 4 + 44179 + + + 4 + 5 + 24971 + + + 5 + 6 + 42258 + + + 6 + 8 + 51863 + + + 8 + 11 + 65309 + + + 11 + 25 + 61467 + + + 25 + 39 + 59546 + + + 43 + 91 + 57625 + + + 91 + 227 + 55704 + + + 227 + 74700 + 30733 + + + + + + + name + value + + + 12 + + + 1 + 2 + 303495 + + + 2 + 3 + 113330 + + + 3 + 4 + 48021 + + + 4 + 5 + 51863 + + + 5 + 9 + 59546 + + + 9 + 21 + 55704 + + + 22 + 64 + 59546 + + + 68 + 2100 + 30733 + + + + + + + name + idx + + + 12 + + + 1 + 2 + 284286 + + + 2 + 3 + 134459 + + + 3 + 4 + 69150 + + + 4 + 5 + 76834 + + + 5 + 7 + 46100 + + + 7 + 10 + 57625 + + + 10 + 21 + 53783 + + + + + + + name + fileid + + + 12 + + + 1 + 2 + 251632 + + + 2 + 3 + 74913 + + + 3 + 4 + 38417 + + + 4 + 5 + 34575 + + + 5 + 6 + 53783 + + + 6 + 9 + 59546 + + + 9 + 17 + 63388 + + + 17 + 34 + 55704 + + + 36 + 91 + 55704 + + + 91 + 223 + 34575 + + + + + + + value + id + + + 12 + + + 1 + 2 + 6308091 + + + 2 + 3 + 1707641 + + + 3 + 5 + 885514 + + + 5 + 31 + 870147 + + + 31 + 91 + 908564 + + + 91 + 1111 + 866306 + + + 3397 + 3398 + 1920 + + + + + + + value + elementid + + + 12 + + + 1 + 2 + 6434868 + + + 2 + 3 + 1626965 + + + 3 + 5 + 897039 + + + 5 + 33 + 910485 + + + 33 + 93 + 891277 + + + 93 + 3398 + 787551 + + + + + + + value + name + + + 12 + + + 1 + 2 + 10480191 + + + 2 + 4 + 929694 + + + 4 + 53 + 138301 + + + + + + + value + idx + + + 12 + + + 1 + 2 + 9563942 + + + 2 + 3 + 1396462 + + + 3 + 20 + 587781 + + + + + + + value + fileid + + + 12 + + + 1 + 2 + 7433713 + + + 2 + 3 + 1252398 + + + 3 + 10 + 897039 + + + 10 + 83 + 877831 + + + 83 + 99 + 881672 + + + 99 + 182 + 205531 + + + + + + + idx + id + + + 12 + + + 1 + 6 + 3841 + + + 12 + 14 + 3841 + + + 17 + 26 + 3841 + + + 39 + 56 + 3841 + + + 83 + 110 + 3841 + + + 153 + 232 + 3841 + + + 316 + 400 + 3841 + + + 468 + 545 + 3841 + + + 626 + 754 + 3841 + + + 951 + 1491 + 3841 + + + 4718 + 6587 + 3841 + + + 77571 + 77572 + 1920 + + + + + + + idx + elementid + + + 12 + + + 1 + 6 + 3841 + + + 12 + 14 + 3841 + + + 17 + 26 + 3841 + + + 39 + 56 + 3841 + + + 83 + 110 + 3841 + + + 153 + 232 + 3841 + + + 316 + 400 + 3841 + + + 468 + 545 + 3841 + + + 626 + 754 + 3841 + + + 951 + 1491 + 3841 + + + 4718 + 6587 + 3841 + + + 77571 + 77572 + 1920 + + + + + + + idx + name + + + 12 + + + 1 + 4 + 3841 + + + 7 + 10 + 3841 + + + 11 + 17 + 3841 + + + 18 + 23 + 3841 + + + 26 + 38 + 3841 + + + 39 + 49 + 3841 + + + 57 + 67 + 3841 + + + 72 + 79 + 3841 + + + 95 + 101 + 3841 + + + 105 + 106 + 3841 + + + 106 + 132 + 3841 + + + 140 + 141 + 1920 + + + + + + + idx + value + + + 12 + + + 1 + 5 + 3841 + + + 7 + 10 + 3841 + + + 11 + 18 + 3841 + + + 22 + 32 + 3841 + + + 46 + 63 + 3841 + + + 85 + 119 + 3841 + + + 142 + 185 + 3841 + + + 212 + 228 + 3841 + + + 253 + 275 + 3841 + + + 307 + 423 + 3841 + + + 580 + 1324 + 3841 + + + 3579 + 3580 + 1920 + + + + + + + idx + fileid + + + 12 + + + 1 + 6 + 3841 + + + 7 + 8 + 3841 + + + 10 + 19 + 3841 + + + 23 + 36 + 3841 + + + 45 + 59 + 3841 + + + 73 + 97 + 3841 + + + 115 + 131 + 3841 + + + 140 + 148 + 3841 + + + 168 + 181 + 3841 + + + 248 + 363 + 3841 + + + 473 + 530 + 3841 + + + 587 + 588 + 1920 + + + + + + + fileid + id + + + 12 + + + 1 + 3 + 84517 + + + 3 + 5 + 86438 + + + 5 + 6 + 51863 + + + 6 + 7 + 86438 + + + 7 + 8 + 72992 + + + 8 + 10 + 82596 + + + 10 + 15 + 92201 + + + 15 + 27 + 86438 + + + 27 + 41 + 86438 + + + 41 + 65 + 86438 + + + 65 + 157 + 92201 + + + 162 + 817 + 86438 + + + 818 + 832 + 94121 + + + 832 + 1187 + 38417 + + + + + + + fileid + elementid + + + 12 + + + 1 + 2 + 128697 + + + 2 + 3 + 265078 + + + 3 + 4 + 159431 + + + 4 + 5 + 109488 + + + 5 + 8 + 101805 + + + 8 + 14 + 86438 + + + 14 + 295 + 86438 + + + 330 + 775 + 71071 + + + 776 + 778 + 92201 + + + 787 + 888 + 26891 + + + + + + + fileid + name + + + 12 + + + 1 + 2 + 71071 + + + 2 + 3 + 92201 + + + 3 + 4 + 71071 + + + 4 + 5 + 94121 + + + 5 + 6 + 170956 + + + 6 + 7 + 161351 + + + 7 + 8 + 71071 + + + 8 + 12 + 86438 + + + 12 + 18 + 97963 + + + 18 + 24 + 96042 + + + 24 + 37 + 88359 + + + 37 + 55 + 26891 + + + + + + + fileid + value + + + 12 + + + 1 + 3 + 97963 + + + 3 + 4 + 55704 + + + 4 + 5 + 103726 + + + 5 + 6 + 124855 + + + 6 + 8 + 88359 + + + 8 + 12 + 99884 + + + 12 + 19 + 86438 + + + 19 + 27 + 97963 + + + 27 + 41 + 86438 + + + 42 + 170 + 86438 + + + 205 + 780 + 80675 + + + 781 + 783 + 92201 + + + 791 + 893 + 26891 + + + + + + + fileid + idx + + + 12 + + + 1 + 2 + 111409 + + + 2 + 3 + 107567 + + + 3 + 4 + 213215 + + + 4 + 5 + 218977 + + + 5 + 6 + 130618 + + + 6 + 10 + 96042 + + + 10 + 12 + 65309 + + + 12 + 15 + 97963 + + + 15 + 24 + 86438 + + + + + + + + + xmlNs + 1811367 + + + id + 11525 + + + prefixName + 13445 + + + URI + 11525 + + + fileid + 1054550 + + + + + id + prefixName + + + 12 + + + 1 + 2 + 9604 + + + 2 + 3 + 1920 + + + + + + + id + URI + + + 12 + + + 1 + 2 + 11525 + + + + + + + id + fileid + + + 12 + + + 2 + 3 + 1920 + + + 20 + 21 + 1920 + + + 88 + 89 + 1920 + + + 167 + 168 + 1920 + + + 213 + 214 + 1920 + + + 453 + 454 + 1920 + + + + + + + prefixName + id + + + 12 + + + 1 + 2 + 13445 + + + + + + + prefixName + URI + + + 12 + + + 1 + 2 + 13445 + + + + + + + prefixName + fileid + + + 12 + + + 1 + 2 + 1920 + + + 2 + 3 + 1920 + + + 20 + 21 + 1920 + + + 88 + 89 + 1920 + + + 166 + 167 + 1920 + + + 213 + 214 + 1920 + + + 453 + 454 + 1920 + + + + + + + URI + id + + + 12 + + + 1 + 2 + 11525 + + + + + + + URI + prefixName + + + 12 + + + 1 + 2 + 9604 + + + 2 + 3 + 1920 + + + + + + + URI + fileid + + + 12 + + + 2 + 3 + 1920 + + + 20 + 21 + 1920 + + + 88 + 89 + 1920 + + + 167 + 168 + 1920 + + + 213 + 214 + 1920 + + + 453 + 454 + 1920 + + + + + + + fileid + id + + + 12 + + + 1 + 2 + 470609 + + + 2 + 3 + 411063 + + + 3 + 4 + 172877 + + + + + + + fileid + prefixName + + + 12 + + + 1 + 2 + 470609 + + + 2 + 3 + 411063 + + + 3 + 4 + 172877 + + + + + + + fileid + URI + + + 12 + + + 1 + 2 + 470609 + + + 2 + 3 + 411063 + + + 3 + 4 + 172877 + + + + + + + + + xmlHasNs + 36540446 + + + elementId + 36540446 + + + nsId + 11525 + + + fileid + 1048787 + + + + + elementId + nsId + + + 12 + + + 1 + 2 + 36540446 + + + + + + + elementId + fileid + + + 12 + + + 1 + 2 + 36540446 + + + + + + + nsId + elementId + + + 12 + + + 13 + 14 + 1920 + + + 84 + 85 + 1920 + + + 2426 + 2427 + 1920 + + + 2733 + 2734 + 1920 + + + 3704 + 3705 + 1920 + + + 10063 + 10064 + 1920 + + + + + + + nsId + fileid + + + 12 + + + 2 + 3 + 1920 + + + 20 + 21 + 1920 + + + 86 + 87 + 1920 + + + 164 + 165 + 1920 + + + 209 + 210 + 1920 + + + 453 + 454 + 1920 + + + + + + + fileid + elementId + + + 12 + + + 1 + 3 + 63388 + + + 3 + 5 + 88359 + + + 5 + 6 + 48021 + + + 6 + 7 + 92201 + + + 7 + 8 + 69150 + + + 8 + 10 + 86438 + + + 10 + 15 + 92201 + + + 15 + 25 + 78755 + + + 25 + 36 + 80675 + + + 36 + 49 + 82596 + + + 49 + 54 + 21129 + + + 54 + 55 + 82596 + + + 55 + 81 + 80675 + + + 81 + 298 + 78755 + + + 298 + 833 + 3841 + + + + + + + fileid + nsId + + + 12 + + + 1 + 2 + 472530 + + + 2 + 3 + 407221 + + + 3 + 4 + 169035 + + + + + + + + + xmlComments + 151257816 + + + id + 151257816 + + + text + 2387624 + + + parentid + 1185168 + + + fileid + 1108333 + + + + + id + text + + + 12 + + + 1 + 2 + 151257816 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 151257816 + + + + + + + id + fileid + + + 12 + + + 1 + 2 + 151257816 + + + + + + + text + id + + + 12 + + + 1 + 2 + 328466 + + + 2 + 7 + 195927 + + + 7 + 32 + 197848 + + + 32 + 61 + 180560 + + + 61 + 76 + 180560 + + + 76 + 84 + 192085 + + + 84 + 90 + 176718 + + + 90 + 94 + 157510 + + + 94 + 95 + 84517 + + + 95 + 96 + 142143 + + + 96 + 98 + 197848 + + + 98 + 100 + 178639 + + + 100 + 460 + 174797 + + + + + + + text + parentid + + + 12 + + + 1 + 2 + 332308 + + + 2 + 6 + 190164 + + + 6 + 32 + 201689 + + + 32 + 61 + 182481 + + + 61 + 75 + 186323 + + + 75 + 84 + 209373 + + + 84 + 90 + 172877 + + + 90 + 94 + 169035 + + + 94 + 95 + 94121 + + + 95 + 96 + 145985 + + + 96 + 98 + 201689 + + + 98 + 100 + 190164 + + + 100 + 460 + 111409 + + + + + + + text + fileid + + + 12 + + + 1 + 2 + 347674 + + + 2 + 7 + 188243 + + + 7 + 32 + 188243 + + + 32 + 61 + 182481 + + + 61 + 75 + 186323 + + + 75 + 84 + 209373 + + + 84 + 90 + 172877 + + + 90 + 94 + 169035 + + + 94 + 95 + 94121 + + + 95 + 96 + 145985 + + + 96 + 98 + 201689 + + + 98 + 100 + 190164 + + + 100 + 460 + 111409 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 943140 + + + 2 + 724 + 90280 + + + 726 + 830 + 109488 + + + 831 + 941 + 42258 + + + + + + + parentid + text + + + 12 + + + 1 + 2 + 943140 + + + 2 + 697 + 90280 + + + 697 + 795 + 48021 + + + 795 + 827 + 90280 + + + 838 + 899 + 13445 + + + + + + + parentid + fileid + + + 12 + + + 1 + 2 + 1185168 + + + + + + + fileid + id + + + 12 + + + 1 + 2 + 847097 + + + 2 + 549 + 84517 + + + 579 + 829 + 57625 + + + 829 + 832 + 92201 + + + 834 + 941 + 26891 + + + + + + + fileid + text + + + 12 + + + 1 + 2 + 847097 + + + 2 + 536 + 84517 + + + 560 + 795 + 72992 + + + 795 + 812 + 84517 + + + 819 + 899 + 19208 + + + + + + + fileid + parentid + + + 12 + + + 1 + 2 + 1052629 + + + 2 + 6 + 55704 + + + + + + + + + xmlChars + 142938589 + + + id + 142938589 + + + text + 109773086 + + + parentid + 142938589 + + + idx + 1920 + + + isCDATA + 3841 + + + fileid + 249711 + + + + + id + text + + + 12 + + + 1 + 2 + 142938589 + + + + + + + id + parentid + + + 12 + + + 1 + 2 + 142938589 + + + + + + + id + idx + + + 12 + + + 1 + 2 + 142938589 + + + + + + + id + isCDATA + + + 12 + + + 1 + 2 + 142938589 + + + + + + + id + fileid + + + 12 + + + 1 + 2 + 142938589 + + + + + + + text + id + + + 12 + + + 1 + 2 + 93927944 + + + 2 + 3 + 9865517 + + + 3 + 128 + 5979625 + + + + + + + text + parentid + + + 12 + + + 1 + 2 + 93927944 + + + 2 + 3 + 9865517 + + + 3 + 128 + 5979625 + + + + + + + text + idx + + + 12 + + + 1 + 2 + 109773086 + + + + + + + text + isCDATA + + + 12 + + + 1 + 2 + 109773086 + + + + + + + text + fileid + + + 12 + + + 1 + 2 + 105030493 + + + 2 + 76 + 4742593 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 142938589 + + + + + + + parentid + text + + + 12 + + + 1 + 2 + 142938589 + + + + + + + parentid + idx + + + 12 + + + 1 + 2 + 142938589 + + + + + + + parentid + isCDATA + + + 12 + + + 1 + 2 + 142938589 + + + + + + + parentid + fileid + + + 12 + + + 1 + 2 + 142938589 + + + + + + + idx + id + + + 12 + + + 74414 + 74415 + 1920 + + + + + + + idx + text + + + 12 + + + 57148 + 57149 + 1920 + + + + + + + idx + parentid + + + 12 + + + 74414 + 74415 + 1920 + + + + + + + idx + isCDATA + + + 12 + + + 2 + 3 + 1920 + + + + + + + idx + fileid + + + 12 + + + 130 + 131 + 1920 + + + + + + + isCDATA + id + + + 12 + + + 518 + 519 + 1920 + + + 73896 + 73897 + 1920 + + + + + + + isCDATA + text + + + 12 + + + 492 + 493 + 1920 + + + 56656 + 56657 + 1920 + + + + + + + isCDATA + parentid + + + 12 + + + 518 + 519 + 1920 + + + 73896 + 73897 + 1920 + + + + + + + isCDATA + idx + + + 12 + + + 1 + 2 + 3841 + + + + + + + isCDATA + fileid + + + 12 + + + 98 + 99 + 1920 + + + 130 + 131 + 1920 + + + + + + + fileid + id + + + 12 + + + 1 + 2 + 21129 + + + 2 + 23 + 19208 + + + 24 + 243 + 19208 + + + 294 + 566 + 19208 + + + 610 + 686 + 19208 + + + 691 + 764 + 19208 + + + 765 + 775 + 19208 + + + 775 + 776 + 5762 + + + 776 + 777 + 69150 + + + 777 + 803 + 19208 + + + 807 + 888 + 19208 + + + + + + + fileid + text + + + 12 + + + 1 + 2 + 21129 + + + 2 + 21 + 19208 + + + 22 + 188 + 19208 + + + 208 + 492 + 19208 + + + 525 + 589 + 19208 + + + 590 + 638 + 19208 + + + 639 + 651 + 19208 + + + 652 + 656 + 17287 + + + 656 + 659 + 23050 + + + 659 + 663 + 21129 + + + 663 + 667 + 19208 + + + 667 + 701 + 19208 + + + 702 + 744 + 13445 + + + + + + + fileid + parentid + + + 12 + + + 1 + 2 + 21129 + + + 2 + 23 + 19208 + + + 24 + 243 + 19208 + + + 294 + 566 + 19208 + + + 610 + 686 + 19208 + + + 691 + 764 + 19208 + + + 765 + 775 + 19208 + + + 775 + 776 + 5762 + + + 776 + 777 + 69150 + + + 777 + 803 + 19208 + + + 807 + 888 + 19208 + + + + + + + fileid + idx + + + 12 + + + 1 + 2 + 249711 + + + + + + + fileid + isCDATA + + + 12 + + + 1 + 2 + 61467 + + + 2 + 3 + 188243 + + + + + + + + + xmllocations + 630217533 + + + xmlElement + 628417691 + + + location + 590551854 + + + + + xmlElement + location + + + 12 + + + 1 + 2 + 628406166 + + + 2 + 454 + 11525 + + + + + + + location + xmlElement + + + 12 + + + 1 + 2 + 577165407 + + + 2 + 25 + 13386446 + + + + + + + + + configs + 1 + + + id + 1 + + + + + + configNames + 1 + + + id + 1 + + + config + 1 + + + name + 1 + + + + + id + config + + + 12 + + + 1 + 2 + 1 + + + + + + + id + name + + + 12 + + + 1 + 2 + 1 + + + + + + + config + id + + + 12 + + + + + + config + name + + + 12 + + + + + + name + id + + + 12 + + + + + + name + config + + + 12 + + + + + + + + configValues + 1 + + + id + 1 + + + config + 1 + + + value + 1 + + + + + id + config + + + 12 + + + 1 + 2 + 1 + + + + + + + id + value + + + 12 + + + 1 + 2 + 1 + + + + + + + config + id + + + 12 + + + + + + config + value + + + 12 + + + + + + value + id + + + 12 + + + + + + value + config + + + 12 + + + + + + + + configLocations + 1 + + + locatable + 1 + + + location + 1 + + + + + locatable + location + + + 12 + + + + + + location + locatable + + + 12 + + + + + + + + ktComments + 188243 + + + id + 188243 + + + kind + 5762 + + + text + 136380 + + + + + id + kind + + + 12 + + + 1 + 2 + 188243 + + + + + + + id + text + + + 12 + + + 1 + 2 + 188243 + + + + + + + kind + id + + + 12 + + + 16 + 17 + 1920 + + + 22 + 23 + 1920 + + + 60 + 61 + 1920 + + + + + + + kind + text + + + 12 + + + 1 + 2 + 1920 + + + 16 + 17 + 1920 + + + 54 + 55 + 1920 + + + + + + + text + id + + + 12 + + + 1 + 2 + 130618 + + + 4 + 23 + 5762 + + + + + + + text + kind + + + 12 + + + 1 + 2 + 136380 + + + + + + + + + ktCommentSections + 52611 + + + id + 52611 + + + comment + 48161 + + + content + 44765 + + + + + id + comment + + + 12 + + + 1 + 2 + 52611 + + + + + + + id + content + + + 12 + + + 1 + 2 + 52611 + + + + + + + comment + id + + + 12 + + + 1 + 2 + 46367 + + + 2 + 18 + 1793 + + + + + + + comment + content + + + 12 + + + 1 + 2 + 46367 + + + 2 + 18 + 1793 + + + + + + + content + id + + + 12 + + + 1 + 2 + 39616 + + + 2 + 3 + 4313 + + + 3 + 63 + 835 + + + + + + + content + comment + + + 12 + + + 1 + 2 + 39712 + + + 2 + 3 + 4231 + + + 3 + 56 + 821 + + + + + + + + + ktCommentSectionNames + 4450 + + + id + 4450 + + + name + 13 + + + + + id + name + + + 12 + + + 1 + 2 + 4450 + + + + + + + name + id + + + 12 + + + 325 + 326 + 13 + + + + + + + + + ktCommentSectionSubjectNames + 4450 + + + id + 4450 + + + subjectname + 2916 + + + + + id + subjectname + + + 12 + + + 1 + 2 + 4450 + + + + + + + subjectname + id + + + 12 + + + 1 + 2 + 2218 + + + 2 + 3 + 438 + + + 3 + 9 + 219 + + + 10 + 16 + 41 + + + + + + + + + ktCommentOwners + 75329 + + + id + 47914 + + + owner + 73508 + + + + + id + owner + + + 12 + + + 1 + 2 + 30838 + + + 2 + 3 + 10872 + + + 3 + 4 + 4025 + + + 4 + 6 + 2177 + + + + + + + owner + id + + + 12 + + + 1 + 2 + 71701 + + + 2 + 4 + 1807 + + + + + + + + + ktExtensionFunctions + 1206297 + + + id + 1206297 + + + typeid + 97963 + + + kttypeid + 1920 + + + + + id + typeid + + + 12 + + + 1 + 2 + 1206297 + + + + + + + id + kttypeid + + + 12 + + + 1 + 2 + 1206297 + + + + + + + typeid + id + + + 12 + + + 1 + 2 + 55704 + + + 2 + 3 + 5762 + + + 3 + 4 + 3841 + + + 5 + 6 + 13445 + + + 7 + 16 + 7683 + + + 20 + 87 + 7683 + + + 109 + 227 + 3841 + + + + + + + typeid + kttypeid + + + 12 + + + 1 + 2 + 97963 + + + + + + + kttypeid + id + + + 12 + + + 628 + 629 + 1920 + + + + + + + kttypeid + typeid + + + 12 + + + 51 + 52 + 1920 + + + + + + + + + ktProperties + 21895839 + + + id + 21895839 + + + nodeName + 13542035 + + + + + id + nodeName + + + 12 + + + 1 + 2 + 21895839 + + + + + + + nodeName + id + + + 12 + + + 1 + 2 + 11824790 + + + 2 + 4 + 1142909 + + + 4 + 352 + 574335 + + + + + + + + + ktPropertyGetters + 5985387 + + + id + 5985387 + + + getter + 5985387 + + + + + id + getter + + + 12 + + + 1 + 2 + 5985387 + + + + + + + getter + id + + + 12 + + + 1 + 2 + 5985387 + + + + + + + + + ktPropertySetters + 366883 + + + id + 366883 + + + setter + 366883 + + + + + id + setter + + + 12 + + + 1 + 2 + 366883 + + + + + + + setter + id + + + 12 + + + 1 + 2 + 366883 + + + + + + + + + ktPropertyBackingFields + 14423708 + + + id + 14423708 + + + backingField + 14423708 + + + + + id + backingField + + + 12 + + + 1 + 2 + 14423708 + + + + + + + backingField + id + + + 12 + + + 1 + 2 + 14423708 + + + + + + + + + ktSyntheticBody + 9108 + + + id + 9108 + + + kind + 1821 + + + + + id + kind + + + 12 + + + 1 + 2 + 9108 + + + + + + + kind + id + + + 12 + + + 5 + 6 + 1821 + + + + + + + + + ktLocalFunction + 3841 + + + id + 3841 + + + + + + ktInitializerAssignment + 199475 + + + id + 199475 + + + + + + ktPropertyDelegates + 5201 + + + id + 5201 + + + variableId + 5201 + + + + + id + variableId + + + 12 + + + 1 + 2 + 5201 + + + + + + + variableId + id + + + 12 + + + 1 + 2 + 5201 + + + + + + + + + compiler_generated + 1467534 + + + id + 1467534 + + + kind + 13445 + + + + + id + kind + + + 12 + + + 1 + 2 + 1467534 + + + + + + + kind + id + + + 12 + + + 1 + 2 + 1920 + + + 8 + 9 + 1920 + + + 38 + 39 + 1920 + + + 81 + 82 + 1920 + + + 85 + 86 + 1920 + + + 236 + 237 + 1920 + + + 315 + 316 + 1920 + + + + + + + + + ktFunctionOriginalNames + 1586627 + + + id + 1586627 + + + name + 186323 + + + + + id + name + + + 12 + + + 1 + 2 + 1586627 + + + + + + + name + id + + + 12 + + + 1 + 2 + 147905 + + + 2 + 4 + 13445 + + + 6 + 16 + 15366 + + + 22 + 339 + 9604 + + + + + + + + + ktDataClasses + 113330 + + + id + 113330 + + + + + + diff --git a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties new file mode 100644 index 00000000000..0c14acf20bd --- /dev/null +++ b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties @@ -0,0 +1,4 @@ +description: Merge class and interface tables +compatibility: full +classes_or_interfaces.rel: run classes_or_interfaces.qlo +isInterface.rel: run isInterface.qlo diff --git a/java/ql/test/library-tests/qlengine/selectAtType.ql b/java/ql/test/library-tests/qlengine/selectAtType.ql index 3947b504059..14fa6ce034f 100644 --- a/java/ql/test/library-tests/qlengine/selectAtType.ql +++ b/java/ql/test/library-tests/qlengine/selectAtType.ql @@ -1,5 +1,5 @@ import java -@class clasz() { any() } +@classorinterface clasz() { any() } select clasz() From f48d87ba55938946fa2f27e041075a080aa573d3 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 7 Feb 2023 12:40:40 +0000 Subject: [PATCH 234/415] Add deletions for removed tables --- .../934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties | 1 + .../44d61b266bebf261cb027872646262e645efa059/upgrade.properties | 2 ++ 2 files changed, 3 insertions(+) diff --git a/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties index 52c95780abc..ad10ae1fc72 100644 --- a/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties +++ b/java/downgrades/934bf10b4bd34cf648893efcd1d0d7be9471d39f/upgrade.properties @@ -3,3 +3,4 @@ compatibility: full classes.rel: run classes.qlo interfaces.rel: run interfaces.qlo isInterface.rel: delete +classes_or_interfaces.rel: delete diff --git a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties index 0c14acf20bd..e027c6666fb 100644 --- a/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties +++ b/java/ql/lib/upgrades/44d61b266bebf261cb027872646262e645efa059/upgrade.properties @@ -2,3 +2,5 @@ description: Merge class and interface tables compatibility: full classes_or_interfaces.rel: run classes_or_interfaces.qlo isInterface.rel: run isInterface.qlo +classes.rel: delete +interfaces.rel: delete From 82a2f4349adfd77ea458438f0e782594ec8acfb1 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 7 Feb 2023 18:38:17 +0000 Subject: [PATCH 235/415] Resolve a newly-introduced ambiguity Also fix a simple redundancy noticed while debugging --- java/ql/lib/semmle/code/java/Type.qll | 2 +- java/ql/src/utils/stub-generator/Stubs.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/semmle/code/java/Type.qll b/java/ql/lib/semmle/code/java/Type.qll index f0b79ee945c..13d3a6ea443 100644 --- a/java/ql/lib/semmle/code/java/Type.qll +++ b/java/ql/lib/semmle/code/java/Type.qll @@ -839,7 +839,7 @@ class LocalClass extends LocalClassOrInterface, NestedClass { class TopLevelType extends RefType { TopLevelType() { not enclInReftype(this, _) and - (this instanceof Class or this instanceof Interface) + this instanceof ClassOrInterface } } diff --git a/java/ql/src/utils/stub-generator/Stubs.qll b/java/ql/src/utils/stub-generator/Stubs.qll index b670d3837bb..86d7beb8c15 100644 --- a/java/ql/src/utils/stub-generator/Stubs.qll +++ b/java/ql/src/utils/stub-generator/Stubs.qll @@ -515,7 +515,7 @@ private RefType getAReferencedType(RefType t) { /** A top level type whose file should be stubbed */ class GeneratedTopLevel extends TopLevelType instanceof GeneratedType { - GeneratedTopLevel() { this = this.getSourceDeclaration() } + GeneratedTopLevel() { this = this.(ClassOrInterface).getSourceDeclaration() } private TopLevelType getAnImportedType() { result = getAReferencedType(this).getSourceDeclaration() and From 7f76d8ae55a62e342902a2ef9af3b505b87b4a97 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 7 Feb 2023 18:40:25 +0000 Subject: [PATCH 236/415] Replace redundant use of `Class or Interface` --- java/ql/src/utils/stub-generator/Stubs.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/utils/stub-generator/Stubs.qll b/java/ql/src/utils/stub-generator/Stubs.qll index 86d7beb8c15..785f621cba0 100644 --- a/java/ql/src/utils/stub-generator/Stubs.qll +++ b/java/ql/src/utils/stub-generator/Stubs.qll @@ -523,9 +523,8 @@ class GeneratedTopLevel extends TopLevelType instanceof GeneratedType { } private string stubAnImport() { - exists(RefType t, string pkg, string name | + exists(ClassOrInterface t, string pkg, string name | t = this.getAnImportedType() and - (t instanceof Class or t instanceof Interface) and t.hasQualifiedName(pkg, name) and t != this and pkg != "java.lang" From d5f7ef08b7259d6713b747bc29dde4ea5475e8bc Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 9 Feb 2023 15:14:43 +0000 Subject: [PATCH 237/415] Update stats --- java/ql/lib/config/semmlecode.dbscheme.stats | 8258 +++++++++--------- 1 file changed, 3992 insertions(+), 4266 deletions(-) diff --git a/java/ql/lib/config/semmlecode.dbscheme.stats b/java/ql/lib/config/semmlecode.dbscheme.stats index 7ebc6e0b93e..05a477fec73 100644 --- a/java/ql/lib/config/semmlecode.dbscheme.stats +++ b/java/ql/lib/config/semmlecode.dbscheme.stats @@ -6,11 +6,11 @@ @kotlincompilation - 7683 + 2356 @diagnostic - 61632 + 64190 @externalDataElement @@ -26,71 +26,67 @@ @file - 9158642 + 1291911 @folder - 1415670 - - - @location_default - 602747369 + 293711 @package - 580098 + 121135 @primitive - 17287 + 5690 @modifier - 26891 + 6259 @errortype - 1 + 22 - @class - 12618104 + @classorinterface + 22273131 @kt_nullable_type - 1920 + 262 @kt_notnull_type - 172391 + 156265 @kt_type_alias - 1821 - - - @interface - 23200100 + 707 @fielddecl - 199475 + 210035 + + + @location_default + 82315299 @field - 19350704 + 2886451 @constructor - 8006128 + 1103682 @method - 109719302 + 15113893 @param - 120852585 + 16587479 @exception @@ -98,27 +94,27 @@ @typevariable - 6288883 + 864332 @wildcard - 3338447 + 458250 @typebound - 4229725 + 581989 @array - 1375332 + 190588 @import - 368550 + 441072 @block - 756817 + 707376 @ifstmt @@ -130,7 +126,7 @@ @enhancedforstmt - 18520 + 23697 @whilestmt @@ -138,7 +134,7 @@ @dostmt - 2405 + 2251 @trystmt @@ -150,11 +146,11 @@ @synchronizedstmt - 18206 + 23121 @returnstmt - 532846 + 345813 @throwstmt @@ -166,7 +162,7 @@ @continuestmt - 3211 + 3257 @emptystmt @@ -178,7 +174,7 @@ @assertstmt - 10815 + 15159 @localvariabledeclstmt @@ -186,7 +182,7 @@ @localtypedeclstmt - 3841 + 3533 @constructorinvocationstmt @@ -194,7 +190,7 @@ @superconstructorinvocationstmt - 201354 + 182518 @case @@ -206,7 +202,7 @@ @labeledstmt - 2342 + 4493 @yieldstmt @@ -218,7 +214,7 @@ @whenbranch - 225101 + 207293 @arrayaccess @@ -290,7 +286,7 @@ @nullliteral - 434113 + 355806 @mulexpr @@ -322,15 +318,15 @@ @urshiftexpr - 5463 + 9644 @andbitexpr - 110212 + 29089 @orbitexpr - 12590 + 11594 @xorbitexpr @@ -362,7 +358,7 @@ @eqexpr - 128429 + 104275 @neexpr @@ -370,7 +366,7 @@ @postincexpr - 29632 + 41859 @postdecexpr @@ -422,15 +418,15 @@ @typeliteral - 144350 + 98504 @thisaccess - 756915 + 490120 @superaccess - 99884 + 53024 @varaccess @@ -442,7 +438,7 @@ @unannotatedtypeaccess - 2608638 + 2374849 @arraytypeaccess @@ -450,7 +446,7 @@ @wildcardtypeaccess - 64091 + 74889 @declannotation @@ -458,7 +454,7 @@ @assignremexpr - 47 + 62 @assignxorexpr @@ -486,11 +482,11 @@ @uniontypeaccess - 917 + 1010 @lambdaexpr - 167982 + 152268 @memberref @@ -518,43 +514,43 @@ @whenexpr - 152111 + 116200 @getclassexpr - 1920 + 733 @safecastexpr - 6402 + 6086 @implicitcastexpr - 30316 + 28818 @implicitnotnullexpr - 216630 + 163412 @implicitcoerciontounitexpr - 81396 + 73781 @notinstanceofexpr - 17306 + 3981 @stmtexpr - 55704 + 50553 @stringtemplateexpr - 59546 + 24879 @notnullexpr - 18820 + 23342 @unsafecoerceexpr @@ -562,15 +558,15 @@ @valueeqexpr - 93060 + 85697 @valueneexpr - 95639 + 22980 @propertyref - 8878 + 8440 @localvar @@ -582,7 +578,7 @@ @requires - 1991 + 3190 @exports @@ -618,23 +614,23 @@ @xmlelement - 150282022 + 20510401 @xmlattribute - 182798274 + 24948200 @xmlnamespace - 11525 + 2845 @xmlcomment - 151257816 + 20643577 @xmlcharacters - 142938589 + 19508174 @config @@ -650,15 +646,15 @@ @ktcomment - 188243 + 74439 @ktcommentsection - 52611 + 47690 @kt_property - 21895839 + 2989117 @@ -880,30 +876,30 @@ compilation_started - 7683 + 2261 id - 7683 + 2261 compilation_info - 15366 + 4523 id - 7683 + 2261 info_key - 3841 + 188 info_value - 3841 + 188 @@ -917,7 +913,7 @@ 2 3 - 7683 + 2261 @@ -933,7 +929,7 @@ 2 3 - 7683 + 2261 @@ -947,9 +943,9 @@ 12 - 4 - 5 - 3841 + 24 + 25 + 188 @@ -965,7 +961,7 @@ 1 2 - 3841 + 188 @@ -979,9 +975,9 @@ 12 - 4 - 5 - 3841 + 24 + 25 + 188 @@ -997,7 +993,7 @@ 1 2 - 3841 + 188 @@ -1007,19 +1003,19 @@ compilation_args - 169035 + 69266 id - 7683 + 2356 num - 48021 + 12062 arg - 90280 + 35151 @@ -1030,20 +1026,45 @@ 12 + + 19 + 20 + 565 + 20 21 - 3841 + 753 - 23 - 24 - 1920 + 21 + 22 + 188 - 25 - 26 - 1920 + 22 + 25 + 188 + + + 32 + 33 + 188 + + + 34 + 43 + 188 + + + 52 + 54 + 188 + + + 128 + 129 + 94 @@ -1056,20 +1077,45 @@ 12 + + 19 + 20 + 565 + 20 21 - 3841 + 753 - 23 - 24 - 1920 + 21 + 22 + 188 - 25 - 26 - 1920 + 22 + 25 + 188 + + + 32 + 33 + 188 + + + 34 + 43 + 188 + + + 52 + 54 + 188 + + + 127 + 128 + 94 @@ -1085,17 +1131,32 @@ 1 2 - 3841 + 7068 2 - 3 - 5762 + 4 + 1036 4 - 5 - 38417 + 6 + 942 + + + 7 + 9 + 942 + + + 9 + 20 + 282 + + + 25 + 26 + 1790 @@ -1111,22 +1172,32 @@ 1 2 - 9604 + 7350 2 3 - 17287 + 188 3 4 - 11525 + 1507 4 - 5 - 9604 + 6 + 1036 + + + 6 + 9 + 942 + + + 9 + 26 + 1036 @@ -1142,17 +1213,12 @@ 1 2 - 61467 + 32607 2 - 3 - 3841 - - - 4 - 5 - 24971 + 26 + 2544 @@ -1168,17 +1234,12 @@ 1 2 - 67229 + 33078 2 - 3 - 19208 - - - 3 - 4 - 3841 + 12 + 2073 @@ -1188,19 +1249,19 @@ compilation_compiling_files - 59495 + 62421 id - 2275 + 731 num - 17556 + 9199 file - 49742 + 62421 @@ -1214,22 +1275,67 @@ 1 2 - 325 + 59 2 - 3 - 650 + 6 + 59 - 35 - 36 - 650 + 6 + 10 + 59 - 54 - 55 - 650 + 10 + 14 + 59 + + + 14 + 20 + 59 + + + 20 + 27 + 67 + + + 27 + 35 + 59 + + + 36 + 47 + 59 + + + 51 + 70 + 59 + + + 72 + 123 + 59 + + + 124 + 176 + 59 + + + 208 + 1130 + 59 + + + 1233 + 1234 + 7 @@ -1245,22 +1351,67 @@ 1 2 - 325 + 59 2 - 3 - 650 + 6 + 59 - 35 - 36 - 650 + 6 + 10 + 59 - 54 - 55 - 650 + 10 + 14 + 59 + + + 14 + 20 + 59 + + + 20 + 27 + 67 + + + 27 + 35 + 59 + + + 36 + 47 + 59 + + + 51 + 70 + 59 + + + 72 + 123 + 59 + + + 124 + 176 + 59 + + + 208 + 1130 + 59 + + + 1233 + 1234 + 7 @@ -1274,19 +1425,44 @@ 12 - 2 - 3 - 6177 + 1 + 2 + 775 - 4 + 2 + 3 + 4342 + + + 3 5 - 10728 + 790 + + + 5 + 6 + 880 6 8 - 650 + 686 + + + 8 + 16 + 768 + + + 16 + 42 + 701 + + + 42 + 99 + 253 @@ -1299,20 +1475,45 @@ 12 + + 1 + 2 + 775 + 2 3 - 6177 + 4342 3 - 4 - 9753 + 5 + 790 - 4 + 5 + 6 + 880 + + + 6 8 - 1625 + 686 + + + 8 + 16 + 768 + + + 16 + 42 + 701 + + + 42 + 99 + 253 @@ -1328,12 +1529,7 @@ 1 2 - 39989 - - - 2 - 3 - 9753 + 62421 @@ -1349,7 +1545,7 @@ 1 2 - 49742 + 62421 @@ -1359,19 +1555,19 @@ compilation_compiling_files_completed - 59495 + 62421 id - 2275 + 731 num - 17556 + 9199 result - 325 + 7 @@ -1385,22 +1581,67 @@ 1 2 - 325 + 59 2 - 3 - 650 + 6 + 59 - 35 - 36 - 650 + 6 + 10 + 59 - 54 - 55 - 650 + 10 + 14 + 59 + + + 14 + 20 + 59 + + + 20 + 27 + 67 + + + 27 + 35 + 59 + + + 36 + 47 + 59 + + + 51 + 70 + 59 + + + 72 + 123 + 59 + + + 124 + 176 + 59 + + + 208 + 1130 + 59 + + + 1233 + 1234 + 7 @@ -1416,7 +1657,7 @@ 1 2 - 2275 + 731 @@ -1430,19 +1671,44 @@ 12 - 2 - 3 - 6177 + 1 + 2 + 775 - 4 + 2 + 3 + 4342 + + + 3 5 - 10728 + 790 + + + 5 + 6 + 880 6 8 - 650 + 686 + + + 8 + 16 + 768 + + + 16 + 42 + 701 + + + 42 + 99 + 253 @@ -1458,7 +1724,7 @@ 1 2 - 17556 + 9199 @@ -1472,9 +1738,9 @@ 12 - 7 - 8 - 325 + 98 + 99 + 7 @@ -1488,9 +1754,9 @@ 12 - 54 - 55 - 325 + 1233 + 1234 + 7 @@ -1500,23 +1766,23 @@ compilation_time - 196471 + 252612 id - 8628 + 731 num - 5144 + 9207 kind - 663 + 29 seconds - 89772 + 123672 @@ -1527,55 +1793,70 @@ 12 - - 1 - 2 - 331 - 2 3 - 1659 + 59 3 - 4 - 1161 - - - 4 - 5 - 2157 - - - 5 - 6 - 663 - - - 6 7 - 497 + 59 7 - 8 - 497 + 11 + 59 - 8 - 12 - 663 + 11 + 15 + 59 - 13 - 16 - 663 + 15 + 21 + 59 - 20 - 32 - 331 + 21 + 28 + 67 + + + 28 + 36 + 59 + + + 37 + 48 + 59 + + + 52 + 71 + 59 + + + 73 + 124 + 59 + + + 125 + 177 + 59 + + + 209 + 1131 + 59 + + + 1234 + 1235 + 7 @@ -1591,7 +1872,7 @@ 4 5 - 8628 + 731 @@ -1604,55 +1885,70 @@ 12 - - 2 - 3 - 331 - 4 5 - 1659 + 59 6 - 7 - 1161 - - - 8 - 9 - 2157 - - - 10 - 11 - 663 - - - 12 13 - 497 + 59 14 - 15 - 497 + 21 + 59 - 16 - 23 - 663 + 22 + 29 + 59 - 26 - 31 - 663 + 30 + 41 + 59 - 40 - 63 - 331 + 42 + 55 + 67 + + + 56 + 71 + 59 + + + 74 + 95 + 59 + + + 104 + 141 + 59 + + + 146 + 247 + 59 + + + 250 + 353 + 59 + + + 418 + 2247 + 59 + + + 2436 + 2437 + 7 @@ -1668,52 +1964,42 @@ 1 2 - 1825 + 775 2 3 - 829 + 4342 3 5 - 331 + 790 + + + 5 + 6 + 880 6 - 7 - 331 - - - 7 8 - 331 + 686 8 - 11 - 331 + 16 + 768 - 13 - 17 - 331 + 16 + 42 + 701 - 20 - 34 - 331 - - - 40 - 51 - 331 - - - 52 - 53 - 165 + 42 + 99 + 261 @@ -1729,7 +2015,7 @@ 4 5 - 5144 + 9207 @@ -1745,52 +2031,42 @@ 3 4 - 1825 + 775 5 6 - 829 + 4342 7 10 - 331 + 790 + + + 11 + 12 + 880 13 - 14 - 331 - - - 15 16 - 331 + 686 17 - 22 - 331 + 32 + 768 - 27 - 34 - 331 + 33 + 84 + 701 - 41 - 54 - 331 - - - 67 - 82 - 331 - - - 101 - 102 - 165 + 85 + 198 + 261 @@ -1804,9 +2080,9 @@ 12 - 52 - 53 - 663 + 98 + 99 + 29 @@ -1820,9 +2096,9 @@ 12 - 31 - 32 - 663 + 1234 + 1235 + 29 @@ -1838,17 +2114,17 @@ 1 2 - 331 + 14 - 245 - 246 - 165 + 8222 + 8223 + 7 - 296 - 297 - 165 + 8364 + 8365 + 7 @@ -1864,12 +2140,12 @@ 1 2 - 89606 + 122389 - 52 - 53 - 165 + 2 + 99 + 1283 @@ -1885,12 +2161,12 @@ 1 2 - 89606 + 121889 - 31 - 32 - 165 + 2 + 1235 + 1783 @@ -1906,12 +2182,12 @@ 1 2 - 89606 + 123582 - 3 + 2 4 - 165 + 89 @@ -1921,23 +2197,23 @@ diagnostic_for - 61632 + 64190 diagnostic - 61632 + 64190 compilation - 574 + 716 file_number - 14797 + 7 file_number_diagnostic_number - 2154 + 14475 @@ -1951,7 +2227,7 @@ 1 2 - 61632 + 64190 @@ -1967,7 +2243,7 @@ 1 2 - 61632 + 64190 @@ -1983,7 +2259,7 @@ 1 2 - 61632 + 64190 @@ -1992,94 +2268,6 @@ compilation diagnostic - - - 12 - - - 14 - 15 - 143 - - - 28 - 29 - 143 - - - 123 - 124 - 143 - - - 264 - 265 - 143 - - - - - - - compilation - file_number - - - 12 - - - 7 - 8 - 143 - - - 14 - 15 - 143 - - - 45 - 46 - 143 - - - 103 - 104 - 143 - - - - - - - compilation - file_number_diagnostic_number - - - 12 - - - 2 - 3 - 287 - - - 14 - 15 - 143 - - - 15 - 16 - 143 - - - - - - - file_number - diagnostic 12 @@ -2087,42 +2275,135 @@ 1 2 - 143 - - - 2 - 3 - 6464 + 268 3 - 4 - 718 - - - 4 5 - 3160 + 59 5 - 6 - 1292 - - - 6 8 - 1149 + 52 8 - 11 - 1292 + 14 + 44 - 12 - 21 - 574 + 14 + 22 + 59 + + + 22 + 39 + 59 + + + 42 + 55 + 59 + + + 60 + 169 + 59 + + + 228 + 1941 + 52 + + + + + + + compilation + file_number + + + 12 + + + 1 + 2 + 716 + + + + + + + compilation + file_number_diagnostic_number + + + 12 + + + 1 + 2 + 268 + + + 3 + 5 + 59 + + + 5 + 8 + 52 + + + 8 + 14 + 44 + + + 14 + 22 + 59 + + + 22 + 39 + 59 + + + 42 + 55 + 59 + + + 60 + 169 + 59 + + + 228 + 1941 + 52 + + + + + + + file_number + diagnostic + + + 12 + + + 8603 + 8604 + 7 @@ -2136,24 +2417,9 @@ 12 - 1 - 2 - 8332 - - - 2 - 3 - 4453 - - - 3 - 4 - 1005 - - - 4 - 5 - 1005 + 96 + 97 + 7 @@ -2167,34 +2433,9 @@ 12 - 1 - 2 - 143 - - - 2 - 3 - 10056 - - - 3 - 4 - 2011 - - - 4 - 5 - 1005 - - - 5 - 8 - 1149 - - - 10 - 16 - 430 + 1940 + 1941 + 7 @@ -2210,52 +2451,42 @@ 1 2 - 143 + 3290 2 3 - 574 + 238 3 4 - 430 + 5081 + + + 4 + 5 + 2439 5 6 - 143 + 261 + + + 6 + 7 + 1462 7 - 8 - 143 + 14 + 1208 - 11 - 12 - 143 - - - 18 - 19 - 143 - - - 33 - 34 - 143 - - - 168 - 169 - 143 - - - 169 - 170 - 143 + 14 + 97 + 492 @@ -2271,17 +2502,42 @@ 1 2 - 143 + 3290 2 3 - 1723 + 238 + + + 3 + 4 + 5081 4 5 - 287 + 2439 + + + 5 + 6 + 261 + + + 6 + 7 + 1462 + + + 7 + 14 + 1208 + + + 14 + 97 + 492 @@ -2297,52 +2553,7 @@ 1 2 - 143 - - - 2 - 3 - 574 - - - 3 - 4 - 430 - - - 5 - 6 - 143 - - - 7 - 8 - 143 - - - 11 - 12 - 143 - - - 18 - 19 - 143 - - - 32 - 33 - 143 - - - 102 - 103 - 143 - - - 103 - 104 - 143 + 14475 @@ -2352,19 +2563,19 @@ compilation_compiler_times - 7683 + 2261 id - 7683 + 2261 cpu_seconds - 1920 + 94 elapsed_seconds - 7683 + 2167 @@ -2378,7 +2589,7 @@ 1 2 - 7683 + 2261 @@ -2394,7 +2605,7 @@ 1 2 - 7683 + 2261 @@ -2408,9 +2619,9 @@ 12 - 4 - 5 - 1920 + 24 + 25 + 94 @@ -2424,9 +2635,9 @@ 12 - 4 - 5 - 1920 + 23 + 24 + 94 @@ -2442,7 +2653,12 @@ 1 2 - 7683 + 2073 + + + 2 + 3 + 94 @@ -2458,7 +2674,7 @@ 1 2 - 7683 + 2167 @@ -2684,35 +2900,35 @@ diagnostics - 61632 + 64190 id - 61632 + 64190 generated_by - 143 + 7 severity - 143 + 29 error_tag - 143 + 7 error_message - 1580 + 2604 full_error_message - 40944 + 7 location - 143 + 7 @@ -2726,7 +2942,7 @@ 1 2 - 61632 + 64190 @@ -2742,7 +2958,7 @@ 1 2 - 61632 + 64190 @@ -2758,7 +2974,7 @@ 1 2 - 61632 + 64190 @@ -2774,7 +2990,7 @@ 1 2 - 61632 + 64190 @@ -2790,7 +3006,7 @@ 1 2 - 61632 + 64190 @@ -2806,7 +3022,7 @@ 1 2 - 61632 + 64190 @@ -2820,9 +3036,9 @@ 12 - 429 - 430 - 143 + 8603 + 8604 + 7 @@ -2836,9 +3052,9 @@ 12 - 1 - 2 - 143 + 4 + 5 + 7 @@ -2854,7 +3070,7 @@ 1 2 - 143 + 7 @@ -2868,9 +3084,9 @@ 12 - 11 - 12 - 143 + 349 + 350 + 7 @@ -2884,9 +3100,9 @@ 12 - 285 - 286 - 143 + 1 + 2 + 7 @@ -2902,7 +3118,7 @@ 1 2 - 143 + 7 @@ -2916,9 +3132,24 @@ 12 - 429 - 430 - 143 + 4 + 5 + 7 + + + 13 + 14 + 7 + + + 95 + 96 + 7 + + + 8491 + 8492 + 7 @@ -2934,7 +3165,7 @@ 1 2 - 143 + 29 @@ -2950,7 +3181,7 @@ 1 2 - 143 + 29 @@ -2964,9 +3195,24 @@ 12 - 11 - 12 - 143 + 4 + 5 + 7 + + + 13 + 14 + 7 + + + 95 + 96 + 7 + + + 237 + 238 + 7 @@ -2980,9 +3226,9 @@ 12 - 285 - 286 - 143 + 1 + 2 + 29 @@ -2998,7 +3244,7 @@ 1 2 - 143 + 29 @@ -3012,9 +3258,9 @@ 12 - 429 - 430 - 143 + 8603 + 8604 + 7 @@ -3030,7 +3276,7 @@ 1 2 - 143 + 7 @@ -3044,9 +3290,9 @@ 12 - 1 - 2 - 143 + 4 + 5 + 7 @@ -3060,9 +3306,9 @@ 12 - 11 - 12 - 143 + 349 + 350 + 7 @@ -3076,9 +3322,9 @@ 12 - 285 - 286 - 143 + 1 + 2 + 7 @@ -3094,7 +3340,7 @@ 1 2 - 143 + 7 @@ -3110,47 +3356,17 @@ 1 2 - 143 + 2290 2 - 3 - 143 - - - 3 - 4 - 143 - - - 6 - 7 - 143 + 9 + 201 9 - 10 - 143 - - - 12 - 13 - 287 - - - 24 - 25 - 143 - - - 28 - 29 - 143 - - - 166 - 167 - 287 + 3692 + 111 @@ -3166,7 +3382,7 @@ 1 2 - 1580 + 2604 @@ -3182,7 +3398,7 @@ 1 2 - 1580 + 2604 @@ -3198,7 +3414,7 @@ 1 2 - 1580 + 2604 @@ -3214,52 +3430,7 @@ 1 2 - 143 - - - 2 - 3 - 143 - - - 3 - 4 - 143 - - - 6 - 7 - 143 - - - 9 - 10 - 143 - - - 12 - 13 - 287 - - - 22 - 23 - 143 - - - 24 - 25 - 143 - - - 28 - 29 - 143 - - - 166 - 167 - 143 + 2604 @@ -3275,7 +3446,7 @@ 1 2 - 1580 + 2604 @@ -3289,14 +3460,9 @@ 12 - 1 - 2 - 38358 - - - 2 - 25 - 2585 + 8603 + 8604 + 7 @@ -3312,7 +3478,7 @@ 1 2 - 40944 + 7 @@ -3326,9 +3492,9 @@ 12 - 1 - 2 - 40944 + 4 + 5 + 7 @@ -3344,7 +3510,7 @@ 1 2 - 40944 + 7 @@ -3358,9 +3524,9 @@ 12 - 1 - 2 - 40944 + 349 + 350 + 7 @@ -3376,7 +3542,7 @@ 1 2 - 40944 + 7 @@ -3390,9 +3556,9 @@ 12 - 429 - 430 - 143 + 8603 + 8604 + 7 @@ -3408,7 +3574,7 @@ 1 2 - 143 + 7 @@ -3422,9 +3588,9 @@ 12 - 1 - 2 - 143 + 4 + 5 + 7 @@ -3440,7 +3606,7 @@ 1 2 - 143 + 7 @@ -3454,9 +3620,9 @@ 12 - 11 - 12 - 143 + 349 + 350 + 7 @@ -3470,9 +3636,9 @@ 12 - 285 - 286 - 143 + 1 + 2 + 7 @@ -3637,11 +3803,11 @@ sourceLocationPrefix - 1920 + 569 prefix - 1920 + 569 @@ -4928,31 +5094,31 @@ locations_default - 602747369 + 82315299 id - 602747369 + 82315299 file - 9158642 + 1291911 beginLine - 3943517 + 538208 beginColumn - 247790 + 33818 endLine - 3945438 + 538471 endColumn - 873989 + 119281 @@ -4966,7 +5132,7 @@ 1 2 - 602747369 + 82315299 @@ -4982,7 +5148,7 @@ 1 2 - 602747369 + 82315299 @@ -4998,7 +5164,7 @@ 1 2 - 602747369 + 82315299 @@ -5014,7 +5180,7 @@ 1 2 - 602747369 + 82315299 @@ -5030,7 +5196,7 @@ 1 2 - 602747369 + 82315299 @@ -5046,17 +5212,17 @@ 1 2 - 7986919 + 1131995 2 11 - 714558 + 97522 11 3605 - 457163 + 62393 @@ -5072,17 +5238,17 @@ 1 2 - 7986919 + 1131995 2 9 - 712637 + 97260 9 1830 - 459084 + 62655 @@ -5098,17 +5264,17 @@ 1 2 - 7986919 + 1131995 2 5 - 776025 + 105911 5 105 - 395696 + 54004 @@ -5124,17 +5290,17 @@ 1 2 - 7986919 + 1131995 2 - 10 - 693429 + 11 + 99619 - 10 + 11 1834 - 478293 + 60296 @@ -5150,17 +5316,17 @@ 1 2 - 7986919 + 1131995 2 - 9 - 695349 + 10 + 99619 - 9 + 10 205 - 476372 + 60296 @@ -5176,67 +5342,67 @@ 1 14 - 313099 + 42731 14 125 - 301574 + 41158 125 142 - 307336 + 41945 142 152 - 316941 + 43255 152 159 - 359200 + 49023 159 164 - 272761 + 37226 164 169 - 343833 + 46926 169 173 - 299653 + 40896 173 178 - 332308 + 45353 178 184 - 347674 + 47450 184 193 - 316941 + 43255 193 211 - 297732 + 40372 211 - 4769 - 134459 + 4929 + 18613 @@ -5252,72 +5418,72 @@ 1 7 - 322703 + 44042 7 65 - 299653 + 40896 65 73 - 307336 + 41945 73 78 - 295811 + 40372 78 81 - 265078 + 36177 81 84 - 357279 + 48761 84 86 - 299653 + 40896 86 87 - 188243 + 25691 87 89 - 357279 + 48761 89 91 - 259315 + 35129 91 94 - 324624 + 44566 94 99 - 328466 + 44828 99 - 141 - 295811 + 142 + 40634 - 141 - 4769 - 42258 + 142 + 4929 + 5505 @@ -5333,62 +5499,62 @@ 1 5 - 313099 + 42731 5 17 - 280444 + 38274 17 19 - 251632 + 34342 19 20 - 309257 + 42207 20 21 - 403379 + 55053 21 22 - 420667 + 57412 22 23 - 476372 + 65015 23 24 - 457163 + 62393 24 25 - 339991 + 46401 25 26 - 213215 + 29099 26 29 - 361120 + 49285 29 40 - 117172 + 15991 @@ -5404,32 +5570,32 @@ 1 2 - 1273527 + 173810 2 3 - 1265844 + 172761 3 4 - 674220 + 92017 4 5 - 299653 + 40896 5 11 - 307336 + 41945 11 97 - 122934 + 16778 @@ -5445,72 +5611,72 @@ 1 13 - 309257 + 42207 13 60 - 307336 + 41945 60 64 - 311178 + 42469 64 66 - 311178 + 42207 66 68 - 353437 + 48499 68 69 - 194006 + 26477 69 70 - 217056 + 29361 70 72 - 359200 + 49023 72 74 - 322703 + 44042 74 76 - 245869 + 33818 76 79 - 330387 + 45091 79 83 - 295811 + 40372 83 91 - 316941 + 43255 91 103 - 69150 + 9437 @@ -5526,67 +5692,67 @@ 1 11 - 21129 + 2883 15 24 - 21129 + 2883 28 - 57 - 19208 + 58 + 2883 - 57 - 79 - 19208 + 58 + 88 + 2621 - 87 - 119 - 19208 + 89 + 131 + 2621 - 130 - 177 - 19208 + 131 + 196 + 2883 - 195 - 269 - 19208 + 213 + 297 + 2621 - 270 - 436 - 19208 + 307 + 496 + 2621 - 443 - 835 - 19208 + 513 + 883 + 2621 - 844 - 1367 - 19208 + 933 + 1470 + 2621 - 1419 - 2155 - 19208 + 1665 + 2279 + 2621 - 2252 - 2517 - 19208 + 2295 + 2583 + 2621 - 2521 - 226452 - 13445 + 2694 + 226487 + 1310 @@ -5602,72 +5768,72 @@ 1 9 - 17287 + 2359 9 11 - 21129 + 2883 11 15 - 15366 + 2097 15 19 - 21129 + 2883 23 68 - 19208 + 2621 69 78 - 19208 + 2621 79 100 - 13445 + 1835 100 104 - 21129 + 2883 104 109 - 19208 + 2621 109 112 - 13445 + 1835 112 115 - 19208 + 2621 115 117 - 19208 + 2621 117 123 - 19208 + 2621 145 - 4769 - 9604 + 4929 + 1310 @@ -5683,67 +5849,67 @@ 1 10 - 21129 + 2883 10 22 - 21129 + 2883 23 39 - 19208 + 2621 41 58 - 19208 + 2621 58 84 - 19208 + 2621 84 106 - 19208 + 2621 108 166 - 19208 + 2621 167 225 - 19208 + 2621 230 376 - 19208 + 2621 381 647 - 19208 + 2621 657 941 - 19208 + 2621 941 1090 - 19208 + 2621 1102 2051 - 13445 + 1835 @@ -5759,67 +5925,67 @@ 1 10 - 21129 + 2883 10 22 - 21129 + 2883 23 39 - 19208 + 2621 41 59 - 19208 + 2621 59 86 - 19208 + 2621 86 109 - 19208 + 2621 114 168 - 19208 + 2621 170 224 - 19208 + 2621 229 379 - 19208 + 2621 382 647 - 19208 + 2621 658 941 - 19208 + 2621 941 1089 - 19208 + 2621 1102 2051 - 13445 + 1835 @@ -5835,67 +6001,67 @@ 1 8 - 21129 + 2883 8 16 - 21129 + 2883 16 23 - 21129 + 2621 - 24 - 31 - 21129 + 23 + 30 + 2621 - 32 - 37 - 21129 + 30 + 36 + 2621 - 37 - 50 - 19208 + 36 + 44 + 2621 - 50 - 60 - 19208 + 46 + 55 + 2621 - 60 - 68 - 19208 + 55 + 65 + 2883 - 68 - 80 - 19208 + 65 + 76 + 2621 - 81 - 101 - 19208 + 77 + 94 + 2621 - 101 - 121 - 19208 + 94 + 117 + 2621 - 126 - 158 - 19208 + 119 + 152 + 2621 - 159 + 153 393 - 7683 + 1572 @@ -5911,67 +6077,67 @@ 1 14 - 309257 + 42207 14 124 - 305416 + 41683 124 143 - 309257 + 42207 143 152 - 334228 + 45615 152 159 - 322703 + 44042 159 164 - 299653 + 40896 164 169 - 341912 + 46664 169 173 - 309257 + 41945 173 178 - 338070 + 46401 178 184 - 305416 + 41683 184 193 - 315020 + 42993 193 212 - 301574 + 41158 212 - 4769 - 153668 + 4929 + 20972 @@ -5987,67 +6153,67 @@ 1 7 - 324624 + 44304 7 66 - 318862 + 43518 66 74 - 320782 + 43780 74 80 - 355358 + 48499 80 83 - 339991 + 46401 83 85 - 268919 + 36702 85 87 - 343833 + 46926 87 89 - 355358 + 48499 89 91 - 266999 + 36439 91 94 - 345754 + 47188 94 99 - 324624 + 44304 99 130 - 301574 + 40896 - 131 - 4769 - 78755 + 130 + 4929 + 11010 @@ -6063,32 +6229,32 @@ 1 2 - 1000766 + 136583 2 3 - 1392620 + 190064 3 4 - 908564 + 124000 4 6 - 336149 + 45877 6 19 - 299653 + 40896 19 22 - 7683 + 1048 @@ -6104,62 +6270,62 @@ 1 5 - 309257 + 42207 5 17 - 284286 + 38799 17 19 - 232423 + 31721 19 20 - 280444 + 38274 20 21 - 420667 + 57412 21 22 - 407221 + 55577 22 23 - 482134 + 65801 23 24 - 437955 + 59771 24 25 - 334228 + 45353 25 26 - 259315 + 35653 26 29 - 363041 + 49547 29 39 - 134459 + 18351 @@ -6175,72 +6341,72 @@ 1 13 - 313099 + 42731 13 60 - 305416 + 41683 60 64 - 305416 + 41683 64 66 - 303495 + 41158 66 68 - 357279 + 49023 68 69 - 197848 + 27002 69 70 - 201689 + 27526 70 71 - 218977 + 29623 71 73 - 326545 + 44828 73 75 - 263157 + 35653 75 77 - 257394 + 35129 77 80 - 299653 + 40896 80 85 - 318862 + 43780 85 119 - 276603 + 37750 @@ -6256,57 +6422,57 @@ 1 2 - 205531 + 28050 2 3 - 90280 + 12321 3 5 - 71071 + 9699 5 13 - 71071 + 9699 13 53 - 67229 + 9175 53 - 138 - 67229 + 144 + 9175 - 142 - 346 - 67229 + 145 + 348 + 9175 357 967 - 67229 + 9175 1050 2386 - 67229 + 9175 2392 - 4902 - 67229 + 4931 + 9175 4949 5933 - 32654 + 4456 @@ -6322,57 +6488,57 @@ 1 2 - 213215 + 29099 2 3 - 86438 + 11797 3 5 - 74913 + 10224 5 13 - 71071 + 9699 13 42 - 67229 + 9175 42 77 - 67229 + 9175 77 102 - 69150 + 9175 102 - 114 - 67229 + 113 + 9175 114 139 - 67229 + 9175 139 - 169 - 69150 + 168 + 9175 - 173 - 4769 - 21129 + 168 + 4929 + 3408 @@ -6388,57 +6554,57 @@ 1 2 - 217056 + 29623 2 3 - 88359 + 12059 3 5 - 69150 + 9437 5 13 - 69150 + 9437 13 - 50 - 67229 + 51 + 9175 - 50 + 51 113 - 67229 + 9175 114 266 - 67229 + 9175 269 636 - 67229 + 9175 648 1197 - 67229 + 9175 1198 1635 - 69150 + 9437 1639 1722 - 24971 + 3408 @@ -6454,47 +6620,47 @@ 1 2 - 274682 + 37488 2 3 - 105647 + 14156 3 6 - 76834 + 10748 6 14 - 76834 + 10486 14 25 - 74913 + 10224 25 36 - 71071 + 9699 36 47 - 67229 + 9175 47 54 - 67229 + 9175 54 65 - 59546 + 8126 @@ -6510,57 +6676,57 @@ 1 2 - 217056 + 29623 2 3 - 86438 + 11797 3 5 - 69150 + 9437 5 13 - 69150 + 9437 13 - 51 - 67229 + 52 + 9175 - 51 + 52 112 - 67229 + 9175 112 262 - 67229 + 9175 262 630 - 67229 + 9175 637 1186 - 67229 + 9175 1197 1625 - 67229 + 9175 1632 1722 - 28812 + 3932 @@ -6570,15 +6736,15 @@ hasLocation - 340930835 + 53281114 locatableid - 340658074 + 53281114 id - 12195515 + 1717130 @@ -6592,12 +6758,7 @@ 1 2 - 340385312 - - - 2 - 3 - 272761 + 53281114 @@ -6613,57 +6774,62 @@ 1 2 - 2091812 + 294140 2 3 - 1333074 + 182199 3 - 4 - 772184 + 5 + 155983 - 4 - 6 - 1085283 + 5 + 7 + 126884 - 6 - 8 - 1062233 + 7 + 10 + 148905 - 8 - 11 - 1100650 + 10 + 13 + 142089 - 11 - 15 - 1048787 + 13 + 17 + 132651 - 15 - 21 - 964269 + 17 + 23 + 130030 - 21 - 32 - 916248 + 23 + 35 + 133175 - 32 + 35 64 - 920090 + 129505 64 - 9549 - 900881 + 396 + 128981 + + + 405 + 9847 + 12583 @@ -6673,23 +6839,23 @@ numlines - 303305105 + 41395164 element_id - 303305105 + 41395164 num_lines - 618515 + 84414 num_code - 612753 + 83628 num_comment - 1893964 + 258487 @@ -6703,7 +6869,7 @@ 1 2 - 303305105 + 41395164 @@ -6719,7 +6885,7 @@ 1 2 - 303305105 + 41395164 @@ -6735,7 +6901,7 @@ 1 2 - 303305105 + 41395164 @@ -6751,37 +6917,37 @@ 1 2 - 320782 + 43780 2 3 - 78755 + 10748 3 4 - 61467 + 8389 4 7 - 49942 + 6816 7 14 - 48021 + 6553 15 194 - 48021 + 6553 320 149659 - 11525 + 1572 @@ -6797,17 +6963,17 @@ 1 2 - 509026 + 69471 2 3 - 69150 + 9437 3 6 - 40337 + 5505 @@ -6823,27 +6989,27 @@ 1 2 - 380329 + 51907 2 3 - 97963 + 13370 3 4 - 51863 + 7078 4 6 - 53783 + 7340 6 987 - 34575 + 4718 @@ -6859,37 +7025,37 @@ 1 2 - 316941 + 43255 2 3 - 78755 + 10748 3 4 - 61467 + 8389 4 7 - 51863 + 7078 7 15 - 46100 + 6291 16 214 - 46100 + 6291 325 78746 - 11525 + 1572 @@ -6905,17 +7071,17 @@ 1 2 - 516710 + 70520 2 3 - 51863 + 7078 3 8 - 44179 + 6029 @@ -6931,27 +7097,27 @@ 1 2 - 370725 + 50596 2 3 - 101805 + 13894 3 4 - 53783 + 7340 4 6 - 46100 + 6291 6 987 - 40337 + 5505 @@ -6967,77 +7133,77 @@ 1 7 - 153668 + 20972 7 49 - 142143 + 19399 49 71 - 147905 + 20186 71 78 - 151747 + 20710 78 83 - 145985 + 19923 83 87 - 163272 + 22283 87 89 - 140222 + 19137 89 91 - 134459 + 18351 91 92 - 80675 + 11010 92 93 - 96042 + 13107 93 94 - 105647 + 14418 94 95 - 97963 + 13370 95 97 - 151747 + 20710 97 119 - 144064 + 19661 120 75134 - 38417 + 5243 @@ -7053,22 +7219,22 @@ 1 2 - 1550130 + 211560 2 3 - 165193 + 22545 3 7 - 145985 + 19923 7 120 - 32654 + 4456 @@ -7084,22 +7250,22 @@ 1 2 - 1550130 + 211560 2 3 - 165193 + 22545 3 7 - 145985 + 19923 7 122 - 32654 + 4456 @@ -7109,15 +7275,15 @@ files - 9158642 + 1291911 id - 9158642 + 1291911 name - 9158642 + 1291911 @@ -7131,7 +7297,7 @@ 1 2 - 9158642 + 1291911 @@ -7147,7 +7313,7 @@ 1 2 - 9158642 + 1291911 @@ -7157,15 +7323,15 @@ folders - 1415670 + 293711 id - 1415670 + 293711 name - 1415670 + 293711 @@ -7179,7 +7345,7 @@ 1 2 - 1415670 + 293711 @@ -7195,7 +7361,7 @@ 1 2 - 1415670 + 293711 @@ -7205,15 +7371,15 @@ containerparent - 10570471 + 1496393 parent - 1463692 + 212871 child - 10570471 + 1496393 @@ -7227,32 +7393,32 @@ 1 2 - 843255 + 125311 2 3 - 149826 + 18613 3 5 - 128697 + 18613 5 - 11 - 124855 + 10 + 18088 - 11 - 21 - 113330 + 10 + 20 + 15991 - 21 + 20 194 - 103726 + 16253 @@ -7268,7 +7434,7 @@ 1 2 - 10570471 + 1496393 @@ -7278,15 +7444,15 @@ cupackage - 7979236 + 1129635 id - 7979236 + 1129635 packageid - 576256 + 85463 @@ -7300,7 +7466,7 @@ 1 2 - 7979236 + 1129635 @@ -7316,52 +7482,57 @@ 1 2 - 121013 + 18351 2 3 - 80675 + 11797 3 4 - 42258 + 6029 4 - 6 - 49942 + 5 + 5505 - 6 + 5 + 7 + 4980 + + + 7 9 - 49942 + 6291 9 - 12 - 51863 + 11 + 6553 - 12 + 11 17 - 48021 + 7864 17 - 23 - 46100 + 26 + 6816 - 24 - 43 - 44179 + 26 + 53 + 6553 - 43 + 54 187 - 42258 + 4718 @@ -7692,23 +7863,23 @@ jarManifestEntries - 30201 + 46193 fileid - 61 + 29 entryName - 30129 + 46141 keyName - 27 + 59 value - 30163 + 46171 @@ -7722,72 +7893,22 @@ 1 2 - 4 + 7 - 4 - 10 - 3 + 264 + 265 + 7 - 10 - 12 - 4 + 1520 + 1521 + 7 - 12 - 31 - 4 - - - 65 - 82 - 4 - - - 123 - 164 - 4 - - - 178 - 240 - 4 - - - 253 - 294 - 4 - - - 307 - 357 - 4 - - - 361 - 395 - 4 - - - 433 - 461 - 4 - - - 591 - 662 - 4 - - - 957 - 2267 - 4 - - - 3647 - 3762 - 3 + 4400 + 4401 + 7 @@ -7796,238 +7917,6 @@ fileid keyName - - - 12 - - - 1 - 2 - 57 - - - 6 - 10 - 3 - - - - - - - fileid - value - - - 12 - - - 1 - 2 - 4 - - - 3 - 8 - 4 - - - 9 - 13 - 4 - - - 24 - 66 - 4 - - - 70 - 124 - 4 - - - 127 - 179 - 4 - - - 195 - 254 - 4 - - - 265 - 308 - 4 - - - 320 - 362 - 4 - - - 381 - 434 - 4 - - - 434 - 592 - 4 - - - 618 - 958 - 4 - - - 1671 - 3648 - 4 - - - 3761 - 3762 - 1 - - - - - - - entryName - fileid - - - 12 - - - 1 - 2 - 30113 - - - 2 - 26 - 16 - - - - - - - entryName - keyName - - - 12 - - - 1 - 2 - 30126 - - - 6 - 10 - 3 - - - - - - - entryName - value - - - 12 - - - 1 - 2 - 30125 - - - 3 - 26 - 4 - - - - - - - keyName - fileid - - - 12 - - - 1 - 2 - 21 - - - 2 - 3 - 3 - - - 3 - 4 - 1 - - - 32 - 33 - 1 - - - - - - - keyName - entryName - - - 12 - - - 1 - 2 - 21 - - - 2 - 3 - 1 - - - 11 - 12 - 1 - - - 369 - 370 - 1 - - - 19366 - 19367 - 1 - - - - - - - keyName - value 12 @@ -8037,20 +7926,167 @@ 2 22 + + 7 + 8 + 7 + + + + + + + fileid + value + + + 12 + + + 4 + 5 + 7 + + + 264 + 265 + 7 + + + 1520 + 1521 + 7 + + + 4400 + 4401 + 7 + + + + + + + entryName + fileid + + + 12 + + + 1 + 2 + 46133 + 2 3 - 1 + 7 + + + + + + + entryName + keyName + + + 12 + + + 1 + 2 + 46133 - 369 - 370 - 1 + 7 + 8 + 7 + + + + + + + entryName + value + + + 12 + + + 1 + 2 + 46126 - 19390 - 19391 - 1 + 2 + 5 + 14 + + + + + + + keyName + fileid + + + 12 + + + 1 + 2 + 52 + + + 3 + 4 + 7 + + + + + + + keyName + entryName + + + 12 + + + 1 + 2 + 52 + + + 6183 + 6184 + 7 + + + + + + + keyName + value + + + 12 + + + 1 + 2 + 52 + + + 6184 + 6185 + 7 @@ -8066,12 +8102,7 @@ 1 2 - 30162 - - - 2 - 3 - 1 + 46171 @@ -8087,12 +8118,7 @@ 1 2 - 30162 - - - 11 - 12 - 1 + 46171 @@ -8108,12 +8134,12 @@ 1 2 - 30155 + 46148 2 3 - 7 + 22 @@ -8123,15 +8149,15 @@ packages - 580098 + 121135 id - 580098 + 121135 nodeName - 580098 + 121135 @@ -8145,7 +8171,7 @@ 1 2 - 580098 + 121135 @@ -8161,7 +8187,7 @@ 1 2 - 580098 + 121135 @@ -8171,15 +8197,15 @@ primitives - 17287 + 5690 id - 17287 + 5690 nodeName - 17287 + 5690 @@ -8193,7 +8219,7 @@ 1 2 - 17287 + 5690 @@ -8209,7 +8235,7 @@ 1 2 - 17287 + 5690 @@ -8219,15 +8245,15 @@ modifiers - 26891 + 6259 id - 26891 + 6259 nodeName - 26891 + 6259 @@ -8241,7 +8267,7 @@ 1 2 - 26891 + 6259 @@ -8257,7 +8283,7 @@ 1 2 - 26891 + 6259 @@ -8267,34 +8293,34 @@ error_type - 1 + 22 id - 1 + 22 - classes - 12618104 + classes_or_interfaces + 22273131 id - 12618104 + 22273131 nodeName - 6732600 + 5754222 parentid - 455242 + 734 sourceid - 5253541 + 26258 @@ -8308,7 +8334,7 @@ 1 2 - 12618104 + 22273131 @@ -8324,7 +8350,7 @@ 1 2 - 12618104 + 22273131 @@ -8340,7 +8366,7 @@ 1 2 - 12618104 + 22273131 @@ -8356,17 +8382,27 @@ 1 2 - 5601216 + 3703195 2 3 - 726083 + 866201 3 - 204 - 405300 + 5 + 424184 + + + 5 + 12 + 451316 + + + 12 + 9655 + 309324 @@ -8382,17 +8418,12 @@ 1 2 - 5950812 + 5753464 2 - 3 - 731846 - - - 3 - 52 - 49942 + 29 + 757 @@ -8408,17 +8439,12 @@ 1 2 - 5921999 + 5753210 2 - 3 - 714558 - - - 3 - 160 - 96042 + 3091 + 1011 @@ -8434,220 +8460,240 @@ 1 2 - 94121 + 132 2 3 - 46100 + 40 3 - 4 - 30733 - - - 4 5 - 26891 + 63 5 - 6 - 24971 + 7 + 46 - 6 + 7 8 - 40337 + 57 8 - 12 - 32654 - - - 12 - 18 - 38417 - - - 18 - 23 - 34575 - - - 23 - 40 - 36496 - - - 40 - 76 - 34575 - - - 83 - 891 - 15366 - - - - - - - parentid - nodeName - - - 12 - - - 1 - 2 - 96042 - - - 2 - 3 - 46100 - - - 3 - 4 - 34575 - - - 4 - 5 - 28812 - - - 5 - 6 - 36496 - - - 6 - 9 - 40337 - - - 9 - 13 - 40337 - - - 13 - 18 - 26891 - - - 18 - 25 - 38417 - - - 26 - 41 - 36496 - - - 41 - 479 - 30733 - - - - - - - parentid - sourceid - - - 12 - - - 1 - 2 - 99884 - - - 2 - 3 - 57625 - - - 3 - 4 - 36496 - - - 4 - 5 - 32654 - - - 5 - 6 - 32654 - - - 6 - 8 - 34575 - - - 8 - 12 - 38417 - - - 12 - 18 - 32654 - - - 18 - 25 - 34575 - - - 25 - 47 - 34575 - - - 51 - 138 - 21129 - - - - - - - sourceid - id - - - 12 - - - 1 - 2 - 4694572 - - - 2 11 - 407221 + 63 11 - 426 - 151747 + 23 + 57 + + + 23 + 41 + 63 + + + 42 + 158 + 57 + + + 162 + 1034 + 57 + + + 1315 + 34752 + 57 + + + 36100 + 2058753 + 34 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 132 + + + 2 + 3 + 40 + + + 3 + 4 + 28 + + + 4 + 5 + 40 + + + 5 + 6 + 34 + + + 6 + 7 + 40 + + + 7 + 9 + 52 + + + 9 + 15 + 57 + + + 15 + 24 + 63 + + + 24 + 56 + 57 + + + 57 + 178 + 57 + + + 186 + 3066 + 57 + + + 3515 + 65688 + 57 + + + 298524 + 495903 + 11 + + + + + + + parentid + sourceid + + + 12 + + + 1 + 2 + 150 + + + 2 + 3 + 80 + + + 3 + 4 + 34 + + + 4 + 5 + 63 + + + 5 + 7 + 40 + + + 7 + 9 + 63 + + + 9 + 11 + 63 + + + 12 + 15 + 46 + + + 16 + 23 + 57 + + + 25 + 41 + 57 + + + 47 + 113 + 57 + + + 113 + 2641 + 17 + + + + + + + sourceid + id + + + 12 + + + 1 + 2 + 23281 + + + 2 + 15 + 1994 + + + 15 + 448199 + 982 @@ -8663,17 +8709,17 @@ 1 2 - 4694572 + 23281 2 - 6 - 426430 + 10 + 2005 - 6 - 224 - 132539 + 10 + 100263 + 971 @@ -8689,7 +8735,7 @@ 1 2 - 5253541 + 26258 @@ -8699,26 +8745,26 @@ file_class - 17287 + 7249 id - 17287 + 7249 class_object - 163272 + 22283 id - 163272 + 22283 instance - 163272 + 22283 @@ -8732,7 +8778,7 @@ 1 2 - 163272 + 22283 @@ -8748,7 +8794,7 @@ 1 2 - 163272 + 22283 @@ -8758,19 +8804,19 @@ type_companion_object - 307336 + 41945 id - 307336 + 41945 instance - 307336 + 41945 companion_object - 307336 + 41945 @@ -8784,7 +8830,7 @@ 1 2 - 307336 + 41945 @@ -8800,7 +8846,7 @@ 1 2 - 307336 + 41945 @@ -8816,7 +8862,7 @@ 1 2 - 307336 + 41945 @@ -8832,7 +8878,7 @@ 1 2 - 307336 + 41945 @@ -8848,7 +8894,7 @@ 1 2 - 307336 + 41945 @@ -8864,7 +8910,7 @@ 1 2 - 307336 + 41945 @@ -8874,15 +8920,15 @@ kt_nullable_types - 1920 + 262 id - 1920 + 262 classid - 1920 + 262 @@ -8896,7 +8942,7 @@ 1 2 - 1920 + 262 @@ -8912,7 +8958,7 @@ 1 2 - 1920 + 262 @@ -8922,15 +8968,15 @@ kt_notnull_types - 172391 + 156265 id - 172391 + 156265 classid - 172391 + 156265 @@ -8944,7 +8990,7 @@ 1 2 - 172391 + 156265 @@ -8960,7 +9006,7 @@ 1 2 - 172391 + 156265 @@ -8970,19 +9016,19 @@ kt_type_alias - 1821 + 707 id - 1821 + 707 name - 1821 + 583 kttypeid - 910 + 12 @@ -8996,7 +9042,7 @@ 1 2 - 1821 + 707 @@ -9012,7 +9058,7 @@ 1 2 - 1821 + 707 @@ -9028,7 +9074,12 @@ 1 2 - 1821 + 459 + + + 2 + 3 + 124 @@ -9044,7 +9095,7 @@ 1 2 - 1821 + 583 @@ -9058,9 +9109,9 @@ 12 - 2 - 3 - 910 + 57 + 58 + 12 @@ -9074,9 +9125,9 @@ 12 - 2 - 3 - 910 + 47 + 48 + 12 @@ -9084,6 +9135,17 @@ + + isInterface + 21473562 + + + id + 21473562 + + + + isRecord 417 @@ -9096,43 +9158,19 @@ - interfaces - 23200100 + fielddecls + 210035 id - 23200100 - - - nodeName - 8705320 + 210035 parentid - 430271 - - - sourceid - 2787162 + 24609 - - id - nodeName - - - 12 - - - 1 - 2 - 23200100 - - - - - id parentid @@ -9143,106 +9181,7 @@ 1 2 - 23200100 - - - - - - - id - sourceid - - - 12 - - - 1 - 2 - 23200100 - - - - - - - nodeName - id - - - 12 - - - 1 - 2 - 6834406 - - - 2 - 3 - 1079521 - - - 3 - 25 - 655011 - - - 25 - 345 - 136380 - - - - - - - nodeName - parentid - - - 12 - - - 1 - 2 - 7996524 - - - 2 - 4 - 695349 - - - 4 - 7 - 13445 - - - - - - - nodeName - sourceid - - - 12 - - - 1 - 2 - 7967711 - - - 2 - 4 - 718400 - - - 4 - 7 - 19208 + 210035 @@ -9258,335 +9197,52 @@ 1 2 - 113330 + 6180 2 3 - 55704 + 2975 3 4 - 48021 + 2769 4 - 5 - 26891 + 6 + 1694 - 5 - 8 - 36496 - - - 8 - 13 - 34575 - - - 13 - 18 - 34575 - - - 18 - 41 - 32654 - - - 42 - 182 - 32654 - - - 187 - 4152 - 15366 - - - - - - - parentid - nodeName - - - 12 - - - 1 - 2 - 113330 - - - 2 - 3 - 55704 - - - 3 - 4 - 48021 - - - 4 - 5 - 38417 - - - 5 + 6 7 - 24971 + 2563 7 - 10 - 32654 + 9 + 938 - 10 + 9 + 12 + 1922 + + + 12 15 - 36496 + 1877 15 - 28 - 32654 + 24 + 1854 - 30 - 94 - 32654 - - - 100 - 1213 - 15366 - - - - - - - parentid - sourceid - - - 12 - - - 1 - 2 - 140222 - - - 2 - 3 - 65309 - - - 3 - 4 - 44179 - - - 4 - 5 - 34575 - - - 5 - 7 - 28812 - - - 7 - 9 - 34575 - - - 9 - 14 - 34575 - - - 14 - 26 - 32654 - - - 26 - 160 - 15366 - - - - - - - sourceid - id - - - 12 - - - 1 - 2 - 2391465 - - - 2 - 11 - 213215 - - - 11 - 1565 - 182481 - - - - - - - sourceid - nodeName - - - 12 - - - 1 - 2 - 2391465 - - - 2 - 6 - 217056 - - - 6 - 492 - 178639 - - - - - - - sourceid - parentid - - - 12 - - - 1 - 2 - 2787162 - - - - - - - - - fielddecls - 199475 - - - id - 199475 - - - parentid - 25503 - - - - - id - parentid - - - 12 - - - 1 - 2 - 199475 - - - - - - - parentid - id - - - 12 - - - 1 - 2 - 4554 - - - 2 - 3 - 5465 - - - 3 - 4 - 1821 - - - 4 - 6 - 1821 - - - 6 - 7 - 2732 - - - 7 - 9 - 1821 - - - 9 - 10 - 910 - - - 10 - 11 - 1821 - - - 13 - 18 - 1821 - - - 19 - 20 - 1821 - - - 57 - 58 - 910 + 24 + 145 + 1831 @@ -9596,19 +9252,19 @@ fieldDeclaredIn - 199475 + 210035 fieldId - 199475 + 135178 fieldDeclId - 199475 + 210035 pos - 910 + 22 @@ -9622,7 +9278,17 @@ 1 2 - 199475 + 94498 + + + 2 + 3 + 6501 + + + 3 + 4 + 34177 @@ -9638,7 +9304,7 @@ 1 2 - 199475 + 135178 @@ -9654,7 +9320,7 @@ 1 2 - 199475 + 210035 @@ -9670,7 +9336,7 @@ 1 2 - 199475 + 210035 @@ -9684,9 +9350,9 @@ 12 - 219 - 220 - 910 + 5905 + 5906 + 22 @@ -9700,9 +9366,9 @@ 12 - 219 - 220 - 910 + 9175 + 9176 + 22 @@ -9712,27 +9378,27 @@ fields - 19350704 + 2886451 id - 19350704 + 2886451 nodeName - 13628474 + 2508459 typeid - 3038794 + 182623 parentid - 4089502 + 249278 sourceid - 19350704 + 2886451 @@ -9746,7 +9412,7 @@ 1 2 - 19350704 + 2886451 @@ -9762,7 +9428,7 @@ 1 2 - 19350704 + 2886451 @@ -9778,7 +9444,7 @@ 1 2 - 19350704 + 2886451 @@ -9794,7 +9460,7 @@ 1 2 - 19350704 + 2886451 @@ -9810,17 +9476,12 @@ 1 2 - 12016876 + 2356342 2 - 3 - 1123700 - - - 3 - 722 - 487897 + 302 + 152116 @@ -9836,17 +9497,12 @@ 1 2 - 12416414 + 2425714 2 - 5 - 1085283 - - - 5 - 160 - 126776 + 183 + 82744 @@ -9862,17 +9518,12 @@ 1 2 - 12016876 + 2356342 2 - 3 - 1123700 - - - 3 - 722 - 487897 + 302 + 152116 @@ -9888,17 +9539,12 @@ 1 2 - 12016876 + 2356342 2 - 3 - 1123700 - - - 3 - 722 - 487897 + 302 + 152116 @@ -9914,27 +9560,27 @@ 1 2 - 2059157 + 124952 2 3 - 320782 + 21104 3 4 - 213215 + 10447 4 8 - 245869 + 14835 8 - 2588 - 199769 + 9650 + 11283 @@ -9950,202 +9596,237 @@ 1 2 - 2120625 + 130385 2 3 - 299653 - - - 3 - 4 - 199769 - - - 4 - 9 - 255473 - - - 9 - 2016 - 163272 - - - - - - - typeid - parentid - - - 12 - - - 1 - 2 - 2706486 - - - 2 - 4 - 251632 - - - 4 - 1014 - 80675 - - - - - - - typeid - sourceid - - - 12 - - - 1 - 2 - 2059157 - - - 2 - 3 - 320782 - - - 3 - 4 - 213215 - - - 4 - 8 - 245869 - - - 8 - 2588 - 199769 - - - - - - - parentid - id - - - 12 - - - 1 - 2 - 2427962 - - - 2 - 3 - 478293 - - - 3 - 4 - 303495 - - - 4 - 6 - 338070 - - - 6 - 13 - 330387 - - - 13 - 1610 - 211294 - - - - - - - parentid - nodeName - - - 12 - - - 1 - 2 - 2427962 - - - 2 - 3 - 478293 - - - 3 - 4 - 303495 - - - 4 - 6 - 338070 - - - 6 - 13 - 330387 - - - 13 - 1610 - 211294 - - - - - - - parentid - typeid - - - 12 - - - 1 - 2 - 3031110 - - - 2 - 3 - 595465 + 17969 3 5 - 347674 + 16716 5 - 76 - 115251 + 20 + 13790 + + + 22 + 8913 + 3761 + + + + + + + typeid + parentid + + + 12 + + + 1 + 2 + 154205 + + + 2 + 3 + 18596 + + + 3 + 679 + 9820 + + + + + + + typeid + sourceid + + + 12 + + + 1 + 2 + 124952 + + + 2 + 3 + 21104 + + + 3 + 4 + 10447 + + + 4 + 8 + 14835 + + + 8 + 9650 + 11283 + + + + + + + parentid + id + + + 12 + + + 1 + 2 + 115132 + + + 2 + 3 + 25074 + + + 3 + 4 + 20477 + + + 4 + 5 + 15253 + + + 5 + 6 + 12328 + + + 6 + 8 + 18387 + + + 8 + 14 + 19641 + + + 14 + 93 + 18805 + + + 95 + 1772 + 4179 + + + + + + + parentid + nodeName + + + 12 + + + 1 + 2 + 115132 + + + 2 + 3 + 25074 + + + 3 + 4 + 20477 + + + 4 + 5 + 15253 + + + 5 + 6 + 12328 + + + 6 + 8 + 18387 + + + 8 + 14 + 19641 + + + 14 + 93 + 18805 + + + 95 + 1772 + 4179 + + + + + + + parentid + typeid + + + 12 + + + 1 + 2 + 165280 + + + 2 + 3 + 39909 + + + 3 + 4 + 20895 + + + 4 + 7 + 18805 + + + 7 + 27 + 4387 @@ -10161,32 +9842,47 @@ 1 2 - 2427962 + 115132 2 3 - 478293 + 25074 3 4 - 303495 + 20477 4 + 5 + 15253 + + + 5 6 - 338070 + 12328 6 - 13 - 330387 + 8 + 18387 - 13 - 1610 - 211294 + 8 + 14 + 19641 + + + 14 + 93 + 18805 + + + 95 + 1772 + 4179 @@ -10202,7 +9898,7 @@ 1 2 - 19350704 + 2886451 @@ -10218,7 +9914,7 @@ 1 2 - 19350704 + 2886451 @@ -10234,7 +9930,7 @@ 1 2 - 19350704 + 2886451 @@ -10250,7 +9946,7 @@ 1 2 - 19350704 + 2886451 @@ -10260,15 +9956,15 @@ fieldsKotlinType - 19350704 + 2667261 id - 19350704 + 2667261 kttypeid - 1920 + 208 @@ -10282,7 +9978,7 @@ 1 2 - 19350704 + 2667261 @@ -10296,9 +9992,9 @@ 12 - 10074 - 10075 - 1920 + 12765 + 12766 + 208 @@ -10308,31 +10004,31 @@ constrs - 8006128 + 1103682 id - 8006128 + 1103682 nodeName - 4333451 + 597980 signature - 6803672 + 938261 typeid - 3841 + 524 parentid - 5639633 + 777558 sourceid - 5720309 + 788044 @@ -10346,7 +10042,7 @@ 1 2 - 8006128 + 1103682 @@ -10362,7 +10058,7 @@ 1 2 - 8006128 + 1103682 @@ -10378,7 +10074,7 @@ 1 2 - 8006128 + 1103682 @@ -10394,7 +10090,7 @@ 1 2 - 8006128 + 1103682 @@ -10410,7 +10106,7 @@ 1 2 - 8006128 + 1103682 @@ -10426,27 +10122,27 @@ 1 2 - 2623889 + 363874 2 3 - 1085283 + 145759 3 4 - 259315 + 38274 4 - 11 - 326545 + 12 + 45615 - 11 + 12 36 - 38417 + 4456 @@ -10462,22 +10158,22 @@ 1 2 - 2977327 + 412373 2 3 - 868226 + 116397 3 5 - 341912 + 49285 5 19 - 145985 + 19923 @@ -10493,7 +10189,7 @@ 1 2 - 4333451 + 597980 @@ -10509,17 +10205,17 @@ 1 2 - 3764878 + 520120 2 3 - 401458 + 54528 3 36 - 167114 + 23332 @@ -10535,22 +10231,22 @@ 1 2 - 2737220 + 379603 2 3 - 1083362 + 145497 3 5 - 353437 + 51120 5 32 - 159431 + 21759 @@ -10566,12 +10262,12 @@ 1 2 - 6302329 + 869575 2 36 - 501343 + 68685 @@ -10587,7 +10283,7 @@ 1 2 - 6803672 + 938261 @@ -10603,7 +10299,7 @@ 1 2 - 6803672 + 938261 @@ -10619,12 +10315,12 @@ 1 2 - 6302329 + 869575 2 36 - 501343 + 68685 @@ -10640,12 +10336,12 @@ 1 2 - 6461760 + 891597 2 23 - 341912 + 46664 @@ -10661,12 +10357,12 @@ 22 23 - 1920 + 262 - 4146 - 4147 - 1920 + 4188 + 4189 + 262 @@ -10682,12 +10378,12 @@ 1 2 - 1920 + 262 - 2255 - 2256 - 1920 + 2280 + 2281 + 262 @@ -10703,12 +10399,12 @@ 1 2 - 1920 + 262 - 3541 - 3542 - 1920 + 3578 + 3579 + 262 @@ -10724,12 +10420,12 @@ 22 23 - 1920 + 262 - 2914 - 2915 - 1920 + 2944 + 2945 + 262 @@ -10745,12 +10441,12 @@ 22 23 - 1920 + 262 - 2956 - 2957 - 1920 + 2984 + 2985 + 262 @@ -10766,22 +10462,22 @@ 1 2 - 4256617 + 588281 2 3 - 895118 + 120068 3 6 - 434113 + 61869 6 19 - 53783 + 7340 @@ -10797,7 +10493,7 @@ 1 2 - 5639633 + 777558 @@ -10813,22 +10509,22 @@ 1 2 - 4256617 + 588281 2 3 - 895118 + 120068 3 6 - 434113 + 61869 6 19 - 53783 + 7340 @@ -10844,7 +10540,7 @@ 1 2 - 5639633 + 777558 @@ -10860,22 +10556,22 @@ 1 2 - 4256617 + 588281 2 3 - 895118 + 120068 3 6 - 434113 + 61869 6 19 - 53783 + 7340 @@ -10891,12 +10587,12 @@ 1 2 - 5357267 + 737710 2 - 209 - 363041 + 219 + 50334 @@ -10912,12 +10608,12 @@ 1 2 - 5357267 + 737710 2 - 172 - 363041 + 178 + 50334 @@ -10933,12 +10629,12 @@ 1 2 - 5357267 + 737710 2 - 172 - 363041 + 178 + 50334 @@ -10954,7 +10650,7 @@ 1 2 - 5720309 + 788044 @@ -10970,12 +10666,12 @@ 1 2 - 5357267 + 737710 2 - 209 - 363041 + 219 + 50334 @@ -10985,15 +10681,15 @@ constrsKotlinType - 8006128 + 1103682 id - 8006128 + 1103682 kttypeid - 1920 + 262 @@ -11007,7 +10703,7 @@ 1 2 - 8006128 + 1103682 @@ -11021,9 +10717,9 @@ 12 - 4168 - 4169 - 1920 + 4210 + 4211 + 262 @@ -11033,31 +10729,31 @@ methods - 109719302 + 15113893 id - 109719302 + 15113893 nodeName - 22908130 + 3165025 signature - 33369112 + 4608463 typeid - 13338425 + 1843228 parentid - 12810189 + 1782931 sourceid - 67091663 + 9250220 @@ -11071,7 +10767,7 @@ 1 2 - 109719302 + 15113893 @@ -11087,7 +10783,7 @@ 1 2 - 109719302 + 15113893 @@ -11103,7 +10799,7 @@ 1 2 - 109719302 + 15113893 @@ -11119,7 +10815,7 @@ 1 2 - 109719302 + 15113893 @@ -11135,7 +10831,7 @@ 1 2 - 109719302 + 15113893 @@ -11151,32 +10847,32 @@ 1 2 - 13324979 + 1845587 2 3 - 4070294 + 561540 3 4 - 1573181 + 218114 4 7 - 2026503 + 277624 7 - 56 - 1719166 + 61 + 238038 - 57 + 61 1769 - 194006 + 24118 @@ -11192,17 +10888,17 @@ 1 2 - 19150935 + 2647264 2 3 - 2228193 + 306986 3 - 298 - 1529001 + 308 + 210774 @@ -11218,22 +10914,22 @@ 1 2 - 19179748 + 2651983 2 3 - 1872834 + 257176 3 25 - 1726849 + 238300 25 - 741 - 128697 + 752 + 17564 @@ -11249,27 +10945,27 @@ 1 2 - 14028012 + 1943110 2 3 - 3889733 + 536111 3 4 - 1502109 + 207628 4 7 - 1817129 + 249311 7 - 1099 - 1671144 + 1120 + 228863 @@ -11285,27 +10981,27 @@ 1 2 - 13743725 + 1905621 2 3 - 4283509 + 589067 3 4 - 1544368 + 213396 4 7 - 1857467 + 254292 7 - 800 - 1479059 + 811 + 202647 @@ -11321,27 +11017,27 @@ 1 2 - 22735253 + 3143266 2 3 - 5434102 + 751080 3 5 - 2635414 + 358893 5 - 157 - 2502875 + 152 + 345785 - 157 - 1096 - 61467 + 155 + 1117 + 9437 @@ -11357,7 +11053,7 @@ 1 2 - 33369112 + 4608463 @@ -11373,17 +11069,17 @@ 1 2 - 29957672 + 4140250 2 5 - 2650781 + 362301 5 - 739 - 760659 + 750 + 105911 @@ -11399,27 +11095,27 @@ 1 2 - 22741015 + 3144052 2 3 - 5432181 + 750818 3 5 - 2631572 + 358369 5 - 157 - 2502875 + 152 + 345785 - 157 - 1096 - 61467 + 155 + 1117 + 9437 @@ -11435,22 +11131,22 @@ 1 2 - 23365294 + 3232137 2 3 - 5656921 + 780704 3 6 - 2900492 + 397692 6 - 795 - 1446404 + 806 + 197928 @@ -11466,32 +11162,32 @@ 1 2 - 6603903 + 915453 2 3 - 2729536 + 377244 3 4 - 1208218 + 167256 4 6 - 1119859 + 153099 6 15 - 1019974 + 140254 15 - 10335 - 656932 + 10397 + 89919 @@ -11507,22 +11203,22 @@ 1 2 - 8714924 + 1203826 2 3 - 2620047 + 363612 3 6 - 1167880 + 160964 6 - 2888 - 835572 + 2934 + 114824 @@ -11538,22 +11234,22 @@ 1 2 - 8565097 + 1183115 2 3 - 2602760 + 361514 3 6 - 1210139 + 165945 6 - 4142 - 960428 + 4201 + 132651 @@ -11569,27 +11265,27 @@ 1 2 - 7714158 + 1068028 2 3 - 2869759 + 396119 3 4 - 1108333 + 153886 4 8 - 1069916 + 146283 8 - 2865 - 576256 + 2901 + 78909 @@ -11605,32 +11301,32 @@ 1 2 - 7166714 + 992265 2 3 - 2524004 + 349717 3 4 - 1096808 + 151789 4 6 - 1094888 + 149167 6 16 - 1016132 + 140254 16 - 6435 - 439876 + 6502 + 60034 @@ -11646,52 +11342,52 @@ 1 2 - 3630418 + 511993 2 3 - 1456008 + 206055 3 4 - 1164038 + 160964 4 5 - 735687 + 100930 5 7 - 1021895 + 139992 7 10 - 1106413 + 153099 10 13 - 1146751 + 159915 13 21 - 1181326 + 162013 21 40 - 1021895 + 140778 40 319 - 345754 + 47188 @@ -11707,52 +11403,52 @@ 1 2 - 3678439 + 518547 2 3 - 1457929 + 206317 3 4 - 1231268 + 170140 4 5 - 791392 + 108533 5 7 - 960428 + 131865 7 10 - 1183247 + 163324 10 13 - 1102571 + 153886 13 18 - 849018 + 116397 18 - 26 - 968111 + 27 + 136846 - 26 + 27 290 - 587781 + 77074 @@ -11768,52 +11464,52 @@ 1 2 - 3630418 + 511993 2 3 - 1456008 + 206055 3 4 - 1164038 + 160964 4 5 - 735687 + 100930 5 7 - 1021895 + 139992 7 10 - 1106413 + 153099 10 13 - 1146751 + 159915 13 21 - 1181326 + 162013 21 40 - 1021895 + 140778 40 319 - 345754 + 47188 @@ -11829,52 +11525,52 @@ 1 2 - 4348818 + 611613 2 3 - 1757583 + 246690 3 4 - 1436800 + 198453 4 5 - 922010 + 126621 5 6 - 743371 + 102503 6 7 - 564731 + 77074 7 8 - 879752 + 122951 8 11 - 1160197 + 160178 11 - 31 - 964269 + 35 + 133962 - 33 + 37 78 - 32654 + 2883 @@ -11890,52 +11586,52 @@ 1 2 - 3630418 + 511993 2 3 - 1456008 + 206055 3 4 - 1164038 + 160964 4 5 - 735687 + 100930 5 7 - 1021895 + 139992 7 10 - 1106413 + 153099 10 13 - 1146751 + 159915 13 21 - 1181326 + 162013 21 40 - 1021895 + 140778 40 319 - 345754 + 47188 @@ -11951,17 +11647,17 @@ 1 2 - 61836200 + 8524569 2 50 - 5032643 + 695241 52 - 286 - 222819 + 296 + 30410 @@ -11977,7 +11673,7 @@ 1 2 - 67091663 + 9250220 @@ -11993,12 +11689,12 @@ 1 2 - 66767038 + 9204343 2 - 284 - 324624 + 294 + 45877 @@ -12014,12 +11710,12 @@ 1 2 - 65030584 + 8968401 2 - 209 - 2061078 + 219 + 281819 @@ -12035,17 +11731,17 @@ 1 2 - 61836200 + 8524569 2 50 - 5032643 + 695241 52 - 286 - 222819 + 296 + 30410 @@ -12055,15 +11751,15 @@ methodsKotlinType - 109719302 + 15113893 id - 109719302 + 15113893 kttypeid - 1920 + 262 @@ -12077,7 +11773,7 @@ 1 2 - 109719302 + 15113893 @@ -12091,9 +11787,9 @@ 12 - 57120 - 57121 - 1920 + 57652 + 57653 + 262 @@ -12103,27 +11799,27 @@ params - 120852585 + 16587479 id - 120852585 + 16587479 typeid - 12833239 + 1772707 pos - 42258 + 5767 parentid - 65007534 + 8942448 sourceid - 73639861 + 10111931 @@ -12137,7 +11833,7 @@ 1 2 - 120852585 + 16587479 @@ -12153,7 +11849,7 @@ 1 2 - 120852585 + 16587479 @@ -12169,7 +11865,7 @@ 1 2 - 120852585 + 16587479 @@ -12185,7 +11881,7 @@ 1 2 - 120852585 + 16587479 @@ -12201,37 +11897,37 @@ 1 2 - 6763334 + 935901 2 3 - 1945827 + 269759 3 4 - 948902 + 130816 4 6 - 1148671 + 158080 6 12 - 1018053 + 138943 12 326 - 966190 + 133438 343 - 6738 - 42258 + 6748 + 5767 @@ -12247,22 +11943,22 @@ 1 2 - 10436011 + 1442651 2 3 - 1342678 + 185345 3 - 8 - 964269 + 9 + 136321 - 8 + 9 17 - 90280 + 8389 @@ -12278,32 +11974,32 @@ 1 2 - 7005362 + 968933 2 3 - 1895885 + 262943 3 4 - 975794 + 134486 4 6 - 1087204 + 149691 6 13 - 1008449 + 137894 13 - 4326 - 860543 + 4336 + 118757 @@ -12319,32 +12015,32 @@ 1 2 - 7216656 + 998032 2 3 - 1788317 + 248787 3 4 - 996924 + 136846 4 6 - 1117938 + 153362 6 13 - 1002686 + 137894 13 5757 - 710716 + 97784 @@ -12360,57 +12056,57 @@ 1 2 - 3841 + 524 50 53 - 3841 + 524 104 106 - 3841 + 524 157 165 - 3841 + 524 214 231 - 3841 + 524 291 315 - 3841 + 524 485 606 - 3841 + 524 804 1067 - 3841 + 524 1445 2015 - 3841 + 524 - 3084 - 5199 - 3841 + 3087 + 5218 + 524 - 12689 - 33844 - 3841 + 12756 + 34112 + 524 @@ -12426,57 +12122,57 @@ 1 2 - 3841 + 524 2 5 - 3841 + 524 6 7 - 3841 + 524 11 14 - 3841 + 524 15 20 - 3841 + 524 27 37 - 3841 + 524 57 75 - 3841 + 524 97 153 - 3841 + 524 201 289 - 3841 + 524 - 403 - 777 - 3841 + 406 + 789 + 524 - 1979 - 5089 - 3841 + 1997 + 5152 + 524 @@ -12492,57 +12188,57 @@ 1 2 - 3841 + 524 50 53 - 3841 + 524 104 106 - 3841 + 524 157 165 - 3841 + 524 214 231 - 3841 + 524 291 315 - 3841 + 524 485 606 - 3841 + 524 804 1067 - 3841 + 524 1445 2015 - 3841 + 524 - 3084 - 5199 - 3841 + 3087 + 5218 + 524 - 12689 - 33844 - 3841 + 12756 + 34112 + 524 @@ -12558,57 +12254,57 @@ 1 2 - 3841 + 524 2 5 - 3841 + 524 6 8 - 3841 + 524 11 15 - 3841 + 524 16 29 - 3841 + 524 39 63 - 3841 + 524 101 144 - 3841 + 524 210 386 - 3841 + 524 628 1069 - 3841 + 524 - 1955 - 3748 - 3841 + 1958 + 3765 + 524 - 8555 - 21355 - 3841 + 8596 + 21529 + 524 @@ -12624,27 +12320,27 @@ 1 2 - 40633790 + 5598369 2 3 - 14389133 + 1976404 3 4 - 4060689 + 558395 4 10 - 4992305 + 682133 10 23 - 931615 + 127146 @@ -12660,17 +12356,17 @@ 1 2 - 45326442 + 6239868 2 3 - 14805959 + 2032767 3 23 - 4875132 + 669811 @@ -12686,27 +12382,27 @@ 1 2 - 40633790 + 5598369 2 3 - 14389133 + 1976404 3 4 - 4060689 + 558395 4 10 - 4992305 + 682133 10 23 - 931615 + 127146 @@ -12722,27 +12418,27 @@ 1 2 - 40633790 + 5598369 2 3 - 14389133 + 1976404 3 4 - 4060689 + 558395 4 10 - 4992305 + 682133 10 23 - 931615 + 127146 @@ -12758,12 +12454,12 @@ 1 2 - 68584168 + 9415117 2 - 286 - 5055693 + 296 + 696814 @@ -12779,12 +12475,12 @@ 1 2 - 71932220 + 9877563 2 - 286 - 1707641 + 296 + 234368 @@ -12800,7 +12496,7 @@ 1 2 - 73639861 + 10111931 @@ -12816,12 +12512,12 @@ 1 2 - 68584168 + 9415117 2 - 286 - 5055693 + 296 + 696814 @@ -12831,15 +12527,15 @@ paramsKotlinType - 120852585 + 16587479 id - 120852585 + 16587479 kttypeid - 1920 + 262 @@ -12853,7 +12549,7 @@ 1 2 - 120852585 + 16587479 @@ -12867,9 +12563,9 @@ 12 - 62916 - 62917 - 1920 + 63273 + 63274 + 262 @@ -12879,15 +12575,15 @@ paramName - 15639610 + 2140514 id - 15639610 + 2140514 nodeName - 2335761 + 319307 @@ -12901,7 +12597,7 @@ 1 2 - 15639610 + 2140514 @@ -12917,37 +12613,37 @@ 1 2 - 998845 + 136321 2 3 - 451401 + 61869 3 4 - 249711 + 34342 4 5 - 170956 + 23332 5 8 - 182481 + 24904 8 - 18 - 176718 + 19 + 24118 - 18 - 769 - 105647 + 19 + 770 + 14418 @@ -12957,11 +12653,11 @@ isVarargsParam - 945061 + 813764 param - 945061 + 813764 @@ -13184,11 +12880,11 @@ isAnnotType - 29260 + 35103 interfaceid - 29260 + 35103 @@ -13472,49 +13168,49 @@ isEnumType - 397617 + 56888 classid - 397617 + 56888 isEnumConst - 3081053 + 435967 fieldid - 3081053 + 435967 typeVars - 6288883 + 864332 id - 6288883 + 864332 nodeName - 86438 + 11797 pos - 7683 + 1048 kind - 1920 + 262 parentid - 4444861 + 612137 @@ -13528,7 +13224,7 @@ 1 2 - 6288883 + 864332 @@ -13544,7 +13240,7 @@ 1 2 - 6288883 + 864332 @@ -13560,7 +13256,7 @@ 1 2 - 6288883 + 864332 @@ -13576,7 +13272,7 @@ 1 2 - 6288883 + 864332 @@ -13592,47 +13288,47 @@ 1 2 - 21129 + 2883 2 3 - 11525 + 1572 3 4 - 9604 + 1310 4 7 - 7683 + 1048 7 10 - 7683 + 1048 10 28 - 7683 + 1048 36 - 69 - 7683 + 70 + 1048 71 412 - 7683 + 1048 - 603 - 710 - 5762 + 605 + 724 + 786 @@ -13648,22 +13344,22 @@ 1 2 - 51863 + 7078 2 3 - 23050 + 3145 3 4 - 9604 + 1310 4 5 - 1920 + 262 @@ -13679,7 +13375,7 @@ 1 2 - 86438 + 11797 @@ -13695,47 +13391,47 @@ 1 2 - 21129 + 2883 2 3 - 11525 + 1572 3 4 - 9604 + 1310 4 7 - 7683 + 1048 7 10 - 7683 + 1048 10 28 - 7683 + 1048 36 - 69 - 7683 + 70 + 1048 71 412 - 7683 + 1048 - 603 - 710 - 5762 + 605 + 724 + 786 @@ -13751,22 +13447,22 @@ 6 7 - 1920 + 262 89 90 - 1920 + 262 - 865 - 866 - 1920 + 867 + 868 + 262 - 2314 - 2315 - 1920 + 2335 + 2336 + 262 @@ -13782,22 +13478,22 @@ 2 3 - 1920 + 262 13 14 - 1920 + 262 21 22 - 1920 + 262 34 35 - 1920 + 262 @@ -13813,7 +13509,7 @@ 1 2 - 7683 + 1048 @@ -13829,22 +13525,22 @@ 6 7 - 1920 + 262 89 90 - 1920 + 262 - 865 - 866 - 1920 + 867 + 868 + 262 - 2314 - 2315 - 1920 + 2335 + 2336 + 262 @@ -13858,9 +13554,9 @@ 12 - 3274 - 3275 - 1920 + 3297 + 3298 + 262 @@ -13876,7 +13572,7 @@ 45 46 - 1920 + 262 @@ -13892,7 +13588,7 @@ 4 5 - 1920 + 262 @@ -13906,9 +13602,9 @@ 12 - 2314 - 2315 - 1920 + 2335 + 2336 + 262 @@ -13924,17 +13620,17 @@ 1 2 - 2783320 + 384846 2 3 - 1490584 + 203958 3 5 - 170956 + 23332 @@ -13950,17 +13646,17 @@ 1 2 - 2783320 + 384846 2 3 - 1490584 + 203958 3 5 - 170956 + 23332 @@ -13976,17 +13672,17 @@ 1 2 - 2783320 + 384846 2 3 - 1490584 + 203958 3 5 - 170956 + 23332 @@ -14002,7 +13698,7 @@ 1 2 - 4444861 + 612137 @@ -14012,19 +13708,19 @@ wildcards - 3338447 + 458250 id - 3338447 + 458250 nodeName - 533998 + 74976 kind - 3841 + 524 @@ -14038,7 +13734,7 @@ 1 2 - 3338447 + 458250 @@ -14054,7 +13750,7 @@ 1 2 - 3338447 + 458250 @@ -14070,22 +13766,22 @@ 1 2 - 397617 + 56363 2 3 - 55704 + 7340 3 7 - 44179 + 6029 7 170 - 36496 + 5243 @@ -14101,7 +13797,7 @@ 1 2 - 533998 + 74976 @@ -14115,14 +13811,14 @@ 12 - 791 - 792 - 1920 + 795 + 796 + 262 - 947 - 948 - 1920 + 953 + 954 + 262 @@ -14136,14 +13832,14 @@ 12 - 91 - 92 - 1920 + 94 + 95 + 262 - 187 - 188 - 1920 + 192 + 193 + 262 @@ -14153,23 +13849,23 @@ typeBounds - 4229725 + 581989 id - 4229725 + 581989 typeid - 2852471 + 392449 pos - 1920 + 262 parentid - 4229725 + 581989 @@ -14183,7 +13879,7 @@ 1 2 - 4229725 + 581989 @@ -14199,7 +13895,7 @@ 1 2 - 4229725 + 581989 @@ -14215,7 +13911,7 @@ 1 2 - 4229725 + 581989 @@ -14231,17 +13927,17 @@ 1 2 - 2091812 + 288635 2 3 - 695349 + 94900 3 52 - 65309 + 8913 @@ -14257,7 +13953,7 @@ 1 2 - 2852471 + 392449 @@ -14273,17 +13969,17 @@ 1 2 - 2091812 + 288635 2 3 - 695349 + 94900 3 52 - 65309 + 8913 @@ -14297,9 +13993,9 @@ 12 - 2202 - 2203 - 1920 + 2220 + 2221 + 262 @@ -14313,9 +14009,9 @@ 12 - 1485 - 1486 - 1920 + 1497 + 1498 + 262 @@ -14329,9 +14025,9 @@ 12 - 2202 - 2203 - 1920 + 2220 + 2221 + 262 @@ -14347,7 +14043,7 @@ 1 2 - 4229725 + 581989 @@ -14363,7 +14059,7 @@ 1 2 - 4229725 + 581989 @@ -14379,7 +14075,7 @@ 1 2 - 4229725 + 581989 @@ -14685,37 +14381,37 @@ isParameterized - 27045654 + 22244248 memberid - 27045654 + 22244248 isRaw - 731846 + 100406 memberid - 731846 + 100406 erasure - 27777500 + 22246872 memberid - 27777500 + 22246872 erasureid - 954665 + 2976 @@ -14729,7 +14425,7 @@ 1 2 - 27777500 + 22246872 @@ -14745,62 +14441,52 @@ 1 2 - 142143 + 184 2 3 - 138301 + 456 3 - 4 - 86438 - - - 4 5 - 57625 + 260 5 6 - 65309 + 734 6 - 8 - 69150 + 9 + 236 - 8 - 10 - 61467 + 9 + 23 + 254 - 10 - 15 - 72992 + 23 + 98 + 225 - 15 - 22 - 76834 + 101 + 288 + 225 - 22 - 44 - 74913 + 345 + 2541 + 225 - 46 - 124 - 72992 - - - 169 - 1564 - 36496 + 2940 + 448198 + 173 @@ -14810,15 +14496,15 @@ isAnonymClass - 174213 + 157916 classid - 174213 + 157916 parent - 174213 + 157916 @@ -14832,7 +14518,7 @@ 1 2 - 174213 + 157916 @@ -14848,7 +14534,7 @@ 1 2 - 174213 + 157916 @@ -14858,15 +14544,15 @@ isLocalClassOrInterface - 3841 + 3533 typeid - 3841 + 3533 parent - 3841 + 3533 @@ -14880,7 +14566,7 @@ 1 2 - 3841 + 3533 @@ -14896,7 +14582,7 @@ 1 2 - 3841 + 3533 @@ -14917,15 +14603,15 @@ lambdaKind - 167982 + 152268 exprId - 167982 + 152268 bodyKind - 13 + 12 @@ -14939,7 +14625,7 @@ 1 2 - 167982 + 152268 @@ -14955,7 +14641,7 @@ 12267 12268 - 13 + 12 @@ -14965,27 +14651,27 @@ arrays - 1375332 + 190588 id - 1375332 + 190588 nodeName - 831730 + 115349 elementtypeid - 1365728 + 189277 dimension - 3841 + 524 componenttypeid - 1375332 + 190588 @@ -14999,7 +14685,7 @@ 1 2 - 1375332 + 190588 @@ -15015,7 +14701,7 @@ 1 2 - 1375332 + 190588 @@ -15031,7 +14717,7 @@ 1 2 - 1375332 + 190588 @@ -15047,7 +14733,7 @@ 1 2 - 1375332 + 190588 @@ -15063,17 +14749,17 @@ 1 2 - 664616 + 92279 2 3 - 140222 + 19137 3 87 - 26891 + 3932 @@ -15089,17 +14775,17 @@ 1 2 - 664616 + 92279 2 3 - 140222 + 19137 3 87 - 26891 + 3932 @@ -15115,7 +14801,7 @@ 1 2 - 831730 + 115349 @@ -15131,17 +14817,17 @@ 1 2 - 664616 + 92279 2 3 - 140222 + 19137 3 87 - 26891 + 3932 @@ -15157,12 +14843,12 @@ 1 2 - 1356124 + 187966 2 3 - 9604 + 1310 @@ -15178,12 +14864,12 @@ 1 2 - 1356124 + 187966 2 3 - 9604 + 1310 @@ -15199,12 +14885,12 @@ 1 2 - 1356124 + 187966 2 3 - 9604 + 1310 @@ -15220,12 +14906,12 @@ 1 2 - 1356124 + 187966 2 3 - 9604 + 1310 @@ -15241,12 +14927,12 @@ 5 6 - 1920 + 262 - 711 - 712 - 1920 + 722 + 723 + 262 @@ -15262,12 +14948,12 @@ 5 6 - 1920 + 262 - 428 - 429 - 1920 + 435 + 436 + 262 @@ -15283,12 +14969,12 @@ 5 6 - 1920 + 262 - 711 - 712 - 1920 + 722 + 723 + 262 @@ -15304,12 +14990,12 @@ 5 6 - 1920 + 262 - 711 - 712 - 1920 + 722 + 723 + 262 @@ -15325,7 +15011,7 @@ 1 2 - 1375332 + 190588 @@ -15341,7 +15027,7 @@ 1 2 - 1375332 + 190588 @@ -15357,7 +15043,7 @@ 1 2 - 1375332 + 190588 @@ -15373,7 +15059,7 @@ 1 2 - 1375332 + 190588 @@ -15383,15 +15069,15 @@ enclInReftype - 4051085 + 564162 child - 4051085 + 564162 parent - 1125621 + 156245 @@ -15405,7 +15091,7 @@ 1 2 - 4051085 + 564162 @@ -15421,32 +15107,32 @@ 1 2 - 666537 + 92803 2 3 - 176718 + 24642 3 4 - 86438 + 11797 4 - 6 - 82596 + 7 + 14418 - 6 - 17 - 84517 + 7 + 55 + 11797 - 17 + 55 265 - 28812 + 786 @@ -15456,15 +15142,15 @@ extendsReftype - 34389087 + 27274828 id1 - 33104034 + 22257941 id2 - 13251986 + 17181115 @@ -15478,12 +15164,12 @@ 1 2 - 32118635 + 20991189 2 - 10 - 985399 + 6 + 1266751 @@ -15499,17 +15185,17 @@ 1 2 - 12030322 + 13982285 2 - 5 - 1023816 + 3 + 1947557 - 5 - 8715 - 197848 + 3 + 937651 + 1251272 @@ -15519,15 +15205,15 @@ implInterface - 14423708 + 3052687 id1 - 8255839 + 757298 id2 - 4487119 + 2275569 @@ -15541,27 +15227,37 @@ 1 2 - 4223962 + 210035 2 3 - 2829421 + 50057 3 4 - 276603 + 67415 4 5 - 920090 + 62041 5 + 6 + 19333 + + + 6 7 - 5762 + 305943 + + + 7 + 10 + 42471 @@ -15577,17 +15273,12 @@ 1 2 - 4003064 + 2200149 2 - 4 - 366883 - - - 4 - 2275 - 117172 + 63705 + 75420 @@ -15597,15 +15288,15 @@ permits - 129 + 132 id1 - 31 + 30 id2 - 129 + 132 @@ -15619,12 +15310,12 @@ 1 2 - 2 + 3 2 3 - 8 + 3 3 @@ -15634,27 +15325,17 @@ 4 5 - 2 - - - 5 - 6 - 2 - - - 6 - 8 - 2 + 10 8 9 - 2 + 3 - 9 + 10 11 - 2 + 3 @@ -15670,7 +15351,7 @@ 1 2 - 129 + 132 @@ -15680,15 +15361,15 @@ hasModifier - 270713939 + 48527772 id1 - 180180147 + 24369293 id2 - 26891 + 63 @@ -15702,17 +15383,17 @@ 1 2 - 90230296 + 356153 2 3 - 89365911 + 23867801 3 4 - 583940 + 145338 @@ -15726,74 +15407,59 @@ 12 - 4 - 5 - 1920 + 22 + 23 + 5 - 14 - 15 - 1920 + 27 + 28 + 5 - 20 - 21 - 1920 + 100 + 101 + 5 - 21 - 22 - 1920 + 262 + 263 + 5 - 34 - 35 - 1920 + 712 + 713 + 5 - 50 - 51 - 1920 + 1374 + 1375 + 5 - 109 - 110 - 1920 + 11041 + 11042 + 5 - 219 - 220 - 1920 + 63640 + 63641 + 5 - 3864 - 3865 - 1920 + 242567 + 242568 + 5 - 7193 - 7194 - 1920 + 3864462 + 3864463 + 5 - 9195 - 9196 - 1920 - - - 14706 - 14707 - 1920 - - - 18810 - 18811 - 1920 - - - 86695 - 86696 - 1920 + 4211558 + 4211559 + 5 @@ -15803,23 +15469,23 @@ imports - 368550 + 441072 id - 368550 + 441072 holder - 58078 + 52468 name - 8794 + 4282 kind - 663 + 29 @@ -15833,7 +15499,7 @@ 1 2 - 368550 + 441072 @@ -15849,7 +15515,7 @@ 1 2 - 368550 + 441072 @@ -15865,7 +15531,7 @@ 1 2 - 368550 + 441072 @@ -15881,120 +15547,120 @@ 1 2 - 28375 + 20638 2 3 - 9292 + 8976 3 4 - 5475 + 4991 4 - 6 - 4646 + 5 + 3335 - 6 - 15 - 4480 - - - 15 - 54 - 4480 - - - 64 - 98 - 1327 - - - - - - - holder - name - - - 12 - - - 1 - 2 - 54593 - - - 2 + 5 7 - 3484 - - - - - - - holder - kind - - - 12 - - - 1 - 2 - 55091 - - - 2 - 3 - 2986 - - - - - - - name - id - - - 12 - - - 1 - 2 - 4148 - - - 2 - 3 - 1825 - - - 3 - 4 - 829 - - - 4 - 7 - 663 + 4096 7 - 26 - 663 + 12 + 4305 - 30 - 1962 - 663 + 12 + 32 + 3984 + + + 32 + 1529 + 2141 + + + + + + + holder + name + + + 12 + + + 1 + 2 + 50871 + + + 2 + 54 + 1596 + + + + + + + holder + kind + + + 12 + + + 1 + 2 + 51200 + + + 2 + 4 + 1268 + + + + + + + name + id + + + 12 + + + 1 + 2 + 2469 + + + 2 + 3 + 962 + + + 3 + 4 + 358 + + + 4 + 7 + 328 + + + 7 + 57945 + 164 @@ -16010,17 +15676,12 @@ 1 2 - 7301 + 4163 2 - 3 - 1161 - - - 3 - 337 - 331 + 6945 + 119 @@ -16036,12 +15697,12 @@ 1 2 - 8628 + 4275 3 4 - 165 + 7 @@ -16055,24 +15716,24 @@ 12 - 1 - 2 - 165 + 15 + 16 + 7 - 6 - 7 - 165 + 68 + 69 + 7 - 260 - 261 - 165 + 1170 + 1171 + 7 - 1954 - 1955 - 165 + 57861 + 57862 + 7 @@ -16086,24 +15747,24 @@ 12 - 1 - 2 - 165 + 10 + 11 + 7 - 3 - 4 - 165 + 25 + 26 + 7 - 31 - 32 - 165 + 257 + 258 + 7 - 333 - 334 - 165 + 6915 + 6916 + 7 @@ -16119,12 +15780,12 @@ 1 2 - 497 + 22 - 52 - 53 - 165 + 573 + 574 + 7 @@ -17973,7 +17634,7 @@ kttypeid - 10930 + 156277 @@ -18003,17 +17664,12 @@ 1 2 - 8197 + 152777 2 - 3 - 1821 - - - 8123 - 8124 - 910 + 584083 + 3500 @@ -18292,22 +17948,22 @@ when_if - 74334 + 56072 id - 74334 + 56072 when_branch_else - 76075 + 70057 id - 76075 + 70057 @@ -18352,12 +18008,12 @@ 1 2 - 162993 + 162995 2 3 - 33137 + 33136 3 @@ -18450,15 +18106,15 @@ propertyRefGetBinding - 8876 + 8437 id - 8876 + 8437 getter - 5366 + 5101 @@ -18472,7 +18128,7 @@ 1 2 - 8876 + 8437 @@ -18488,17 +18144,17 @@ 1 2 - 1951 + 1855 2 3 - 3328 + 3164 3 6 - 86 + 82 @@ -18556,15 +18212,15 @@ propertyRefSetBinding - 2600 + 2226 id - 2600 + 2226 setter - 1300 + 1094 @@ -18578,7 +18234,7 @@ 1 2 - 2600 + 2226 @@ -18591,10 +18247,20 @@ 12 + + 1 + 2 + 32 + 2 3 - 1300 + 994 + + + 3 + 5 + 67 @@ -19053,15 +18719,15 @@ localvarsKotlinType - 240107 + 149454 id - 240107 + 149454 kttypeid - 1920 + 2 @@ -19075,7 +18741,7 @@ 1 2 - 240107 + 149454 @@ -19089,9 +18755,9 @@ 12 - 125 - 126 - 1920 + 59940 + 59941 + 2 @@ -19340,11 +19006,11 @@ isOpen - 1 + 13 id - 1 + 13 @@ -19502,15 +19168,15 @@ requires - 1991 + 3190 id - 1991 + 3190 target - 995 + 377 @@ -19524,7 +19190,7 @@ 1 2 - 1991 + 3190 @@ -19540,17 +19206,52 @@ 1 2 - 663 + 33 2 3 - 165 + 40 + + + 3 + 4 + 23 + + + 4 + 5 + 23 + + + 5 + 6 + 33 6 - 7 - 165 + 9 + 10 + + + 9 + 10 + 142 + + + 10 + 11 + 30 + + + 11 + 29 + 30 + + + 56 + 73 + 6 @@ -19571,11 +19272,11 @@ isStatic - 1 + 33 id - 1 + 33 @@ -20991,15 +20692,15 @@ xmlEncoding - 1129463 + 154148 id - 1129463 + 154148 encoding - 1920 + 262 @@ -21013,7 +20714,7 @@ 1 2 - 1129463 + 154148 @@ -21029,7 +20730,7 @@ 588 589 - 1920 + 262 @@ -21387,27 +21088,27 @@ xmlElements - 150282022 + 20510401 id - 150282022 + 20510401 name - 476372 + 65015 parentid - 3876287 + 529033 idx - 1703799 + 232533 fileid - 1129463 + 154148 @@ -21421,7 +21122,7 @@ 1 2 - 150282022 + 20510401 @@ -21437,7 +21138,7 @@ 1 2 - 150282022 + 20510401 @@ -21453,7 +21154,7 @@ 1 2 - 150282022 + 20510401 @@ -21469,7 +21170,7 @@ 1 2 - 150282022 + 20510401 @@ -21485,57 +21186,57 @@ 1 2 - 149826 + 20448 2 3 - 57625 + 7864 3 4 - 23050 + 3145 4 6 - 42258 + 5767 6 8 - 34575 + 4718 8 9 - 17287 + 2359 9 10 - 32654 + 4456 10 18 - 40337 + 5505 18 48 - 36496 + 4980 52 250 - 36496 + 4980 342 73380 - 5762 + 786 @@ -21551,52 +21252,52 @@ 1 2 - 174797 + 23856 2 3 - 65309 + 8913 3 4 - 24971 + 3408 4 5 - 21129 + 2883 5 6 - 26891 + 3670 6 8 - 40337 + 5505 8 10 - 40337 + 5505 10 21 - 38417 + 5243 22 128 - 36496 + 4980 130 229 - 7683 + 1048 @@ -21612,37 +21313,37 @@ 1 2 - 263157 + 35915 2 3 - 69150 + 9437 3 4 - 34575 + 4718 4 6 - 28812 + 3932 6 9 - 28812 + 3932 9 38 - 36496 + 4980 45 888 - 15366 + 2097 @@ -21658,42 +21359,42 @@ 1 2 - 259315 + 35391 2 3 - 51863 + 7078 3 4 - 24971 + 3408 4 5 - 19208 + 2621 5 7 - 42258 + 5767 7 16 - 36496 + 4980 17 114 - 38417 + 5243 118 131 - 3841 + 524 @@ -21709,32 +21410,32 @@ 1 2 - 2358811 + 321929 2 3 - 605069 + 82579 3 4 - 251632 + 34342 4 8 - 301574 + 41158 8 777 - 316941 + 43255 777 888 - 42258 + 5767 @@ -21750,17 +21451,17 @@ 1 2 - 3200146 + 436754 2 3 - 411063 + 56101 3 17 - 265078 + 36177 @@ -21776,32 +21477,32 @@ 1 2 - 2358811 + 321929 2 3 - 605069 + 82579 3 4 - 251632 + 34342 4 8 - 301574 + 41158 8 777 - 316941 + 43255 777 888 - 42258 + 5767 @@ -21817,7 +21518,7 @@ 1 2 - 3876287 + 529033 @@ -21833,67 +21534,67 @@ 2 8 - 144064 + 19661 9 76 - 136380 + 18613 76 82 - 128697 + 17564 82 89 - 122934 + 16778 89 92 - 111409 + 15205 92 95 - 134459 + 18351 95 97 - 149826 + 20448 97 98 - 211294 + 28837 98 99 - 130618 + 17826 99 104 - 155589 + 21234 104 106 - 130618 + 17826 106 159 - 128697 + 17564 162 2019 - 19208 + 2621 @@ -21909,22 +21610,22 @@ 1 2 - 1381095 + 188491 2 5 - 126776 + 17302 5 9 - 145985 + 19923 9 150 - 49942 + 6816 @@ -21940,67 +21641,67 @@ 2 8 - 144064 + 19661 9 76 - 136380 + 18613 76 82 - 128697 + 17564 82 89 - 122934 + 16778 89 92 - 111409 + 15205 92 95 - 134459 + 18351 95 97 - 149826 + 20448 97 98 - 211294 + 28837 98 99 - 130618 + 17826 99 104 - 155589 + 21234 104 106 - 130618 + 17826 106 159 - 128697 + 17564 162 2019 - 19208 + 2621 @@ -22016,67 +21717,67 @@ 2 8 - 144064 + 19661 9 76 - 136380 + 18613 76 82 - 128697 + 17564 82 89 - 122934 + 16778 89 92 - 111409 + 15205 92 95 - 134459 + 18351 95 97 - 149826 + 20448 97 98 - 211294 + 28837 98 99 - 130618 + 17826 99 104 - 155589 + 21234 104 106 - 130618 + 17826 106 139 - 128697 + 17564 141 589 - 19208 + 2621 @@ -22092,57 +21793,57 @@ 1 2 - 82596 + 11272 2 3 - 190164 + 25953 3 4 - 249711 + 34080 4 5 - 105647 + 14418 5 7 - 84517 + 11534 7 10 - 94121 + 12845 10 31 - 88359 + 12059 35 694 - 86438 + 11797 738 776 - 28812 + 3932 777 779 - 92201 + 12583 788 889 - 26891 + 3670 @@ -22158,37 +21859,37 @@ 1 2 - 82596 + 11272 2 3 - 562810 + 76812 3 4 - 195927 + 26740 4 5 - 92201 + 12583 5 6 - 86438 + 11797 6 9 - 92201 + 12583 9 69 - 17287 + 2359 @@ -22204,27 +21905,27 @@ 1 2 - 82596 + 11272 2 3 - 800997 + 109319 3 4 - 80675 + 11010 4 6 - 82596 + 11272 6 165 - 82596 + 11272 @@ -22240,42 +21941,42 @@ 1 2 - 286207 + 39061 2 3 - 309257 + 42207 3 4 - 124855 + 17040 4 7 - 94121 + 12845 7 17 - 94121 + 12845 18 763 - 86438 + 11797 764 777 - 92201 + 12583 777 888 - 42258 + 5767 @@ -22285,31 +21986,31 @@ xmlAttrs - 182798274 + 24948200 id - 182798274 + 24948200 elementid - 149002731 + 20335805 name - 722241 + 98571 value - 11548187 + 1576089 idx - 44179 + 6029 fileid - 1127542 + 153886 @@ -22323,7 +22024,7 @@ 1 2 - 182798274 + 24948200 @@ -22339,7 +22040,7 @@ 1 2 - 182798274 + 24948200 @@ -22355,7 +22056,7 @@ 1 2 - 182798274 + 24948200 @@ -22371,7 +22072,7 @@ 1 2 - 182798274 + 24948200 @@ -22387,7 +22088,7 @@ 1 2 - 182798274 + 24948200 @@ -22403,17 +22104,17 @@ 1 2 - 136351973 + 18609237 2 6 - 11204353 + 1529163 6 24 - 1446404 + 197404 @@ -22429,17 +22130,17 @@ 1 2 - 136351973 + 18609237 2 6 - 11223562 + 1531785 6 23 - 1427196 + 194782 @@ -22455,17 +22156,17 @@ 1 2 - 136426886 + 18619461 2 6 - 11279267 + 1539387 6 21 - 1296577 + 176956 @@ -22481,17 +22182,17 @@ 1 2 - 136351973 + 18609237 2 6 - 11204353 + 1529163 6 24 - 1446404 + 197404 @@ -22507,7 +22208,7 @@ 1 2 - 149002731 + 20335805 @@ -22523,62 +22224,62 @@ 1 2 - 149826 + 20448 2 3 - 78755 + 10748 3 4 - 44179 + 6029 4 5 - 24971 + 3408 5 6 - 42258 + 5767 6 8 - 51863 + 7078 8 11 - 59546 + 8126 11 22 - 55704 + 7602 23 38 - 57625 + 7864 38 79 - 57625 + 7864 81 168 - 55704 + 7602 168 74700 - 44179 + 6029 @@ -22594,62 +22295,62 @@ 1 2 - 149826 + 20448 2 3 - 78755 + 10748 3 4 - 44179 + 6029 4 5 - 24971 + 3408 5 6 - 42258 + 5767 6 8 - 51863 + 7078 8 11 - 65309 + 8913 11 25 - 61467 + 8389 25 39 - 59546 + 8126 43 91 - 57625 + 7864 91 227 - 55704 + 7602 227 74700 - 30733 + 4194 @@ -22665,42 +22366,42 @@ 1 2 - 303495 + 41420 2 3 - 113330 + 15467 3 4 - 48021 + 6553 4 5 - 51863 + 7078 5 9 - 59546 + 8126 9 21 - 55704 + 7602 22 64 - 59546 + 8126 68 2100 - 30733 + 4194 @@ -22716,37 +22417,37 @@ 1 2 - 284286 + 38799 2 3 - 134459 + 18351 3 4 - 69150 + 9437 4 5 - 76834 + 10486 5 7 - 46100 + 6291 7 10 - 57625 + 7864 10 21 - 53783 + 7340 @@ -22762,52 +22463,52 @@ 1 2 - 251632 + 34342 2 3 - 74913 + 10224 3 4 - 38417 + 5243 4 5 - 34575 + 4718 5 6 - 53783 + 7340 6 9 - 59546 + 8126 9 17 - 63388 + 8651 17 34 - 55704 + 7602 36 91 - 55704 + 7602 91 223 - 34575 + 4718 @@ -22823,37 +22524,37 @@ 1 2 - 6308091 + 860924 2 3 - 1707641 + 233057 3 5 - 885514 + 120854 5 31 - 870147 + 118757 31 91 - 908564 + 124000 91 1111 - 866306 + 118232 3397 3398 - 1920 + 262 @@ -22869,32 +22570,32 @@ 1 2 - 6434868 + 878227 2 3 - 1626965 + 222047 3 5 - 897039 + 122427 5 33 - 910485 + 124262 33 93 - 891277 + 121640 93 3398 - 787551 + 107484 @@ -22910,17 +22611,17 @@ 1 2 - 10480191 + 1430330 2 4 - 929694 + 126884 4 53 - 138301 + 18875 @@ -22936,17 +22637,17 @@ 1 2 - 9563942 + 1305281 2 3 - 1396462 + 190588 3 20 - 587781 + 80220 @@ -22962,32 +22663,32 @@ 1 2 - 7433713 + 1014548 2 3 - 1252398 + 170926 3 10 - 897039 + 122427 10 83 - 877831 + 119805 83 99 - 881672 + 120330 99 182 - 205531 + 28050 @@ -23003,62 +22704,62 @@ 1 6 - 3841 + 524 12 14 - 3841 + 524 17 26 - 3841 + 524 39 56 - 3841 + 524 83 110 - 3841 + 524 153 232 - 3841 + 524 316 400 - 3841 + 524 468 545 - 3841 + 524 626 754 - 3841 + 524 951 1491 - 3841 + 524 4718 6587 - 3841 + 524 77571 77572 - 1920 + 262 @@ -23074,62 +22775,62 @@ 1 6 - 3841 + 524 12 14 - 3841 + 524 17 26 - 3841 + 524 39 56 - 3841 + 524 83 110 - 3841 + 524 153 232 - 3841 + 524 316 400 - 3841 + 524 468 545 - 3841 + 524 626 754 - 3841 + 524 951 1491 - 3841 + 524 4718 6587 - 3841 + 524 77571 77572 - 1920 + 262 @@ -23145,62 +22846,62 @@ 1 4 - 3841 + 524 7 10 - 3841 + 524 11 17 - 3841 + 524 18 23 - 3841 + 524 26 38 - 3841 + 524 39 49 - 3841 + 524 57 67 - 3841 + 524 72 79 - 3841 + 524 95 101 - 3841 + 524 105 106 - 3841 + 524 106 132 - 3841 + 524 140 141 - 1920 + 262 @@ -23216,62 +22917,62 @@ 1 5 - 3841 + 524 7 10 - 3841 + 524 11 18 - 3841 + 524 22 32 - 3841 + 524 46 63 - 3841 + 524 85 119 - 3841 + 524 142 185 - 3841 + 524 212 228 - 3841 + 524 253 275 - 3841 + 524 307 423 - 3841 + 524 580 1324 - 3841 + 524 3579 3580 - 1920 + 262 @@ -23287,62 +22988,62 @@ 1 6 - 3841 + 524 7 8 - 3841 + 524 10 19 - 3841 + 524 23 36 - 3841 + 524 45 59 - 3841 + 524 73 97 - 3841 + 524 115 131 - 3841 + 524 140 148 - 3841 + 524 168 181 - 3841 + 524 248 363 - 3841 + 524 473 530 - 3841 + 524 587 588 - 1920 + 262 @@ -23358,72 +23059,72 @@ 1 3 - 84517 + 11534 3 5 - 86438 + 11797 5 6 - 51863 + 7078 6 7 - 86438 + 11797 7 8 - 72992 + 9961 8 10 - 82596 + 11272 10 15 - 92201 + 12583 15 27 - 86438 + 11797 27 41 - 86438 + 11797 41 65 - 86438 + 11797 65 157 - 92201 + 12583 162 817 - 86438 + 11797 818 832 - 94121 + 12845 832 1187 - 38417 + 5243 @@ -23439,52 +23140,52 @@ 1 2 - 128697 + 17564 2 3 - 265078 + 36177 3 4 - 159431 + 21759 4 5 - 109488 + 14942 5 8 - 101805 + 13894 8 14 - 86438 + 11797 14 295 - 86438 + 11797 330 775 - 71071 + 9699 776 778 - 92201 + 12583 787 888 - 26891 + 3670 @@ -23500,62 +23201,62 @@ 1 2 - 71071 + 9699 2 3 - 92201 + 12583 3 4 - 71071 + 9699 4 5 - 94121 + 12845 5 6 - 170956 + 23332 6 7 - 161351 + 22021 7 8 - 71071 + 9699 8 12 - 86438 + 11797 12 18 - 97963 + 13370 18 24 - 96042 + 13107 24 37 - 88359 + 12059 37 55 - 26891 + 3670 @@ -23571,67 +23272,67 @@ 1 3 - 97963 + 13370 3 4 - 55704 + 7602 4 5 - 103726 + 14156 5 6 - 124855 + 17040 6 8 - 88359 + 12059 8 12 - 99884 + 13632 12 19 - 86438 + 11797 19 27 - 97963 + 13370 27 41 - 86438 + 11797 42 170 - 86438 + 11797 205 780 - 80675 + 11010 781 783 - 92201 + 12583 791 893 - 26891 + 3670 @@ -23647,47 +23348,47 @@ 1 2 - 111409 + 15205 2 3 - 107567 + 14680 3 4 - 213215 + 29099 4 5 - 218977 + 29885 5 6 - 130618 + 17826 6 10 - 96042 + 13107 10 12 - 65309 + 8913 12 15 - 97963 + 13370 15 24 - 86438 + 11797 @@ -23697,23 +23398,23 @@ xmlNs - 1811367 + 247214 id - 11525 + 1572 prefixName - 13445 + 1835 URI - 11525 + 1572 fileid - 1054550 + 143924 @@ -23727,12 +23428,12 @@ 1 2 - 9604 + 1310 2 3 - 1920 + 262 @@ -23748,7 +23449,7 @@ 1 2 - 11525 + 1572 @@ -23764,32 +23465,32 @@ 2 3 - 1920 + 262 20 21 - 1920 + 262 88 89 - 1920 + 262 167 168 - 1920 + 262 213 214 - 1920 + 262 453 454 - 1920 + 262 @@ -23805,7 +23506,7 @@ 1 2 - 13445 + 1835 @@ -23821,7 +23522,7 @@ 1 2 - 13445 + 1835 @@ -23837,37 +23538,37 @@ 1 2 - 1920 + 262 2 3 - 1920 + 262 20 21 - 1920 + 262 88 89 - 1920 + 262 166 167 - 1920 + 262 213 214 - 1920 + 262 453 454 - 1920 + 262 @@ -23883,7 +23584,7 @@ 1 2 - 11525 + 1572 @@ -23899,12 +23600,12 @@ 1 2 - 9604 + 1310 2 3 - 1920 + 262 @@ -23920,32 +23621,32 @@ 2 3 - 1920 + 262 20 21 - 1920 + 262 88 89 - 1920 + 262 167 168 - 1920 + 262 213 214 - 1920 + 262 453 454 - 1920 + 262 @@ -23961,17 +23662,17 @@ 1 2 - 470609 + 64228 2 3 - 411063 + 56101 3 4 - 172877 + 23594 @@ -23987,17 +23688,17 @@ 1 2 - 470609 + 64228 2 3 - 411063 + 56101 3 4 - 172877 + 23594 @@ -24013,17 +23714,17 @@ 1 2 - 470609 + 64228 2 3 - 411063 + 56101 3 4 - 172877 + 23594 @@ -24033,19 +23734,19 @@ xmlHasNs - 36540446 + 4987018 elementId - 36540446 + 4987018 nsId - 11525 + 1572 fileid - 1048787 + 143137 @@ -24059,7 +23760,7 @@ 1 2 - 36540446 + 4987018 @@ -24075,7 +23776,7 @@ 1 2 - 36540446 + 4987018 @@ -24091,32 +23792,32 @@ 13 14 - 1920 + 262 84 85 - 1920 + 262 2426 2427 - 1920 + 262 2733 2734 - 1920 + 262 3704 3705 - 1920 + 262 10063 10064 - 1920 + 262 @@ -24132,32 +23833,32 @@ 2 3 - 1920 + 262 20 21 - 1920 + 262 86 87 - 1920 + 262 164 165 - 1920 + 262 209 210 - 1920 + 262 453 454 - 1920 + 262 @@ -24173,77 +23874,77 @@ 1 3 - 63388 + 8651 3 5 - 88359 + 12059 5 6 - 48021 + 6553 6 7 - 92201 + 12583 7 8 - 69150 + 9437 8 10 - 86438 + 11797 10 15 - 92201 + 12583 15 25 - 78755 + 10748 25 36 - 80675 + 11010 36 49 - 82596 + 11272 49 54 - 21129 + 2883 54 55 - 82596 + 11272 55 81 - 80675 + 11010 81 298 - 78755 + 10748 298 833 - 3841 + 524 @@ -24259,17 +23960,17 @@ 1 2 - 472530 + 64490 2 3 - 407221 + 55577 3 4 - 169035 + 23069 @@ -24279,23 +23980,23 @@ xmlComments - 151257816 + 20643577 id - 151257816 + 20643577 text - 2387624 + 325861 parentid - 1185168 + 161751 fileid - 1108333 + 151264 @@ -24309,7 +24010,7 @@ 1 2 - 151257816 + 20643577 @@ -24325,7 +24026,7 @@ 1 2 - 151257816 + 20643577 @@ -24341,7 +24042,7 @@ 1 2 - 151257816 + 20643577 @@ -24357,67 +24058,67 @@ 1 2 - 328466 + 44828 2 7 - 195927 + 26740 7 32 - 197848 + 27002 32 61 - 180560 + 24642 61 76 - 180560 + 24642 76 84 - 192085 + 26215 84 90 - 176718 + 24118 90 94 - 157510 + 21496 94 95 - 84517 + 11534 95 96 - 142143 + 19399 96 98 - 197848 + 27002 98 100 - 178639 + 24380 100 460 - 174797 + 23856 @@ -24433,67 +24134,67 @@ 1 2 - 332308 + 45353 2 6 - 190164 + 25953 6 32 - 201689 + 27526 32 61 - 182481 + 24904 61 75 - 186323 + 25429 75 84 - 209373 + 28575 84 90 - 172877 + 23594 90 94 - 169035 + 23069 94 95 - 94121 + 12845 95 96 - 145985 + 19923 96 98 - 201689 + 27526 98 100 - 190164 + 25953 100 460 - 111409 + 15205 @@ -24509,67 +24210,67 @@ 1 2 - 347674 + 47450 2 7 - 188243 + 25691 7 32 - 188243 + 25691 32 61 - 182481 + 24904 61 75 - 186323 + 25429 75 84 - 209373 + 28575 84 90 - 172877 + 23594 90 94 - 169035 + 23069 94 95 - 94121 + 12845 95 96 - 145985 + 19923 96 98 - 201689 + 27526 98 100 - 190164 + 25953 100 460 - 111409 + 15205 @@ -24585,22 +24286,22 @@ 1 2 - 943140 + 128719 2 724 - 90280 + 12321 726 830 - 109488 + 14942 831 941 - 42258 + 5767 @@ -24616,27 +24317,27 @@ 1 2 - 943140 + 128719 2 697 - 90280 + 12321 697 795 - 48021 + 6553 795 827 - 90280 + 12321 838 899 - 13445 + 1835 @@ -24652,7 +24353,7 @@ 1 2 - 1185168 + 161751 @@ -24668,27 +24369,27 @@ 1 2 - 847097 + 115611 2 549 - 84517 + 11534 579 829 - 57625 + 7864 829 832 - 92201 + 12583 834 941 - 26891 + 3670 @@ -24704,27 +24405,27 @@ 1 2 - 847097 + 115611 2 536 - 84517 + 11534 560 795 - 72992 + 9961 795 812 - 84517 + 11534 819 899 - 19208 + 2621 @@ -24740,12 +24441,12 @@ 1 2 - 1052629 + 143662 2 6 - 55704 + 7602 @@ -24755,31 +24456,31 @@ xmlChars - 142938589 + 19508174 id - 142938589 + 19508174 text - 109773086 + 14981766 parentid - 142938589 + 19508174 idx - 1920 + 262 isCDATA - 3841 + 524 fileid - 249711 + 34080 @@ -24793,7 +24494,7 @@ 1 2 - 142938589 + 19508174 @@ -24809,7 +24510,7 @@ 1 2 - 142938589 + 19508174 @@ -24825,7 +24526,7 @@ 1 2 - 142938589 + 19508174 @@ -24841,7 +24542,7 @@ 1 2 - 142938589 + 19508174 @@ -24857,7 +24558,7 @@ 1 2 - 142938589 + 19508174 @@ -24873,17 +24574,17 @@ 1 2 - 93927944 + 12819230 2 3 - 9865517 + 1346439 3 128 - 5979625 + 816095 @@ -24899,17 +24600,17 @@ 1 2 - 93927944 + 12819230 2 3 - 9865517 + 1346439 3 128 - 5979625 + 816095 @@ -24925,7 +24626,7 @@ 1 2 - 109773086 + 14981766 @@ -24941,7 +24642,7 @@ 1 2 - 109773086 + 14981766 @@ -24957,12 +24658,12 @@ 1 2 - 105030493 + 14334499 2 76 - 4742593 + 647266 @@ -24978,7 +24679,7 @@ 1 2 - 142938589 + 19508174 @@ -24994,7 +24695,7 @@ 1 2 - 142938589 + 19508174 @@ -25010,7 +24711,7 @@ 1 2 - 142938589 + 19508174 @@ -25026,7 +24727,7 @@ 1 2 - 142938589 + 19508174 @@ -25042,7 +24743,7 @@ 1 2 - 142938589 + 19508174 @@ -25058,7 +24759,7 @@ 74414 74415 - 1920 + 262 @@ -25074,7 +24775,7 @@ 57148 57149 - 1920 + 262 @@ -25090,7 +24791,7 @@ 74414 74415 - 1920 + 262 @@ -25106,7 +24807,7 @@ 2 3 - 1920 + 262 @@ -25122,7 +24823,7 @@ 130 131 - 1920 + 262 @@ -25138,12 +24839,12 @@ 518 519 - 1920 + 262 73896 73897 - 1920 + 262 @@ -25159,12 +24860,12 @@ 492 493 - 1920 + 262 56656 56657 - 1920 + 262 @@ -25180,12 +24881,12 @@ 518 519 - 1920 + 262 73896 73897 - 1920 + 262 @@ -25201,7 +24902,7 @@ 1 2 - 3841 + 524 @@ -25217,12 +24918,12 @@ 98 99 - 1920 + 262 130 131 - 1920 + 262 @@ -25238,57 +24939,57 @@ 1 2 - 21129 + 2883 2 23 - 19208 + 2621 24 243 - 19208 + 2621 294 566 - 19208 + 2621 610 686 - 19208 + 2621 691 764 - 19208 + 2621 765 775 - 19208 + 2621 775 776 - 5762 + 786 776 777 - 69150 + 9437 777 803 - 19208 + 2621 807 888 - 19208 + 2621 @@ -25304,67 +25005,67 @@ 1 2 - 21129 + 2883 2 21 - 19208 + 2621 22 188 - 19208 + 2621 208 492 - 19208 + 2621 525 589 - 19208 + 2621 590 638 - 19208 + 2621 639 651 - 19208 + 2621 652 656 - 17287 + 2359 656 659 - 23050 + 3145 659 663 - 21129 + 2883 663 667 - 19208 + 2621 667 701 - 19208 + 2621 702 744 - 13445 + 1835 @@ -25380,57 +25081,57 @@ 1 2 - 21129 + 2883 2 23 - 19208 + 2621 24 243 - 19208 + 2621 294 566 - 19208 + 2621 610 686 - 19208 + 2621 691 764 - 19208 + 2621 765 775 - 19208 + 2621 775 776 - 5762 + 786 776 777 - 69150 + 9437 777 803 - 19208 + 2621 807 888 - 19208 + 2621 @@ -25446,7 +25147,7 @@ 1 2 - 249711 + 34080 @@ -25462,12 +25163,12 @@ 1 2 - 61467 + 8389 2 3 - 188243 + 25691 @@ -25477,15 +25178,15 @@ xmllocations - 630217533 + 86011718 xmlElement - 628417691 + 85766076 location - 590551854 + 80598169 @@ -25499,12 +25200,12 @@ 1 2 - 628406166 + 85764503 2 454 - 11525 + 1572 @@ -25520,12 +25221,12 @@ 1 2 - 577165407 + 78771195 2 25 - 13386446 + 1826974 @@ -25766,19 +25467,19 @@ ktComments - 188243 + 74439 id - 188243 + 74439 kind - 5762 + 37 text - 136380 + 51562 @@ -25792,7 +25493,7 @@ 1 2 - 188243 + 74439 @@ -25808,7 +25509,7 @@ 1 2 - 188243 + 74439 @@ -25822,19 +25523,19 @@ 12 - 16 - 17 - 1920 + 1196 + 1197 + 12 - 22 - 23 - 1920 + 1284 + 1285 + 12 - 60 - 61 - 1920 + 3517 + 3518 + 12 @@ -25848,19 +25549,19 @@ 12 - 1 - 2 - 1920 + 17 + 18 + 12 - 16 - 17 - 1920 + 1073 + 1074 + 12 - 54 - 55 - 1920 + 3064 + 3065 + 12 @@ -25876,12 +25577,17 @@ 1 2 - 130618 + 46101 - 4 - 23 - 5762 + 2 + 3 + 4232 + + + 3 + 572 + 1228 @@ -25897,7 +25603,7 @@ 1 2 - 136380 + 51562 @@ -25907,19 +25613,19 @@ ktCommentSections - 52611 + 47690 id - 52611 + 47690 comment - 48161 + 43655 content - 44765 + 40577 @@ -25933,7 +25639,7 @@ 1 2 - 52611 + 47690 @@ -25949,7 +25655,7 @@ 1 2 - 52611 + 47690 @@ -25965,12 +25671,12 @@ 1 2 - 46367 + 42029 2 18 - 1793 + 1626 @@ -25986,12 +25692,12 @@ 1 2 - 46367 + 42029 2 18 - 1793 + 1626 @@ -26007,17 +25713,17 @@ 1 2 - 39616 + 35910 2 3 - 4313 + 3910 3 63 - 835 + 757 @@ -26033,17 +25739,17 @@ 1 2 - 39712 + 35997 2 3 - 4231 + 3835 3 56 - 821 + 744 @@ -26053,15 +25759,15 @@ ktCommentSectionNames - 4450 + 4034 id - 4450 + 4034 name - 13 + 12 @@ -26075,7 +25781,7 @@ 1 2 - 4450 + 4034 @@ -26091,7 +25797,7 @@ 325 326 - 13 + 12 @@ -26101,15 +25807,15 @@ ktCommentSectionSubjectNames - 4450 + 4034 id - 4450 + 4034 subjectname - 2916 + 2643 @@ -26123,7 +25829,7 @@ 1 2 - 4450 + 4034 @@ -26139,22 +25845,22 @@ 1 2 - 2218 + 2010 2 3 - 438 + 397 3 9 - 219 + 198 10 16 - 41 + 37 @@ -26164,15 +25870,15 @@ ktCommentOwners - 75329 + 68171 id - 47914 + 43432 owner - 73508 + 66520 @@ -26186,22 +25892,22 @@ 1 2 - 30838 + 28065 2 3 - 10872 + 9744 3 4 - 4025 + 3649 4 6 - 2177 + 1973 @@ -26217,12 +25923,12 @@ 1 2 - 71701 + 64881 2 4 - 1807 + 1638 @@ -26232,19 +25938,19 @@ ktExtensionFunctions - 1206297 + 166732 id - 1206297 + 166732 typeid - 97963 + 13632 kttypeid - 1920 + 262 @@ -26258,7 +25964,7 @@ 1 2 - 1206297 + 166732 @@ -26274,7 +25980,7 @@ 1 2 - 1206297 + 166732 @@ -26290,37 +25996,37 @@ 1 2 - 55704 + 7864 2 3 - 5762 + 524 3 4 - 3841 + 786 5 6 - 13445 + 1310 - 7 - 16 - 7683 + 6 + 13 + 1048 - 20 - 87 - 7683 + 13 + 30 + 1048 - 109 + 35 227 - 3841 + 1048 @@ -26336,7 +26042,7 @@ 1 2 - 97963 + 13632 @@ -26350,9 +26056,9 @@ 12 - 628 - 629 - 1920 + 636 + 637 + 262 @@ -26366,9 +26072,9 @@ 12 - 51 - 52 - 1920 + 52 + 53 + 262 @@ -26378,15 +26084,15 @@ ktProperties - 21895839 + 2989117 id - 21895839 + 2989117 nodeName - 13542035 + 1848733 @@ -26400,7 +26106,7 @@ 1 2 - 21895839 + 2989117 @@ -26416,17 +26122,17 @@ 1 2 - 11824790 + 1614626 2 4 - 1142909 + 155721 4 352 - 574335 + 78385 @@ -26436,15 +26142,15 @@ ktPropertyGetters - 5985387 + 816357 id - 5985387 + 816357 getter - 5985387 + 816357 @@ -26458,7 +26164,7 @@ 1 2 - 5985387 + 816357 @@ -26474,7 +26180,7 @@ 1 2 - 5985387 + 816357 @@ -26484,15 +26190,15 @@ ktPropertySetters - 366883 + 53073 id - 366883 + 53073 setter - 366883 + 53073 @@ -26506,7 +26212,7 @@ 1 2 - 366883 + 53073 @@ -26522,7 +26228,7 @@ 1 2 - 366883 + 53073 @@ -26532,15 +26238,15 @@ ktPropertyBackingFields - 14423708 + 2459964 id - 14423708 + 2459964 backingField - 14423708 + 2459964 @@ -26554,7 +26260,7 @@ 1 2 - 14423708 + 2459964 @@ -26570,7 +26276,7 @@ 1 2 - 14423708 + 2459964 @@ -26580,15 +26286,15 @@ ktSyntheticBody - 9108 + 1497 id - 9108 + 1497 kind - 1821 + 124 @@ -26602,7 +26308,7 @@ 1 2 - 9108 + 1497 @@ -26616,9 +26322,9 @@ 12 - 5 - 6 - 1821 + 12 + 13 + 124 @@ -26628,37 +26334,37 @@ ktLocalFunction - 3841 + 1573 id - 3841 + 1573 ktInitializerAssignment - 199475 + 69820 id - 199475 + 69820 ktPropertyDelegates - 5201 + 4944 id - 5201 + 4944 variableId - 5201 + 4944 @@ -26672,7 +26378,7 @@ 1 2 - 5201 + 4944 @@ -26688,7 +26394,7 @@ 1 2 - 5201 + 4944 @@ -26698,15 +26404,15 @@ compiler_generated - 1467534 + 268390 id - 1467534 + 268390 kind - 13445 + 148 @@ -26720,7 +26426,7 @@ 1 2 - 1467534 + 268390 @@ -26734,39 +26440,59 @@ 12 - 1 - 2 - 1920 + 61 + 62 + 12 - 8 - 9 - 1920 + 84 + 85 + 24 - 38 - 39 - 1920 + 94 + 95 + 12 - 81 - 82 - 1920 + 143 + 144 + 12 - 85 - 86 - 1920 + 186 + 187 + 12 - 236 - 237 - 1920 + 203 + 204 + 12 - 315 - 316 - 1920 + 737 + 738 + 12 + + + 1028 + 1029 + 12 + + + 1275 + 1276 + 12 + + + 5140 + 5141 + 12 + + + 12589 + 12590 + 12 @@ -26776,15 +26502,15 @@ ktFunctionOriginalNames - 1586627 + 216279 id - 1586627 + 216279 name - 186323 + 25167 @@ -26798,7 +26524,7 @@ 1 2 - 1586627 + 216279 @@ -26814,22 +26540,22 @@ 1 2 - 147905 + 19923 2 4 - 13445 + 1835 6 16 - 15366 + 2097 22 339 - 9604 + 1310 @@ -26839,11 +26565,11 @@ ktDataClasses - 113330 + 15467 id - 113330 + 15467 From 62d10f91d8c0d887907fd7c6eb2fc3123426a238 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 8 Feb 2023 16:43:27 +0000 Subject: [PATCH 238/415] Improve join ordering --- java/ql/lib/semmle/code/java/Member.qll | 19 +++++++++++----- .../semmle/code/java/dataflow/TypeFlow.qll | 11 +++++++--- .../java/dispatch/internal/Unification.qll | 22 ++++++++++++++----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/java/ql/lib/semmle/code/java/Member.qll b/java/ql/lib/semmle/code/java/Member.qll index e14b1d1c981..00c9648c9a4 100644 --- a/java/ql/lib/semmle/code/java/Member.qll +++ b/java/ql/lib/semmle/code/java/Member.qll @@ -397,14 +397,21 @@ private predicate potentialInterfaceImplementationWithSignature(string sig, RefT not t.isAbstract() } -pragma[nomagic] -private predicate implementsInterfaceMethod(SrcMethod impl, SrcMethod m) { - exists(RefType t, Interface i, Method minst, Method implinst | - m = minst.getSourceDeclaration() and +pragma[noinline] +private predicate isInterfaceSourceImplementation(Method minst, RefType t) { + exists(Interface i | i = minst.getDeclaringType() and t.extendsOrImplements+(i) and - t.isSourceDeclaration() and + t.isSourceDeclaration() + ) +} + +pragma[nomagic] +private predicate implementsInterfaceMethod(SrcMethod impl, SrcMethod m) { + exists(RefType t, Method minst, Method implinst | + isInterfaceSourceImplementation(minst, t) and potentialInterfaceImplementationWithSignature(minst.getSignature(), t, implinst) and + m = minst.getSourceDeclaration() and impl = implinst.getSourceDeclaration() ) } @@ -542,7 +549,7 @@ class Method extends Callable, @method { /** A method that is the same as its source declaration. */ class SrcMethod extends Method { - SrcMethod() { methods(_, _, _, _, _, this) } + SrcMethod() { methods(this, _, _, _, _, this) } /** * All the methods that could possibly be called when this method diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll index 1c76f554020..8bac5eefd6b 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll @@ -681,9 +681,14 @@ private predicate unionTypeFlow0(TypeFlowNode n, RefType t, boolean exact) { private predicate unionTypeFlow(TypeFlowNode n, RefType t, boolean exact) { unionTypeFlow0(n, t, exact) and // filter impossible union parts: - if exact = true - then t.getErasure().(RefType).getASourceSupertype*() = getTypeBound(n).getErasure() - else haveIntersection(getTypeBound(n), t) + exists(RefType tErased, RefType boundErased | + pragma[only_bind_into](tErased) = t.getErasure() and + pragma[only_bind_into](boundErased) = getTypeBound(n).getErasure() + | + if exact = true + then tErased.getASourceSupertype*() = boundErased + else erasedHaveIntersection(tErased, boundErased) + ) } /** diff --git a/java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll b/java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll index 46bcc3a2201..6c92f7298d9 100644 --- a/java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll +++ b/java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll @@ -22,6 +22,17 @@ module MkUnification Date: Tue, 14 Feb 2023 17:34:47 +0000 Subject: [PATCH 239/415] Upgrade Go extractor compiler and dependency versions --- go/go.mod | 6 +- go/go.sum | 6 + go/vendor/golang.org/x/mod/modfile/read.go | 2 +- go/vendor/golang.org/x/mod/modfile/rule.go | 3 + go/vendor/golang.org/x/mod/module/module.go | 4 +- .../golang.org/x/sys/execabs/execabs_go119.go | 8 +- .../x/tools/go/gcexportdata/gcexportdata.go | 32 +- .../go/internal/gcimporter/gcimporter.go | 1125 ----------------- .../golang.org/x/tools/go/packages/golist.go | 22 +- .../x/tools/go/packages/packages.go | 87 +- .../{go => }/internal/gcimporter/bexport.go | 9 +- .../{go => }/internal/gcimporter/bimport.go | 0 .../internal/gcimporter/exportdata.go | 0 .../x/tools/internal/gcimporter/gcimporter.go | 265 ++++ .../{go => }/internal/gcimporter/iexport.go | 198 ++- .../{go => }/internal/gcimporter/iimport.go | 112 +- .../internal/gcimporter/newInterface10.go | 0 .../internal/gcimporter/newInterface11.go | 0 .../internal/gcimporter/support_go117.go | 0 .../internal/gcimporter/support_go118.go | 14 + .../internal/gcimporter/unified_no.go | 0 .../internal/gcimporter/unified_yes.go | 0 .../internal/gcimporter/ureader_no.go | 0 .../internal/gcimporter/ureader_yes.go | 220 +++- .../x/tools/internal/gocommand/invoke.go | 83 +- .../x/tools/internal/gocommand/version.go | 36 +- .../tools/{go => }/internal/pkgbits/codes.go | 0 .../{go => }/internal/pkgbits/decoder.go | 108 +- .../x/tools/{go => }/internal/pkgbits/doc.go | 0 .../{go => }/internal/pkgbits/encoder.go | 20 +- .../tools/{go => }/internal/pkgbits/flags.go | 0 .../{go => }/internal/pkgbits/frames_go1.go | 0 .../{go => }/internal/pkgbits/frames_go17.go | 0 .../tools/{go => }/internal/pkgbits/reloc.go | 4 +- .../{go => }/internal/pkgbits/support.go | 0 .../x/tools/{go => }/internal/pkgbits/sync.go | 0 .../internal/pkgbits/syncmarker_string.go | 0 .../internal/tokeninternal/tokeninternal.go | 59 + .../tools/internal/typesinternal/errorcode.go | 38 +- .../typesinternal/errorcode_string.go | 26 +- go/vendor/modules.txt | 11 +- 41 files changed, 1208 insertions(+), 1290 deletions(-) delete mode 100644 go/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/bexport.go (99%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/bimport.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/exportdata.go (100%) create mode 100644 go/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/iexport.go (78%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/iimport.go (86%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/newInterface10.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/newInterface11.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/support_go117.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/support_go118.go (62%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/unified_no.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/unified_yes.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/ureader_no.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/gcimporter/ureader_yes.go (70%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/codes.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/decoder.go (83%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/doc.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/encoder.go (95%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/flags.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/frames_go1.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/frames_go17.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/reloc.go (95%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/support.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/sync.go (100%) rename go/vendor/golang.org/x/tools/{go => }/internal/pkgbits/syncmarker_string.go (100%) create mode 100644 go/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go diff --git a/go/go.mod b/go/go.mod index 48bdb72b158..b8ef80e2c6c 100644 --- a/go/go.mod +++ b/go/go.mod @@ -3,11 +3,11 @@ module github.com/github/codeql-go go 1.18 require ( - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 - golang.org/x/tools v0.1.12 + golang.org/x/mod v0.8.0 + golang.org/x/tools v0.6.0 ) require ( - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/sys v0.5.0 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/go/go.sum b/go/go.sum index 9054efe904e..d92f42b1d05 100644 --- a/go/go.sum +++ b/go/go.sum @@ -6,6 +6,8 @@ golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -19,6 +21,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0v golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -28,6 +32,8 @@ golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/go/vendor/golang.org/x/mod/modfile/read.go b/go/vendor/golang.org/x/mod/modfile/read.go index 70947ee7794..a503bc2105d 100644 --- a/go/vendor/golang.org/x/mod/modfile/read.go +++ b/go/vendor/golang.org/x/mod/modfile/read.go @@ -494,7 +494,7 @@ func (in *input) endToken(kind tokenKind) { in.token.endPos = in.pos } -// peek returns the kind of the the next token returned by lex. +// peek returns the kind of the next token returned by lex. func (in *input) peek() tokenKind { return in.token.kind } diff --git a/go/vendor/golang.org/x/mod/modfile/rule.go b/go/vendor/golang.org/x/mod/modfile/rule.go index ed2f31aa70e..6bcde8fabe3 100644 --- a/go/vendor/golang.org/x/mod/modfile/rule.go +++ b/go/vendor/golang.org/x/mod/modfile/rule.go @@ -513,6 +513,9 @@ func parseReplace(filename string, line *Line, verb string, args []string, fix V nv := "" if len(args) == arrow+2 { if !IsDirectoryPath(ns) { + if strings.Contains(ns, "@") { + return nil, errorf("replacement module must match format 'path version', not 'path@version'") + } return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)") } if filepath.Separator == '/' && strings.Contains(ns, `\`) { diff --git a/go/vendor/golang.org/x/mod/module/module.go b/go/vendor/golang.org/x/mod/module/module.go index c26d1d29ec3..e9dec6e6148 100644 --- a/go/vendor/golang.org/x/mod/module/module.go +++ b/go/vendor/golang.org/x/mod/module/module.go @@ -96,13 +96,13 @@ package module // Changes to the semantics in this file require approval from rsc. import ( + "errors" "fmt" "path" "sort" "strings" "unicode" "unicode/utf8" - "errors" "golang.org/x/mod/semver" ) @@ -258,7 +258,7 @@ func modPathOK(r rune) bool { return false } -// modPathOK reports whether r can appear in a package import path element. +// importPathOK reports whether r can appear in a package import path element. // // Import paths are intermediate between module paths and file paths: we allow // disallow characters that would be confusing or ambiguous as arguments to diff --git a/go/vendor/golang.org/x/sys/execabs/execabs_go119.go b/go/vendor/golang.org/x/sys/execabs/execabs_go119.go index 1e7a9ada0b0..46c5b525e7b 100644 --- a/go/vendor/golang.org/x/sys/execabs/execabs_go119.go +++ b/go/vendor/golang.org/x/sys/execabs/execabs_go119.go @@ -7,9 +7,11 @@ package execabs -import "strings" +import ( + "errors" + "os/exec" +) func isGo119ErrDot(err error) bool { - // TODO: return errors.Is(err, exec.ErrDot) - return strings.Contains(err.Error(), "current directory") + return errors.Is(err, exec.ErrDot) } diff --git a/go/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/go/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go index 2ed25a75024..165ede0f8f3 100644 --- a/go/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go +++ b/go/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go @@ -27,10 +27,9 @@ import ( "go/token" "go/types" "io" - "io/ioutil" "os/exec" - "golang.org/x/tools/go/internal/gcimporter" + "golang.org/x/tools/internal/gcimporter" ) // Find returns the name of an object (.o) or archive (.a) file @@ -85,9 +84,26 @@ func NewReader(r io.Reader) (io.Reader, error) { } } +// readAll works the same way as io.ReadAll, but avoids allocations and copies +// by preallocating a byte slice of the necessary size if the size is known up +// front. This is always possible when the input is an archive. In that case, +// NewReader will return the known size using an io.LimitedReader. +func readAll(r io.Reader) ([]byte, error) { + if lr, ok := r.(*io.LimitedReader); ok { + data := make([]byte, lr.N) + _, err := io.ReadFull(lr, data) + return data, err + } + return io.ReadAll(r) +} + // Read reads export data from in, decodes it, and returns type // information for the package. -// The package name is specified by path. +// +// The package path (effectively its linker symbol prefix) is +// specified by path, since unlike the package name, this information +// may not be recorded in the export data. +// // File position information is added to fset. // // Read may inspect and add to the imports map to ensure that references @@ -98,7 +114,7 @@ func NewReader(r io.Reader) (io.Reader, error) { // // On return, the state of the reader is undefined. func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) { - data, err := ioutil.ReadAll(in) + data, err := readAll(in) if err != nil { return nil, fmt.Errorf("reading export data for %q: %v", path, err) } @@ -107,12 +123,6 @@ func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, return nil, fmt.Errorf("can't read export data for %q directly from an archive file (call gcexportdata.NewReader first to extract export data)", path) } - // The App Engine Go runtime v1.6 uses the old export data format. - // TODO(adonovan): delete once v1.7 has been around for a while. - if bytes.HasPrefix(data, []byte("package ")) { - return gcimporter.ImportData(imports, path, path, bytes.NewReader(data)) - } - // The indexed export format starts with an 'i'; the older // binary export format starts with a 'c', 'd', or 'v' // (from "version"). Select appropriate importer. @@ -161,7 +171,7 @@ func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error { // // Experimental: This API is experimental and may change in the future. func ReadBundle(in io.Reader, fset *token.FileSet, imports map[string]*types.Package) ([]*types.Package, error) { - data, err := ioutil.ReadAll(in) + data, err := readAll(in) if err != nil { return nil, fmt.Errorf("reading export bundle: %v", err) } diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go b/go/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go deleted file mode 100644 index e96c39600d1..00000000000 --- a/go/vendor/golang.org/x/tools/go/internal/gcimporter/gcimporter.go +++ /dev/null @@ -1,1125 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file is a modified copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go, -// but it also contains the original source-based importer code for Go1.6. -// Once we stop supporting 1.6, we can remove that code. - -// Package gcimporter provides various functions for reading -// gc-generated object files that can be used to implement the -// Importer interface defined by the Go 1.5 standard library package. -package gcimporter // import "golang.org/x/tools/go/internal/gcimporter" - -import ( - "bufio" - "errors" - "fmt" - "go/build" - "go/constant" - "go/token" - "go/types" - "io" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - "text/scanner" -) - -const ( - // Enable debug during development: it adds some additional checks, and - // prevents errors from being recovered. - debug = false - - // If trace is set, debugging output is printed to std out. - trace = false -) - -var pkgExts = [...]string{".a", ".o"} - -// FindPkg returns the filename and unique package id for an import -// path based on package information provided by build.Import (using -// the build.Default build.Context). A relative srcDir is interpreted -// relative to the current working directory. -// If no file was found, an empty filename is returned. -func FindPkg(path, srcDir string) (filename, id string) { - if path == "" { - return - } - - var noext string - switch { - default: - // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" - // Don't require the source files to be present. - if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 - srcDir = abs - } - bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) - if bp.PkgObj == "" { - id = path // make sure we have an id to print in error message - return - } - noext = strings.TrimSuffix(bp.PkgObj, ".a") - id = bp.ImportPath - - case build.IsLocalImport(path): - // "./x" -> "/this/directory/x.ext", "/this/directory/x" - noext = filepath.Join(srcDir, path) - id = noext - - case filepath.IsAbs(path): - // for completeness only - go/build.Import - // does not support absolute imports - // "/x" -> "/x.ext", "/x" - noext = path - id = path - } - - if false { // for debugging - if path != id { - fmt.Printf("%s -> %s\n", path, id) - } - } - - // try extensions - for _, ext := range pkgExts { - filename = noext + ext - if f, err := os.Stat(filename); err == nil && !f.IsDir() { - return - } - } - - filename = "" // not found - return -} - -// ImportData imports a package by reading the gc-generated export data, -// adds the corresponding package object to the packages map indexed by id, -// and returns the object. -// -// The packages map must contains all packages already imported. The data -// reader position must be the beginning of the export data section. The -// filename is only used in error messages. -// -// If packages[id] contains the completely imported package, that package -// can be used directly, and there is no need to call this function (but -// there is also no harm but for extra time used). -func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) { - // support for parser error handling - defer func() { - switch r := recover().(type) { - case nil: - // nothing to do - case importError: - err = r - default: - panic(r) // internal error - } - }() - - var p parser - p.init(filename, id, data, packages) - pkg = p.parseExport() - - return -} - -// Import imports a gc-generated package given its import path and srcDir, adds -// the corresponding package object to the packages map, and returns the object. -// The packages map must contain all packages already imported. -func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { - var rc io.ReadCloser - var filename, id string - if lookup != nil { - // With custom lookup specified, assume that caller has - // converted path to a canonical import path for use in the map. - if path == "unsafe" { - return types.Unsafe, nil - } - id = path - - // No need to re-import if the package was imported completely before. - if pkg = packages[id]; pkg != nil && pkg.Complete() { - return - } - f, err := lookup(path) - if err != nil { - return nil, err - } - rc = f - } else { - filename, id = FindPkg(path, srcDir) - if filename == "" { - if path == "unsafe" { - return types.Unsafe, nil - } - return nil, fmt.Errorf("can't find import: %q", id) - } - - // no need to re-import if the package was imported completely before - if pkg = packages[id]; pkg != nil && pkg.Complete() { - return - } - - // open file - f, err := os.Open(filename) - if err != nil { - return nil, err - } - defer func() { - if err != nil { - // add file name to error - err = fmt.Errorf("%s: %v", filename, err) - } - }() - rc = f - } - defer rc.Close() - - var hdr string - var size int64 - buf := bufio.NewReader(rc) - if hdr, size, err = FindExportData(buf); err != nil { - return - } - - switch hdr { - case "$$\n": - // Work-around if we don't have a filename; happens only if lookup != nil. - // Either way, the filename is only needed for importer error messages, so - // this is fine. - if filename == "" { - filename = path - } - return ImportData(packages, filename, id, buf) - - case "$$B\n": - var data []byte - data, err = ioutil.ReadAll(buf) - if err != nil { - break - } - - // TODO(gri): allow clients of go/importer to provide a FileSet. - // Or, define a new standard go/types/gcexportdata package. - fset := token.NewFileSet() - - // The indexed export format starts with an 'i'; the older - // binary export format starts with a 'c', 'd', or 'v' - // (from "version"). Select appropriate importer. - if len(data) > 0 { - switch data[0] { - case 'i': - _, pkg, err := IImportData(fset, packages, data[1:], id) - return pkg, err - - case 'v', 'c', 'd': - _, pkg, err := BImportData(fset, packages, data, id) - return pkg, err - - case 'u': - _, pkg, err := UImportData(fset, packages, data[1:size], id) - return pkg, err - - default: - l := len(data) - if l > 10 { - l = 10 - } - return nil, fmt.Errorf("unexpected export data with prefix %q for path %s", string(data[:l]), id) - } - } - - default: - err = fmt.Errorf("unknown export data header: %q", hdr) - } - - return -} - -// ---------------------------------------------------------------------------- -// Parser - -// TODO(gri) Imported objects don't have position information. -// Ideally use the debug table line info; alternatively -// create some fake position (or the position of the -// import). That way error messages referring to imported -// objects can print meaningful information. - -// parser parses the exports inside a gc compiler-produced -// object/archive file and populates its scope with the results. -type parser struct { - scanner scanner.Scanner - tok rune // current token - lit string // literal string; only valid for Ident, Int, String tokens - id string // package id of imported package - sharedPkgs map[string]*types.Package // package id -> package object (across importer) - localPkgs map[string]*types.Package // package id -> package object (just this package) -} - -func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) { - p.scanner.Init(src) - p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) } - p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments - p.scanner.Whitespace = 1<<'\t' | 1<<' ' - p.scanner.Filename = filename // for good error messages - p.next() - p.id = id - p.sharedPkgs = packages - if debug { - // check consistency of packages map - for _, pkg := range packages { - if pkg.Name() == "" { - fmt.Printf("no package name for %s\n", pkg.Path()) - } - } - } -} - -func (p *parser) next() { - p.tok = p.scanner.Scan() - switch p.tok { - case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·': - p.lit = p.scanner.TokenText() - default: - p.lit = "" - } - if debug { - fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit) - } -} - -func declTypeName(pkg *types.Package, name string) *types.TypeName { - scope := pkg.Scope() - if obj := scope.Lookup(name); obj != nil { - return obj.(*types.TypeName) - } - obj := types.NewTypeName(token.NoPos, pkg, name, nil) - // a named type may be referred to before the underlying type - // is known - set it up - types.NewNamed(obj, nil, nil) - scope.Insert(obj) - return obj -} - -// ---------------------------------------------------------------------------- -// Error handling - -// Internal errors are boxed as importErrors. -type importError struct { - pos scanner.Position - err error -} - -func (e importError) Error() string { - return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err) -} - -func (p *parser) error(err interface{}) { - if s, ok := err.(string); ok { - err = errors.New(s) - } - // panic with a runtime.Error if err is not an error - panic(importError{p.scanner.Pos(), err.(error)}) -} - -func (p *parser) errorf(format string, args ...interface{}) { - p.error(fmt.Sprintf(format, args...)) -} - -func (p *parser) expect(tok rune) string { - lit := p.lit - if p.tok != tok { - p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit) - } - p.next() - return lit -} - -func (p *parser) expectSpecial(tok string) { - sep := 'x' // not white space - i := 0 - for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' { - sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token - p.next() - i++ - } - if i < len(tok) { - p.errorf("expected %q, got %q", tok, tok[0:i]) - } -} - -func (p *parser) expectKeyword(keyword string) { - lit := p.expect(scanner.Ident) - if lit != keyword { - p.errorf("expected keyword %s, got %q", keyword, lit) - } -} - -// ---------------------------------------------------------------------------- -// Qualified and unqualified names - -// parsePackageID parses a PackageId: -// -// PackageId = string_lit . -func (p *parser) parsePackageID() string { - id, err := strconv.Unquote(p.expect(scanner.String)) - if err != nil { - p.error(err) - } - // id == "" stands for the imported package id - // (only known at time of package installation) - if id == "" { - id = p.id - } - return id -} - -// parsePackageName parse a PackageName: -// -// PackageName = ident . -func (p *parser) parsePackageName() string { - return p.expect(scanner.Ident) -} - -// parseDotIdent parses a dotIdentifier: -// -// dotIdentifier = ( ident | '·' ) { ident | int | '·' } . -func (p *parser) parseDotIdent() string { - ident := "" - if p.tok != scanner.Int { - sep := 'x' // not white space - for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' { - ident += p.lit - sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token - p.next() - } - } - if ident == "" { - p.expect(scanner.Ident) // use expect() for error handling - } - return ident -} - -// parseQualifiedName parses a QualifiedName: -// -// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) . -func (p *parser) parseQualifiedName() (id, name string) { - p.expect('@') - id = p.parsePackageID() - p.expect('.') - // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields. - if p.tok == '?' { - p.next() - } else { - name = p.parseDotIdent() - } - return -} - -// getPkg returns the package for a given id. If the package is -// not found, create the package and add it to the p.localPkgs -// and p.sharedPkgs maps. name is the (expected) name of the -// package. If name == "", the package name is expected to be -// set later via an import clause in the export data. -// -// id identifies a package, usually by a canonical package path like -// "encoding/json" but possibly by a non-canonical import path like -// "./json". -func (p *parser) getPkg(id, name string) *types.Package { - // package unsafe is not in the packages maps - handle explicitly - if id == "unsafe" { - return types.Unsafe - } - - pkg := p.localPkgs[id] - if pkg == nil { - // first import of id from this package - pkg = p.sharedPkgs[id] - if pkg == nil { - // first import of id by this importer; - // add (possibly unnamed) pkg to shared packages - pkg = types.NewPackage(id, name) - p.sharedPkgs[id] = pkg - } - // add (possibly unnamed) pkg to local packages - if p.localPkgs == nil { - p.localPkgs = make(map[string]*types.Package) - } - p.localPkgs[id] = pkg - } else if name != "" { - // package exists already and we have an expected package name; - // make sure names match or set package name if necessary - if pname := pkg.Name(); pname == "" { - pkg.SetName(name) - } else if pname != name { - p.errorf("%s package name mismatch: %s (given) vs %s (expected)", id, pname, name) - } - } - return pkg -} - -// parseExportedName is like parseQualifiedName, but -// the package id is resolved to an imported *types.Package. -func (p *parser) parseExportedName() (pkg *types.Package, name string) { - id, name := p.parseQualifiedName() - pkg = p.getPkg(id, "") - return -} - -// ---------------------------------------------------------------------------- -// Types - -// parseBasicType parses a BasicType: -// -// BasicType = identifier . -func (p *parser) parseBasicType() types.Type { - id := p.expect(scanner.Ident) - obj := types.Universe.Lookup(id) - if obj, ok := obj.(*types.TypeName); ok { - return obj.Type() - } - p.errorf("not a basic type: %s", id) - return nil -} - -// parseArrayType parses an ArrayType: -// -// ArrayType = "[" int_lit "]" Type . -func (p *parser) parseArrayType(parent *types.Package) types.Type { - // "[" already consumed and lookahead known not to be "]" - lit := p.expect(scanner.Int) - p.expect(']') - elem := p.parseType(parent) - n, err := strconv.ParseInt(lit, 10, 64) - if err != nil { - p.error(err) - } - return types.NewArray(elem, n) -} - -// parseMapType parses a MapType: -// -// MapType = "map" "[" Type "]" Type . -func (p *parser) parseMapType(parent *types.Package) types.Type { - p.expectKeyword("map") - p.expect('[') - key := p.parseType(parent) - p.expect(']') - elem := p.parseType(parent) - return types.NewMap(key, elem) -} - -// parseName parses a Name: -// -// Name = identifier | "?" | QualifiedName . -// -// For unqualified and anonymous names, the returned package is the parent -// package unless parent == nil, in which case the returned package is the -// package being imported. (The parent package is not nil if the name -// is an unqualified struct field or interface method name belonging to a -// type declared in another package.) -// -// For qualified names, the returned package is nil (and not created if -// it doesn't exist yet) unless materializePkg is set (which creates an -// unnamed package with valid package path). In the latter case, a -// subsequent import clause is expected to provide a name for the package. -func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) { - pkg = parent - if pkg == nil { - pkg = p.sharedPkgs[p.id] - } - switch p.tok { - case scanner.Ident: - name = p.lit - p.next() - case '?': - // anonymous - p.next() - case '@': - // exported name prefixed with package path - pkg = nil - var id string - id, name = p.parseQualifiedName() - if materializePkg { - pkg = p.getPkg(id, "") - } - default: - p.error("name expected") - } - return -} - -func deref(typ types.Type) types.Type { - if p, _ := typ.(*types.Pointer); p != nil { - return p.Elem() - } - return typ -} - -// parseField parses a Field: -// -// Field = Name Type [ string_lit ] . -func (p *parser) parseField(parent *types.Package) (*types.Var, string) { - pkg, name := p.parseName(parent, true) - - if name == "_" { - // Blank fields should be package-qualified because they - // are unexported identifiers, but gc does not qualify them. - // Assuming that the ident belongs to the current package - // causes types to change during re-exporting, leading - // to spurious "can't assign A to B" errors from go/types. - // As a workaround, pretend all blank fields belong - // to the same unique dummy package. - const blankpkg = "<_>" - pkg = p.getPkg(blankpkg, blankpkg) - } - - typ := p.parseType(parent) - anonymous := false - if name == "" { - // anonymous field - typ must be T or *T and T must be a type name - switch typ := deref(typ).(type) { - case *types.Basic: // basic types are named types - pkg = nil // objects defined in Universe scope have no package - name = typ.Name() - case *types.Named: - name = typ.Obj().Name() - default: - p.errorf("anonymous field expected") - } - anonymous = true - } - tag := "" - if p.tok == scanner.String { - s := p.expect(scanner.String) - var err error - tag, err = strconv.Unquote(s) - if err != nil { - p.errorf("invalid struct tag %s: %s", s, err) - } - } - return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag -} - -// parseStructType parses a StructType: -// -// StructType = "struct" "{" [ FieldList ] "}" . -// FieldList = Field { ";" Field } . -func (p *parser) parseStructType(parent *types.Package) types.Type { - var fields []*types.Var - var tags []string - - p.expectKeyword("struct") - p.expect('{') - for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { - if i > 0 { - p.expect(';') - } - fld, tag := p.parseField(parent) - if tag != "" && tags == nil { - tags = make([]string, i) - } - if tags != nil { - tags = append(tags, tag) - } - fields = append(fields, fld) - } - p.expect('}') - - return types.NewStruct(fields, tags) -} - -// parseParameter parses a Parameter: -// -// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] . -func (p *parser) parseParameter() (par *types.Var, isVariadic bool) { - _, name := p.parseName(nil, false) - // remove gc-specific parameter numbering - if i := strings.Index(name, "·"); i >= 0 { - name = name[:i] - } - if p.tok == '.' { - p.expectSpecial("...") - isVariadic = true - } - typ := p.parseType(nil) - if isVariadic { - typ = types.NewSlice(typ) - } - // ignore argument tag (e.g. "noescape") - if p.tok == scanner.String { - p.next() - } - // TODO(gri) should we provide a package? - par = types.NewVar(token.NoPos, nil, name, typ) - return -} - -// parseParameters parses a Parameters: -// -// Parameters = "(" [ ParameterList ] ")" . -// ParameterList = { Parameter "," } Parameter . -func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) { - p.expect('(') - for p.tok != ')' && p.tok != scanner.EOF { - if len(list) > 0 { - p.expect(',') - } - par, variadic := p.parseParameter() - list = append(list, par) - if variadic { - if isVariadic { - p.error("... not on final argument") - } - isVariadic = true - } - } - p.expect(')') - - return -} - -// parseSignature parses a Signature: -// -// Signature = Parameters [ Result ] . -// Result = Type | Parameters . -func (p *parser) parseSignature(recv *types.Var) *types.Signature { - params, isVariadic := p.parseParameters() - - // optional result type - var results []*types.Var - if p.tok == '(' { - var variadic bool - results, variadic = p.parseParameters() - if variadic { - p.error("... not permitted on result type") - } - } - - return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic) -} - -// parseInterfaceType parses an InterfaceType: -// -// InterfaceType = "interface" "{" [ MethodList ] "}" . -// MethodList = Method { ";" Method } . -// Method = Name Signature . -// -// The methods of embedded interfaces are always "inlined" -// by the compiler and thus embedded interfaces are never -// visible in the export data. -func (p *parser) parseInterfaceType(parent *types.Package) types.Type { - var methods []*types.Func - - p.expectKeyword("interface") - p.expect('{') - for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { - if i > 0 { - p.expect(';') - } - pkg, name := p.parseName(parent, true) - sig := p.parseSignature(nil) - methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig)) - } - p.expect('}') - - // Complete requires the type's embedded interfaces to be fully defined, - // but we do not define any - return newInterface(methods, nil).Complete() -} - -// parseChanType parses a ChanType: -// -// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type . -func (p *parser) parseChanType(parent *types.Package) types.Type { - dir := types.SendRecv - if p.tok == scanner.Ident { - p.expectKeyword("chan") - if p.tok == '<' { - p.expectSpecial("<-") - dir = types.SendOnly - } - } else { - p.expectSpecial("<-") - p.expectKeyword("chan") - dir = types.RecvOnly - } - elem := p.parseType(parent) - return types.NewChan(dir, elem) -} - -// parseType parses a Type: -// -// Type = -// BasicType | TypeName | ArrayType | SliceType | StructType | -// PointerType | FuncType | InterfaceType | MapType | ChanType | -// "(" Type ")" . -// -// BasicType = ident . -// TypeName = ExportedName . -// SliceType = "[" "]" Type . -// PointerType = "*" Type . -// FuncType = "func" Signature . -func (p *parser) parseType(parent *types.Package) types.Type { - switch p.tok { - case scanner.Ident: - switch p.lit { - default: - return p.parseBasicType() - case "struct": - return p.parseStructType(parent) - case "func": - // FuncType - p.next() - return p.parseSignature(nil) - case "interface": - return p.parseInterfaceType(parent) - case "map": - return p.parseMapType(parent) - case "chan": - return p.parseChanType(parent) - } - case '@': - // TypeName - pkg, name := p.parseExportedName() - return declTypeName(pkg, name).Type() - case '[': - p.next() // look ahead - if p.tok == ']' { - // SliceType - p.next() - return types.NewSlice(p.parseType(parent)) - } - return p.parseArrayType(parent) - case '*': - // PointerType - p.next() - return types.NewPointer(p.parseType(parent)) - case '<': - return p.parseChanType(parent) - case '(': - // "(" Type ")" - p.next() - typ := p.parseType(parent) - p.expect(')') - return typ - } - p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit) - return nil -} - -// ---------------------------------------------------------------------------- -// Declarations - -// parseImportDecl parses an ImportDecl: -// -// ImportDecl = "import" PackageName PackageId . -func (p *parser) parseImportDecl() { - p.expectKeyword("import") - name := p.parsePackageName() - p.getPkg(p.parsePackageID(), name) -} - -// parseInt parses an int_lit: -// -// int_lit = [ "+" | "-" ] { "0" ... "9" } . -func (p *parser) parseInt() string { - s := "" - switch p.tok { - case '-': - s = "-" - p.next() - case '+': - p.next() - } - return s + p.expect(scanner.Int) -} - -// parseNumber parses a number: -// -// number = int_lit [ "p" int_lit ] . -func (p *parser) parseNumber() (typ *types.Basic, val constant.Value) { - // mantissa - mant := constant.MakeFromLiteral(p.parseInt(), token.INT, 0) - if mant == nil { - panic("invalid mantissa") - } - - if p.lit == "p" { - // exponent (base 2) - p.next() - exp, err := strconv.ParseInt(p.parseInt(), 10, 0) - if err != nil { - p.error(err) - } - if exp < 0 { - denom := constant.MakeInt64(1) - denom = constant.Shift(denom, token.SHL, uint(-exp)) - typ = types.Typ[types.UntypedFloat] - val = constant.BinaryOp(mant, token.QUO, denom) - return - } - if exp > 0 { - mant = constant.Shift(mant, token.SHL, uint(exp)) - } - typ = types.Typ[types.UntypedFloat] - val = mant - return - } - - typ = types.Typ[types.UntypedInt] - val = mant - return -} - -// parseConstDecl parses a ConstDecl: -// -// ConstDecl = "const" ExportedName [ Type ] "=" Literal . -// Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit . -// bool_lit = "true" | "false" . -// complex_lit = "(" float_lit "+" float_lit "i" ")" . -// rune_lit = "(" int_lit "+" int_lit ")" . -// string_lit = `"` { unicode_char } `"` . -func (p *parser) parseConstDecl() { - p.expectKeyword("const") - pkg, name := p.parseExportedName() - - var typ0 types.Type - if p.tok != '=' { - // constant types are never structured - no need for parent type - typ0 = p.parseType(nil) - } - - p.expect('=') - var typ types.Type - var val constant.Value - switch p.tok { - case scanner.Ident: - // bool_lit - if p.lit != "true" && p.lit != "false" { - p.error("expected true or false") - } - typ = types.Typ[types.UntypedBool] - val = constant.MakeBool(p.lit == "true") - p.next() - - case '-', scanner.Int: - // int_lit - typ, val = p.parseNumber() - - case '(': - // complex_lit or rune_lit - p.next() - if p.tok == scanner.Char { - p.next() - p.expect('+') - typ = types.Typ[types.UntypedRune] - _, val = p.parseNumber() - p.expect(')') - break - } - _, re := p.parseNumber() - p.expect('+') - _, im := p.parseNumber() - p.expectKeyword("i") - p.expect(')') - typ = types.Typ[types.UntypedComplex] - val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) - - case scanner.Char: - // rune_lit - typ = types.Typ[types.UntypedRune] - val = constant.MakeFromLiteral(p.lit, token.CHAR, 0) - p.next() - - case scanner.String: - // string_lit - typ = types.Typ[types.UntypedString] - val = constant.MakeFromLiteral(p.lit, token.STRING, 0) - p.next() - - default: - p.errorf("expected literal got %s", scanner.TokenString(p.tok)) - } - - if typ0 == nil { - typ0 = typ - } - - pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val)) -} - -// parseTypeDecl parses a TypeDecl: -// -// TypeDecl = "type" ExportedName Type . -func (p *parser) parseTypeDecl() { - p.expectKeyword("type") - pkg, name := p.parseExportedName() - obj := declTypeName(pkg, name) - - // The type object may have been imported before and thus already - // have a type associated with it. We still need to parse the type - // structure, but throw it away if the object already has a type. - // This ensures that all imports refer to the same type object for - // a given type declaration. - typ := p.parseType(pkg) - - if name := obj.Type().(*types.Named); name.Underlying() == nil { - name.SetUnderlying(typ) - } -} - -// parseVarDecl parses a VarDecl: -// -// VarDecl = "var" ExportedName Type . -func (p *parser) parseVarDecl() { - p.expectKeyword("var") - pkg, name := p.parseExportedName() - typ := p.parseType(pkg) - pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ)) -} - -// parseFunc parses a Func: -// -// Func = Signature [ Body ] . -// Body = "{" ... "}" . -func (p *parser) parseFunc(recv *types.Var) *types.Signature { - sig := p.parseSignature(recv) - if p.tok == '{' { - p.next() - for i := 1; i > 0; p.next() { - switch p.tok { - case '{': - i++ - case '}': - i-- - } - } - } - return sig -} - -// parseMethodDecl parses a MethodDecl: -// -// MethodDecl = "func" Receiver Name Func . -// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" . -func (p *parser) parseMethodDecl() { - // "func" already consumed - p.expect('(') - recv, _ := p.parseParameter() // receiver - p.expect(')') - - // determine receiver base type object - base := deref(recv.Type()).(*types.Named) - - // parse method name, signature, and possibly inlined body - _, name := p.parseName(nil, false) - sig := p.parseFunc(recv) - - // methods always belong to the same package as the base type object - pkg := base.Obj().Pkg() - - // add method to type unless type was imported before - // and method exists already - // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small. - base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) -} - -// parseFuncDecl parses a FuncDecl: -// -// FuncDecl = "func" ExportedName Func . -func (p *parser) parseFuncDecl() { - // "func" already consumed - pkg, name := p.parseExportedName() - typ := p.parseFunc(nil) - pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ)) -} - -// parseDecl parses a Decl: -// -// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" . -func (p *parser) parseDecl() { - if p.tok == scanner.Ident { - switch p.lit { - case "import": - p.parseImportDecl() - case "const": - p.parseConstDecl() - case "type": - p.parseTypeDecl() - case "var": - p.parseVarDecl() - case "func": - p.next() // look ahead - if p.tok == '(' { - p.parseMethodDecl() - } else { - p.parseFuncDecl() - } - } - } - p.expect('\n') -} - -// ---------------------------------------------------------------------------- -// Export - -// parseExport parses an Export: -// -// Export = "PackageClause { Decl } "$$" . -// PackageClause = "package" PackageName [ "safe" ] "\n" . -func (p *parser) parseExport() *types.Package { - p.expectKeyword("package") - name := p.parsePackageName() - if p.tok == scanner.Ident && p.lit == "safe" { - // package was compiled with -u option - ignore - p.next() - } - p.expect('\n') - - pkg := p.getPkg(p.id, name) - - for p.tok != '$' && p.tok != scanner.EOF { - p.parseDecl() - } - - if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' { - // don't call next()/expect() since reading past the - // export data may cause scanner errors (e.g. NUL chars) - p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch) - } - - if n := p.scanner.ErrorCount; n != 0 { - p.errorf("expected no scanner errors, got %d", n) - } - - // Record all locally referenced packages as imports. - var imports []*types.Package - for id, pkg2 := range p.localPkgs { - if pkg2.Name() == "" { - p.errorf("%s package has no name", id) - } - if id == p.id { - continue // avoid self-edge - } - imports = append(imports, pkg2) - } - sort.Sort(byPath(imports)) - pkg.SetImports(imports) - - // package was imported completely and without errors - pkg.MarkComplete() - - return pkg -} - -type byPath []*types.Package - -func (a byPath) Len() int { return len(a) } -func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } diff --git a/go/vendor/golang.org/x/tools/go/packages/golist.go b/go/vendor/golang.org/x/tools/go/packages/golist.go index de881562de1..6bb7168d2e3 100644 --- a/go/vendor/golang.org/x/tools/go/packages/golist.go +++ b/go/vendor/golang.org/x/tools/go/packages/golist.go @@ -60,6 +60,7 @@ func (r *responseDeduper) addAll(dr *driverResponse) { for _, root := range dr.Roots { r.addRoot(root) } + r.dr.GoVersion = dr.GoVersion } func (r *responseDeduper) addPackage(p *Package) { @@ -454,11 +455,14 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse if err != nil { return nil, err } + seen := make(map[string]*jsonPackage) pkgs := make(map[string]*Package) additionalErrors := make(map[string][]Error) // Decode the JSON and convert it to Package form. - var response driverResponse + response := &driverResponse{ + GoVersion: goVersion, + } for dec := json.NewDecoder(buf); dec.More(); { p := new(jsonPackage) if err := dec.Decode(p); err != nil { @@ -600,17 +604,12 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse // Work around https://golang.org/issue/28749: // cmd/go puts assembly, C, and C++ files in CompiledGoFiles. - // Filter out any elements of CompiledGoFiles that are also in OtherFiles. - // We have to keep this workaround in place until go1.12 is a distant memory. - if len(pkg.OtherFiles) > 0 { - other := make(map[string]bool, len(pkg.OtherFiles)) - for _, f := range pkg.OtherFiles { - other[f] = true - } - + // Remove files from CompiledGoFiles that are non-go files + // (or are not files that look like they are from the cache). + if len(pkg.CompiledGoFiles) > 0 { out := pkg.CompiledGoFiles[:0] for _, f := range pkg.CompiledGoFiles { - if other[f] { + if ext := filepath.Ext(f); ext != ".go" && ext != "" { // ext == "" means the file is from the cache, so probably cgo-processed file continue } out = append(out, f) @@ -730,7 +729,7 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse } sort.Slice(response.Packages, func(i, j int) bool { return response.Packages[i].ID < response.Packages[j].ID }) - return &response, nil + return response, nil } func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool { @@ -756,6 +755,7 @@ func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool { return len(p.Error.ImportStack) == 0 || p.Error.ImportStack[len(p.Error.ImportStack)-1] == p.ImportPath } +// getGoVersion returns the effective minor version of the go command. func (state *golistState) getGoVersion() (int, error) { state.goVersionOnce.Do(func() { state.goVersion, state.goVersionError = gocommand.GoVersion(state.ctx, state.cfgInvocation(), state.cfg.gocmdRunner) diff --git a/go/vendor/golang.org/x/tools/go/packages/packages.go b/go/vendor/golang.org/x/tools/go/packages/packages.go index a93dc6add4d..0f1505b808a 100644 --- a/go/vendor/golang.org/x/tools/go/packages/packages.go +++ b/go/vendor/golang.org/x/tools/go/packages/packages.go @@ -15,10 +15,12 @@ import ( "go/scanner" "go/token" "go/types" + "io" "io/ioutil" "log" "os" "path/filepath" + "runtime" "strings" "sync" "time" @@ -233,6 +235,11 @@ type driverResponse struct { // Imports will be connected and then type and syntax information added in a // later pass (see refine). Packages []*Package + + // GoVersion is the minor version number used by the driver + // (e.g. the go command on the PATH) when selecting .go files. + // Zero means unknown. + GoVersion int } // Load loads and returns the Go packages named by the given patterns. @@ -256,7 +263,7 @@ func Load(cfg *Config, patterns ...string) ([]*Package, error) { return nil, err } l.sizes = response.Sizes - return l.refine(response.Roots, response.Packages...) + return l.refine(response) } // defaultDriver is a driver that implements go/packages' fallback behavior. @@ -297,6 +304,9 @@ type Package struct { // of the package, or while parsing or type-checking its files. Errors []Error + // TypeErrors contains the subset of errors produced during type checking. + TypeErrors []types.Error + // GoFiles lists the absolute file paths of the package's Go source files. GoFiles []string @@ -532,6 +542,7 @@ type loaderPackage struct { needsrc bool // load from source (Mode >= LoadTypes) needtypes bool // type information is either requested or depended on initial bool // package was matched by a pattern + goVersion int // minor version number of go command on PATH } // loader holds the working state of a single call to load. @@ -618,7 +629,8 @@ func newLoader(cfg *Config) *loader { // refine connects the supplied packages into a graph and then adds type and // and syntax information as requested by the LoadMode. -func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { +func (ld *loader) refine(response *driverResponse) ([]*Package, error) { + roots := response.Roots rootMap := make(map[string]int, len(roots)) for i, root := range roots { rootMap[root] = i @@ -626,7 +638,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { ld.pkgs = make(map[string]*loaderPackage) // first pass, fixup and build the map and roots var initial = make([]*loaderPackage, len(roots)) - for _, pkg := range list { + for _, pkg := range response.Packages { rootIndex := -1 if i, found := rootMap[pkg.ID]; found { rootIndex = i @@ -648,6 +660,7 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { Package: pkg, needtypes: needtypes, needsrc: needsrc, + goVersion: response.GoVersion, } ld.pkgs[lpkg.ID] = lpkg if rootIndex >= 0 { @@ -865,12 +878,19 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { // never has to create a types.Package for an indirect dependency, // which would then require that such created packages be explicitly // inserted back into the Import graph as a final step after export data loading. + // (Hence this return is after the Types assignment.) // The Diamond test exercises this case. if !lpkg.needtypes && !lpkg.needsrc { return } if !lpkg.needsrc { - ld.loadFromExportData(lpkg) + if err := ld.loadFromExportData(lpkg); err != nil { + lpkg.Errors = append(lpkg.Errors, Error{ + Pos: "-", + Msg: err.Error(), + Kind: UnknownError, // e.g. can't find/open/parse export data + }) + } return // not a source package, don't get syntax trees } @@ -902,6 +922,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { case types.Error: // from type checker + lpkg.TypeErrors = append(lpkg.TypeErrors, err) errs = append(errs, Error{ Pos: err.Fset.Position(err.Pos).String(), Msg: err.Msg, @@ -923,11 +944,41 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { lpkg.Errors = append(lpkg.Errors, errs...) } + // If the go command on the PATH is newer than the runtime, + // then the go/{scanner,ast,parser,types} packages from the + // standard library may be unable to process the files + // selected by go list. + // + // There is currently no way to downgrade the effective + // version of the go command (see issue 52078), so we proceed + // with the newer go command but, in case of parse or type + // errors, we emit an additional diagnostic. + // + // See: + // - golang.org/issue/52078 (flag to set release tags) + // - golang.org/issue/50825 (gopls legacy version support) + // - golang.org/issue/55883 (go/packages confusing error) + // + // Should we assert a hard minimum of (currently) go1.16 here? + var runtimeVersion int + if _, err := fmt.Sscanf(runtime.Version(), "go1.%d", &runtimeVersion); err == nil && runtimeVersion < lpkg.goVersion { + defer func() { + if len(lpkg.Errors) > 0 { + appendError(Error{ + Pos: "-", + Msg: fmt.Sprintf("This application uses version go1.%d of the source-processing packages but runs version go1.%d of 'go list'. It may fail to process source files that rely on newer language features. If so, rebuild the application using a newer version of Go.", runtimeVersion, lpkg.goVersion), + Kind: UnknownError, + }) + } + }() + } + if ld.Config.Mode&NeedTypes != 0 && len(lpkg.CompiledGoFiles) == 0 && lpkg.ExportFile != "" { // The config requested loading sources and types, but sources are missing. // Add an error to the package and fall back to loading from export data. appendError(Error{"-", fmt.Sprintf("sources missing for package %s", lpkg.ID), ParseError}) - ld.loadFromExportData(lpkg) + _ = ld.loadFromExportData(lpkg) // ignore any secondary errors + return // can't get syntax trees for this package } @@ -981,7 +1032,7 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { tc := &types.Config{ Importer: importer, - // Type-check bodies of functions only in non-initial packages. + // Type-check bodies of functions only in initial packages. // Example: for import graph A->B->C and initial packages {A,C}, // we can ignore function bodies in B. IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial, @@ -1151,9 +1202,10 @@ func sameFile(x, y string) bool { return false } -// loadFromExportData returns type information for the specified +// loadFromExportData ensures that type information is present for the specified // package, loading it from an export data file on the first request. -func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error) { +// On success it sets lpkg.Types to a new Package. +func (ld *loader) loadFromExportData(lpkg *loaderPackage) error { if lpkg.PkgPath == "" { log.Fatalf("internal error: Package %s has no PkgPath", lpkg) } @@ -1164,8 +1216,8 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error // must be sequential. (Finer-grained locking would require // changes to the gcexportdata API.) // - // The exportMu lock guards the Package.Pkg field and the - // types.Package it points to, for each Package in the graph. + // The exportMu lock guards the lpkg.Types field and the + // types.Package it points to, for each loaderPackage in the graph. // // Not all accesses to Package.Pkg need to be protected by exportMu: // graph ordering ensures that direct dependencies of source @@ -1174,18 +1226,18 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error defer ld.exportMu.Unlock() if tpkg := lpkg.Types; tpkg != nil && tpkg.Complete() { - return tpkg, nil // cache hit + return nil // cache hit } lpkg.IllTyped = true // fail safe if lpkg.ExportFile == "" { // Errors while building export data will have been printed to stderr. - return nil, fmt.Errorf("no export data file") + return fmt.Errorf("no export data file") } f, err := os.Open(lpkg.ExportFile) if err != nil { - return nil, err + return err } defer f.Close() @@ -1197,7 +1249,7 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error // queries.) r, err := gcexportdata.NewReader(f) if err != nil { - return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) + return fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) } // Build the view. @@ -1241,7 +1293,7 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error // (May modify incomplete packages in view but not create new ones.) tpkg, err := gcexportdata.Read(r, ld.Fset, view, lpkg.PkgPath) if err != nil { - return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) + return fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) } if _, ok := view["go.shape"]; ok { // Account for the pseudopackage "go.shape" that gets @@ -1254,8 +1306,7 @@ func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error lpkg.Types = tpkg lpkg.IllTyped = false - - return tpkg, nil + return nil } // impliedLoadMode returns loadMode with its dependencies. @@ -1271,3 +1322,5 @@ func impliedLoadMode(loadMode LoadMode) LoadMode { func usesExportData(cfg *Config) bool { return cfg.Mode&NeedExportFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedDeps == 0 } + +var _ interface{} = io.Discard // assert build toolchain is go1.16 or later diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go b/go/vendor/golang.org/x/tools/internal/gcimporter/bexport.go similarity index 99% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/bexport.go index 196cb3f9b41..30582ed6d3d 100644 --- a/go/vendor/golang.org/x/tools/go/internal/gcimporter/bexport.go +++ b/go/vendor/golang.org/x/tools/internal/gcimporter/bexport.go @@ -12,7 +12,6 @@ import ( "bytes" "encoding/binary" "fmt" - "go/ast" "go/constant" "go/token" "go/types" @@ -145,7 +144,7 @@ func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) objcount := 0 scope := pkg.Scope() for _, name := range scope.Names() { - if !ast.IsExported(name) { + if !token.IsExported(name) { continue } if trace { @@ -482,7 +481,7 @@ func (p *exporter) method(m *types.Func) { p.pos(m) p.string(m.Name()) - if m.Name() != "_" && !ast.IsExported(m.Name()) { + if m.Name() != "_" && !token.IsExported(m.Name()) { p.pkg(m.Pkg(), false) } @@ -501,7 +500,7 @@ func (p *exporter) fieldName(f *types.Var) { // 3) field name doesn't match base type name (alias name) bname := basetypeName(f.Type()) if name == bname { - if ast.IsExported(name) { + if token.IsExported(name) { name = "" // 1) we don't need to know the field name or package } else { name = "?" // 2) use unexported name "?" to force package export @@ -514,7 +513,7 @@ func (p *exporter) fieldName(f *types.Var) { } p.string(name) - if name != "" && !ast.IsExported(name) { + if name != "" && !token.IsExported(name) { p.pkg(f.Pkg(), false) } } diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go b/go/vendor/golang.org/x/tools/internal/gcimporter/bimport.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/bimport.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/bimport.go diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go b/go/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/exportdata.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go diff --git a/go/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go b/go/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go new file mode 100644 index 00000000000..0372fb3a646 --- /dev/null +++ b/go/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go @@ -0,0 +1,265 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file is a reduced copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go. + +// Package gcimporter provides various functions for reading +// gc-generated object files that can be used to implement the +// Importer interface defined by the Go 1.5 standard library package. +package gcimporter // import "golang.org/x/tools/internal/gcimporter" + +import ( + "bufio" + "bytes" + "fmt" + "go/build" + "go/token" + "go/types" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "sync" +) + +const ( + // Enable debug during development: it adds some additional checks, and + // prevents errors from being recovered. + debug = false + + // If trace is set, debugging output is printed to std out. + trace = false +) + +var exportMap sync.Map // package dir → func() (string, bool) + +// lookupGorootExport returns the location of the export data +// (normally found in the build cache, but located in GOROOT/pkg +// in prior Go releases) for the package located in pkgDir. +// +// (We use the package's directory instead of its import path +// mainly to simplify handling of the packages in src/vendor +// and cmd/vendor.) +func lookupGorootExport(pkgDir string) (string, bool) { + f, ok := exportMap.Load(pkgDir) + if !ok { + var ( + listOnce sync.Once + exportPath string + ) + f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) { + listOnce.Do(func() { + cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir) + cmd.Dir = build.Default.GOROOT + var output []byte + output, err := cmd.Output() + if err != nil { + return + } + + exports := strings.Split(string(bytes.TrimSpace(output)), "\n") + if len(exports) != 1 { + return + } + + exportPath = exports[0] + }) + + return exportPath, exportPath != "" + }) + } + + return f.(func() (string, bool))() +} + +var pkgExts = [...]string{".a", ".o"} + +// FindPkg returns the filename and unique package id for an import +// path based on package information provided by build.Import (using +// the build.Default build.Context). A relative srcDir is interpreted +// relative to the current working directory. +// If no file was found, an empty filename is returned. +func FindPkg(path, srcDir string) (filename, id string) { + if path == "" { + return + } + + var noext string + switch { + default: + // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" + // Don't require the source files to be present. + if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 + srcDir = abs + } + bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) + if bp.PkgObj == "" { + var ok bool + if bp.Goroot && bp.Dir != "" { + filename, ok = lookupGorootExport(bp.Dir) + } + if !ok { + id = path // make sure we have an id to print in error message + return + } + } else { + noext = strings.TrimSuffix(bp.PkgObj, ".a") + id = bp.ImportPath + } + + case build.IsLocalImport(path): + // "./x" -> "/this/directory/x.ext", "/this/directory/x" + noext = filepath.Join(srcDir, path) + id = noext + + case filepath.IsAbs(path): + // for completeness only - go/build.Import + // does not support absolute imports + // "/x" -> "/x.ext", "/x" + noext = path + id = path + } + + if false { // for debugging + if path != id { + fmt.Printf("%s -> %s\n", path, id) + } + } + + if filename != "" { + if f, err := os.Stat(filename); err == nil && !f.IsDir() { + return + } + } + + // try extensions + for _, ext := range pkgExts { + filename = noext + ext + if f, err := os.Stat(filename); err == nil && !f.IsDir() { + return + } + } + + filename = "" // not found + return +} + +// Import imports a gc-generated package given its import path and srcDir, adds +// the corresponding package object to the packages map, and returns the object. +// The packages map must contain all packages already imported. +func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { + var rc io.ReadCloser + var filename, id string + if lookup != nil { + // With custom lookup specified, assume that caller has + // converted path to a canonical import path for use in the map. + if path == "unsafe" { + return types.Unsafe, nil + } + id = path + + // No need to re-import if the package was imported completely before. + if pkg = packages[id]; pkg != nil && pkg.Complete() { + return + } + f, err := lookup(path) + if err != nil { + return nil, err + } + rc = f + } else { + filename, id = FindPkg(path, srcDir) + if filename == "" { + if path == "unsafe" { + return types.Unsafe, nil + } + return nil, fmt.Errorf("can't find import: %q", id) + } + + // no need to re-import if the package was imported completely before + if pkg = packages[id]; pkg != nil && pkg.Complete() { + return + } + + // open file + f, err := os.Open(filename) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + // add file name to error + err = fmt.Errorf("%s: %v", filename, err) + } + }() + rc = f + } + defer rc.Close() + + var hdr string + var size int64 + buf := bufio.NewReader(rc) + if hdr, size, err = FindExportData(buf); err != nil { + return + } + + switch hdr { + case "$$B\n": + var data []byte + data, err = ioutil.ReadAll(buf) + if err != nil { + break + } + + // TODO(gri): allow clients of go/importer to provide a FileSet. + // Or, define a new standard go/types/gcexportdata package. + fset := token.NewFileSet() + + // The indexed export format starts with an 'i'; the older + // binary export format starts with a 'c', 'd', or 'v' + // (from "version"). Select appropriate importer. + if len(data) > 0 { + switch data[0] { + case 'i': + _, pkg, err := IImportData(fset, packages, data[1:], id) + return pkg, err + + case 'v', 'c', 'd': + _, pkg, err := BImportData(fset, packages, data, id) + return pkg, err + + case 'u': + _, pkg, err := UImportData(fset, packages, data[1:size], id) + return pkg, err + + default: + l := len(data) + if l > 10 { + l = 10 + } + return nil, fmt.Errorf("unexpected export data with prefix %q for path %s", string(data[:l]), id) + } + } + + default: + err = fmt.Errorf("unknown export data header: %q", hdr) + } + + return +} + +func deref(typ types.Type) types.Type { + if p, _ := typ.(*types.Pointer); p != nil { + return p.Elem() + } + return typ +} + +type byPath []*types.Package + +func (a byPath) Len() int { return len(a) } +func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go b/go/vendor/golang.org/x/tools/internal/gcimporter/iexport.go similarity index 78% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/iexport.go index 9a4ff329e12..ba53cdcdd10 100644 --- a/go/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go +++ b/go/vendor/golang.org/x/tools/internal/gcimporter/iexport.go @@ -12,7 +12,6 @@ import ( "bytes" "encoding/binary" "fmt" - "go/ast" "go/constant" "go/token" "go/types" @@ -23,9 +22,45 @@ import ( "strconv" "strings" + "golang.org/x/tools/internal/tokeninternal" "golang.org/x/tools/internal/typeparams" ) +// IExportShallow encodes "shallow" export data for the specified package. +// +// No promises are made about the encoding other than that it can be +// decoded by the same version of IIExportShallow. If you plan to save +// export data in the file system, be sure to include a cryptographic +// digest of the executable in the key to avoid version skew. +func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) { + // In principle this operation can only fail if out.Write fails, + // but that's impossible for bytes.Buffer---and as a matter of + // fact iexportCommon doesn't even check for I/O errors. + // TODO(adonovan): handle I/O errors properly. + // TODO(adonovan): use byte slices throughout, avoiding copying. + const bundle, shallow = false, true + var out bytes.Buffer + err := iexportCommon(&out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) + return out.Bytes(), err +} + +// IImportShallow decodes "shallow" types.Package data encoded by IExportShallow +// in the same executable. This function cannot import data from +// cmd/compile or gcexportdata.Write. +func IImportShallow(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string, insert InsertType) (*types.Package, error) { + const bundle = false + pkgs, err := iimportCommon(fset, imports, data, bundle, path, insert) + if err != nil { + return nil, err + } + return pkgs[0], nil +} + +// InsertType is the type of a function that creates a types.TypeName +// object for a named type and inserts it into the scope of the +// specified Package. +type InsertType = func(pkg *types.Package, name string) + // Current bundled export format version. Increase with each format change. // 0: initial implementation const bundleVersion = 0 @@ -36,15 +71,17 @@ const bundleVersion = 0 // The package path of the top-level package will not be recorded, // so that calls to IImportData can override with a provided package path. func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error { - return iexportCommon(out, fset, false, iexportVersion, []*types.Package{pkg}) + const bundle, shallow = false, false + return iexportCommon(out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) } // IExportBundle writes an indexed export bundle for pkgs to out. func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { - return iexportCommon(out, fset, true, iexportVersion, pkgs) + const bundle, shallow = true, false + return iexportCommon(out, fset, bundle, shallow, iexportVersion, pkgs) } -func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, pkgs []*types.Package) (err error) { +func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, version int, pkgs []*types.Package) (err error) { if !debug { defer func() { if e := recover(); e != nil { @@ -61,6 +98,7 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, p := iexporter{ fset: fset, version: version, + shallow: shallow, allPkgs: map[*types.Package]bool{}, stringIndex: map[string]uint64{}, declIndex: map[types.Object]uint64{}, @@ -82,7 +120,7 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, for _, pkg := range pkgs { scope := pkg.Scope() for _, name := range scope.Names() { - if ast.IsExported(name) { + if token.IsExported(name) { p.pushDecl(scope.Lookup(name)) } } @@ -101,6 +139,17 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, p.doDecl(p.declTodo.popHead()) } + // Produce index of offset of each file record in files. + var files intWriter + var fileOffset []uint64 // fileOffset[i] is offset in files of file encoded as i + if p.shallow { + fileOffset = make([]uint64, len(p.fileInfos)) + for i, info := range p.fileInfos { + fileOffset[i] = uint64(files.Len()) + p.encodeFile(&files, info.file, info.needed) + } + } + // Append indices to data0 section. dataLen := uint64(p.data0.Len()) w := p.newWriter() @@ -126,16 +175,75 @@ func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, } hdr.uint64(uint64(p.version)) hdr.uint64(uint64(p.strings.Len())) + if p.shallow { + hdr.uint64(uint64(files.Len())) + hdr.uint64(uint64(len(fileOffset))) + for _, offset := range fileOffset { + hdr.uint64(offset) + } + } hdr.uint64(dataLen) // Flush output. io.Copy(out, &hdr) io.Copy(out, &p.strings) + if p.shallow { + io.Copy(out, &files) + } io.Copy(out, &p.data0) return nil } +// encodeFile writes to w a representation of the file sufficient to +// faithfully restore position information about all needed offsets. +// Mutates the needed array. +func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) { + _ = needed[0] // precondition: needed is non-empty + + w.uint64(p.stringOff(file.Name())) + + size := uint64(file.Size()) + w.uint64(size) + + // Sort the set of needed offsets. Duplicates are harmless. + sort.Slice(needed, func(i, j int) bool { return needed[i] < needed[j] }) + + lines := tokeninternal.GetLines(file) // byte offset of each line start + w.uint64(uint64(len(lines))) + + // Rather than record the entire array of line start offsets, + // we save only a sparse list of (index, offset) pairs for + // the start of each line that contains a needed position. + var sparse [][2]int // (index, offset) pairs +outer: + for i, lineStart := range lines { + lineEnd := size + if i < len(lines)-1 { + lineEnd = uint64(lines[i+1]) + } + // Does this line contains a needed offset? + if needed[0] < lineEnd { + sparse = append(sparse, [2]int{i, lineStart}) + for needed[0] < lineEnd { + needed = needed[1:] + if len(needed) == 0 { + break outer + } + } + } + } + + // Delta-encode the columns. + w.uint64(uint64(len(sparse))) + var prev [2]int + for _, pair := range sparse { + w.uint64(uint64(pair[0] - prev[0])) + w.uint64(uint64(pair[1] - prev[1])) + prev = pair + } +} + // writeIndex writes out an object index. mainIndex indicates whether // we're writing out the main index, which is also read by // non-compiler tools and includes a complete package description @@ -205,7 +313,8 @@ type iexporter struct { out *bytes.Buffer version int - localpkg *types.Package + shallow bool // don't put types from other packages in the index + localpkg *types.Package // (nil in bundle mode) // allPkgs tracks all packages that have been referenced by // the export data, so we can ensure to include them in the @@ -217,6 +326,12 @@ type iexporter struct { strings intWriter stringIndex map[string]uint64 + // In shallow mode, object positions are encoded as (file, offset). + // Each file is recorded as a line-number table. + // Only the lines of needed positions are saved faithfully. + fileInfo map[*token.File]uint64 // value is index in fileInfos + fileInfos []*filePositions + data0 intWriter declIndex map[types.Object]uint64 tparamNames map[types.Object]string // typeparam->exported name @@ -225,6 +340,11 @@ type iexporter struct { indent int // for tracing support } +type filePositions struct { + file *token.File + needed []uint64 // unordered list of needed file offsets +} + func (p *iexporter) trace(format string, args ...interface{}) { if !trace { // Call sites should also be guarded, but having this check here allows @@ -248,6 +368,25 @@ func (p *iexporter) stringOff(s string) uint64 { return off } +// fileIndexAndOffset returns the index of the token.File and the byte offset of pos within it. +func (p *iexporter) fileIndexAndOffset(file *token.File, pos token.Pos) (uint64, uint64) { + index, ok := p.fileInfo[file] + if !ok { + index = uint64(len(p.fileInfo)) + p.fileInfos = append(p.fileInfos, &filePositions{file: file}) + if p.fileInfo == nil { + p.fileInfo = make(map[*token.File]uint64) + } + p.fileInfo[file] = index + } + // Record each needed offset. + info := p.fileInfos[index] + offset := uint64(file.Offset(pos)) + info.needed = append(info.needed, offset) + + return index, offset +} + // pushDecl adds n to the declaration work queue, if not already present. func (p *iexporter) pushDecl(obj types.Object) { // Package unsafe is known to the compiler and predeclared. @@ -256,6 +395,11 @@ func (p *iexporter) pushDecl(obj types.Object) { panic("cannot export package unsafe") } + // Shallow export data: don't index decls from other packages. + if p.shallow && obj.Pkg() != p.localpkg { + return + } + if _, ok := p.declIndex[obj]; ok { return } @@ -303,7 +447,13 @@ func (p *iexporter) doDecl(obj types.Object) { case *types.Func: sig, _ := obj.Type().(*types.Signature) if sig.Recv() != nil { - panic(internalErrorf("unexpected method: %v", sig)) + // We shouldn't see methods in the package scope, + // but the type checker may repair "func () F() {}" + // to "func (Invalid) F()" and then treat it like "func F()", + // so allow that. See golang/go#57729. + if sig.Recv().Type() != types.Typ[types.Invalid] { + panic(internalErrorf("unexpected method: %v", sig)) + } } // Function. @@ -415,13 +565,30 @@ func (w *exportWriter) tag(tag byte) { } func (w *exportWriter) pos(pos token.Pos) { - if w.p.version >= iexportVersionPosCol { + if w.p.shallow { + w.posV2(pos) + } else if w.p.version >= iexportVersionPosCol { w.posV1(pos) } else { w.posV0(pos) } } +// posV2 encoding (used only in shallow mode) records positions as +// (file, offset), where file is the index in the token.File table +// (which records the file name and newline offsets) and offset is a +// byte offset. It effectively ignores //line directives. +func (w *exportWriter) posV2(pos token.Pos) { + if pos == token.NoPos { + w.uint64(0) + return + } + file := w.p.fset.File(pos) // fset must be non-nil + index, offset := w.p.fileIndexAndOffset(file, pos) + w.uint64(1 + index) + w.uint64(offset) +} + func (w *exportWriter) posV1(pos token.Pos) { if w.p.fset == nil { w.int64(0) @@ -497,7 +664,7 @@ func (w *exportWriter) pkg(pkg *types.Package) { w.string(w.exportPath(pkg)) } -func (w *exportWriter) qualifiedIdent(obj types.Object) { +func (w *exportWriter) qualifiedType(obj *types.TypeName) { name := w.p.exportName(obj) // Ensure any referenced declarations are written out too. @@ -556,11 +723,11 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { return } w.startType(definedType) - w.qualifiedIdent(t.Obj()) + w.qualifiedType(t.Obj()) case *typeparams.TypeParam: w.startType(typeParamType) - w.qualifiedIdent(t.Obj()) + w.qualifiedType(t.Obj()) case *types.Pointer: w.startType(pointerType) @@ -602,14 +769,17 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { case *types.Struct: w.startType(structType) - w.setPkg(pkg, true) - n := t.NumFields() + if n > 0 { + w.setPkg(t.Field(0).Pkg(), true) // qualifying package for field objects + } else { + w.setPkg(pkg, true) + } w.uint64(uint64(n)) for i := 0; i < n; i++ { f := t.Field(i) w.pos(f.Pos()) - w.string(f.Name()) + w.string(f.Name()) // unexported fields implicitly qualified by prior setPkg w.typ(f.Type(), pkg) w.bool(f.Anonymous()) w.string(t.Tag(i)) // note (or tag) diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go b/go/vendor/golang.org/x/tools/internal/gcimporter/iimport.go similarity index 86% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/iimport.go index 4caa0f55d9d..448f903e86a 100644 --- a/go/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go +++ b/go/vendor/golang.org/x/tools/internal/gcimporter/iimport.go @@ -51,6 +51,8 @@ const ( iexportVersionPosCol = 1 iexportVersionGo1_18 = 2 iexportVersionGenerics = 2 + + iexportVersionCurrent = 2 ) type ident struct { @@ -83,7 +85,7 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { - pkgs, err := iimportCommon(fset, imports, data, false, path) + pkgs, err := iimportCommon(fset, imports, data, false, path, nil) if err != nil { return 0, nil, err } @@ -92,11 +94,11 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] // IImportBundle imports a set of packages from the serialized package bundle. func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) { - return iimportCommon(fset, imports, data, true, "") + return iimportCommon(fset, imports, data, true, "", nil) } -func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) { - const currentVersion = 1 +func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) { + const currentVersion = iexportVersionCurrent version := int64(-1) if !debug { defer func() { @@ -135,19 +137,34 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data } sLen := int64(r.uint64()) + var fLen int64 + var fileOffset []uint64 + if insert != nil { + // Shallow mode uses a different position encoding. + fLen = int64(r.uint64()) + fileOffset = make([]uint64, r.uint64()) + for i := range fileOffset { + fileOffset[i] = r.uint64() + } + } dLen := int64(r.uint64()) whence, _ := r.Seek(0, io.SeekCurrent) stringData := data[whence : whence+sLen] - declData := data[whence+sLen : whence+sLen+dLen] - r.Seek(sLen+dLen, io.SeekCurrent) + fileData := data[whence+sLen : whence+sLen+fLen] + declData := data[whence+sLen+fLen : whence+sLen+fLen+dLen] + r.Seek(sLen+fLen+dLen, io.SeekCurrent) p := iimporter{ version: int(version), ipath: path, + insert: insert, stringData: stringData, stringCache: make(map[uint64]string), + fileOffset: fileOffset, + fileData: fileData, + fileCache: make([]*token.File, len(fileOffset)), pkgCache: make(map[uint64]*types.Package), declData: declData, @@ -185,11 +202,18 @@ func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data } else if pkg.Name() != pkgName { errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) } + if i == 0 && !bundle { + p.localpkg = pkg + } p.pkgCache[pkgPathOff] = pkg + // Read index for package. nameIndex := make(map[string]uint64) - for nSyms := r.uint64(); nSyms > 0; nSyms-- { + nSyms := r.uint64() + // In shallow mode we don't expect an index for other packages. + assert(nSyms == 0 || p.localpkg == pkg || p.insert == nil) + for ; nSyms > 0; nSyms-- { name := p.stringAt(r.uint64()) nameIndex[name] = r.uint64() } @@ -265,8 +289,14 @@ type iimporter struct { version int ipath string + localpkg *types.Package + insert func(pkg *types.Package, name string) // "shallow" mode only + stringData []byte stringCache map[uint64]string + fileOffset []uint64 // fileOffset[i] is offset in fileData for info about file encoded as i + fileData []byte + fileCache []*token.File // memoized decoding of file encoded as i pkgCache map[uint64]*types.Package declData []byte @@ -308,6 +338,13 @@ func (p *iimporter) doDecl(pkg *types.Package, name string) { off, ok := p.pkgIndex[pkg][name] if !ok { + // In "shallow" mode, call back to the application to + // find the object and insert it into the package scope. + if p.insert != nil { + assert(pkg != p.localpkg) + p.insert(pkg, name) // "can't fail" + return + } errorf("%v.%v not in index", pkg, name) } @@ -332,6 +369,55 @@ func (p *iimporter) stringAt(off uint64) string { return s } +func (p *iimporter) fileAt(index uint64) *token.File { + file := p.fileCache[index] + if file == nil { + off := p.fileOffset[index] + file = p.decodeFile(intReader{bytes.NewReader(p.fileData[off:]), p.ipath}) + p.fileCache[index] = file + } + return file +} + +func (p *iimporter) decodeFile(rd intReader) *token.File { + filename := p.stringAt(rd.uint64()) + size := int(rd.uint64()) + file := p.fake.fset.AddFile(filename, -1, size) + + // SetLines requires a nondecreasing sequence. + // Because it is common for clients to derive the interval + // [start, start+len(name)] from a start position, and we + // want to ensure that the end offset is on the same line, + // we fill in the gaps of the sparse encoding with values + // that strictly increase by the largest possible amount. + // This allows us to avoid having to record the actual end + // offset of each needed line. + + lines := make([]int, int(rd.uint64())) + var index, offset int + for i, n := 0, int(rd.uint64()); i < n; i++ { + index += int(rd.uint64()) + offset += int(rd.uint64()) + lines[index] = offset + + // Ensure monotonicity between points. + for j := index - 1; j > 0 && lines[j] == 0; j-- { + lines[j] = lines[j+1] - 1 + } + } + + // Ensure monotonicity after last point. + for j := len(lines) - 1; j > 0 && lines[j] == 0; j-- { + size-- + lines[j] = size + } + + if !file.SetLines(lines) { + errorf("SetLines failed: %d", lines) // can't happen + } + return file +} + func (p *iimporter) pkgAt(off uint64) *types.Package { if pkg, ok := p.pkgCache[off]; ok { return pkg @@ -625,6 +711,9 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) { } func (r *importReader) pos() token.Pos { + if r.p.insert != nil { // shallow mode + return r.posv2() + } if r.p.version >= iexportVersionPosCol { r.posv1() } else { @@ -661,6 +750,15 @@ func (r *importReader) posv1() { } } +func (r *importReader) posv2() token.Pos { + file := r.uint64() + if file == 0 { + return token.NoPos + } + tf := r.p.fileAt(file - 1) + return tf.Pos(int(r.uint64())) +} + func (r *importReader) typ() types.Type { return r.p.typAt(r.uint64(), nil) } diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go b/go/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go b/go/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/support_go117.go b/go/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/support_go117.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go b/go/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go similarity index 62% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go index a993843230c..edbe6ea7041 100644 --- a/go/vendor/golang.org/x/tools/go/internal/gcimporter/support_go118.go +++ b/go/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go @@ -21,3 +21,17 @@ func additionalPredeclared() []types.Type { types.Universe.Lookup("any").Type(), } } + +// See cmd/compile/internal/types.SplitVargenSuffix. +func splitVargenSuffix(name string) (base, suffix string) { + i := len(name) + for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' { + i-- + } + const dot = "·" + if i >= len(dot) && name[i-len(dot):i] == dot { + i -= len(dot) + return name[:i], name[i:] + } + return name, "" +} diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/unified_no.go b/go/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/unified_no.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/unified_yes.go b/go/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/unified_yes.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/ureader_no.go b/go/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/ureader_no.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go diff --git a/go/vendor/golang.org/x/tools/go/internal/gcimporter/ureader_yes.go b/go/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go similarity index 70% rename from go/vendor/golang.org/x/tools/go/internal/gcimporter/ureader_yes.go rename to go/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go index 3c1a4375435..b285a11ce25 100644 --- a/go/vendor/golang.org/x/tools/go/internal/gcimporter/ureader_yes.go +++ b/go/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go @@ -14,7 +14,7 @@ import ( "go/types" "strings" - "golang.org/x/tools/go/internal/pkgbits" + "golang.org/x/tools/internal/pkgbits" ) // A pkgReader holds the shared state for reading a unified IR package @@ -36,6 +36,12 @@ type pkgReader struct { // laterFns holds functions that need to be invoked at the end of // import reading. laterFns []func() + // laterFors is used in case of 'type A B' to ensure that B is processed before A. + laterFors map[types.Type]int + + // ifaces holds a list of constructed Interfaces, which need to have + // Complete called after importing is done. + ifaces []*types.Interface } // later adds a function to be invoked at the end of import reading. @@ -63,6 +69,15 @@ func UImportData(fset *token.FileSet, imports map[string]*types.Package, data [] return } +// laterFor adds a function to be invoked at the end of import reading, and records the type that function is finishing. +func (pr *pkgReader) laterFor(t types.Type, fn func()) { + if pr.laterFors == nil { + pr.laterFors = make(map[types.Type]int) + } + pr.laterFors[t] = len(pr.laterFns) + pr.laterFns = append(pr.laterFns, fn) +} + // readUnifiedPackage reads a package description from the given // unified IR export data decoder. func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package { @@ -102,6 +117,10 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st fn() } + for _, iface := range pr.ifaces { + iface.Complete() + } + pkg.MarkComplete() return pkg } @@ -139,6 +158,17 @@ func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pk } } +func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader { + return &reader{ + Decoder: pr.TempDecoder(k, idx, marker), + p: pr, + } +} + +func (pr *pkgReader) retireReader(r *reader) { + pr.RetireDecoder(&r.Decoder) +} + // @@@ Positions func (r *reader) pos() token.Pos { @@ -163,26 +193,29 @@ func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string { return b } - r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) + var filename string + { + r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) - // Within types2, position bases have a lot more details (e.g., - // keeping track of where //line directives appeared exactly). - // - // For go/types, we just track the file name. + // Within types2, position bases have a lot more details (e.g., + // keeping track of where //line directives appeared exactly). + // + // For go/types, we just track the file name. - filename := r.String() + filename = r.String() - if r.Bool() { // file base - // Was: "b = token.NewTrimmedFileBase(filename, true)" - } else { // line base - pos := r.pos() - line := r.Uint() - col := r.Uint() + if r.Bool() { // file base + // Was: "b = token.NewTrimmedFileBase(filename, true)" + } else { // line base + pos := r.pos() + line := r.Uint() + col := r.Uint() - // Was: "b = token.NewLineBase(pos, filename, true, line, col)" - _, _, _ = pos, line, col + // Was: "b = token.NewLineBase(pos, filename, true, line, col)" + _, _, _ = pos, line, col + } + pr.retireReader(r) } - b := filename pr.posBases[idx] = b return b @@ -231,11 +264,35 @@ func (r *reader) doPkg() *types.Package { for i := range imports { imports[i] = r.pkg() } - pkg.SetImports(imports) + pkg.SetImports(flattenImports(imports)) return pkg } +// flattenImports returns the transitive closure of all imported +// packages rooted from pkgs. +func flattenImports(pkgs []*types.Package) []*types.Package { + var res []*types.Package + seen := make(map[*types.Package]struct{}) + for _, pkg := range pkgs { + if _, ok := seen[pkg]; ok { + continue + } + seen[pkg] = struct{}{} + res = append(res, pkg) + + // pkg.Imports() is already flattened. + for _, pkg := range pkg.Imports() { + if _, ok := seen[pkg]; ok { + continue + } + seen[pkg] = struct{}{} + res = append(res, pkg) + } + } + return res +} + // @@@ Types func (r *reader) typ() types.Type { @@ -264,12 +321,15 @@ func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type { return typ } - r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) - r.dict = dict - - typ := r.doTyp() - assert(typ != nil) + var typ types.Type + { + r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) + r.dict = dict + typ = r.doTyp() + assert(typ != nil) + pr.retireReader(r) + } // See comment in pkgReader.typIdx explaining how this happens. if prev := *where; prev != nil { return prev @@ -372,6 +432,16 @@ func (r *reader) interfaceType() *types.Interface { if implicit { iface.MarkImplicit() } + + // We need to call iface.Complete(), but if there are any embedded + // defined types, then we may not have set their underlying + // interface type yet. So we need to defer calling Complete until + // after we've called SetUnderlying everywhere. + // + // TODO(mdempsky): After CL 424876 lands, it should be safe to call + // iface.Complete() immediately. + r.p.ifaces = append(r.p.ifaces, iface) + return iface } @@ -425,18 +495,30 @@ func (r *reader) obj() (types.Object, []types.Type) { } func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { - rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) - objPkg, objName := rname.qualifiedIdent() - assert(objName != "") + var objPkg *types.Package + var objName string + var tag pkgbits.CodeObj + { + rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) - tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) + objPkg, objName = rname.qualifiedIdent() + assert(objName != "") + + tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) + pr.retireReader(rname) + } if tag == pkgbits.ObjStub { assert(objPkg == nil || objPkg == types.Unsafe) return objPkg, objName } + // Ignore local types promoted to global scope (#55110). + if _, suffix := splitVargenSuffix(objName); suffix != "" { + return objPkg, objName + } + if objPkg.Scope().Lookup(objName) == nil { dict := pr.objDictIdx(idx) @@ -477,15 +559,56 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { named.SetTypeParams(r.typeParamNames()) - // TODO(mdempsky): Rewrite receiver types to underlying is an - // Interface? The go/types importer does this (I think because - // unit tests expected that), but cmd/compile doesn't care - // about it, so maybe we can avoid worrying about that here. - rhs := r.typ() - r.p.later(func() { - underlying := rhs.Underlying() + setUnderlying := func(underlying types.Type) { + // If the underlying type is an interface, we need to + // duplicate its methods so we can replace the receiver + // parameter's type (#49906). + if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 { + methods := make([]*types.Func, iface.NumExplicitMethods()) + for i := range methods { + fn := iface.ExplicitMethod(i) + sig := fn.Type().(*types.Signature) + + recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named) + methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic())) + } + + embeds := make([]types.Type, iface.NumEmbeddeds()) + for i := range embeds { + embeds[i] = iface.EmbeddedType(i) + } + + newIface := types.NewInterfaceType(methods, embeds) + r.p.ifaces = append(r.p.ifaces, newIface) + underlying = newIface + } + named.SetUnderlying(underlying) - }) + } + + // Since go.dev/cl/455279, we can assume rhs.Underlying() will + // always be non-nil. However, to temporarily support users of + // older snapshot releases, we continue to fallback to the old + // behavior for now. + // + // TODO(mdempsky): Remove fallback code and simplify after + // allowing time for snapshot users to upgrade. + rhs := r.typ() + if underlying := rhs.Underlying(); underlying != nil { + setUnderlying(underlying) + } else { + pk := r.p + pk.laterFor(named, func() { + // First be sure that the rhs is initialized, if it needs to be initialized. + delete(pk.laterFors, named) // prevent cycles + if i, ok := pk.laterFors[rhs]; ok { + f := pk.laterFns[i] + pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op + f() // initialize RHS + } + setUnderlying(rhs.Underlying()) + }) + } for i, n := 0, r.Len(); i < n; i++ { named.AddMethod(r.method()) @@ -502,25 +625,28 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { } func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict { - r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) var dict readerDict - if implicits := r.Len(); implicits != 0 { - errorf("unexpected object with %v implicit type parameter(s)", implicits) - } + { + r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) + if implicits := r.Len(); implicits != 0 { + errorf("unexpected object with %v implicit type parameter(s)", implicits) + } - dict.bounds = make([]typeInfo, r.Len()) - for i := range dict.bounds { - dict.bounds[i] = r.typInfo() - } + dict.bounds = make([]typeInfo, r.Len()) + for i := range dict.bounds { + dict.bounds[i] = r.typInfo() + } - dict.derived = make([]derivedInfo, r.Len()) - dict.derivedTypes = make([]types.Type, len(dict.derived)) - for i := range dict.derived { - dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} - } + dict.derived = make([]derivedInfo, r.Len()) + dict.derivedTypes = make([]types.Type, len(dict.derived)) + for i := range dict.derived { + dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} + } + pr.retireReader(r) + } // function references follow, but reader doesn't need those return &dict diff --git a/go/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/go/vendor/golang.org/x/tools/internal/gocommand/invoke.go index 67256dc3974..d50551693f3 100644 --- a/go/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ b/go/vendor/golang.org/x/tools/internal/gocommand/invoke.go @@ -10,8 +10,10 @@ import ( "context" "fmt" "io" + "log" "os" "regexp" + "runtime" "strconv" "strings" "sync" @@ -232,6 +234,12 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { return runCmdContext(ctx, cmd) } +// DebugHangingGoCommands may be set by tests to enable additional +// instrumentation (including panics) for debugging hanging Go commands. +// +// See golang/go#54461 for details. +var DebugHangingGoCommands = false + // runCmdContext is like exec.CommandContext except it sends os.Interrupt // before os.Kill. func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { @@ -243,11 +251,24 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { resChan <- cmd.Wait() }() - select { - case err := <-resChan: - return err - case <-ctx.Done(): + // If we're interested in debugging hanging Go commands, stop waiting after a + // minute and panic with interesting information. + if DebugHangingGoCommands { + select { + case err := <-resChan: + return err + case <-time.After(1 * time.Minute): + HandleHangingGoCommand(cmd.Process) + case <-ctx.Done(): + } + } else { + select { + case err := <-resChan: + return err + case <-ctx.Done(): + } } + // Cancelled. Interrupt and see if it ends voluntarily. cmd.Process.Signal(os.Interrupt) select { @@ -255,11 +276,63 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { return err case <-time.After(time.Second): } + // Didn't shut down in response to interrupt. Kill it hard. - cmd.Process.Kill() + // TODO(rfindley): per advice from bcmills@, it may be better to send SIGQUIT + // on certain platforms, such as unix. + if err := cmd.Process.Kill(); err != nil && DebugHangingGoCommands { + // Don't panic here as this reliably fails on windows with EINVAL. + log.Printf("error killing the Go command: %v", err) + } + + // See above: don't wait indefinitely if we're debugging hanging Go commands. + if DebugHangingGoCommands { + select { + case err := <-resChan: + return err + case <-time.After(10 * time.Second): // a shorter wait as resChan should return quickly following Kill + HandleHangingGoCommand(cmd.Process) + } + } return <-resChan } +func HandleHangingGoCommand(proc *os.Process) { + switch runtime.GOOS { + case "linux", "darwin", "freebsd", "netbsd": + fmt.Fprintln(os.Stderr, `DETECTED A HANGING GO COMMAND + +The gopls test runner has detected a hanging go command. In order to debug +this, the output of ps and lsof/fstat is printed below. + +See golang/go#54461 for more details.`) + + fmt.Fprintln(os.Stderr, "\nps axo ppid,pid,command:") + fmt.Fprintln(os.Stderr, "-------------------------") + psCmd := exec.Command("ps", "axo", "ppid,pid,command") + psCmd.Stdout = os.Stderr + psCmd.Stderr = os.Stderr + if err := psCmd.Run(); err != nil { + panic(fmt.Sprintf("running ps: %v", err)) + } + + listFiles := "lsof" + if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" { + listFiles = "fstat" + } + + fmt.Fprintln(os.Stderr, "\n"+listFiles+":") + fmt.Fprintln(os.Stderr, "-----") + listFilesCmd := exec.Command(listFiles) + listFilesCmd.Stdout = os.Stderr + listFilesCmd.Stderr = os.Stderr + if err := listFilesCmd.Run(); err != nil { + panic(fmt.Sprintf("running %s: %v", listFiles, err)) + } + } + panic(fmt.Sprintf("detected hanging go command (pid %d): see golang/go#54461 for more details", proc.Pid)) +} + func cmdDebugStr(cmd *exec.Cmd) string { env := make(map[string]string) for _, kv := range cmd.Env { diff --git a/go/vendor/golang.org/x/tools/internal/gocommand/version.go b/go/vendor/golang.org/x/tools/internal/gocommand/version.go index 71304368020..307a76d474a 100644 --- a/go/vendor/golang.org/x/tools/internal/gocommand/version.go +++ b/go/vendor/golang.org/x/tools/internal/gocommand/version.go @@ -7,11 +7,19 @@ package gocommand import ( "context" "fmt" + "regexp" "strings" ) -// GoVersion checks the go version by running "go list" with modules off. -// It returns the X in Go 1.X. +// GoVersion reports the minor version number of the highest release +// tag built into the go command on the PATH. +// +// Note that this may be higher than the version of the go tool used +// to build this application, and thus the versions of the standard +// go/{scanner,parser,ast,types} packages that are linked into it. +// In that case, callers should either downgrade to the version of +// go used to build the application, or report an error that the +// application is too old to use the go command on the PATH. func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) { inv.Verb = "list" inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`, `--`, `unsafe`} @@ -38,7 +46,7 @@ func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) { if len(stdout) < 3 { return 0, fmt.Errorf("bad ReleaseTags output: %q", stdout) } - // Split up "[go1.1 go1.15]" + // Split up "[go1.1 go1.15]" and return highest go1.X value. tags := strings.Fields(stdout[1 : len(stdout)-2]) for i := len(tags) - 1; i >= 0; i-- { var version int @@ -49,3 +57,25 @@ func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) { } return 0, fmt.Errorf("no parseable ReleaseTags in %v", tags) } + +// GoVersionOutput returns the complete output of the go version command. +func GoVersionOutput(ctx context.Context, inv Invocation, r *Runner) (string, error) { + inv.Verb = "version" + goVersion, err := r.Run(ctx, inv) + if err != nil { + return "", err + } + return goVersion.String(), nil +} + +// ParseGoVersionOutput extracts the Go version string +// from the output of the "go version" command. +// Given an unrecognized form, it returns an empty string. +func ParseGoVersionOutput(data string) string { + re := regexp.MustCompile(`^go version (go\S+|devel \S+)`) + m := re.FindStringSubmatch(data) + if len(m) != 2 { + return "" // unrecognized version + } + return m[1] +} diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/codes.go b/go/vendor/golang.org/x/tools/internal/pkgbits/codes.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/codes.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/codes.go diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/decoder.go b/go/vendor/golang.org/x/tools/internal/pkgbits/decoder.go similarity index 83% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/decoder.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/decoder.go index 2bc793668ec..b92e8e6eb32 100644 --- a/go/vendor/golang.org/x/tools/go/internal/pkgbits/decoder.go +++ b/go/vendor/golang.org/x/tools/internal/pkgbits/decoder.go @@ -6,9 +6,11 @@ package pkgbits import ( "encoding/binary" + "errors" "fmt" "go/constant" "go/token" + "io" "math/big" "os" "runtime" @@ -51,6 +53,8 @@ type PkgDecoder struct { // For example, section K's end positions start at elemEndsEnds[K-1] // (or 0, if K==0) and end at elemEndsEnds[K]. elemEndsEnds [numRelocs]uint32 + + scratchRelocEnt []RelocEnt } // PkgPath returns the package path for the package @@ -94,7 +98,7 @@ func NewPkgDecoder(pkgPath, input string) PkgDecoder { pr.elemEnds = make([]uint32, pr.elemEndsEnds[len(pr.elemEndsEnds)-1]) assert(binary.Read(r, binary.LittleEndian, pr.elemEnds[:]) == nil) - pos, err := r.Seek(0, os.SEEK_CUR) + pos, err := r.Seek(0, io.SeekCurrent) assert(err == nil) pr.elemData = input[pos:] @@ -164,6 +168,21 @@ func (pr *PkgDecoder) NewDecoder(k RelocKind, idx Index, marker SyncMarker) Deco return r } +// TempDecoder returns a Decoder for the given (section, index) pair, +// and decodes the given SyncMarker from the element bitstream. +// If possible the Decoder should be RetireDecoder'd when it is no longer +// needed, this will avoid heap allocations. +func (pr *PkgDecoder) TempDecoder(k RelocKind, idx Index, marker SyncMarker) Decoder { + r := pr.TempDecoderRaw(k, idx) + r.Sync(marker) + return r +} + +func (pr *PkgDecoder) RetireDecoder(d *Decoder) { + pr.scratchRelocEnt = d.Relocs + d.Relocs = nil +} + // NewDecoderRaw returns a Decoder for the given (section, index) pair. // // Most callers should use NewDecoder instead. @@ -187,6 +206,30 @@ func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder { return r } +func (pr *PkgDecoder) TempDecoderRaw(k RelocKind, idx Index) Decoder { + r := Decoder{ + common: pr, + k: k, + Idx: idx, + } + + r.Data.Reset(pr.DataIdx(k, idx)) + r.Sync(SyncRelocs) + l := r.Len() + if cap(pr.scratchRelocEnt) >= l { + r.Relocs = pr.scratchRelocEnt[:l] + pr.scratchRelocEnt = nil + } else { + r.Relocs = make([]RelocEnt, l) + } + for i := range r.Relocs { + r.Sync(SyncReloc) + r.Relocs[i] = RelocEnt{RelocKind(r.Len()), Index(r.Len())} + } + + return r +} + // A Decoder provides methods for decoding an individual element's // bitstream data. type Decoder struct { @@ -206,11 +249,39 @@ func (r *Decoder) checkErr(err error) { } func (r *Decoder) rawUvarint() uint64 { - x, err := binary.ReadUvarint(&r.Data) + x, err := readUvarint(&r.Data) r.checkErr(err) return x } +// readUvarint is a type-specialized copy of encoding/binary.ReadUvarint. +// This avoids the interface conversion and thus has better escape properties, +// which flows up the stack. +func readUvarint(r *strings.Reader) (uint64, error) { + var x uint64 + var s uint + for i := 0; i < binary.MaxVarintLen64; i++ { + b, err := r.ReadByte() + if err != nil { + if i > 0 && err == io.EOF { + err = io.ErrUnexpectedEOF + } + return x, err + } + if b < 0x80 { + if i == binary.MaxVarintLen64-1 && b > 1 { + return x, overflow + } + return x | uint64(b)<= 0); w.Uint64(uint64(x)) } // Int encodes and writes an int value into the element bitstream. func (w *Encoder) Int(x int) { w.Int64(int64(x)) } -// Len encodes and writes a uint value into the element bitstream. +// Uint encodes and writes a uint value into the element bitstream. func (w *Encoder) Uint(x uint) { w.Uint64(uint64(x)) } // Reloc encodes and writes a relocation for the given (section, diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/flags.go b/go/vendor/golang.org/x/tools/internal/pkgbits/flags.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/flags.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/flags.go diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/frames_go1.go b/go/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/frames_go1.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/frames_go17.go b/go/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/frames_go17.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/reloc.go b/go/vendor/golang.org/x/tools/internal/pkgbits/reloc.go similarity index 95% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/reloc.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/reloc.go index 7a8f04ab3fc..fcdfb97ca99 100644 --- a/go/vendor/golang.org/x/tools/go/internal/pkgbits/reloc.go +++ b/go/vendor/golang.org/x/tools/internal/pkgbits/reloc.go @@ -5,11 +5,11 @@ package pkgbits // A RelocKind indicates a particular section within a unified IR export. -type RelocKind int +type RelocKind int32 // An Index represents a bitstream element index within a particular // section. -type Index int +type Index int32 // A relocEnt (relocation entry) is an entry in an element's local // reference table. diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/support.go b/go/vendor/golang.org/x/tools/internal/pkgbits/support.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/support.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/support.go diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/sync.go b/go/vendor/golang.org/x/tools/internal/pkgbits/sync.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/sync.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/sync.go diff --git a/go/vendor/golang.org/x/tools/go/internal/pkgbits/syncmarker_string.go b/go/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go similarity index 100% rename from go/vendor/golang.org/x/tools/go/internal/pkgbits/syncmarker_string.go rename to go/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go diff --git a/go/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go b/go/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go new file mode 100644 index 00000000000..a3fb2d4f29d --- /dev/null +++ b/go/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go @@ -0,0 +1,59 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// package tokeninternal provides access to some internal features of the token +// package. +package tokeninternal + +import ( + "go/token" + "sync" + "unsafe" +) + +// GetLines returns the table of line-start offsets from a token.File. +func GetLines(file *token.File) []int { + // token.File has a Lines method on Go 1.21 and later. + if file, ok := (interface{})(file).(interface{ Lines() []int }); ok { + return file.Lines() + } + + // This declaration must match that of token.File. + // This creates a risk of dependency skew. + // For now we check that the size of the two + // declarations is the same, on the (fragile) assumption + // that future changes would add fields. + type tokenFile119 struct { + _ string + _ int + _ int + mu sync.Mutex // we're not complete monsters + lines []int + _ []struct{} + } + type tokenFile118 struct { + _ *token.FileSet // deleted in go1.19 + tokenFile119 + } + + type uP = unsafe.Pointer + switch unsafe.Sizeof(*file) { + case unsafe.Sizeof(tokenFile118{}): + var ptr *tokenFile118 + *(*uP)(uP(&ptr)) = uP(file) + ptr.mu.Lock() + defer ptr.mu.Unlock() + return ptr.lines + + case unsafe.Sizeof(tokenFile119{}): + var ptr *tokenFile119 + *(*uP)(uP(&ptr)) = uP(file) + ptr.mu.Lock() + defer ptr.mu.Unlock() + return ptr.lines + + default: + panic("unexpected token.File size") + } +} diff --git a/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go b/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go index d38ee3c27cd..07484073a57 100644 --- a/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go +++ b/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go @@ -30,6 +30,12 @@ type ErrorCode int // convention that "bad" implies a problem with syntax, and "invalid" implies a // problem with types. +const ( + // InvalidSyntaxTree occurs if an invalid syntax tree is provided + // to the type checker. It should never happen. + InvalidSyntaxTree ErrorCode = -1 +) + const ( _ ErrorCode = iota @@ -153,12 +159,12 @@ const ( /* decls > var (+ other variable assignment codes) */ - // UntypedNil occurs when the predeclared (untyped) value nil is used to + // UntypedNilUse occurs when the predeclared (untyped) value nil is used to // initialize a variable declared without an explicit type. // // Example: // var x = nil - UntypedNil + UntypedNilUse // WrongAssignCount occurs when the number of values on the right-hand side // of an assignment or or initialization expression does not match the number @@ -1523,4 +1529,32 @@ const ( // Example: // type T[P any] struct{ *P } MisplacedTypeParam + + // InvalidUnsafeSliceData occurs when unsafe.SliceData is called with + // an argument that is not of slice type. It also occurs if it is used + // in a package compiled for a language version before go1.20. + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.SliceData(x) + InvalidUnsafeSliceData + + // InvalidUnsafeString occurs when unsafe.String is called with + // a length argument that is not of integer type, negative, or + // out of bounds. It also occurs if it is used in a package + // compiled for a language version before go1.20. + // + // Example: + // import "unsafe" + // + // var b [10]byte + // var _ = unsafe.String(&b[0], -1) + InvalidUnsafeString + + // InvalidUnsafeStringData occurs if it is used in a package + // compiled for a language version before go1.20. + _ // not used anymore + ) diff --git a/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go b/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go index de90e9515ae..15ecf7c5ded 100644 --- a/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go +++ b/go/vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go @@ -8,6 +8,7 @@ func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} + _ = x[InvalidSyntaxTree - -1] _ = x[Test-1] _ = x[BlankPkgName-2] _ = x[MismatchedPkgName-3] @@ -23,7 +24,7 @@ func _() { _ = x[InvalidConstInit-13] _ = x[InvalidConstVal-14] _ = x[InvalidConstType-15] - _ = x[UntypedNil-16] + _ = x[UntypedNilUse-16] _ = x[WrongAssignCount-17] _ = x[UnassignableOperand-18] _ = x[NoNewVar-19] @@ -152,16 +153,27 @@ func _() { _ = x[MisplacedConstraintIface-142] _ = x[InvalidMethodTypeParams-143] _ = x[MisplacedTypeParam-144] + _ = x[InvalidUnsafeSliceData-145] + _ = x[InvalidUnsafeString-146] } -const _ErrorCode_name = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParam" +const ( + _ErrorCode_name_0 = "InvalidSyntaxTree" + _ErrorCode_name_1 = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilUseWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString" +) -var _ErrorCode_index = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 215, 231, 250, 258, 274, 292, 309, 327, 351, 359, 374, 390, 408, 425, 440, 447, 458, 481, 496, 508, 519, 534, 548, 563, 578, 591, 600, 614, 629, 640, 655, 664, 680, 700, 718, 737, 749, 768, 787, 803, 820, 839, 853, 864, 879, 892, 907, 923, 937, 953, 968, 985, 1003, 1018, 1028, 1038, 1055, 1077, 1091, 1105, 1125, 1143, 1163, 1181, 1204, 1220, 1235, 1248, 1258, 1270, 1281, 1295, 1308, 1319, 1329, 1344, 1355, 1366, 1379, 1395, 1412, 1436, 1453, 1468, 1478, 1487, 1500, 1516, 1532, 1543, 1558, 1574, 1588, 1604, 1618, 1635, 1655, 1668, 1684, 1698, 1715, 1732, 1749, 1764, 1778, 1792, 1803, 1815, 1828, 1845, 1858, 1869, 1882, 1894, 1903, 1910, 1922, 1938, 1956, 1974, 1989, 2006, 2025, 2039, 2059, 2071, 2095, 2118, 2136} +var ( + _ErrorCode_index_1 = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 218, 234, 253, 261, 277, 295, 312, 330, 354, 362, 377, 393, 411, 428, 443, 450, 461, 484, 499, 511, 522, 537, 551, 566, 581, 594, 603, 617, 632, 643, 658, 667, 683, 703, 721, 740, 752, 771, 790, 806, 823, 842, 856, 867, 882, 895, 910, 926, 940, 956, 971, 988, 1006, 1021, 1031, 1041, 1058, 1080, 1094, 1108, 1128, 1146, 1166, 1184, 1207, 1223, 1238, 1251, 1261, 1273, 1284, 1298, 1311, 1322, 1332, 1347, 1358, 1369, 1382, 1398, 1415, 1439, 1456, 1471, 1481, 1490, 1503, 1519, 1535, 1546, 1561, 1577, 1591, 1607, 1621, 1638, 1658, 1671, 1687, 1701, 1718, 1735, 1752, 1767, 1781, 1795, 1806, 1818, 1831, 1848, 1861, 1872, 1885, 1897, 1906, 1913, 1925, 1941, 1959, 1977, 1992, 2009, 2028, 2042, 2062, 2074, 2098, 2121, 2139, 2161, 2180} +) func (i ErrorCode) String() string { - i -= 1 - if i < 0 || i >= ErrorCode(len(_ErrorCode_index)-1) { - return "ErrorCode(" + strconv.FormatInt(int64(i+1), 10) + ")" + switch { + case i == -1: + return _ErrorCode_name_0 + case 1 <= i && i <= 146: + i -= 1 + return _ErrorCode_name_1[_ErrorCode_index_1[i]:_ErrorCode_index_1[i+1]] + default: + return "ErrorCode(" + strconv.FormatInt(int64(i), 10) + ")" } - return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]] } diff --git a/go/vendor/modules.txt b/go/vendor/modules.txt index 47121546873..596bd8e8ae9 100644 --- a/go/vendor/modules.txt +++ b/go/vendor/modules.txt @@ -1,25 +1,26 @@ -# golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 +# golang.org/x/mod v0.8.0 ## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f +# golang.org/x/sys v0.5.0 ## explicit; go 1.17 golang.org/x/sys/execabs -# golang.org/x/tools v0.1.12 +# golang.org/x/tools v0.6.0 ## explicit; go 1.18 golang.org/x/tools/go/gcexportdata -golang.org/x/tools/go/internal/gcimporter golang.org/x/tools/go/internal/packagesdriver -golang.org/x/tools/go/internal/pkgbits golang.org/x/tools/go/packages golang.org/x/tools/internal/event golang.org/x/tools/internal/event/core golang.org/x/tools/internal/event/keys golang.org/x/tools/internal/event/label +golang.org/x/tools/internal/gcimporter golang.org/x/tools/internal/gocommand golang.org/x/tools/internal/packagesinternal +golang.org/x/tools/internal/pkgbits +golang.org/x/tools/internal/tokeninternal golang.org/x/tools/internal/typeparams golang.org/x/tools/internal/typesinternal # golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 From de4f5017e101d35a848b73042fa523ee8f6e5556 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Tue, 14 Feb 2023 18:36:07 +0100 Subject: [PATCH 240/415] add change-note --- .../change-notes/2023-02-14-regex-injection-process-env.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2023-02-14-regex-injection-process-env.md diff --git a/javascript/ql/lib/change-notes/2023-02-14-regex-injection-process-env.md b/javascript/ql/lib/change-notes/2023-02-14-regex-injection-process-env.md new file mode 100644 index 00000000000..504b71a92b5 --- /dev/null +++ b/javascript/ql/lib/change-notes/2023-02-14-regex-injection-process-env.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `js/regex-injection` query now recognizes environment variables and command-line arguments as sources. \ No newline at end of file From d075e016b21d2e2516e61648db7b867214af5f73 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 14 Feb 2023 17:43:02 +0000 Subject: [PATCH 241/415] Upgrade Go to 1.20 --- .github/workflows/go-tests-other-os.yml | 8 ++++---- .github/workflows/go-tests.yml | 4 ++-- go/go.mod | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/go-tests-other-os.yml b/.github/workflows/go-tests-other-os.yml index edf6eb63d49..97207f573c0 100644 --- a/.github/workflows/go-tests-other-os.yml +++ b/.github/workflows/go-tests-other-os.yml @@ -12,10 +12,10 @@ jobs: name: Test MacOS runs-on: macos-latest steps: - - name: Set up Go 1.19 + - name: Set up Go 1.20 uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.20.0 id: go - name: Check out code @@ -47,10 +47,10 @@ jobs: name: Test Windows runs-on: windows-latest-xl steps: - - name: Set up Go 1.19 + - name: Set up Go 1.20 uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.20.0 id: go - name: Check out code diff --git a/.github/workflows/go-tests.yml b/.github/workflows/go-tests.yml index eceabb0410a..4cf299e5e44 100644 --- a/.github/workflows/go-tests.yml +++ b/.github/workflows/go-tests.yml @@ -20,10 +20,10 @@ jobs: name: Test Linux (Ubuntu) runs-on: ubuntu-latest-xl steps: - - name: Set up Go 1.19 + - name: Set up Go 1.20 uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: 1.20.0 id: go - name: Check out code diff --git a/go/go.mod b/go/go.mod index b8ef80e2c6c..516bc228330 100644 --- a/go/go.mod +++ b/go/go.mod @@ -1,6 +1,6 @@ module github.com/github/codeql-go -go 1.18 +go 1.20 require ( golang.org/x/mod v0.8.0 From 194316d1c0f8fd7847308b8c798f8d2c9d465411 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 14 Feb 2023 18:33:53 +0000 Subject: [PATCH 242/415] Accept test changes Some diagnostics have been reworded for Go 1.20, and a standard library type parameter is visible to the TypeParamType test. --- .../CONSISTENCY/UnexpectedFrontendErrors.expected | 6 +++--- go/ql/test/extractor-tests/diagnostics/Diagnostics.expected | 6 +++--- .../library-tests/semmle/go/Function/TypeParamType.expected | 1 + .../go/Types/CONSISTENCY/UnexpectedFrontendErrors.expected | 2 +- .../CONSISTENCY/UnexpectedFrontendErrors.expected | 2 +- .../test/query-tests/Diagnostics/ExtractionErrors.expected | 2 +- .../CONSISTENCY/UnexpectedFrontendErrors.expected | 2 +- .../CONSISTENCY/UnexpectedFrontendErrors.expected | 2 +- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/go/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected b/go/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected index fc69f87cc3f..aa526b3e750 100644 --- a/go/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/go/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1,7 +1,7 @@ | -:0:0:0:0 | package ; expected main | -| broken2/test1.go:4:2:4:2 | undeclared name: fmt | -| broken2/test1.go:5:2:5:2 | undeclared name: fmt | -| broken2/test1.go:5:14:5:14 | undeclared name: a | +| broken2/test1.go:4:2:4:2 | undefined: fmt | +| broken2/test1.go:5:2:5:2 | undefined: fmt | +| broken2/test1.go:5:14:5:14 | undefined: a | | broken2/test.go:3:1:3:1 | expected 'package', found pac | | broken2/test.go:3:1:3:1 | expected 'package', found pac | | broken2/test.go:3:4:3:4 | expected 'IDENT', found newline | diff --git a/go/ql/test/extractor-tests/diagnostics/Diagnostics.expected b/go/ql/test/extractor-tests/diagnostics/Diagnostics.expected index af155e81213..9d89f8c411b 100644 --- a/go/ql/test/extractor-tests/diagnostics/Diagnostics.expected +++ b/go/ql/test/extractor-tests/diagnostics/Diagnostics.expected @@ -5,8 +5,8 @@ qcompilations | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | go.mod:0:0:0:0 | go.mod | | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | notbroken/test.go:0:0:0:0 | notbroken/test.go | qdiagnostics -| broken2/test1.go:4:2:4:2 | error: undeclared name: fmt | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | broken2/test1.go:0:0:0:0 | broken2/test1.go | -| broken2/test1.go:5:2:5:2 | error: undeclared name: fmt | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | broken2/test1.go:0:0:0:0 | broken2/test1.go | -| broken2/test1.go:5:14:5:14 | error: undeclared name: a | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | broken2/test1.go:0:0:0:0 | broken2/test1.go | +| broken2/test1.go:4:2:4:2 | error: undefined: fmt | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | broken2/test1.go:0:0:0:0 | broken2/test1.go | +| broken2/test1.go:5:2:5:2 | error: undefined: fmt | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | broken2/test1.go:0:0:0:0 | broken2/test1.go | +| broken2/test1.go:5:14:5:14 | error: undefined: a | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | broken2/test1.go:0:0:0:0 | broken2/test1.go | | broken/test.go:7:1:7:1 | error: expected declaration, found This | compilation in 'diagnostics': go-extractor -mod=vendor -- ./... | broken/test.go:0:0:0:0 | broken/test.go | duplicateerrs diff --git a/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected b/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected index 661cc77556f..6178ffff530 100644 --- a/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected +++ b/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected @@ -13,3 +13,4 @@ | TG2 | interface { } | | U | interface { } | | V | interface { int64 \| float64 } | +| bytes | interface { []uint8 \| string } | diff --git a/go/ql/test/library-tests/semmle/go/Types/CONSISTENCY/UnexpectedFrontendErrors.expected b/go/ql/test/library-tests/semmle/go/Types/CONSISTENCY/UnexpectedFrontendErrors.expected index fa64f5084a9..be9b19ab4f1 100644 --- a/go/ql/test/library-tests/semmle/go/Types/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/go/ql/test/library-tests/semmle/go/Types/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1 +1 @@ -| unknownFunction.go:9:7:9:7 | undeclared name: unknownFunction | +| unknownFunction.go:9:7:9:7 | undefined: unknownFunction | diff --git a/go/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected b/go/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected index 7c7600b70da..a608f356a30 100644 --- a/go/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/go/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -5,5 +5,5 @@ | bad.go:3:5:3:5 | expected 'IDENT', found newline | | bad.go:5:1:5:1 | expected ';', found wnvwun | | badimport.go:6:2:6:2 | invalid import path (invalid character U+007B '{') | -| badimport.go:6:2:6:2 | invalid import path: "github.com/pkg{}" | +| badimport.go:6:2:6:2 | malformed import path "github.com/pkg{}": invalid char '{' | | type.go:11:9:11:9 | cannot use v (variable of type V) as T value in argument to takesT | diff --git a/go/ql/test/query-tests/Diagnostics/ExtractionErrors.expected b/go/ql/test/query-tests/Diagnostics/ExtractionErrors.expected index 50b08606056..52fc92b4973 100644 --- a/go/ql/test/query-tests/Diagnostics/ExtractionErrors.expected +++ b/go/ql/test/query-tests/Diagnostics/ExtractionErrors.expected @@ -1,5 +1,5 @@ | Extraction failed in query-tests/Diagnostics/badimport.go with error invalid import path (invalid character U+007B '{') | 2 | -| Extraction failed in query-tests/Diagnostics/badimport.go with error invalid import path: "github.com/pkg{}" | 2 | +| Extraction failed in query-tests/Diagnostics/badimport.go with error malformed import path "github.com/pkg{}": invalid char '{' | 2 | | Extraction failed in query-tests/Diagnostics/type.go with error cannot use v (variable of type V) as T value in argument to takesT | 2 | | Extraction failed with error expected ';', found wnvwun | 2 | | Extraction failed with error expected 'IDENT', found newline | 2 | diff --git a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/CONSISTENCY/UnexpectedFrontendErrors.expected b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/CONSISTENCY/UnexpectedFrontendErrors.expected index 13fa384da0e..a7a03f17abc 100644 --- a/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/go/ql/test/query-tests/RedundantCode/DeadStoreOfLocal/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1 +1 @@ -| main.go:36:9:36:9 | undeclared name: unknownFunction | +| main.go:36:9:36:9 | undefined: unknownFunction | diff --git a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/CONSISTENCY/UnexpectedFrontendErrors.expected b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/CONSISTENCY/UnexpectedFrontendErrors.expected index f0a094c5bab..7c35a931673 100644 --- a/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/go/ql/test/query-tests/RedundantCode/ImpossibleInterfaceNilCheck/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1 +1 @@ -| err.go:6:7:6:7 | undeclared name: unknownFunction | +| err.go:6:7:6:7 | undefined: unknownFunction | From b7305fd229d321c0211320468a2d41213fd1b703 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Tue, 14 Feb 2023 21:08:13 +0100 Subject: [PATCH 243/415] also consider relative exports when finding library inputs --- javascript/ql/lib/semmle/javascript/NPM.qll | 14 +++++++------- .../semmle/javascript/NodeModuleResolutionImpl.qll | 11 +++++------ .../ql/lib/semmle/javascript/PackageExports.qll | 4 +++- .../UnsafeHtmlConstruction.expected | 9 +++++++++ .../UnsafeHtmlConstruction/lib2/package.json | 2 +- .../UnsafeHtmlConstruction/lib2/src/MyNode.ts | 2 +- 6 files changed, 26 insertions(+), 16 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/NPM.qll b/javascript/ql/lib/semmle/javascript/NPM.qll index 515e900f277..72fc54e8467 100644 --- a/javascript/ql/lib/semmle/javascript/NPM.qll +++ b/javascript/ql/lib/semmle/javascript/NPM.qll @@ -198,9 +198,7 @@ class PackageJson extends JsonObject { /** * Gets the main module of this package. */ - Module getMainModule() { - result = min(Module m, int prio | m.getFile() = resolveMainModule(this, prio) | m order by prio) - } + Module getMainModule() { result = getExportedModule(".") } /** * Gets the module exported under the given relative path. @@ -208,10 +206,12 @@ class PackageJson extends JsonObject { * The main module is considered exported under the path `"."`. */ Module getExportedModule(string relativePath) { - relativePath = "." and - result = this.getMainModule() - or - result.getFile() = MainModulePath::of(this, relativePath).resolve() + result = + min(Module m, int prio | + m.getFile() = resolveMainModule(this, prio, relativePath) + | + m order by prio + ) } /** diff --git a/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll b/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll index 2fd172cc277..f6eabf7483c 100644 --- a/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll +++ b/javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll @@ -62,7 +62,7 @@ File loadAsFile(Require req, int rootPriority, int priority) { */ File loadAsDirectory(Require req, int rootPriority, int priority) { exists(Folder dir | dir = req.getImportedPath().resolve(rootPriority) | - result = resolveMainModule(dir.(NpmPackage).getPackageJson(), priority) or + result = resolveMainModule(dir.(NpmPackage).getPackageJson(), priority, ".") or result = tryExtensions(dir, "index", priority - (numberOfExtensions() + 1)) ) } @@ -132,12 +132,10 @@ private File resolveMainPath(PackageJson pkg, string mainPath, int priority) { /** * Gets the main module described by `pkg` with the given `priority`. */ -File resolveMainModule(PackageJson pkg, int priority) { - exists(int subPriority, string mainPath | - result = resolveMainPath(pkg, mainPath, subPriority) and - if mainPath = "." then subPriority = priority else priority = subPriority + 1000 - ) +File resolveMainModule(PackageJson pkg, int priority, string exportPath) { + result = resolveMainPath(pkg, exportPath, priority) or + exportPath = "." and exists(Folder folder, Folder child | child = folder or child = folder.getChildContainer(getASrcFolderName()) or @@ -149,6 +147,7 @@ File resolveMainModule(PackageJson pkg, int priority) { ) or // if there is no main module, then we look for files that are explicitly included in the published package. + exportPath = "." and exists(PathExpr file | // `FilesPath` only exists if there is no main module for a given package. file = FilesPath::of(pkg) and priority = 100 // fixing the priority, because there might be multiple files in the package. diff --git a/javascript/ql/lib/semmle/javascript/PackageExports.qll b/javascript/ql/lib/semmle/javascript/PackageExports.qll index 64205648588..ace840613e1 100644 --- a/javascript/ql/lib/semmle/javascript/PackageExports.qll +++ b/javascript/ql/lib/semmle/javascript/PackageExports.qll @@ -133,7 +133,9 @@ private DataFlow::Node getAValueExportedByPackage() { DataFlow::globalVarRef("define").getACall().getAnArgument() = factory.getALocalUse() and func.getFile() = min(int j, File f | - f = NodeModule::resolveMainModule(any(PackageJson pack | exists(pack.getPackageName())), j) + f = + NodeModule::resolveMainModule(any(PackageJson pack | exists(pack.getPackageName())), j, + ".") | f order by j ) diff --git a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/UnsafeHtmlConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/UnsafeHtmlConstruction.expected index 0dea7f25189..726fb896435 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/UnsafeHtmlConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/UnsafeHtmlConstruction.expected @@ -12,6 +12,10 @@ nodes | lib2/index.ts:1:28:1:28 | s | | lib2/index.ts:2:29:2:29 | s | | lib2/index.ts:2:29:2:29 | s | +| lib2/src/MyNode.ts:1:28:1:28 | s | +| lib2/src/MyNode.ts:1:28:1:28 | s | +| lib2/src/MyNode.ts:2:29:2:29 | s | +| lib2/src/MyNode.ts:2:29:2:29 | s | | lib/src/MyNode.ts:1:28:1:28 | s | | lib/src/MyNode.ts:1:28:1:28 | s | | lib/src/MyNode.ts:2:29:2:29 | s | @@ -108,6 +112,10 @@ edges | lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s | | lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s | | lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s | +| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s | +| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s | +| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s | +| lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s | | lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s | | lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s | | lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s | @@ -200,6 +208,7 @@ edges | jquery-plugin.js:12:31:12:41 | options.foo | jquery-plugin.js:11:34:11:40 | options | jquery-plugin.js:12:31:12:41 | options.foo | This HTML construction which depends on $@ might later allow $@. | jquery-plugin.js:11:34:11:40 | options | library input | jquery-plugin.js:12:20:12:53 | " ... /span>" | cross-site scripting | | jquery-plugin.js:14:31:14:35 | stuff | jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff | This HTML construction which depends on $@ might later allow $@. | jquery-plugin.js:11:27:11:31 | stuff | library input | jquery-plugin.js:14:20:14:47 | " ... /span>" | cross-site scripting | | lib2/index.ts:2:29:2:29 | s | lib2/index.ts:1:28:1:28 | s | lib2/index.ts:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | lib2/index.ts:1:28:1:28 | s | library input | lib2/index.ts:3:49:3:52 | html | cross-site scripting | +| lib2/src/MyNode.ts:2:29:2:29 | s | lib2/src/MyNode.ts:1:28:1:28 | s | lib2/src/MyNode.ts:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | lib2/src/MyNode.ts:1:28:1:28 | s | library input | lib2/src/MyNode.ts:3:49:3:52 | html | cross-site scripting | | lib/src/MyNode.ts:2:29:2:29 | s | lib/src/MyNode.ts:1:28:1:28 | s | lib/src/MyNode.ts:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | lib/src/MyNode.ts:1:28:1:28 | s | library input | lib/src/MyNode.ts:3:49:3:52 | html | cross-site scripting | | main.js:2:29:2:29 | s | main.js:1:55:1:55 | s | main.js:2:29:2:29 | s | This HTML construction which depends on $@ might later allow $@. | main.js:1:55:1:55 | s | library input | main.js:3:49:3:52 | html | cross-site scripting | | main.js:7:49:7:49 | s | main.js:6:49:6:49 | s | main.js:7:49:7:49 | s | This XML parsing which depends on $@ might later allow $@. | main.js:6:49:6:49 | s | library input | main.js:8:48:8:66 | doc.documentElement | cross-site scripting | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/package.json b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/package.json index 8c1cbff3c1d..5c0fb2e5b7c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/package.json +++ b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/package.json @@ -1,6 +1,6 @@ { "name": "my-unsafe-library", - "main": "./foobar.js", + "main": "./index.ts", "exports": { "./MyNode": { "require": "./lib/MyNode.cjs", diff --git a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/src/MyNode.ts b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/src/MyNode.ts index 35908c88f16..e28325ce0cf 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/src/MyNode.ts +++ b/javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/lib2/src/MyNode.ts @@ -1,4 +1,4 @@ export function trivialXss(s: string) { - const html = "" + s + ""; // OK - this file is not recognized as a main file. + const html = "" + s + ""; // NOT OK - this file is not recognized as a main file. document.querySelector("#html").innerHTML = html; } \ No newline at end of file From 5f07d1f385bd8ac8940257d62792675c64ef825c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Feb 2023 00:17:48 +0000 Subject: [PATCH 244/415] Add changed framework coverage reports --- .../library-coverage/coverage.csv | 264 +++++++++--------- .../library-coverage/coverage.rst | 4 +- 2 files changed, 134 insertions(+), 134 deletions(-) diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index e834d085511..fbdd50b2091 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -1,132 +1,132 @@ -package,sink,source,summary,sink:bean-validation,sink:create-file,sink:fragment-injection,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:regex-use,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:set-hostname-verifier,sink:sql,sink:ssti,sink:url-open-stream,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-external-storage-dir,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value -android.app,35,,103,,,11,,,,7,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,18,85 -android.content,24,31,154,,,,,,,16,,,,,,,,,,,,,,,,,,8,,,,,,,,4,,27,,63,91 -android.database,59,,39,,,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,,39, -android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 -android.os,,2,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,41,81 -android.support.v4.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -android.util,6,16,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,16,, -android.webkit,3,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,2,, -android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1, -androidx.core.app,6,,95,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,12,83 -androidx.fragment.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -androidx.slice,2,5,88,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,5,,27,61 -cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -com.google.common.base,4,,85,,,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,,,,62,23 -com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 -com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 -com.google.common.flogger,29,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,,,,, -com.google.common.io,6,,73,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,72,1 -com.hubspot.jinjava,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,, -com.mitchellbosecke.pebble,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,, -com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,,, -com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, -com.unboundid.ldap.sdk,17,,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,, -com.zaxxer.hikari,2,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 -freemarker.cache,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,, -freemarker.template,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,, -groovy.lang,26,,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -groovy.util,5,,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, -jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 -java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -java.io,37,,42,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,,41,1 -java.lang,13,,76,,,,,,,,,,,,8,,,,,,4,,,1,,,,,,,,,,,,,,,,53,23 -java.net,10,3,7,,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,,,3,7, -java.nio,15,,16,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,16, -java.sql,11,,2,,,,,,,,4,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,1,1 -java.util,44,,465,,,,,,,,,,,,34,,,,,,,5,2,,1,2,,,,,,,,,,,,,,38,427 -javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, -javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, -javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 -javax.management.remote,2,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,, -javax.naming,7,,,,,,,,,,,,6,1,,,,,,,,,,,,,,,,,,,,,,,,,,, -javax.net.ssl,2,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,, -javax.script,1,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,, -javax.servlet,4,21,2,,,,,3,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,2, -javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,, -javax.ws.rs.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, -javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, -javax.ws.rs.core,3,,149,,,,,1,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 -javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,6, -javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,, -jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 -kotlin,12,,1835,,10,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,1828,7 -net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,,, -ognl,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,, -okhttp3,2,,47,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,22,25 -org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, -org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 -org.apache.commons.io,106,,560,,91,,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,546,14 -org.apache.commons.jexl2,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.jexl3,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.lang3,6,,424,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,293,131 -org.apache.commons.logging,6,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.ognl,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 -org.apache.directory.ldap.client.api,1,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,2,39, -org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2, -org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 -org.apache.http,27,3,70,,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,,,2,,,,3,62,8 -org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,57, -org.apache.log4j,11,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.logging.log4j,359,,8,,,,,,,,,,,,359,,,,,,,,,,,,,,,,,,,,,,,,,4,4 -org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.apache.shiro.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.apache.velocity.app,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,,, -org.apache.velocity.runtime,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,,, -org.codehaus.groovy.control,1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,,, -org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,, -org.jboss.logging,324,,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,,,,, -org.jdbi.v3.core,6,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,, -org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 -org.mvel2,16,,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,,,,, -org.scijava.log,13,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,,,,, -org.slf4j,55,,6,,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,,,,2,4 -org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 -org.springframework.boot.jdbc,1,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 -org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -org.springframework.data.repository,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 -org.springframework.http,14,,70,,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,,,,60,10 -org.springframework.jdbc.core,10,,,,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,,,, -org.springframework.jdbc.datasource,4,,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,,,, -org.springframework.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.ldap,47,,,,,,,,,,,,33,14,,,,,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, -org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 -org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,87,52 -org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, -org.springframework.web.client,13,3,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,3,, -org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, -org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, -org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,, -org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,138,25 -org.thymeleaf,2,,2,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,2, -org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, -org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, -play.mvc,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,, -ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 -ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, -ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, -ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, -ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 -retrofit2,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,, +package,sink,source,summary,sink:bean-validation,sink:create-file,sink:fragment-injection,sink:groovy,sink:header-splitting,sink:information-leak,sink:intent-start,sink:jdbc-url,sink:jexl,sink:jndi-injection,sink:ldap,sink:logging,sink:mvel,sink:ognl-injection,sink:open-url,sink:pending-intent-sent,sink:read-file,sink:regex-use,sink:regex-use[-1],sink:regex-use[0],sink:regex-use[],sink:regex-use[f-1],sink:regex-use[f1],sink:regex-use[f],sink:set-hostname-verifier,sink:sql,sink:ssti,sink:url-open-stream,sink:url-redirect,sink:write-file,sink:xpath,sink:xslt,sink:xss,source:android-external-storage-dir,source:android-widget,source:contentprovider,source:remote,summary:taint,summary:value +android.app,35,,103,,,11,,,,7,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,18,85 +android.content,24,31,154,,,,,,,16,,,,,,,,,,,,,,,,,,,8,,,,,,,,4,,27,,63,91 +android.database,59,,39,,,,,,,,,,,,,,,,,,,,,,,,,,59,,,,,,,,,,,,39, +android.net,,,60,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,45,15 +android.os,,2,122,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,41,81 +android.support.v4.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +android.util,6,16,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,16,, +android.webkit,3,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,2,, +android.widget,,1,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1, +androidx.core.app,6,,95,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,12,83 +androidx.fragment.app,11,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +androidx.slice,2,5,88,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,5,,27,61 +cn.hutool.core.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.esotericsoftware.kryo5.io,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.core,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +com.fasterxml.jackson.databind,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +com.google.common.base,4,,85,,,,,,,,,,,,,,,,,,,,3,1,,,,,,,,,,,,,,,,,62,23 +com.google.common.cache,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17 +com.google.common.collect,,,553,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,551 +com.google.common.flogger,29,,,,,,,,,,,,,,29,,,,,,,,,,,,,,,,,,,,,,,,,,, +com.google.common.io,6,,73,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,72,1 +com.hubspot.jinjava,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,, +com.mitchellbosecke.pebble,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,, +com.opensymphony.xwork2.ognl,3,,,,,,,,,,,,,,,,3,,,,,,,,,,,,,,,,,,,,,,,,, +com.rabbitmq.client,,21,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,7, +com.unboundid.ldap.sdk,17,,,,,,,,,,,,,17,,,,,,,,,,,,,,,,,,,,,,,,,,,, +com.zaxxer.hikari,2,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +flexjson,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +freemarker.cache,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,, +freemarker.template,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,, +groovy.lang,26,,,,,,26,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +groovy.util,5,,,,,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +jakarta.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, +jakarta.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +jakarta.ws.rs.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,, +jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 +java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +java.io,37,,42,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,22,,,,,,,,41,1 +java.lang,13,,76,,,,,,,,,,,,8,,,,,,,4,,,1,,,,,,,,,,,,,,,,53,23 +java.net,10,3,7,,,,,,,,,,,,,,,10,,,,,,,,,,,,,,,,,,,,,,3,7, +java.nio,16,,16,,13,,,,,,,,,,,,,,,1,,,,,,,,,,,,,2,,,,,,,,16, +java.sql,11,,2,,,,,,,,4,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,1,1 +java.util,44,,465,,,,,,,,,,,,34,,,,,,,,5,2,,1,2,,,,,,,,,,,,,,38,427 +javax.faces.context,2,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,7,, +javax.jms,,9,57,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,57, +javax.json,,,123,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,100,23 +javax.management.remote,2,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +javax.naming,7,,,,,,,,,,,,6,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, +javax.net.ssl,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,, +javax.script,1,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,, +javax.servlet,4,21,2,,,,,3,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,21,2, +javax.validation,1,1,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,, +javax.ws.rs.client,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,, +javax.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,, +javax.ws.rs.core,3,,149,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,94,55 +javax.xml.transform,1,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,6, +javax.xml.xpath,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,,,,,,,, +jodd.json,,,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10 +kotlin,12,,1835,,10,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,1828,7 +net.sf.saxon.s9api,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,5,,,,,,, +ognl,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,, +okhttp3,2,,47,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,22,25 +org.apache.commons.codec,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6, +org.apache.commons.collections,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.collections4,,,800,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,17,783 +org.apache.commons.io,106,,560,,91,,,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,546,14 +org.apache.commons.jexl2,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.jexl3,15,,,,,,,,,,,15,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.lang3,6,,424,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,293,131 +org.apache.commons.logging,6,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.ognl,6,,,,,,,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.commons.text,,,272,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,220,52 +org.apache.directory.ldap.client.api,1,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.hc.core5.http,1,2,39,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,2,39, +org.apache.hc.core5.net,,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2, +org.apache.hc.core5.util,,,24,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,18,6 +org.apache.http,27,3,70,,,,,,,,,,,,,,,25,,,,,,,,,,,,,,,,,,2,,,,3,62,8 +org.apache.ibatis.jdbc,6,,57,,,,,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,,,57, +org.apache.log4j,11,,,,,,,,,,,,,,11,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.logging.log4j,359,,8,,,,,,,,,,,,359,,,,,,,,,,,,,,,,,,,,,,,,,,4,4 +org.apache.shiro.codec,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.apache.shiro.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.apache.velocity.app,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,,, +org.apache.velocity.runtime,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,,,,,,,,,,,, +org.codehaus.groovy.control,1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.dom4j,20,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,20,,,,,,,, +org.hibernate,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,7,,,,,,,,,,,,, +org.jboss.logging,324,,,,,,,,,,,,,,324,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.jdbi.v3.core,6,,,,,,,,,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.jooq,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,, +org.json,,,236,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,198,38 +org.mvel2,16,,,,,,,,,,,,,,,16,,,,,,,,,,,,,,,,,,,,,,,,,, +org.scijava.log,13,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.slf4j,55,,6,,,,,,,,,,,,55,,,,,,,,,,,,,,,,,,,,,,,,,,2,4 +org.springframework.beans,,,30,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30 +org.springframework.boot.jdbc,1,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.cache,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13 +org.springframework.context,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +org.springframework.data.repository,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +org.springframework.http,14,,70,,,,,,,,,,,,,,,14,,,,,,,,,,,,,,,,,,,,,,,60,10 +org.springframework.jdbc.core,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,,,,,,,,,,,,, +org.springframework.jdbc.datasource,4,,,,,,,,,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.jdbc.object,9,,,,,,,,,,,,,,,,,,,,,,,,,,,,9,,,,,,,,,,,,, +org.springframework.jndi,1,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.ldap,47,,,,,,,,,,,,33,14,,,,,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.security.web.savedrequest,,6,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,, +org.springframework.ui,,,32,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,32 +org.springframework.util,,,139,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,87,52 +org.springframework.validation,,,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,13, +org.springframework.web.client,13,3,,,,,,,,,,,,,,,,13,,,,,,,,,,,,,,,,,,,,,,3,, +org.springframework.web.context.request,,8,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,, +org.springframework.web.multipart,,12,13,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,12,13, +org.springframework.web.reactive.function.client,2,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,,,,,, +org.springframework.web.util,,,163,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,138,25 +org.thymeleaf,2,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,2, +org.xml.sax,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, +org.xmlpull.v1,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,, +play.mvc,,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,4,, +ratpack.core.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.core.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.core.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.exec,,,48,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,48 +ratpack.form,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3, +ratpack.func,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +ratpack.handling,,6,4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,6,4, +ratpack.http,,10,10,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,10,10, +ratpack.util,,,35,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,35 +retrofit2,1,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index c4630ca11d6..59c21e3ed29 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -18,10 +18,10 @@ Java framework & library support `Google Guava `_,``com.google.common.*``,,728,39,,6,,,,, JBoss Logging,``org.jboss.logging``,,,324,,,,,,, `JSON-java `_,``org.json``,,236,,,,,,,, - Java Standard Library,``java.*``,3,609,130,28,,,7,,,10 + Java Standard Library,``java.*``,3,609,131,28,,,7,,,10 Java extensions,"``javax.*``, ``jakarta.*``",63,609,32,,,4,,1,1,2 Kotlin Standard Library,``kotlin*``,,1835,12,10,,,,,,2 `Spring `_,``org.springframework.*``,29,477,101,,,,19,14,,29 Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.hubspot.jinjava``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2.ognl``, ``com.rabbitmq.client``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``freemarker.cache``, ``freemarker.template``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``okhttp3``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.logging``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.log4j``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.velocity.app``, ``org.apache.velocity.runtime``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jdbi.v3.core``, ``org.jooq``, ``org.mvel2``, ``org.scijava.log``, ``org.slf4j``, ``org.thymeleaf``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``retrofit2``",60,300,269,,,,14,18,,3 - Totals,,217,8456,1563,129,6,10,107,33,1,86 + Totals,,217,8456,1564,129,6,10,107,33,1,86 From 9e2eb560320e6ecd9a27de518f2e0294ae9b0a2d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Sun, 12 Feb 2023 21:03:34 +0100 Subject: [PATCH 245/415] Python: Remove support for late `*args` arguments I found this to cause bad performance, so the implementation of this has to be thought out more carefully. --- .../new/internal/DataFlowDispatch.qll | 21 --------- .../dataflow/new/internal/DataFlowPrivate.qll | 47 ------------------- .../dataflow/new/internal/DataFlowPublic.qll | 8 ---- .../dataflow/coverage/argumentPassing.py | 2 +- 4 files changed, 1 insertion(+), 77 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index 864642deb69..0d391d7f98d 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -64,7 +64,6 @@ newtype TParameterPosition = index = any(Parameter p).getPosition() + 1 } or TSynthStarArgsElementParameterPosition(int index) { exists(TStarArgsParameterPosition(index)) } or - TSynthLateStarArgsParameterPosition(int index) { exists(TStarArgsParameterPosition(index)) } or TDictSplatParameterPosition() /** A parameter position. */ @@ -90,14 +89,6 @@ class ParameterPosition extends TParameterPosition { this = TSynthStarArgsElementParameterPosition(index) } - /** - * Holds if this position represents a synthetic `*args` parameter after the real - * `*args` parameter. The real `*args` parameter is at the 0-based index `index`. - */ - predicate isSynthLateStarArgsParameterPosition(int index) { - this = TSynthLateStarArgsParameterPosition(index) - } - /** Holds if this position represents a `**kwargs` parameter. */ predicate isDictSplat() { this = TDictSplatParameterPosition() } @@ -116,11 +107,6 @@ class ParameterPosition extends TParameterPosition { result = "synthetic *args element at (or after) " + index ) or - exists(int index | - this.isSynthLateStarArgsParameterPosition(index) and - result = "synthetic late *args after " + index - ) - or this.isDictSplat() and result = "**" } } @@ -192,10 +178,6 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos.isSynthStarArgsElement(paramIndex) and apos.isPositional(argIndex) ) or - exists(int realStarArgsIndex, int argIndex | argIndex > realStarArgsIndex | - ppos.isSynthLateStarArgsParameterPosition(realStarArgsIndex) and apos.isStarArgs(argIndex) - ) - or ppos.isDictSplat() and apos.isDictSplat() } @@ -329,9 +311,6 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { or ppos.isSynthStarArgsElement(index) and result = TSynthStarArgsElementParameterNode(this) - or - ppos.isSynthLateStarArgsParameterPosition(index) and - result = TSynthLateStarArgsParameterNode(this) ) | // a `*args` parameter comes after the last positional parameter. We need to take diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index e21594c8385..c46cd74e3d4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -135,49 +135,6 @@ predicate synthStarArgsElementParameterNodeStoreStep( ) } -/** - * A synthetic node to capture a `*args` argument that is passed to a `*args` - * parameter, but "too late" in the argument list, so we cannot just do a 1-1 mapping - * without messing up the indexes; instead we make a list/tuple/set read step to - * `SynthStarArgsElementParameterNode`. - * - * Example. The `*args` arguments starts at index 1, while the `*args` parameter accepts - * arguments starting at index 0. - * - * ```py - * def func(*args): ... - * func(1, *args) - */ -class SynthLateStarArgsParameterNode extends ParameterNodeImpl, TSynthLateStarArgsParameterNode { - DataFlowCallable callable; - - SynthLateStarArgsParameterNode() { this = TSynthLateStarArgsParameterNode(callable) } - - override string toString() { result = "SynthLateStarArgsParameterNode" } - - override Scope getScope() { result = callable.getScope() } - - override Location getLocation() { result = callable.getLocation() } - - override Parameter getParameter() { none() } -} - -predicate synthLateStarArgsParameterNodeReadStep( - SynthLateStarArgsParameterNode nodeFrom, Content c, ParameterNode nodeTo -) { - ( - c instanceof ListElementContent - or - c instanceof TupleElementContent - or - c instanceof SetElementContent - ) and - exists(DataFlowCallable callable | - nodeFrom = TSynthLateStarArgsParameterNode(callable) and - nodeTo = TSynthStarArgsElementParameterNode(callable) - ) -} - // ============================================================================= // **kwargs (DictSplat) related // ============================================================================= @@ -843,8 +800,6 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) { or FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom, c, nodeTo) or - synthLateStarArgsParameterNodeReadStep(nodeFrom, c, nodeTo) - or synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo) } @@ -1006,8 +961,6 @@ predicate nodeIsHidden(Node n) { or n instanceof SynthStarArgsElementParameterNode or - n instanceof SynthLateStarArgsParameterNode - or n instanceof SynthDictSplatArgumentNode or n instanceof SynthDictSplatParameterNode diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index d46712738cf..440ce3b70d4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -117,14 +117,6 @@ newtype TNode = TSynthStarArgsElementParameterNode(DataFlowCallable callable) { exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos))) } or - /** - * A synthetic node to capture a `*args` argument that is passed to a `*args` - * parameter, but "too late" in the argument list, so we cannot just do a 1-1 mapping - * without messing up the indexes. - */ - TSynthLateStarArgsParameterNode(DataFlowCallable callable) { - exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos))) - } or /** A synthetic node to capture keyword arguments that are passed to a `**kwargs` parameter. */ TSynthDictSplatArgumentNode(CallNode call) { exists(call.getArgByName(_)) } or /** A synthetic node to allow flow to keyword parameters from a `**kwargs` argument. */ diff --git a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py index ecf4a0d201d..35695b01f03 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentPassing.py +++ b/python/ql/test/experimental/dataflow/coverage/argumentPassing.py @@ -213,7 +213,7 @@ def starargs_only(*args): def test_only_starargs(): starargs_only(arg1, arg2, "safe") # $ arg1 arg2 SPURIOUS: bad2,bad3="arg1" bad1,bad3="arg2" - args = (arg2, "safe") # $ arg2 func=starargs_only SPURIOUS: bad1,bad3="arg2" + args = (arg2, "safe") # $ MISSING: arg2 starargs_only(arg1, *args) # $ arg1 SPURIOUS: bad2,bad3="arg1" args = (arg1, arg2, "safe") # $ arg1 arg2 func=starargs_only From bec8dc67755399e32be877df48ba4ba6ba9f9826 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Wed, 15 Feb 2023 10:44:57 +0100 Subject: [PATCH 246/415] add explicit this --- javascript/ql/lib/semmle/javascript/NPM.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/NPM.qll b/javascript/ql/lib/semmle/javascript/NPM.qll index 72fc54e8467..d05045784a6 100644 --- a/javascript/ql/lib/semmle/javascript/NPM.qll +++ b/javascript/ql/lib/semmle/javascript/NPM.qll @@ -198,7 +198,7 @@ class PackageJson extends JsonObject { /** * Gets the main module of this package. */ - Module getMainModule() { result = getExportedModule(".") } + Module getMainModule() { result = this.getExportedModule(".") } /** * Gets the module exported under the given relative path. From 368ca6cb3040dfdbc5b1a8d62713204d076bca92 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 12:31:09 +0000 Subject: [PATCH 247/415] Add test exercising Go 1.20 array conversions --- .../dataflow/ArrayConversion/Flows.expected | 0 .../go/dataflow/ArrayConversion/Flows.ql | 58 +++++++++++++++++++ .../go/dataflow/ArrayConversion/main.go | 26 +++++++++ 3 files changed, 84 insertions(+) create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/Flows.expected create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/Flows.ql create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/Flows.expected b/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/Flows.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/Flows.ql new file mode 100644 index 00000000000..e6e99b0e6c2 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/Flows.ql @@ -0,0 +1,58 @@ +import go +import TestUtilities.InlineExpectationsTest + +class DataConfiguration extends DataFlow::Configuration { + DataConfiguration() { this = "data-configuration" } + + override predicate isSource(DataFlow::Node source) { + source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0) + } + + override predicate isSink(DataFlow::Node sink) { + sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0) + } +} + +class DataFlowTest extends InlineExpectationsTest { + DataFlowTest() { this = "DataFlowTest" } + + override string getARelevantTag() { result = "dataflow" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "dataflow" and + exists(DataFlow::Node sink | any(DataConfiguration c).hasFlow(_, sink) | + element = sink.toString() and + value = "" and + sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) + ) + } +} + +class TaintConfiguration extends TaintTracking::Configuration { + TaintConfiguration() { this = "taint-configuration" } + + override predicate isSource(DataFlow::Node source) { + source = any(DataFlow::CallNode c | c.getCalleeName() = "source").getResult(0) + } + + override predicate isSink(DataFlow::Node sink) { + sink = any(DataFlow::CallNode c | c.getCalleeName() = "sink").getArgument(0) + } +} + +class TaintFlowTest extends InlineExpectationsTest { + TaintFlowTest() { this = "TaintFlowTest" } + + override string getARelevantTag() { result = "taintflow" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "taintflow" and + exists(DataFlow::Node sink | any(TaintConfiguration c).hasFlow(_, sink) | + element = sink.toString() and + value = "" and + sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) + ) + } +} diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go b/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go new file mode 100644 index 00000000000..b91dfd28718 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go @@ -0,0 +1,26 @@ +package main + +func source() string { + return "untrusted data" +} + +func sink(string) { +} + +func sliceToArray(p []string) [1]string { + return [1]string(p) +} + +func main() { + // Test the new slice->array conversion permitted in Go 1.20 + var a [4]string + a[0] = source() + alias := sliceToArray(a[:]) + sink(alias[0]) // $ taintflow + + // Compare with the standard dataflow support for arrays + var b [4]string + b[0] = source() + sink(b[0]) // $ taintflow +} + From e1ae3c3cfb6798ecd1c35a743692517763b756d7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 15 Feb 2023 13:44:45 +0100 Subject: [PATCH 248/415] Python: sys.exit if import resolution tests fail --- python/ql/test/experimental/import-resolution/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/import-resolution/main.py b/python/ql/test/experimental/import-resolution/main.py index 45c84559fb6..ca31a825782 100644 --- a/python/ql/test/experimental/import-resolution/main.py +++ b/python/ql/test/experimental/import-resolution/main.py @@ -91,4 +91,4 @@ print() if status() == 0: print("PASS") else: - print("FAIL") + sys.exit("FAIL") From df6039d6cf0842cdb769a4bd80c83b6b10e79372 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 15 Feb 2023 13:50:27 +0100 Subject: [PATCH 249/415] Python: Add import resolution regression --- python/ql/test/experimental/import-resolution/main.py | 6 ++++++ .../import-resolution/package/subpackage2/__init__.py | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 python/ql/test/experimental/import-resolution/package/subpackage2/__init__.py diff --git a/python/ql/test/experimental/import-resolution/main.py b/python/ql/test/experimental/import-resolution/main.py index ca31a825782..faddcaef093 100644 --- a/python/ql/test/experimental/import-resolution/main.py +++ b/python/ql/test/experimental/import-resolution/main.py @@ -84,6 +84,12 @@ from attr_clash import clashing_attr, non_clashing_submodule #$ imports=attr_cla check("clashing_attr", clashing_attr, "clashing_attr", globals()) #$ prints=clashing_attr SPURIOUS: prints="" check("non_clashing_submodule", non_clashing_submodule, "", globals()) #$ prints="" + +# check that import * from an __init__ file works +from package.subpackage2 import * +check("subpackage2_attr", subpackage2_attr, "subpackage2_attr", globals()) #$ MISSING: prints=subpackage2_attr + + exit(__file__) print() diff --git a/python/ql/test/experimental/import-resolution/package/subpackage2/__init__.py b/python/ql/test/experimental/import-resolution/package/subpackage2/__init__.py new file mode 100644 index 00000000000..8f0b8fe857f --- /dev/null +++ b/python/ql/test/experimental/import-resolution/package/subpackage2/__init__.py @@ -0,0 +1,6 @@ +from trace import * +enter(__file__) + +subpackage2_attr = "subpackage2_attr" + +exit(__file__) From 66c35294652079a4521c7f5b68d53f38a2e7cff9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 15 Feb 2023 13:57:18 +0100 Subject: [PATCH 250/415] Python: Fix import * from `__init__.py` files --- .../semmle/python/dataflow/new/internal/ImportResolution.qll | 3 ++- python/ql/test/experimental/import-resolution/main.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index e4af21caacc..aaea46fb4b8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -167,8 +167,9 @@ module ImportResolution { ) } + /** Gets the module from which attributes are imported by `i`. */ Module getModuleImportedByImportStar(ImportStar i) { - isPreferredModuleForName(result.getFile(), i.getImportedModuleName()) + isPreferredModuleForName(result.getFile(), i.getImportedModuleName() + ["", ".__init__"]) } /** diff --git a/python/ql/test/experimental/import-resolution/main.py b/python/ql/test/experimental/import-resolution/main.py index faddcaef093..0dac9689d7f 100644 --- a/python/ql/test/experimental/import-resolution/main.py +++ b/python/ql/test/experimental/import-resolution/main.py @@ -87,7 +87,7 @@ check("non_clashing_submodule", non_clashing_submodule, " Date: Wed, 15 Feb 2023 14:18:42 +0100 Subject: [PATCH 251/415] Python: Add wrapper for `isPreferredModuleForName` We talked about how it's annoying that we in 4 places have the same fix `isPreferredModuleForName(.getFile(), + ["", ".__init__"])` , and that it would be nice to have a simple wrapper predicate that ensures we never forget to do the `+ ["", ".__init__"]` dance... I had trouble coming up with a name for this (ironically), but I think `getModuleFromName` is good enough. --- .../new/internal/ImportResolution.qll | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index aaea46fb4b8..5cfc28d0a5f 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -167,9 +167,22 @@ module ImportResolution { ) } + /** + * Gets the (most likely) module for the name `name`, if any. + * + * Handles the fact that for the name `` representing a package the actual module + * is `.__init__`. + * + * See `isPreferredModuleForName` for more details on what "most likely" module means. + */ + pragma[inline] + private Module getModuleFromName(string name) { + isPreferredModuleForName(result.getFile(), name + ["", ".__init__"]) + } + /** Gets the module from which attributes are imported by `i`. */ Module getModuleImportedByImportStar(ImportStar i) { - isPreferredModuleForName(result.getFile(), i.getImportedModuleName() + ["", ".__init__"]) + result = getModuleFromName(i.getImportedModuleName()) } /** @@ -224,7 +237,7 @@ module ImportResolution { exists(string module_name | result = getReferenceToModuleName(module_name) | // Depending on whether the referenced module is a package or not, we may need to add a // trailing `.__init__` to the module name. - isPreferredModuleForName(m.getFile(), module_name + ["", ".__init__"]) + m = getModuleFromName(module_name) or // Module defined via `sys.modules` m = sys_modules_module_with_name(module_name) @@ -235,7 +248,7 @@ module ImportResolution { ar.accesses(getModuleReference(p), attr_name) and result = ar | - isPreferredModuleForName(m.getFile(), p.getPackageName() + "." + attr_name + ["", ".__init__"]) + m = getModuleFromName(p.getPackageName() + "." + attr_name) ) or // This is also true for attributes that come from reexports. @@ -249,8 +262,7 @@ module ImportResolution { exists(string submodule, Module package | SsaSource::init_module_submodule_defn(result.asVar().getSourceVariable(), package.getEntryNode()) and - isPreferredModuleForName(m.getFile(), - package.getPackageName() + "." + submodule + ["", ".__init__"]) + m = getModuleFromName(package.getPackageName() + "." + submodule) ) } From 7e16fa9cbe6bb99cc5ad9d8e5f99d974ab9c7373 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 15 Feb 2023 14:25:33 +0100 Subject: [PATCH 252/415] Python: Add change-note --- python/ql/lib/change-notes/2023-02-15-import-star-package.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 python/ql/lib/change-notes/2023-02-15-import-star-package.md diff --git a/python/ql/lib/change-notes/2023-02-15-import-star-package.md b/python/ql/lib/change-notes/2023-02-15-import-star-package.md new file mode 100644 index 00000000000..c2f3e24cc2d --- /dev/null +++ b/python/ql/lib/change-notes/2023-02-15-import-star-package.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed module resolution so we properly recognize that in `from import *`, where `` is a package, the actual imports are made from the `/__init__.py` file. From 8ee36a527846550ee453c90c296528c8f458c038 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 15 Feb 2023 16:11:22 +0000 Subject: [PATCH 253/415] Test generator improvements - Accept yml files as input - Output the correct type for constructors --- .../flowtestcasegenerator/FlowTestCase.qll | 2 +- .../FlowTestCaseUtils.qll | 5 ++ .../GenerateFlowTestCase.py | 78 +++++++++++++++---- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll b/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll index f90bbf2c908..9d72b1a9996 100644 --- a/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll +++ b/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll @@ -228,7 +228,7 @@ class TestCase extends TTestCase { */ Type getOutputType() { if baseOutput = SummaryComponentStack::return() - then result = callable.getReturnType() + then result = getReturnType(callable) else exists(int i | baseOutput = SummaryComponentStack::argument(i) and diff --git a/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll b/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll index 8a48272a2ae..4c4979e1285 100644 --- a/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll +++ b/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll @@ -16,6 +16,11 @@ Type getRootSourceDeclaration(Type t) { else result = t } +/** Gets the return type of the callable c, or the constructed tpe if it's a constructor */ +Type getReturnType(Callable c) { + if c instanceof Constructor then result = c.getDeclaringType() else result = c.getReturnType() +} + /** * Holds if type `t` does not clash with another type we want to import that has the same base name. */ diff --git a/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py b/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py index fb10c934afd..79b3d174e61 100755 --- a/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py +++ b/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import errno import json @@ -47,7 +47,7 @@ if len(sys.argv) != 4: try: os.makedirs(sys.argv[3]) -except Exception as e: +except OSError as e: if e.errno != errno.EEXIST: print("Failed to create output directory %s: %s" % (sys.argv[3], e)) sys.exit(1) @@ -75,38 +75,86 @@ except Exception as e: (sys.argv[2], e), file=sys.stderr) sys.exit(1) -commentRegex = re.compile("^\s*(//|#)") +commentRegex = re.compile(r"^\s*(//|#)") def isComment(s): return commentRegex.match(s) is not None -try: - with open(sys.argv[1], "r") as f: - specs = [l for l in f if not isComment(l)] -except Exception as e: - print("Failed to open %s: %s\n" % (sys.argv[1], e)) +def readCsv(file): + try: + with open(file, "r") as f: + specs = [l for l in f if not isComment(l)] + except Exception as e: + print("Failed to open %s: %s\n" % (file, e)) + sys.exit(1) + + specs = [row.split(";") for row in specs] + return specs + + +def readYml(file): + try: + import yaml + with open(file, "r") as f: + doc = yaml.load(f.read(), yaml.Loader) + specs = [] + for ext in doc['extensions']: + if ext['addsTo']['extensible'] == 'summaryModel': + for row in ext['data']: + if isinstance(row[2], bool): + row[2] = str(row[2]).lower() + specs.append(row) + return specs + except ImportError: + print("PyYAML not found - try \n pip install pyyaml") + sys.exit(1) + except ValueError as e: + print("Invalid yaml model in %s: %s\n" % (file, e)) + sys.exit(1) + except OSError as e: + print("Failed to open %s: %s\n" % (file, e)) + sys.exit(1) + + +def readYmlDir(dirname): + specs = [] + for f in os.listdir(dirname): + if f.endswith('.yml'): + specs += readYml(f"{dirname}/{f}") + return specs + + +specsFile = sys.argv[1] +if os.path.isdir(specsFile): + specs = readYmlDir(specsFile) +elif specsFile.endswith(".yml") or specsFile.endswith(".yaml"): + specs = readYml(specsFile) +elif specsFile.endswith(".csv"): + spcs = readCsv(specsFile) +else: + print(f"Invalid specs {specsFile}. Must be a csv file, a yml file, or a directory of yml files.") sys.exit(1) + projectTestPkgDir = os.path.join(projectDir, "src", "main", "java", "test") projectTestFile = os.path.join(projectTestPkgDir, "Test.java") os.makedirs(projectTestPkgDir) -def qualifiedOuterNameFromCsvRow(row): - cells = row.split(";") - if len(cells) < 2: +def qualifiedOuterNameFromRow(row): + if len(row) < 2: return None - return cells[0] + "." + cells[1].replace("$", ".") + return row[0] + "." + row[1].replace("$", ".") with open(projectTestFile, "w") as testJava: testJava.write("package test;\n\npublic class Test {\n\n") for i, spec in enumerate(specs): - outerName = qualifiedOuterNameFromCsvRow(spec) + outerName = qualifiedOuterNameFromRow(spec) if outerName is None: print("A taint specification has the wrong format: should be 'package;classname;methodname....'", file=sys.stderr) print("Mis-formatted row: " + spec, file=sys.stderr) @@ -140,7 +188,7 @@ dependencies: with open(qlFile, "w") as f: f.write( "import java\nimport utils.flowtestcasegenerator.GenerateFlowTestCase\n\nclass GenRow extends TargetSummaryModelCsv {\n\n\toverride predicate row(string r) {\n\t\tr = [\n") - f.write(",\n".join('\t\t\t"%s"' % spec.strip() for spec in specs)) + f.write(",\n".join('\t\t\t"%s"' % ';'.join(spec) for spec in specs)) f.write("\n\t\t]\n\t}\n}\n") print("Generating tests") @@ -221,7 +269,7 @@ if len(supportModelRows) != 0: # Make a test extension file with open(resultYml, "w") as f: models = "\n".join(' - [%s]' % - modelSpecRow[0].strip() for modelSpecRow in supportModelRows) + modelSpecRow[0].strip() for modelSpecRow in supportModelRows) dataextensions = f"""extensions: - addsTo: pack: codeql/java-tests From 95a131d0d335dcd51ace153e8d7f8e179ad7aceb Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 15 Feb 2023 16:18:47 +0000 Subject: [PATCH 254/415] Update help text --- .../GenerateFlowTestCase.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py b/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py index 79b3d174e61..67f5117fabe 100755 --- a/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py +++ b/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py @@ -13,11 +13,14 @@ import tempfile if any(s == "--help" for s in sys.argv): print("""Usage: -GenerateFlowTestCase.py specsToTest.csv projectPom.xml outdir [--force] +GenerateFlowTestCase.py specsToTest projectPom.xml outdir [--force] -This generates test cases exercising function model specifications found in specsToTest.csv +This generates test cases exercising function model specifications found in specsToTest producing files Test.java, test.ql, test.ext.yml and test.expected in outdir. +specsToTest should either be a .csv file, a .yml file, or a directory of .yml files, containing the +model specifications to test. + projectPom.xml should be a Maven pom sufficient to resolve the classes named in specsToTest.csv. Typically this means supplying a skeleton POM section that retrieves whatever jars contain the needed classes. @@ -40,9 +43,10 @@ if "--force" in sys.argv: if len(sys.argv) != 4: print( - "Usage: GenerateFlowTestCase.py specsToTest.csv projectPom.xml outdir [--force]", file=sys.stderr) - print("specsToTest.csv should contain CSV rows describing method taint-propagation specifications to test", file=sys.stderr) - print("projectPom.xml should import dependencies sufficient to resolve the types used in specsToTest.csv", file=sys.stderr) + "Usage: GenerateFlowTestCase.py specsToTest projectPom.xml outdir [--force]", file=sys.stderr) + print("specsToTest should contain CSV rows or YAML models describing method taint-propagation specifications to test", file=sys.stderr) + print("projectPom.xml should import dependencies sufficient to resolve the types used in specsToTest", file=sys.stderr) + print("\nRun with --help for more details.", file=sys.stderr) sys.exit(1) try: @@ -85,7 +89,7 @@ def isComment(s): def readCsv(file): try: with open(file, "r") as f: - specs = [l for l in f if not isComment(l)] + specs = [l.strip() for l in f if not isComment(l)] except Exception as e: print("Failed to open %s: %s\n" % (file, e)) sys.exit(1) From c7aaad9ed0e7bda3f9847b6443df7b64d343f2dc Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Tue, 14 Feb 2023 16:41:28 +0000 Subject: [PATCH 255/415] JS: avoid adding a deprecated CryptographicOperation#getInput to py/ruby --- .../ql/lib/semmle/javascript/Concepts.qll | 19 ++++++++++++++++++- .../javascript/internal/ConceptsShared.qll | 6 ------ .../semmle/python/internal/ConceptsShared.qll | 6 ------ .../codeql/ruby/internal/ConceptsShared.qll | 6 ------ 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/Concepts.qll b/javascript/ql/lib/semmle/javascript/Concepts.qll index a760e746030..14308a3d17b 100644 --- a/javascript/ql/lib/semmle/javascript/Concepts.qll +++ b/javascript/ql/lib/semmle/javascript/Concepts.qll @@ -115,5 +115,22 @@ abstract class PersistentWriteAccess extends DataFlow::Node { * Provides models for cryptographic things. */ module Cryptography { - import semmle.javascript.internal.ConceptsShared::Cryptography + private import semmle.javascript.internal.ConceptsShared::Cryptography as SC + + class CryptographicOperation extends SC::CryptographicOperation instanceof CryptographicOperation::Range { + /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + deprecated final DataFlow::Node getInput() { result = this.getAnInput() } + } + + class EncryptionAlgorithm = SC::EncryptionAlgorithm; + + class HashingAlgorithm = SC::HashingAlgorithm; + + class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm; + + module CryptographicOperation = SC::CryptographicOperation; + + class BlockMode = SC::BlockMode; + + class CryptographicAlgorithm = SC::CryptographicAlgorithm; } diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 522c883e0b4..449aca6e5c4 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -43,9 +43,6 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ DataFlow::Node getAnInput() { result = super.getAnInput() } - /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ - deprecated final DataFlow::Node getInput() { result = super.getInput() } - /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used @@ -70,9 +67,6 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ abstract DataFlow::Node getAnInput(); - /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ - deprecated final DataFlow::Node getInput() { result = this.getAnInput() } - /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 522c883e0b4..449aca6e5c4 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -43,9 +43,6 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ DataFlow::Node getAnInput() { result = super.getAnInput() } - /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ - deprecated final DataFlow::Node getInput() { result = super.getInput() } - /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used @@ -70,9 +67,6 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ abstract DataFlow::Node getAnInput(); - /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ - deprecated final DataFlow::Node getInput() { result = this.getAnInput() } - /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 522c883e0b4..449aca6e5c4 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -43,9 +43,6 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ DataFlow::Node getAnInput() { result = super.getAnInput() } - /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ - deprecated final DataFlow::Node getInput() { result = super.getInput() } - /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used @@ -70,9 +67,6 @@ module Cryptography { /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ abstract DataFlow::Node getAnInput(); - /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ - deprecated final DataFlow::Node getInput() { result = this.getAnInput() } - /** * Gets the block mode used to perform this cryptographic operation. * This may have no result - for example if the `CryptographicAlgorithm` used From d4d0b910853b3609bae33c966adf65f904afdbe4 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 15 Feb 2023 15:22:49 +0000 Subject: [PATCH 256/415] dynamic: switch CryptographicOperation::Range#getBlockMode() back to being an abstract predicate --- javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll | 2 +- python/ql/lib/semmle/python/internal/ConceptsShared.qll | 2 +- ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 449aca6e5c4..66089988419 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -72,7 +72,7 @@ module Cryptography { * This may have no result - for example if the `CryptographicAlgorithm` used * is a stream cipher rather than a block cipher. */ - BlockMode getBlockMode() { none() } + abstract BlockMode getBlockMode(); } } diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 449aca6e5c4..66089988419 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -72,7 +72,7 @@ module Cryptography { * This may have no result - for example if the `CryptographicAlgorithm` used * is a stream cipher rather than a block cipher. */ - BlockMode getBlockMode() { none() } + abstract BlockMode getBlockMode(); } } diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 449aca6e5c4..66089988419 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -72,7 +72,7 @@ module Cryptography { * This may have no result - for example if the `CryptographicAlgorithm` used * is a stream cipher rather than a block cipher. */ - BlockMode getBlockMode() { none() } + abstract BlockMode getBlockMode(); } } From 925b4a3fa88caca6c4f48c0eab3d88fa11528f55 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 15 Feb 2023 16:20:08 +0000 Subject: [PATCH 257/415] JS: improve documentation on deprecated CryptographicOperation#getInput() predicate --- javascript/ql/lib/semmle/javascript/Concepts.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/ql/lib/semmle/javascript/Concepts.qll b/javascript/ql/lib/semmle/javascript/Concepts.qll index 14308a3d17b..c70a6f3804f 100644 --- a/javascript/ql/lib/semmle/javascript/Concepts.qll +++ b/javascript/ql/lib/semmle/javascript/Concepts.qll @@ -118,7 +118,13 @@ module Cryptography { private import semmle.javascript.internal.ConceptsShared::Cryptography as SC class CryptographicOperation extends SC::CryptographicOperation instanceof CryptographicOperation::Range { - /** DEPRECATED. This predicate has been renamed to `getAnInput`. */ + /** + * DEPRECATED. This predicate has been renamed to `getAnInput`. + * + * To implement `CryptographicOperation`, please extend + * `CryptographicOperation::Range` and implement `getAnInput` instead of + * extending this class directly. + */ deprecated final DataFlow::Node getInput() { result = this.getAnInput() } } From e8cbf7287d66538d89c19c2bd9cf1532f45a24e9 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 15 Feb 2023 16:50:24 +0000 Subject: [PATCH 258/415] JS: breaking change note for CryptographicOperation sync --- ...23-02-15-cryptographic-operation-getinput-deprecated.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2023-02-15-cryptographic-operation-getinput-deprecated.md diff --git a/javascript/ql/lib/change-notes/2023-02-15-cryptographic-operation-getinput-deprecated.md b/javascript/ql/lib/change-notes/2023-02-15-cryptographic-operation-getinput-deprecated.md new file mode 100644 index 00000000000..246d23739c1 --- /dev/null +++ b/javascript/ql/lib/change-notes/2023-02-15-cryptographic-operation-getinput-deprecated.md @@ -0,0 +1,7 @@ +--- +category: breaking +--- +* The `CryptographicOperation` concept has been changed to use a range pattern. This is a breaking change and existing implementations of `CryptographicOperation` will need to be updated in order to compile. These implementations can be updated by: + 1. Extending `CryptographicOperation::Range` rather than `CryptographicOperation` + 2. Renaming the `getInput()` member predicate as `getAnInput()` + 3. Implementing the `BlockMode getBlockMode()` member predicate. The implementation for this can be `none()` if the operation is a hashing operation or an encryption operation using a stream cipher. From 43af306d602fcb63a22772b90b4214d3ad8bed10 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 15 Feb 2023 16:55:18 +0000 Subject: [PATCH 259/415] dynamic: more detailed qldoc for CryptographicOperation#getBlockMode() --- .../javascript/internal/ConceptsShared.qll | 16 ++++++++++++---- .../semmle/python/internal/ConceptsShared.qll | 16 ++++++++++++---- .../lib/codeql/ruby/internal/ConceptsShared.qll | 16 ++++++++++++---- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 66089988419..def6e7da103 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -45,8 +45,12 @@ module Cryptography { /** * Gets the block mode used to perform this cryptographic operation. - * This may have no result - for example if the `CryptographicAlgorithm` used - * is a stream cipher rather than a block cipher. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. */ BlockMode getBlockMode() { result = super.getBlockMode() } } @@ -69,8 +73,12 @@ module Cryptography { /** * Gets the block mode used to perform this cryptographic operation. - * This may have no result - for example if the `CryptographicAlgorithm` used - * is a stream cipher rather than a block cipher. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. */ abstract BlockMode getBlockMode(); } diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 66089988419..def6e7da103 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -45,8 +45,12 @@ module Cryptography { /** * Gets the block mode used to perform this cryptographic operation. - * This may have no result - for example if the `CryptographicAlgorithm` used - * is a stream cipher rather than a block cipher. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. */ BlockMode getBlockMode() { result = super.getBlockMode() } } @@ -69,8 +73,12 @@ module Cryptography { /** * Gets the block mode used to perform this cryptographic operation. - * This may have no result - for example if the `CryptographicAlgorithm` used - * is a stream cipher rather than a block cipher. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. */ abstract BlockMode getBlockMode(); } diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 66089988419..def6e7da103 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -45,8 +45,12 @@ module Cryptography { /** * Gets the block mode used to perform this cryptographic operation. - * This may have no result - for example if the `CryptographicAlgorithm` used - * is a stream cipher rather than a block cipher. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. */ BlockMode getBlockMode() { result = super.getBlockMode() } } @@ -69,8 +73,12 @@ module Cryptography { /** * Gets the block mode used to perform this cryptographic operation. - * This may have no result - for example if the `CryptographicAlgorithm` used - * is a stream cipher rather than a block cipher. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. */ abstract BlockMode getBlockMode(); } From 1958b9dcd548261fe089de26d7089c1f11bcf952 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 15 Feb 2023 16:59:03 +0000 Subject: [PATCH 260/415] JS: add missing qldoc --- javascript/ql/lib/semmle/javascript/Concepts.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/Concepts.qll b/javascript/ql/lib/semmle/javascript/Concepts.qll index c70a6f3804f..831fd0fe145 100644 --- a/javascript/ql/lib/semmle/javascript/Concepts.qll +++ b/javascript/ql/lib/semmle/javascript/Concepts.qll @@ -117,6 +117,13 @@ abstract class PersistentWriteAccess extends DataFlow::Node { module Cryptography { private import semmle.javascript.internal.ConceptsShared::Cryptography as SC + /** + * A data-flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CryptographicOperation` instead. + */ class CryptographicOperation extends SC::CryptographicOperation instanceof CryptographicOperation::Range { /** * DEPRECATED. This predicate has been renamed to `getAnInput`. From 801ed1ce7c304cfb10bcf31c435d9d1660fc51fe Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Wed, 15 Feb 2023 17:05:33 +0000 Subject: [PATCH 261/415] Ruby: add Twirp.expected --- ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected diff --git a/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected new file mode 100644 index 00000000000..66da43ab78b --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/Twirp/Twirp.expected @@ -0,0 +1,6 @@ +sourceTest +| hello_world_server.rb:8:13:8:15 | req | +ssrfSinkTest +| hello_world_client.rb:6:47:6:75 | "http://localhost:8080/twirp" | +serviceInstantiationTest +| hello_world_server.rb:24:11:24:61 | call to new | From 7d2b78b46350ad79f7c46ff0498f374688e36073 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 17:15:00 +0000 Subject: [PATCH 262/415] Note that all interface types are considered comparable as of Go 1.20 --- go/ql/lib/semmle/go/Types.qll | 20 ++----- .../semmle/go/Types/QualifiedNames.expected | 50 ++++++++--------- .../semmle/go/Types/Types.expected | 50 ++++++++--------- .../semmle/go/Types/interface.go | 54 ++++++++++--------- 4 files changed, 83 insertions(+), 91 deletions(-) diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 76a0455a20b..ea522b2e11e 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -112,22 +112,10 @@ class Type extends @type { or u instanceof ArrayType and u.(ArrayType).getElementType().implementsComparable() or - exists(InterfaceType uif | uif = u | - not uif instanceof BasicInterfaceType and - if exists(uif.getAnEmbeddedTypeSetLiteral()) - then - // All types in the intersection of all the embedded type set - // literals must implement comparable. - forall(Type intersectionType | - intersectionType = uif.getAnEmbeddedTypeSetLiteral().getATerm().getType() and - forall(TypeSetLiteralType tslit | tslit = uif.getAnEmbeddedTypeSetLiteral() | - intersectionType = tslit.getATerm().getType() - ) - | - intersectionType.implementsComparable() - ) - else uif.isOrEmbedsComparable() - ) + // As of Go 1.20, any interface type satisfies the `comparable` constraint, even though comparison + // may panic at runtime depending on the actual object's concrete type. + // Look at git history here if you need the old definition. + u instanceof InterfaceType ) } diff --git a/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected b/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected index b658da877e7..3f170370284 100644 --- a/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected +++ b/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected @@ -51,31 +51,31 @@ | interface.go:95:6:95:8 | i18 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.i18 | | interface.go:101:6:101:8 | i19 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.i19 | | interface.go:105:6:105:8 | i20 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.i20 | -| interface.go:110:6:110:19 | testComparable | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable | -| interface.go:111:6:111:20 | testComparable0 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable0 | -| interface.go:112:6:112:20 | testComparable1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable1 | -| interface.go:113:6:113:20 | testComparable2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable2 | -| interface.go:114:6:114:20 | testComparable3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable3 | -| interface.go:115:6:115:20 | testComparable4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable4 | -| interface.go:116:6:116:20 | testComparable5 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable5 | -| interface.go:117:6:117:20 | testComparable6 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable6 | -| interface.go:118:6:118:20 | testComparable7 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable7 | -| interface.go:119:6:119:20 | testComparable8 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable8 | -| interface.go:120:6:120:20 | testComparable9 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable9 | -| interface.go:121:6:121:21 | testComparable10 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable10 | -| interface.go:122:6:122:21 | testComparable11 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable11 | -| interface.go:123:6:123:21 | testComparable12 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable12 | -| interface.go:124:6:124:21 | testComparable13 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable13 | -| interface.go:125:6:125:21 | testComparable14 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable14 | -| interface.go:126:6:126:21 | testComparable15 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable15 | -| interface.go:127:6:127:21 | testComparable16 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable16 | -| interface.go:128:6:128:21 | testComparable17 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable17 | -| interface.go:129:6:129:21 | testComparable18 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable18 | -| interface.go:130:6:130:21 | testComparable19 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable19 | -| interface.go:131:6:131:21 | testComparable20 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable20 | -| interface.go:132:6:132:21 | testComparable21 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable21 | -| interface.go:133:6:133:21 | testComparable22 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable22 | -| interface.go:134:6:134:21 | testComparable23 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable23 | +| interface.go:114:6:114:19 | testComparable | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable | +| interface.go:115:6:115:20 | testComparable0 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable0 | +| interface.go:116:6:116:20 | testComparable1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable1 | +| interface.go:117:6:117:20 | testComparable2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable2 | +| interface.go:118:6:118:20 | testComparable3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable3 | +| interface.go:119:6:119:20 | testComparable4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable4 | +| interface.go:120:6:120:20 | testComparable5 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable5 | +| interface.go:121:6:121:20 | testComparable6 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable6 | +| interface.go:122:6:122:20 | testComparable7 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable7 | +| interface.go:123:6:123:20 | testComparable8 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable8 | +| interface.go:124:6:124:20 | testComparable9 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable9 | +| interface.go:125:6:125:21 | testComparable10 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable10 | +| interface.go:126:6:126:21 | testComparable11 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable11 | +| interface.go:127:6:127:21 | testComparable12 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable12 | +| interface.go:128:6:128:21 | testComparable13 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable13 | +| interface.go:129:6:129:21 | testComparable14 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable14 | +| interface.go:130:6:130:21 | testComparable15 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable15 | +| interface.go:131:6:131:21 | testComparable16 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable16 | +| interface.go:132:6:132:21 | testComparable17 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable17 | +| interface.go:133:6:133:21 | testComparable18 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable18 | +| interface.go:134:6:134:21 | testComparable19 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable19 | +| interface.go:135:6:135:21 | testComparable20 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable20 | +| interface.go:136:6:136:21 | testComparable21 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable21 | +| interface.go:137:6:137:21 | testComparable22 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable22 | +| interface.go:138:6:138:21 | testComparable23 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable23 | | pkg1/embedding.go:8:6:8:9 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.base | | pkg1/embedding.go:19:6:19:13 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder | | pkg1/embedding.go:22:6:22:16 | ptrembedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.ptrembedder | diff --git a/go/ql/test/library-tests/semmle/go/Types/Types.expected b/go/ql/test/library-tests/semmle/go/Types/Types.expected index 76933af4008..b4a05a8858d 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Types.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Types.expected @@ -51,31 +51,31 @@ | interface.go:95:6:95:8 | i18 | i18 | | interface.go:101:6:101:8 | i19 | i19 | | interface.go:105:6:105:8 | i20 | i20 | -| interface.go:110:6:110:19 | testComparable | testComparable | -| interface.go:111:6:111:20 | testComparable0 | testComparable0 | -| interface.go:112:6:112:20 | testComparable1 | testComparable1 | -| interface.go:113:6:113:20 | testComparable2 | testComparable2 | -| interface.go:114:6:114:20 | testComparable3 | testComparable3 | -| interface.go:115:6:115:20 | testComparable4 | testComparable4 | -| interface.go:116:6:116:20 | testComparable5 | testComparable5 | -| interface.go:117:6:117:20 | testComparable6 | testComparable6 | -| interface.go:118:6:118:20 | testComparable7 | testComparable7 | -| interface.go:119:6:119:20 | testComparable8 | testComparable8 | -| interface.go:120:6:120:20 | testComparable9 | testComparable9 | -| interface.go:121:6:121:21 | testComparable10 | testComparable10 | -| interface.go:122:6:122:21 | testComparable11 | testComparable11 | -| interface.go:123:6:123:21 | testComparable12 | testComparable12 | -| interface.go:124:6:124:21 | testComparable13 | testComparable13 | -| interface.go:125:6:125:21 | testComparable14 | testComparable14 | -| interface.go:126:6:126:21 | testComparable15 | testComparable15 | -| interface.go:127:6:127:21 | testComparable16 | testComparable16 | -| interface.go:128:6:128:21 | testComparable17 | testComparable17 | -| interface.go:129:6:129:21 | testComparable18 | testComparable18 | -| interface.go:130:6:130:21 | testComparable19 | testComparable19 | -| interface.go:131:6:131:21 | testComparable20 | testComparable20 | -| interface.go:132:6:132:21 | testComparable21 | testComparable21 | -| interface.go:133:6:133:21 | testComparable22 | testComparable22 | -| interface.go:134:6:134:21 | testComparable23 | testComparable23 | +| interface.go:114:6:114:19 | testComparable | testComparable | +| interface.go:115:6:115:20 | testComparable0 | testComparable0 | +| interface.go:116:6:116:20 | testComparable1 | testComparable1 | +| interface.go:117:6:117:20 | testComparable2 | testComparable2 | +| interface.go:118:6:118:20 | testComparable3 | testComparable3 | +| interface.go:119:6:119:20 | testComparable4 | testComparable4 | +| interface.go:120:6:120:20 | testComparable5 | testComparable5 | +| interface.go:121:6:121:20 | testComparable6 | testComparable6 | +| interface.go:122:6:122:20 | testComparable7 | testComparable7 | +| interface.go:123:6:123:20 | testComparable8 | testComparable8 | +| interface.go:124:6:124:20 | testComparable9 | testComparable9 | +| interface.go:125:6:125:21 | testComparable10 | testComparable10 | +| interface.go:126:6:126:21 | testComparable11 | testComparable11 | +| interface.go:127:6:127:21 | testComparable12 | testComparable12 | +| interface.go:128:6:128:21 | testComparable13 | testComparable13 | +| interface.go:129:6:129:21 | testComparable14 | testComparable14 | +| interface.go:130:6:130:21 | testComparable15 | testComparable15 | +| interface.go:131:6:131:21 | testComparable16 | testComparable16 | +| interface.go:132:6:132:21 | testComparable17 | testComparable17 | +| interface.go:133:6:133:21 | testComparable18 | testComparable18 | +| interface.go:134:6:134:21 | testComparable19 | testComparable19 | +| interface.go:135:6:135:21 | testComparable20 | testComparable20 | +| interface.go:136:6:136:21 | testComparable21 | testComparable21 | +| interface.go:137:6:137:21 | testComparable22 | testComparable22 | +| interface.go:138:6:138:21 | testComparable23 | testComparable23 | | pkg1/embedding.go:8:6:8:9 | base | base | | pkg1/embedding.go:19:6:19:13 | embedder | embedder | | pkg1/embedding.go:22:6:22:16 | ptrembedder | ptrembedder | diff --git a/go/ql/test/library-tests/semmle/go/Types/interface.go b/go/ql/test/library-tests/semmle/go/Types/interface.go index 40653aaca71..afda7e759a0 100644 --- a/go/ql/test/library-tests/semmle/go/Types/interface.go +++ b/go/ql/test/library-tests/semmle/go/Types/interface.go @@ -107,28 +107,32 @@ type i20 interface { StringB() string } -type testComparable[T comparable] struct{} // $ implementsComparable -type testComparable0[T0 i0] struct{} // $ implementsComparable -type testComparable1[T1 i1] struct{} // $ implementsComparable -type testComparable2[T2 i2] struct{} // $ implementsComparable -type testComparable3[T3 i3] struct{} // $ implementsComparable -type testComparable4[T4 i4] struct{} // $ implementsComparable -type testComparable5[T5 i5] struct{} // does not implement comparable -type testComparable6[T6 i6] struct{} // does not implement comparable -type testComparable7[T7 i7] struct{} // $ implementsComparable -type testComparable8[T8 i8] struct{} // does not implement comparable -type testComparable9[T9 i9] struct{} // does not implement comparable -type testComparable10[T10 i10] struct{} // $ implementsComparable -type testComparable11[T11 i11] struct{} // $ implementsComparable -type testComparable12[T12 i12] struct{} // does not implement comparable -type testComparable13[T13 i13] struct{} // does not implement comparable -type testComparable14[T14 i14] struct{} // $ implementsComparable -type testComparable15[T15 i15] struct{} // $ implementsComparable -type testComparable16[T16 i16] struct{} // does not implement comparable -type testComparable17[T17 i17] struct{} // does not implement comparable -type testComparable18[T18 i18] struct{} // $ implementsComparable -type testComparable19[T19 i19] struct{} // does not implement comparable -type testComparable20[T20 i20] struct{} // $ implementsComparable -type testComparable21[T21 ~[]byte | string] struct{} // does not implement comparable -type testComparable22[T22 any] struct{} // does not implement comparable -type testComparable23[T23 ~[5]byte | string] struct{} // $ implementsComparable +// These used to distinguish strictly-comparable interfaces (i.e. those which will not panic at runtime on attempting a comparison), +// which were required to satisfy the `comparable` type constraint in Go <1.20. Now they all match `comparable` as all interfaces +// are accepted. I mark those which are also strictly comparable for the future in case we want to expose that concept in QL. + +type testComparable[T comparable] struct{} // $ implementsComparable isStrictlyComparable +type testComparable0[T0 i0] struct{} // $ implementsComparable isStrictlyComparable +type testComparable1[T1 i1] struct{} // $ implementsComparable isStrictlyComparable +type testComparable2[T2 i2] struct{} // $ implementsComparable isStrictlyComparable +type testComparable3[T3 i3] struct{} // $ implementsComparable isStrictlyComparable +type testComparable4[T4 i4] struct{} // $ implementsComparable isStrictlyComparable +type testComparable5[T5 i5] struct{} // $ implementsComparable +type testComparable6[T6 i6] struct{} // $ implementsComparable +type testComparable7[T7 i7] struct{} // $ implementsComparable isStrictlyComparable +type testComparable8[T8 i8] struct{} // $ implementsComparable +type testComparable9[T9 i9] struct{} // $ implementsComparable +type testComparable10[T10 i10] struct{} // $ implementsComparable isStrictlyComparable +type testComparable11[T11 i11] struct{} // $ implementsComparable isStrictlyComparable +type testComparable12[T12 i12] struct{} // $ implementsComparable +type testComparable13[T13 i13] struct{} // $ implementsComparable +type testComparable14[T14 i14] struct{} // $ implementsComparable isStrictlyComparable +type testComparable15[T15 i15] struct{} // $ implementsComparable isStrictlyComparable +type testComparable16[T16 i16] struct{} // $ implementsComparable +type testComparable17[T17 i17] struct{} // $ implementsComparable +type testComparable18[T18 i18] struct{} // $ implementsComparable isStrictlyComparable +type testComparable19[T19 i19] struct{} // $ implementsComparable +type testComparable20[T20 i20] struct{} // $ implementsComparable isStrictlyComparable +type testComparable21[T21 ~[]byte | string] struct{} // $ implementsComparable +type testComparable22[T22 any] struct{} // $ implementsComparable +type testComparable23[T23 ~[5]byte | string] struct{} // $ implementsComparable isStrictlyComparable From d9e5c6c48a0d5f678a783a69222d6466cdb4d173 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 15 Feb 2023 17:21:03 +0000 Subject: [PATCH 263/415] Fix typo --- java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py b/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py index 67f5117fabe..5e35ca52dd1 100755 --- a/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py +++ b/java/ql/src/utils/flowtestcasegenerator/GenerateFlowTestCase.py @@ -136,7 +136,7 @@ if os.path.isdir(specsFile): elif specsFile.endswith(".yml") or specsFile.endswith(".yaml"): specs = readYml(specsFile) elif specsFile.endswith(".csv"): - spcs = readCsv(specsFile) + specs = readCsv(specsFile) else: print(f"Invalid specs {specsFile}. Must be a csv file, a yml file, or a directory of yml files.") sys.exit(1) From 7e7850374e15ed46ee2f438f76e2659aa379fb5e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 18:29:49 +0000 Subject: [PATCH 264/415] Implement standard library models for Go 1.20 --- go/ql/lib/semmle/go/frameworks/Stdlib.qll | 1 + .../lib/semmle/go/frameworks/stdlib/Bytes.qll | 9 +++ .../semmle/go/frameworks/stdlib/Errors.qll | 4 ++ .../lib/semmle/go/frameworks/stdlib/Sync.qll | 10 ++++ .../semmle/go/frameworks/stdlib/Unsafe.qll | 22 +++++++ .../go/frameworks/StdlibTaintFlow/Bytes.go | 58 +++++++++++++++++++ .../go/frameworks/StdlibTaintFlow/Errors.go | 22 +++++++ .../go/frameworks/StdlibTaintFlow/Sync.go | 44 ++++++++++++++ .../go/frameworks/StdlibTaintFlow/Unsafe.go | 46 +++++++++++++++ 9 files changed, 216 insertions(+) create mode 100644 go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll create mode 100644 go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go diff --git a/go/ql/lib/semmle/go/frameworks/Stdlib.qll b/go/ql/lib/semmle/go/frameworks/Stdlib.qll index db46167d205..232055ca751 100644 --- a/go/ql/lib/semmle/go/frameworks/Stdlib.qll +++ b/go/ql/lib/semmle/go/frameworks/Stdlib.qll @@ -65,6 +65,7 @@ import semmle.go.frameworks.stdlib.Syscall import semmle.go.frameworks.stdlib.TextScanner import semmle.go.frameworks.stdlib.TextTabwriter import semmle.go.frameworks.stdlib.TextTemplate +import semmle.go.frameworks.stdlib.Unsafe /** A `String()` method. */ class StringMethod extends TaintTracking::FunctionModel, Method { diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Bytes.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Bytes.qll index c2791b1eaa3..3d8df63f5fa 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Bytes.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Bytes.qll @@ -11,6 +11,15 @@ module Bytes { FunctionOutput outp; FunctionModels() { + hasQualifiedName("bytes", "Clone") and + (inp.isParameter(0) and outp.isResult()) + or + hasQualifiedName("bytes", "Cut") and + (inp.isParameter(0) and outp.isResult([0, 1])) + or + hasQualifiedName("bytes", ["CutPrefix", "CutSuffix"]) and + (inp.isParameter(0) and outp.isResult(0)) + or // signature: func Fields(s []byte) [][]byte hasQualifiedName("bytes", "Fields") and (inp.isParameter(0) and outp.isResult()) diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll index 5225ad97fee..b38584f1e92 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Errors.qll @@ -22,6 +22,10 @@ module Errors { // signature: func Unwrap(err error) error hasQualifiedName("errors", "Unwrap") and (inp.isParameter(0) and outp.isResult()) + or + // signature: func Join(errs ...error) error + hasQualifiedName("errors", "Join") and + (inp.isParameter(_) and outp.isResult()) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Sync.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Sync.qll index b82e1e59804..fcdb7660441 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Sync.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Sync.qll @@ -11,6 +11,9 @@ module Sync { FunctionOutput outp; MethodModels() { + hasQualifiedName("sync", "Map", "CompareAndSwap") and + (inp.isParameter(2) and outp.isReceiver()) + or // signature: func (*Map) Load(key interface{}) (value interface{}, ok bool) hasQualifiedName("sync", "Map", "Load") and (inp.isReceiver() and outp.isResult(0)) @@ -28,6 +31,13 @@ module Sync { hasQualifiedName("sync", "Map", "Store") and (inp.isParameter(_) and outp.isReceiver()) or + hasQualifiedName("sync", "Map", "Swap") and + ( + inp.isReceiver() and outp.isResult(0) + or + inp.isParameter(_) and outp.isReceiver() + ) + or // signature: func (*Pool) Get() interface{} hasQualifiedName("sync", "Pool", "Get") and (inp.isReceiver() and outp.isResult()) diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll new file mode 100644 index 00000000000..d9b83da9f24 --- /dev/null +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Unsafe.qll @@ -0,0 +1,22 @@ +/** + * Provides classes modeling security-relevant aspects of the `unsafe` package. + */ + +import go + +/** Provides models of commonly used functions in the `unsafe` package. */ +module Unsafe { + private class FunctionModels extends TaintTracking::FunctionModel { + FunctionInput inp; + FunctionOutput outp; + + FunctionModels() { + hasQualifiedName("unsafe", ["String", "StringData", "Slice", "SliceData"]) and + (inp.isParameter(0) and outp.isResult()) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = inp and output = outp + } + } +} diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go index a4d3230c009..70cf904d08b 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go @@ -316,6 +316,39 @@ func TaintStepTest_BytesReaderWriteTo_B0I0O0(sourceCQL interface{}) interface{} return intoWriter197 } +func TaintStepTest_Clone(sourceCQL interface{}) interface{} { + fromReader628 := sourceCQL.([]byte) + return bytes.Clone(fromReader628) +} + +func TaintStepTest_Cutleft(sourceCQL interface{}) interface{} { + fromReader628 := sourceCQL.([]byte) + sep := []byte{} + left, _, _ := bytes.Cut(fromReader628, sep) + return left +} + +func TaintStepTest_Cutright(sourceCQL interface{}) interface{} { + fromReader628 := sourceCQL.([]byte) + sep := []byte{} + _, right, _ := bytes.Cut(fromReader628, sep) + return right +} + +func TaintStepTest_CutPrefix(sourceCQL interface{}) interface{} { + fromReader628 := sourceCQL.([]byte) + sep := []byte{} + result, _ := bytes.CutPrefix(fromReader628, sep) + return result +} + +func TaintStepTest_CutSuffix(sourceCQL interface{}) interface{} { + fromReader628 := sourceCQL.([]byte) + sep := []byte{} + result, _ := bytes.CutSuffix(fromReader628, sep) + return result +} + func RunAllTaints_Bytes() { { source := newSource(0) @@ -567,4 +600,29 @@ func RunAllTaints_Bytes() { out := TaintStepTest_BytesReaderWriteTo_B0I0O0(source) sink(49, out) } + { + source := newSource(50) + out := TaintStepTest_Cutleft(source) + sink(50, out) + } + { + source := newSource(51) + out := TaintStepTest_Cutright(source) + sink(51, out) + } + { + source := newSource(52) + out := TaintStepTest_CutPrefix(source) + sink(52, out) + } + { + source := newSource(53) + out := TaintStepTest_CutSuffix(source) + sink(53, out) + } + { + source := newSource(54) + out := TaintStepTest_Clone(source) + sink(54, out) + } } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Errors.go b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Errors.go index 84ea857e58b..324f1e36ae7 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Errors.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Errors.go @@ -23,6 +23,18 @@ func TaintStepTest_ErrorsUnwrap_B0I0O0(sourceCQL interface{}) interface{} { return intoError957 } +func TaintStepTest_ErrorsJoin1(sourceCQL interface{}) interface{} { + fromError784 := sourceCQL.(error) + intoError957 := errors.Join(fromError784, errors.New("")) + return intoError957 +} + +func TaintStepTest_ErrorsJoin2(sourceCQL interface{}) interface{} { + fromError784 := sourceCQL.(error) + intoError957 := errors.Join(errors.New(""), fromError784) + return intoError957 +} + func RunAllTaints_Errors() { { source := newSource(0) @@ -39,4 +51,14 @@ func RunAllTaints_Errors() { out := TaintStepTest_ErrorsUnwrap_B0I0O0(source) sink(2, out) } + { + source := newSource(3) + out := TaintStepTest_ErrorsJoin1(source) + sink(3, out) + } + { + source := newSource(4) + out := TaintStepTest_ErrorsJoin2(source) + sink(4, out) + } } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Sync.go b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Sync.go index 3bc8c2d3dfe..25a0f7d96d0 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Sync.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Sync.go @@ -58,6 +58,30 @@ func TaintStepTest_SyncMapStore_B0I1O0(sourceCQL interface{}) interface{} { return intoMap881 } +func TaintStepTest_SyncMapSwapinkey(sourceCQL interface{}) interface{} { + var m sync.Map + m.Swap(sourceCQL, "value") + return m +} + +func TaintStepTest_SyncMapSwapinvalue(sourceCQL interface{}) interface{} { + var m sync.Map + m.Swap("key", sourceCQL) + return m +} + +func TaintStepTest_SyncMapSwapout(sourceCQL interface{}) interface{} { + m := sourceCQL.(sync.Map) + oldVal, _ := m.Swap("key", "value") + return oldVal +} + +func TaintStepTest_SyncMapCompareAndSwap(sourceCQL interface{}) interface{} { + var m sync.Map + m.CompareAndSwap("key", "compareTo", sourceCQL) + return m +} + func TaintStepTest_SyncPoolGet_B0I0O0(sourceCQL interface{}) interface{} { fromPool186 := sourceCQL.(sync.Pool) intoInterface284 := fromPool186.Get() @@ -122,4 +146,24 @@ func RunAllTaints_Sync() { out := TaintStepTest_SyncPoolPut_B0I0O0(source) sink(9, out) } + { + source := newSource(10) + out := TaintStepTest_SyncMapSwapinkey(source) + sink(10, out) + } + { + source := newSource(11) + out := TaintStepTest_SyncMapSwapinvalue(source) + sink(11, out) + } + { + source := newSource(12) + out := TaintStepTest_SyncMapSwapout(source) + sink(12, out) + } + { + source := newSource(13) + out := TaintStepTest_SyncMapCompareAndSwap(source) + sink(13, out) + } } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go new file mode 100644 index 00000000000..63df7bb8d66 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go @@ -0,0 +1,46 @@ +package main + +import "unsafe" + +func TaintStepTest_UnsafeSlice(sourceCQL interface{}) interface{} { + s := sourceCQL.(*byte) + return unsafe.Slice(s, 1) +} + +func TaintStepTest_UnsafeSliceData(sourceCQL interface{}) interface{} { + s := sourceCQL.([]byte) + return unsafe.SliceData(s) +} + +func TaintStepTest_UnsafeString(sourceCQL interface{}) interface{} { + s := sourceCQL.(*byte) + return unsafe.String(s, 1) +} + +func TaintStepTest_UnsafeStringData(sourceCQL interface{}) interface{} { + s := sourceCQL.(string) + return unsafe.StringData(s) +} + +func RunAllTaints_Sync() { + { + source := newSource(0) + out := TaintStepTest_UnsafeSlice(source) + sink(0, out) + } + { + source := newSource(1) + out := TaintStepTest_UnsafeSliceData(source) + sink(1, out) + } + { + source := newSource(2) + out := TaintStepTest_UnsafeString(source) + sink(2, out) + } + { + source := newSource(3) + out := TaintStepTest_UnsafeStringData(source) + sink(3, out) + } +} From 233bd8ce8c5254792f2021064dda57d0b710d8ab Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 18:31:28 +0000 Subject: [PATCH 265/415] Claim Go 1.20 support --- docs/codeql/reusables/supported-versions-compilers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index 5f6f5993a32..f9f4e091a90 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -16,7 +16,7 @@ .NET Core up to 3.1 .NET 5, .NET 6","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" - Go (aka Golang), "Go up to 1.19", "Go 1.11 or more recent", ``.go`` + Go (aka Golang), "Go up to 1.20", "Go 1.11 or more recent", ``.go`` Java,"Java 7 to 19 [4]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [5]_",``.java`` From c65fd69374fee363f6bf3c20d478330c7eeaea36 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 18:35:17 +0000 Subject: [PATCH 266/415] Add change note --- go/ql/lib/change-notes/2023-02-15-golang-120.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 go/ql/lib/change-notes/2023-02-15-golang-120.md diff --git a/go/ql/lib/change-notes/2023-02-15-golang-120.md b/go/ql/lib/change-notes/2023-02-15-golang-120.md new file mode 100644 index 00000000000..37e7433cbcb --- /dev/null +++ b/go/ql/lib/change-notes/2023-02-15-golang-120.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed, the definitions of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules, and taint flow models have been added for relevant new standard library functions. From 261a1348f007d5632af54bf86f5a10e9eac8a32e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 18:37:50 +0000 Subject: [PATCH 267/415] Update Twirp change note to new style --- .../2023-02-01--add-support-for-twirp-framework.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md b/go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md index 1bbf2df72cf..a5e70658c4a 100644 --- a/go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md +++ b/go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md @@ -1,2 +1,4 @@ -lgtm,codescanning +--- +category: minorAnalysis +--- * Support for the Twirp framework has been added. From 14655e1d8cdb04c83854ff61f02b16da23f1bad1 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 18:41:14 +0000 Subject: [PATCH 268/415] Autoformat go --- .../semmle/go/dataflow/ArrayConversion/main.go | 1 - .../go/frameworks/StdlibTaintFlow/Bytes.go | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go b/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go index b91dfd28718..1c83b891680 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ArrayConversion/main.go @@ -23,4 +23,3 @@ func main() { b[0] = source() sink(b[0]) // $ taintflow } - diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go index 70cf904d08b..8e31c32aba4 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Bytes.go @@ -323,29 +323,29 @@ func TaintStepTest_Clone(sourceCQL interface{}) interface{} { func TaintStepTest_Cutleft(sourceCQL interface{}) interface{} { fromReader628 := sourceCQL.([]byte) - sep := []byte{} - left, _, _ := bytes.Cut(fromReader628, sep) + sep := []byte{} + left, _, _ := bytes.Cut(fromReader628, sep) return left } func TaintStepTest_Cutright(sourceCQL interface{}) interface{} { fromReader628 := sourceCQL.([]byte) - sep := []byte{} - _, right, _ := bytes.Cut(fromReader628, sep) + sep := []byte{} + _, right, _ := bytes.Cut(fromReader628, sep) return right } func TaintStepTest_CutPrefix(sourceCQL interface{}) interface{} { fromReader628 := sourceCQL.([]byte) - sep := []byte{} - result, _ := bytes.CutPrefix(fromReader628, sep) + sep := []byte{} + result, _ := bytes.CutPrefix(fromReader628, sep) return result } func TaintStepTest_CutSuffix(sourceCQL interface{}) interface{} { fromReader628 := sourceCQL.([]byte) - sep := []byte{} - result, _ := bytes.CutSuffix(fromReader628, sep) + sep := []byte{} + result, _ := bytes.CutSuffix(fromReader628, sep) return result } From 3ce7fafb676b341034f120c3a2106def39e49a83 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 15 Feb 2023 19:05:01 +0000 Subject: [PATCH 269/415] Fix unsafe test routine name --- .../semmle/go/frameworks/StdlibTaintFlow/Unsafe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go index 63df7bb8d66..50f7e2281fa 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Unsafe.go @@ -22,7 +22,7 @@ func TaintStepTest_UnsafeStringData(sourceCQL interface{}) interface{} { return unsafe.StringData(s) } -func RunAllTaints_Sync() { +func RunAllTaints_Unsafe() { { source := newSource(0) out := TaintStepTest_UnsafeSlice(source) From 2f576a4fe949b1b2385589257120c3347c361f19 Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Wed, 15 Feb 2023 18:26:56 -0500 Subject: [PATCH 270/415] test both arguments of getConnection Co-authored-by: Tony Torralba --- .../CWE-798/semmle/tests/HardcodedMSSQLCredentials.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java index 476c724bdc0..173c965a8c7 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedMSSQLCredentials.java @@ -4,6 +4,7 @@ public class HardcodedMSSQLCredentials { public static void main(SQLServerDataSource ds) throws Exception { ds.setUser("Username"); // $ HardcodedCredentialsApiCall ds.setPassword("password"); // $ HardcodedCredentialsApiCall - ds.getConnection("Username", "password"); // $ HardcodedCredentialsApiCall + ds.getConnection("Username", null); // $ HardcodedCredentialsApiCall + ds.getConnection(null, "password"); // $ HardcodedCredentialsApiCall } } \ No newline at end of file From 2f1bd93a497d51963388c1a6addf591edf267d3a Mon Sep 17 00:00:00 2001 From: Chad Bentz <1760475+felickz@users.noreply.github.com> Date: Wed, 15 Feb 2023 18:40:40 -0500 Subject: [PATCH 271/415] change-notes for this minorAnalysis lib change --- .../2023-02-15-mssql-jdbc-hardcoded-credential-api.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 java/ql/lib/change-notes/2023-02-15-mssql-jdbc-hardcoded-credential-api.md diff --git a/java/ql/lib/change-notes/2023-02-15-mssql-jdbc-hardcoded-credential-api.md b/java/ql/lib/change-notes/2023-02-15-mssql-jdbc-hardcoded-credential-api.md new file mode 100644 index 00000000000..63fbb5647c1 --- /dev/null +++ b/java/ql/lib/change-notes/2023-02-15-mssql-jdbc-hardcoded-credential-api.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The query `java/hardcoded-credential-api-call` now recognizes methods that accept user and password from the SQLServerDataSource class of the Microsoft JDBC Driver for SQL Server. \ No newline at end of file From e2d7a6910c4e5c3b1352fb20238cc243f22b9067 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 16 Feb 2023 10:46:52 +0100 Subject: [PATCH 272/415] Swift: generate raw helpers in synthesized stubs This will add helpers to get the underlying raw entities or constructor arguments on stubs for synthesized classes. For example a schema like: ``` @synth.from_class(A) class B: pass @synth.on_arguments(base=A, index=int) class C: pass ``` will generate ``` cached private Raw::A getUnderlyingEntity() { this = Synth::TB(result) } ``` in the `B.qll` stub and ``` cached private Raw::A getUnderlyingBase() { this = Synth::TC(result, _) } cached private int getUnderlyingIndex() { this = Synth::TC(_, result) } ``` in the `C.qll` stub. As stubs these can be freely changed later on. --- swift/.gitignore | 3 +- swift/codegen/generators/qlgen.py | 38 ++- swift/codegen/lib/ql.py | 17 ++ swift/codegen/templates/ql_stub.mustache | 11 +- swift/codegen/test/test_ql.py | 7 + swift/codegen/test/test_qlgen.py | 24 ++ swift/ql/.generated.list | 296 ++++++++++++----------- 7 files changed, 244 insertions(+), 152 deletions(-) diff --git a/swift/.gitignore b/swift/.gitignore index 28451c72aaa..445d287f34a 100644 --- a/swift/.gitignore +++ b/swift/.gitignore @@ -11,5 +11,6 @@ compile_commands.json /.idea /cmake* -# VSCode default build directory +# VSCode default build directory and project directory /build +/.vscode diff --git a/swift/codegen/generators/qlgen.py b/swift/codegen/generators/qlgen.py index d7a6436a0a1..c6d285148fd 100755 --- a/swift/codegen/generators/qlgen.py +++ b/swift/codegen/generators/qlgen.py @@ -146,7 +146,7 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, prev_child: str = return ql.Property(**args) -def get_ql_class(cls: schema.Class): +def get_ql_class(cls: schema.Class) -> ql.Class: pragmas = {k: True for k in cls.pragmas if k.startswith("ql")} prev_child = "" properties = [] @@ -228,6 +228,10 @@ def format(codeql, files): log.debug(line.strip()) +def _get_path(cls: schema.Class) -> pathlib.Path: + return pathlib.Path(cls.group or "", cls.name).with_suffix(".qll") + + def _get_all_properties(cls: schema.Class, lookup: typing.Dict[str, schema.Class], already_seen: typing.Optional[typing.Set[int]] = None) -> \ typing.Iterable[typing.Tuple[schema.Class, schema.Property]]: @@ -283,6 +287,29 @@ def _should_skip_qltest(cls: schema.Class, lookup: typing.Dict[str, schema.Class cls, lookup) +def _get_stub(cls: schema.Class, base_import: str) -> ql.Stub: + if isinstance(cls.ipa, schema.IpaInfo): + if cls.ipa.from_class is not None: + accessors = [ + ql.IpaUnderlyingAccessor( + argument="Entity", + type=_to_db_type(cls.ipa.from_class), + constructorparams=["result"] + ) + ] + elif cls.ipa.on_arguments is not None: + accessors = [ + ql.IpaUnderlyingAccessor( + argument=inflection.camelize(arg), + type=_to_db_type(type), + constructorparams=["result" if a == arg else "_" for a in cls.ipa.on_arguments] + ) for arg, type in cls.ipa.on_arguments.items() + ] + else: + accessors = [] + return ql.Stub(name=cls.name, base_import=base_import, ipa_accessors=accessors) + + def generate(opts, renderer): input = opts.schema out = opts.ql_output @@ -323,10 +350,13 @@ def generate(opts, renderer): qll = out / c.path.with_suffix(".qll") c.imports = [imports[t] for t in get_classes_used_by(c)] renderer.render(c, qll) - stub_file = stub_out / c.path.with_suffix(".qll") + + for c in data.classes.values(): + path = _get_path(c) + stub_file = stub_out / path if not renderer.is_customized_stub(stub_file): - stub = ql.Stub(name=c.name, base_import=get_import(qll, opts.swift_dir)) - renderer.render(stub, stub_file) + base_import = get_import(out / path, opts.swift_dir) + renderer.render(_get_stub(c, base_import), stub_file) # for example path/to/elements -> path/to/elements.qll renderer.render(ql.ImportList([i for name, i in imports.items() if not classes[name].ql_internal]), diff --git a/swift/codegen/lib/ql.py b/swift/codegen/lib/ql.py index c40c42aa33f..fd1b0154d7d 100644 --- a/swift/codegen/lib/ql.py +++ b/swift/codegen/lib/ql.py @@ -134,12 +134,29 @@ class Class: return bool(self.doc) or self.ql_internal +@dataclass +class IpaUnderlyingAccessor: + argument: str + type: str + constructorparams: List[Param] + + def __post_init__(self): + if self.constructorparams: + self.constructorparams = [Param(x) for x in self.constructorparams] + self.constructorparams[0].first = True + + @dataclass class Stub: template: ClassVar = 'ql_stub' name: str base_import: str + ipa_accessors: List[IpaUnderlyingAccessor] = field(default_factory=list) + + @property + def has_ipa_accessors(self) -> bool: + return bool(self.ipa_accessors) @dataclass diff --git a/swift/codegen/templates/ql_stub.mustache b/swift/codegen/templates/ql_stub.mustache index d15127d9870..99e133fd7c9 100644 --- a/swift/codegen/templates/ql_stub.mustache +++ b/swift/codegen/templates/ql_stub.mustache @@ -1,9 +1,18 @@ // generated by {{generator}}, remove this comment if you wish to edit this file private import {{base_import}} +{{#has_ipa_accessors}} +private import codeql.swift.generated.Raw +private import codeql.swift.generated.Synth +{{/has_ipa_accessors}} {{#ql_internal}} /** * INTERNAL: Do not use. */ {{/ql_internal}} -class {{name}} extends Generated::{{name}} {} +class {{name}} extends Generated::{{name}} { + {{#ipa_accessors}} + private + cached {{type}} getUnderlying{{argument}}() { this = Synth::T{{name}}({{#constructorparams}}{{^first}},{{/first}}{{param}}{{/constructorparams}})} + {{/ipa_accessors}} +} diff --git a/swift/codegen/test/test_ql.py b/swift/codegen/test/test_ql.py index 5f5b1aebd73..f5b5218bd43 100644 --- a/swift/codegen/test/test_ql.py +++ b/swift/codegen/test/test_ql.py @@ -149,5 +149,12 @@ def test_class_without_description(): assert prop.has_description is False +def test_ipa_accessor_has_first_constructor_param_marked(): + params = ["a", "b", "c"] + x = ql.IpaUnderlyingAccessor("foo", "bar", params) + assert x.constructorparams[0].first + assert [p.param for p in x.constructorparams] == params + + if __name__ == '__main__': sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index 7a290ba76b8..02c9247509a 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -816,5 +816,29 @@ def test_property_on_class_with_default_doc_name(generate_classes): } +def test_stub_on_class_with_ipa_from_class(generate_classes): + assert generate_classes([ + schema.Class("MyObject", ipa=schema.IpaInfo(from_class="A")), + ]) == { + "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ + ql.IpaUnderlyingAccessor(argument="Entity", type="Raw::A", constructorparams=["result"]), + ]), + ql.Class(name="MyObject", final=True, ipa=True)), + } + + +def test_stub_on_class_with_ipa_on_arguments(generate_classes): + assert generate_classes([ + schema.Class("MyObject", ipa=schema.IpaInfo(on_arguments={"base": "A", "index": "int", "label": "string"})), + ]) == { + "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ + ql.IpaUnderlyingAccessor(argument="Base", type="Raw::A", constructorparams=["result", "_", "_"]), + ql.IpaUnderlyingAccessor(argument="Index", type="int", constructorparams=["_", "result", "_"]), + ql.IpaUnderlyingAccessor(argument="Label", type="string", constructorparams=["_", "_", "result"]), + ]), + ql.Class(name="MyObject", final=True, ipa=True)), + } + + if __name__ == '__main__': sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/swift/ql/.generated.list b/swift/ql/.generated.list index 80b5bc94c24..666b78c05b2 100644 --- a/swift/ql/.generated.list +++ b/swift/ql/.generated.list @@ -1,77 +1,77 @@ ql/lib/codeql/swift/elements/AvailabilityInfoConstructor.qll 15100f8446c961ca57871ac296c854a19678a84ebaa8faac0b6eb1377a3e0f77 f079769d6e7f9e38995e196863e11108fc1bc42e8f037d6f6bb51cfd351a3465 -ql/lib/codeql/swift/elements/AvailabilitySpec.qll 1e885dc834114454ee7dc1c7127cabcf4af1cb7d8ce634d60bb60f20e630de53 893fc1c2f8317af35dc9039e4c43c4554c4502993d9f0bb0debf8e0e760670bb +ql/lib/codeql/swift/elements/AvailabilitySpec.qll c38bfdebf34bb32463c80870f3dd45d99793bfa9511d33366d6a8a771f5d22bf 893fc1c2f8317af35dc9039e4c43c4554c4502993d9f0bb0debf8e0e760670bb ql/lib/codeql/swift/elements/CommentConstructor.qll c5a4c55fb26e57a9b4efcff329b428f7de22406b35198d99290b6e646794777a 326365475f2fda857ffa00e1c7841089660eca02d739400b6d62ed6f39ea4d03 -ql/lib/codeql/swift/elements/DbFile.qll 9e0f3c54075f75af82a9c917777755f47cb04a5777b064f5cba4a951414ac004 a3b08dd6ccd18d1a5f6f29b829da473c28a921e8d626b264b4b73515a49164f9 +ql/lib/codeql/swift/elements/DbFile.qll 7f94f506d4549233576781de58a538f427179aecb4f3ecbfec4a7c39a1b6e54e a3b08dd6ccd18d1a5f6f29b829da473c28a921e8d626b264b4b73515a49164f9 ql/lib/codeql/swift/elements/DbFileConstructor.qll 2913b16780f4369b405a088bb70f3b0f941b2978e8827ed30745f2ab7ba0cd8e c21b21b100d0b245bb1d498b4c3696db73dd710a5be211c6b825ebf733681da7 -ql/lib/codeql/swift/elements/DbLocation.qll e3e7bf56c7857329e250a44e9df1ccb31f6c2ada47d5199d549b4b92b44bc2f8 aa46535db08966b8045ceb2820b9fd580637272ae4e487192ee57b6215c16e49 +ql/lib/codeql/swift/elements/DbLocation.qll 2b07fe465cc6ea0e876892d8312bedca35d2bef5167b338b0ef5b6101f71693d aa46535db08966b8045ceb2820b9fd580637272ae4e487192ee57b6215c16e49 ql/lib/codeql/swift/elements/DbLocationConstructor.qll 88366e22ba40eaaee097f413130117925dda488f1bcbd3989e301e86dd394df3 c61b32994d403a8c4f85c26251e24ffb8c6ea34dbbe935872d868ccbfb6c1ff6 ql/lib/codeql/swift/elements/DiagnosticsConstructor.qll 6a3e312f3ed57465747c672cbb6d615eca89f42586519221d2973ac3e2ab052c a010ef546f9ed2a75b812ee47db00110056b3076b1f939efa2addb000c327427 -ql/lib/codeql/swift/elements/ErrorElement.qll 6b6be3731a2fd178e5093ddebb7cd519ecc5fbbd549bd4dbd5f69687791c3630 ab0028bab8a9ed14c6b4bfe0f8a10e4768ea1e21f86b495258021ab9b8e65aeb +ql/lib/codeql/swift/elements/ErrorElement.qll e054242b883bcc7fe1e2ee844268325a0a0b83486d5c7b4e334c73a5f8bd1d9f ab0028bab8a9ed14c6b4bfe0f8a10e4768ea1e21f86b495258021ab9b8e65aeb ql/lib/codeql/swift/elements/OtherAvailabilitySpecConstructor.qll fe03628ffbad9369e4b6bf325a58a3013b621090eecd9e01a76710e0d234d66a 0b7ffc7ed88d2b0da9aad86d83272daf124a4597c0fee1184f7d2f3511063afd ql/lib/codeql/swift/elements/PlatformVersionAvailabilitySpecConstructor.qll ce9cc9b15eff28cf0f9ef94f1d7a9dbfbbb2fb64c0053c2b537046784fcd6ee6 8b776cb89ec44704babbce7ac69efb534bf0925ca43f04e7a7dc795435404393 ql/lib/codeql/swift/elements/UnspecifiedElementConstructor.qll 0d179f8189f6268916f88c78a2665f8d4e78dc71e71b6229354677e915ac505d e8f5c313b7d8b0e93cee84151a5f080013d2ca502f3facbbde4cdb0889bc7f8e -ql/lib/codeql/swift/elements/decl/AbstractStorageDecl.qll 6196ecc35d358e6fe1c34b0478c0479acd0f0de67a64daac4d814af90a87d514 74a74330a953d16ce1cc19b2dbabdf8c8ff0fc3d250d101b8108a6597844e179 -ql/lib/codeql/swift/elements/decl/AbstractTypeParamDecl.qll 83950437007703c0f35ef154f46577d8754fb191c93772ff718b29107ce8852e 737ad9c857c079605e84dc7ebaecbafa86fe129283756b98e6e574ac9e24c22c +ql/lib/codeql/swift/elements/decl/AbstractStorageDecl.qll 5cfb9920263784224359ebd60a67ec0b46a7ea60d550d782eb1283d968386a66 74a74330a953d16ce1cc19b2dbabdf8c8ff0fc3d250d101b8108a6597844e179 +ql/lib/codeql/swift/elements/decl/AbstractTypeParamDecl.qll 1847039787c20c187f2df25ea15d645d7225e1f1fd2ca543f19927fe3161fd09 737ad9c857c079605e84dc7ebaecbafa86fe129283756b98e6e574ac9e24c22c ql/lib/codeql/swift/elements/decl/AccessorDeclConstructor.qll 08376434fd14a2b07280e931d3e22d3eafd2063d745f7c78cad0f9fd7e6156ba 6f74d15a88433953998a07eb2131841679a88cb13efb0569ed9b5502c4a2e362 -ql/lib/codeql/swift/elements/decl/AssociatedTypeDecl.qll ae6107c8d9ee9affa7e8430a4d8cd58879578eafcfba668275af4d20f8ea9c53 e81dc740623b4e2c75f83104acaa3d2b6cc6d001dd36a8520c381e0de10e15c4 +ql/lib/codeql/swift/elements/decl/AssociatedTypeDecl.qll 2f6f634fe6e3b69f1925aff0d216680962a3aaa3205bf3a89e2b66394be48f8e e81dc740623b4e2c75f83104acaa3d2b6cc6d001dd36a8520c381e0de10e15c4 ql/lib/codeql/swift/elements/decl/AssociatedTypeDeclConstructor.qll ec9007ea072ff22c367f40da69db2f0a8463bb411bbfd33e2d6c8b489a496027 631f688a8410ddcfbaa575fa2f8ffcdbc1b51ee37639b337c804ca1d5af56e0c ql/lib/codeql/swift/elements/decl/CapturedDeclConstructor.qll 4a33802b047de8d52778c262329f17b88de79c2b3162ebfa3d2b1d40dbf97041 0ed1c94469236252cf81e014138a6b2e6478e3b194512ba36e2a43e03e46cc4a -ql/lib/codeql/swift/elements/decl/ClassDecl.qll 225405ad04e5e959319fbc1ea086ec4eab0b66f5671ebc58290cce45e4103c51 ac681bdc1770a823ea529456f32b1da7b389621254ccd9102e6a49136c53854b +ql/lib/codeql/swift/elements/decl/ClassDecl.qll 40dd7d0d66217023c8f5695eac862b38428d8f2431635f62a65b336c3cc0e9bb ac681bdc1770a823ea529456f32b1da7b389621254ccd9102e6a49136c53854b ql/lib/codeql/swift/elements/decl/ClassDeclConstructor.qll 0092ab4b76cd858489d76be94a43442c0e5f395b1d5684309674957e107979b7 9bc496e483feb88552ca0d48e32039aa4566f4612fc27073fea48ad954985d46 -ql/lib/codeql/swift/elements/decl/ConcreteFuncDecl.qll 7dd23b6145977ec6ca60dd39cf9db09673e0340cdb8de2080279c83599ccd831 3a07a73dc11ef06ddaeb3d401748ef14a1ee66447c86d2e8c8f187dda92b34a2 +ql/lib/codeql/swift/elements/decl/ConcreteFuncDecl.qll 43f54876f39f58beb1d0b8293976648d1e4f5585046a502835eb7befb278f6b0 3a07a73dc11ef06ddaeb3d401748ef14a1ee66447c86d2e8c8f187dda92b34a2 ql/lib/codeql/swift/elements/decl/ConcreteFuncDeclConstructor.qll 4eb2e9dc8b4c93e457bb594085d8f50862dc07a712ce7a0f2dee7f108467ce3e 1f994d6ae1ca2e4fd5da075b70ea22322181bdaf43034face1e82ef353fe34bf -ql/lib/codeql/swift/elements/decl/ConcreteVarDecl.qll be33f40e8870a10aec413f35d8f62a502d7d5dd8a52665730740e880566206d7 d821efa43c6d83aedfb959500de42c5ecabbf856f8556f739bc6cec30a88dfab +ql/lib/codeql/swift/elements/decl/ConcreteVarDecl.qll 94bcbdd91f461295c5b6b49fa597b7e3384556c2383ad0c2a7c58276bade79e6 d821efa43c6d83aedfb959500de42c5ecabbf856f8556f739bc6cec30a88dfab ql/lib/codeql/swift/elements/decl/ConcreteVarDeclConstructor.qll 4b6a9f458db5437f9351b14464b3809a78194029554ea818b3e18272c17afba3 a60d695b0d0ffa917ad01908bec2beaa663e644eddb00fb370fbc906623775d4 ql/lib/codeql/swift/elements/decl/ConstructorDeclConstructor.qll ba5cc6f440cba3d47b364a37febd64f85941cdc0237db52a2b8844d1dc75d483 9fc039ca7a0f33f03b3f573186f02efecbac0c2e0dc5abba5d47876ca26390fe ql/lib/codeql/swift/elements/decl/DestructorDeclConstructor.qll c33b113a3ccb0b1bfd9aad8b909940776da5fdb8a24e1b998c5ebde3903be981 155ad928fbebf9688eec30a2cf61d9a2d4cd15d1161dc3f6202e6331bdb3a56a ql/lib/codeql/swift/elements/decl/EnumCaseDeclConstructor.qll 8c907544170671f713a8665d294eeefdbe78a607c2f16e2c630ea9c33f484baf eec83efc930683628185dbdad8f73311aad510074d168a53d85ea09d13f1f7e1 -ql/lib/codeql/swift/elements/decl/EnumDecl.qll 04271e164379af3a33eb060d230b768878e06acc37c3d132cad089a2c663c6c4 779940ebdbd510eb651972c57eb84b04af39c44ef59a8c307a44549ab730febb +ql/lib/codeql/swift/elements/decl/EnumDecl.qll 29f9d8cbfb19c174af9a666162fd918af7f962fa5d97756105e78d5eec38cb9e 779940ebdbd510eb651972c57eb84b04af39c44ef59a8c307a44549ab730febb ql/lib/codeql/swift/elements/decl/EnumDeclConstructor.qll 642bbfb71e917d84695622f3b2c7b36bf5be4e185358609810267ab1fc4e221b f6e06d79e7ff65fbabf72c553508b67406fb59c577215d28cc47971d34b6af05 ql/lib/codeql/swift/elements/decl/EnumElementDeclConstructor.qll 736074246a795c14a30a8ec7bb8da595a729983187887294e485487309919dc6 4614fb380fad7af1b5fb8afce920f3e7350378254ece60d19722046046672fbb ql/lib/codeql/swift/elements/decl/ExtensionDeclConstructor.qll 4f811e3332720327d2b9019edbb2fa70fb24322e72881afc040e7927452409d6 554f9832311dfc30762507e0bd4b25c5b6fdb9d0c4e8252cc5a1ef1033fafacb -ql/lib/codeql/swift/elements/decl/FuncDecl.qll 47ff5eaccc79944bb01ad819a4a9e373475d7511d477e76226538fc4efc9c88d ba8e48682e93af0804e66f5bf0207049e291a0c1430a872252dc67af17ea700a -ql/lib/codeql/swift/elements/decl/GenericContext.qll b8f21d625cfdccc201201e0d84aab7b5c1e7ccaec21ee788ac425916be8f8ac9 4747af5faf0a93d7508e0ec58021a842ca5ec41831b5d71cbc7fce2a2389a820 -ql/lib/codeql/swift/elements/decl/GenericTypeDecl.qll 774e087cc7208a4fe5df753a848191f4b986265b2b74856a52049aeb018c937a 42e1e3e055f3e5fa70c8624910d635ab10fe4015d378be9e1e6e1adb39f0dc40 -ql/lib/codeql/swift/elements/decl/GenericTypeParamDecl.qll bbcf2844cb26435e3af6d58c2b37ffeee3295a5f3330fbee34881fada7bde85b 569a380917adf4e26b286343c654954d472eabf3fe91e0d1b5f26549d9c6d24e +ql/lib/codeql/swift/elements/decl/FuncDecl.qll d3ff8bfb16c54b4d82bc2a0b9fe400bb511376d008eb0180859e7b6ad5c32b4a ba8e48682e93af0804e66f5bf0207049e291a0c1430a872252dc67af17ea700a +ql/lib/codeql/swift/elements/decl/GenericContext.qll de30cdd5cdf05024dfd25dbe3be91607bd871b03a0d97c9d7c21430d7d5bb325 4747af5faf0a93d7508e0ec58021a842ca5ec41831b5d71cbc7fce2a2389a820 +ql/lib/codeql/swift/elements/decl/GenericTypeDecl.qll ace55c6a6cea01df01a9270c38b0d9867dee1b733bca1d1b23070fc2fe1307a5 42e1e3e055f3e5fa70c8624910d635ab10fe4015d378be9e1e6e1adb39f0dc40 +ql/lib/codeql/swift/elements/decl/GenericTypeParamDecl.qll 8d8c148342b4d77ecb9a849b7172708139509aca19f744b0badf422c07b6d47a 569a380917adf4e26b286343c654954d472eabf3fe91e0d1b5f26549d9c6d24e ql/lib/codeql/swift/elements/decl/GenericTypeParamDeclConstructor.qll 63db91dc8d42746bfdd9a6bcf1f8df5b723b4ee752bd80cc61d512f2813ef959 096972e3f7f5775e60af189345bece7c0e8baec9e218709a49ed9511a3089424 ql/lib/codeql/swift/elements/decl/IfConfigDeclConstructor.qll ebd945f0a081421bd720235d0aefde800a8ad8a1db4cbd37b44447c417ff7114 1448bfdd290ad41e038a1a1ffd5ea60a75b5ec06f3a8d4d138bd56b8b960332e ql/lib/codeql/swift/elements/decl/ImportDeclConstructor.qll f2f09df91784d7a6d348d67eaf3429780ac820d2d3a08f66e1922ea1d4c8c60d 4496865a26be2857a335cbc00b112beb78a319ff891d0c5d2ad41a4d299f0457 -ql/lib/codeql/swift/elements/decl/InfixOperatorDecl.qll ca3af3b403b9d456029cb4f4b94b610a93d2d70ea71a3d6c4532088ebc83bd0b 5dec87f0c43948f38e942b204583043eb4f7386caa80cec8bf2857a2fd933ed4 +ql/lib/codeql/swift/elements/decl/InfixOperatorDecl.qll 58ba4d318b958d73e2446c6c8a839deb041ac965c22fbc218e5107c0f00763f8 5dec87f0c43948f38e942b204583043eb4f7386caa80cec8bf2857a2fd933ed4 ql/lib/codeql/swift/elements/decl/InfixOperatorDeclConstructor.qll ca6c5c477e35e2d6c45f8e7a08577c43e151d3e16085f1eae5c0a69081714b04 73543543dff1f9847f3299091979fdf3d105a84e2bcdb890ce5d72ea18bba6c8 ql/lib/codeql/swift/elements/decl/MissingMemberDeclConstructor.qll 82738836fa49447262e184d781df955429c5e3697d39bf3689397d828f04ce65 8ef82ed7c4f641dc8b4d71cd83944582da539c34fb3d946c2377883abada8578 -ql/lib/codeql/swift/elements/decl/ModuleDecl.qll 0d39d88c926d5633f467ab7a1db0101e8d61250ee5e4847de862232f997de783 410311bf3ae1efac53d8fd6515c2fe69d9ab79902c1048780e87d478cd200e26 +ql/lib/codeql/swift/elements/decl/ModuleDecl.qll a6d2f27dc70a76ec8f3360322cde3961871222c8621d99fec3a3ac5762967687 410311bf3ae1efac53d8fd6515c2fe69d9ab79902c1048780e87d478cd200e26 ql/lib/codeql/swift/elements/decl/ModuleDeclConstructor.qll 9b18b6d3517fd0c524ac051fd5dea288e8f923ada00fe4cc809cbebce036f890 0efc90492417089b0982a9a6d60310faba7a1fce5c1749396e3a29b3aac75dc5 -ql/lib/codeql/swift/elements/decl/OpaqueTypeDecl.qll 7c4a5fda798c9b44e481905f28e6c105ab3f8ab5567c2c336b24d27102fd7d66 e84e0dd1a3175ad29123def00e71efbd6f4526a12601fc027b0892930602046b +ql/lib/codeql/swift/elements/decl/OpaqueTypeDecl.qll 06e94ab2b5cebfc72a390dc420bb4c122d66e80de6d90a6bf77b230aab355f6e e84e0dd1a3175ad29123def00e71efbd6f4526a12601fc027b0892930602046b ql/lib/codeql/swift/elements/decl/OpaqueTypeDeclConstructor.qll f707aab3627801e94c63aedcded21eab14d3617c35da5cf317692eeb39c84710 20888ae6e386ae31e3cb9ff78155cb408e781ef1e7b6d687c2705843bcac0340 ql/lib/codeql/swift/elements/decl/ParamDeclConstructor.qll cfa0ba73a9727b8222efbf65845d6df0d01800646feaf7b407b8ffe21a6691d8 916ff2d3e96546eac6828e1b151d4b045ce5f7bcd5d7dbb074f82ecf126b0e09 ql/lib/codeql/swift/elements/decl/PatternBindingDeclConstructor.qll bcefa54011001b2559f90eb6ddcd286d8c47f2707103226abe3f2701ec1f45ef d58ca16ab91943a2fd97e4c7b71881b097e927156f56f3bd9dfaababccfda8f7 -ql/lib/codeql/swift/elements/decl/PostfixOperatorDecl.qll af46544addbb5bf5241e71c1846b40f33f73d64ae0932f0d057058a32ad63bee 3befb6218e934681e874c7655677eb4618edc817111ed18ef4ebcf16e06f4027 +ql/lib/codeql/swift/elements/decl/PostfixOperatorDecl.qll c2e813e1598902ef62d37d0bec40c8dbe879474b74b74a5ae07e74821760edb4 3befb6218e934681e874c7655677eb4618edc817111ed18ef4ebcf16e06f4027 ql/lib/codeql/swift/elements/decl/PostfixOperatorDeclConstructor.qll 27356cfe1d1c45a1999a200a3f1268bf09cfb019fbb7f9fb48cd32aa38b67880 6638c1acc9b0b642c106b1a14f98dfad7a9ebcc78a1b8212037d32a147e40086 ql/lib/codeql/swift/elements/decl/PoundDiagnosticDeclConstructor.qll 1b85ec959c92d1e8b218ae99d0dcd0acaa1b96e741cf7d0cf1137f2dca25d765 b8f164d00d4c5db4356933de5c3b6833b54ae8d3e9fcb908e324fcdc91a5f6ec ql/lib/codeql/swift/elements/decl/PrecedenceGroupDeclConstructor.qll 4f7548c613ee98f561a104f46ae61335d51be1b4598ae420397ae63d3ae619ca 87c11e093fb0bc5ed498f7fd36bfb844099f0e93e55de731c3e8c5fdeded35f1 -ql/lib/codeql/swift/elements/decl/PrefixOperatorDecl.qll d314c804e5ab476920a6e970b1c33cb09bf1ad076bc1f889b5068053d9de8ab5 19558ab5d027f580463ea096eb7882066d0ff95123493b8e23be79613bfdd28d +ql/lib/codeql/swift/elements/decl/PrefixOperatorDecl.qll ca4728051e2c1757a8ecf0c5a57b786b90bc38fa88b06021bb1f8f18db946215 19558ab5d027f580463ea096eb7882066d0ff95123493b8e23be79613bfdd28d ql/lib/codeql/swift/elements/decl/PrefixOperatorDeclConstructor.qll eee048d4c2314234df17966deefeee08e769a831fa500e6e494f64fca9e9dda1 01d9b09f809645c91f92b981a46c9ed6e332f5734d768ab369b7a328a9a391d4 -ql/lib/codeql/swift/elements/decl/ProtocolDecl.qll 17e89e410275aa2fbc1687a5380e23354a1b64e1b9581d52875210921b0eed8f 0bb0dca7980934cfb98dab5b83fd253153740ac8054cdf85bdce8b5ed6db9398 +ql/lib/codeql/swift/elements/decl/ProtocolDecl.qll 6c2bc4d5de3383e34d17d025f6a7cac0c98242b1fc2bd222be04c56cc5fb88d1 0bb0dca7980934cfb98dab5b83fd253153740ac8054cdf85bdce8b5ed6db9398 ql/lib/codeql/swift/elements/decl/ProtocolDeclConstructor.qll 2bbc92ddcec810cefb6cfa85320f873f1c542b1c62a197a8fbafa12e0e949c00 b2060fb804a16619e235afcd76856cdc377c4e47cfb43c5a6f9d32ff5b852e74 -ql/lib/codeql/swift/elements/decl/StructDecl.qll 1cb599afb1c574a64c2033a2c20bddbf2142b593f0775abc3d5b1cfafccca6b6 ebc04601ac1cd736151783073ef4ad1a42311731aab36b38dc02760ecb22bd4a +ql/lib/codeql/swift/elements/decl/StructDecl.qll 708711bf4236f32174caa256f3b19e00b6337f2fcfdbc67cf9d2fc8e86d65f2c ebc04601ac1cd736151783073ef4ad1a42311731aab36b38dc02760ecb22bd4a ql/lib/codeql/swift/elements/decl/StructDeclConstructor.qll 653fef1ce7a5924f9db110dfab4ebc191b6688fa14ebeb6cf2a09fe338f00646 c7ed15002c41b7dd11a5dd768e0f6f1fe241c680d155364404c64d6251adee5c ql/lib/codeql/swift/elements/decl/SubscriptDeclConstructor.qll 3a88617b41f96827cb6edd596d6d95ebcf5baf99ba113bdd298276666c6aeadf 166e04fc72507cb27e2c16ad2d5217074f8678d286cb6d0980e5b84125648abe ql/lib/codeql/swift/elements/decl/TopLevelCodeDeclConstructor.qll 6920a4e7aec45ae2a561cef95b9082b861f81c16c259698541f317481645e194 4bd65820b93a5ec7332dd1bbf59326fc19b77e94c122ad65d41393c84e6ac581 -ql/lib/codeql/swift/elements/decl/TypeAliasDecl.qll ecb457a9a81c6b13a1068f471c0b87e59227838f54c5d4effe7d4c2f6e7f5800 630dc9cbf20603855c599a9f86037ba0d889ad3d2c2b6f9ac17508d398bff9e3 +ql/lib/codeql/swift/elements/decl/TypeAliasDecl.qll 984c5802c35e595388f7652cef1a50fb963b32342ab4f9d813b7200a0e6a37ca 630dc9cbf20603855c599a9f86037ba0d889ad3d2c2b6f9ac17508d398bff9e3 ql/lib/codeql/swift/elements/decl/TypeAliasDeclConstructor.qll ba70bb69b3a14283def254cc1859c29963838f624b3f1062a200a8df38f1edd5 96ac51d1b3156d4139e583f7f803e9eb95fe25cc61c12986e1b2972a781f9c8b -ql/lib/codeql/swift/elements/decl/ValueDecl.qll b344768498e0d1794d92bc5b7c0417e75079aa8a82e27d7b3449f1e52f78d1e9 e3056cf6a883da2737cb220a89499a9e3977eb1c56b9e1d2f41a56b71a0c29f9 -ql/lib/codeql/swift/elements/expr/AbiSafeConversionExpr.qll 599bdb52d99a1e2800563209cecc01a5b5eb80cb4aff36b2d037b67c34ebb948 a87738539276438cef63145461adf25309d1938cfac367f53f53d33db9b12844 +ql/lib/codeql/swift/elements/decl/ValueDecl.qll 1b7d8eeb17be4bdbabc156cb0689641ed4f9e697e334d2d14f423ed3d1a419f6 e3056cf6a883da2737cb220a89499a9e3977eb1c56b9e1d2f41a56b71a0c29f9 +ql/lib/codeql/swift/elements/expr/AbiSafeConversionExpr.qll 39b856c89b8aff769b75051fd9e319f2d064c602733eaa6fed90d8f626516306 a87738539276438cef63145461adf25309d1938cfac367f53f53d33db9b12844 ql/lib/codeql/swift/elements/expr/AbiSafeConversionExprConstructor.qll 7d70e7c47a9919efcb1ebcbf70e69cab1be30dd006297b75f6d72b25ae75502a e7a741c42401963f0c1da414b3ae779adeba091e9b8f56c9abf2a686e3a04d52 -ql/lib/codeql/swift/elements/expr/AbstractClosureExpr.qll 125f8bd8f21c95c439616744539577afcfa9fd63c65683132a2c971abcec3523 400790fe643585ad39f40c433eff8934bbe542d140b81341bca3b6dfc5b22861 -ql/lib/codeql/swift/elements/expr/AnyHashableErasureExpr.qll 20dd848a35a47af94d0fb8cf1a33a2bd6582c751440708c365cf338e522f6de5 bf80cab3e9ff5366a6223153409f4852acdb9e4a5d464fb73b2a8cffc664ca29 +ql/lib/codeql/swift/elements/expr/AbstractClosureExpr.qll 4027b51a171387332f96cb7b78ca87a6906aec76419938157ac24a60cff16519 400790fe643585ad39f40c433eff8934bbe542d140b81341bca3b6dfc5b22861 +ql/lib/codeql/swift/elements/expr/AnyHashableErasureExpr.qll d6193ef0ba97877dfbdb3ea1c18e27dad5b5d0596b4b5b12416b31cbe1b3d1d6 bf80cab3e9ff5366a6223153409f4852acdb9e4a5d464fb73b2a8cffc664ca29 ql/lib/codeql/swift/elements/expr/AnyHashableErasureExprConstructor.qll 12816f18d079477176519a20b0f1262fc84da98f60bce3d3dd6476098c6542e7 4cc5c8492a97f4639e7d857f2fca9065293dfa953d6af451206ce911cda9f323 -ql/lib/codeql/swift/elements/expr/AnyTryExpr.qll 51aa09941b366d147a685452b3b89be4f0cc35f8cf9ff5ebcd53622ddd7df727 988b5df28972e877486704a43698ada91e68fe875efc331f0d7139c78b36f7dd -ql/lib/codeql/swift/elements/expr/AppliedPropertyWrapperExpr.qll b1a6c026b0167c7299d1f2de30935a8f805382edd8d91c1f7f18e9278ccd564c 9508f93ca59561455e1eb194eaddd9f071960a752f985844c65b3b498f057461 +ql/lib/codeql/swift/elements/expr/AnyTryExpr.qll 4a56bb49ed1d9f3c81c1c6cce3c60657e389facd87807eaefa407532259cec70 988b5df28972e877486704a43698ada91e68fe875efc331f0d7139c78b36f7dd +ql/lib/codeql/swift/elements/expr/AppliedPropertyWrapperExpr.qll d72d5fe299aa28c69fa9d42d683a9f7ebc9a51cbb4d889afc40c5701fb441aa6 9508f93ca59561455e1eb194eaddd9f071960a752f985844c65b3b498f057461 ql/lib/codeql/swift/elements/expr/AppliedPropertyWrapperExprConstructor.qll d9baf27c0d64e08466952b584ef08e4f40f7dfb861582aef2e7ebb16bb3da13b 2f19e7dbc02f9450c5521728ff1c5f178b14f50de4ff345fcd9bc834070a21d6 -ql/lib/codeql/swift/elements/expr/ArchetypeToSuperExpr.qll ea81d53ed038e29d0454b2411feb069e3396e6f7a0aa93bcfd05793772fe1d52 64e21e6f3307cd39d817ea66be2935e717168187bbeaedd4247bb77cec9d95ea +ql/lib/codeql/swift/elements/expr/ArchetypeToSuperExpr.qll d792d9eed5f624d2be6097bef5ebdd1c85dc722fac30974fdf5ab073e140e2bc 64e21e6f3307cd39d817ea66be2935e717168187bbeaedd4247bb77cec9d95ea ql/lib/codeql/swift/elements/expr/ArchetypeToSuperExprConstructor.qll df9f0db27fd2420e9d9cc4e1c6796b5513f6781940b5f571e8b8b9850a6e163f b4b15aa01de7ce91f74bd47a2e654c3ea360b90687c92ef9e19257289696f97e ql/lib/codeql/swift/elements/expr/ArrayExprConstructor.qll 57d37bb5a745f504c1bf06e51ffa0c757e224c158034c34e2bbb805b4efdc9f4 808753dccddfc0a02ef871af8f3d6487289ca48e7b4e4ea6356e0a87e3692583 -ql/lib/codeql/swift/elements/expr/ArrayToPointerExpr.qll 202b724bcf20f8083028d9d683d748ffceab3d0becf02c29c57228fe8aca30a5 035b15b1ecb700c4e6961b9a99e3c33476cedaa1a96310601b558e7ede9de39f +ql/lib/codeql/swift/elements/expr/ArrayToPointerExpr.qll dc48c33afea524dd5d2eab8a531cf0d1e3c274706b1047c23637da0554f1ef01 035b15b1ecb700c4e6961b9a99e3c33476cedaa1a96310601b558e7ede9de39f ql/lib/codeql/swift/elements/expr/ArrayToPointerExprConstructor.qll ad4346298ff16512f06f9841bf8171b163f59fde949e24e257db7379eb524c4f b2d038e1e13340b0616044fc28005904562035bc8c9871bd6c9b117f15adffe6 ql/lib/codeql/swift/elements/expr/AssignExprConstructor.qll 14cb0d217bc9ca982d29cdbf39c79399b39faa7e031469bc47884f413507e743 646658cb2f664ba0675f48cb51591c64cf2107a0c756038bfc66243b4c092b45 ql/lib/codeql/swift/elements/expr/AutoClosureExprConstructor.qll 928391f52b914e42625fafadbdfa703e6fb246a09a7d8e39bf7700bc2fc8c22c 2d698cceed54a230890f5f2ad9f019ebe82fdd15831b8a5b6aaabf1ea855063f @@ -79,71 +79,71 @@ ql/lib/codeql/swift/elements/expr/AwaitExprConstructor.qll 5c73999bf54f43c845e3a ql/lib/codeql/swift/elements/expr/BinaryExprConstructor.qll 99baa77331e4e5b2d0fe0ca31e839c901ba677e4337bed3aa4d580c3258fb610 7f42ac4bfc73c18743f73a3e961b529f1d302e70a634ab91fcf3676b959ddb22 ql/lib/codeql/swift/elements/expr/BindOptionalExprConstructor.qll 1dd7074d6513977eb50f857de87aea35686ddda8f1ee442569fcfac16fc02fd6 1c23977e1f5ad4fd1a9d43a01765dda2fe72496a0361701f92212f7eef3f13c2 ql/lib/codeql/swift/elements/expr/BooleanLiteralExprConstructor.qll 561ac38c94fdc3eb7baab09d0f2f2d7f64424dbfe879c395470ee6d5cd6a9354 2b76d00a58cd7d051d422f050d187c36e97614de6d99f52068aff3c20a45c7af -ql/lib/codeql/swift/elements/expr/BridgeFromObjCExpr.qll 129251956d27cd32ce806c4b11cd2ea1774723d53c4dc1d8112cab7401a2db0b 91385232931b55817e53e4caebf7a2dd9c0a520ec055012de82e7b1da923f0ec +ql/lib/codeql/swift/elements/expr/BridgeFromObjCExpr.qll 1a658c5bc73029bc5945c23210ec7a66801e4d58f75fdd5331fd71d9ac93a65b 91385232931b55817e53e4caebf7a2dd9c0a520ec055012de82e7b1da923f0ec ql/lib/codeql/swift/elements/expr/BridgeFromObjCExprConstructor.qll f91e80dad19b7177c6ea1b127c7622d145cb250575acba9bf34d99b933849b94 c3133e6ad25d86bcec697999c16d0c18db1abf894068f5b8d14c90ffae35ca09 -ql/lib/codeql/swift/elements/expr/BridgeToObjCExpr.qll 436b10412525fb6fca966416f2fb563efd569ee2826b003c9cee594a4887658f 8fc781a59f6009fa64fbbf28f302b2e83b0f7fcbe0cf13d5236637248dcb6579 +ql/lib/codeql/swift/elements/expr/BridgeToObjCExpr.qll b44c9b3ef1c540feaaa1459acc1bec1e07cd6b96a0056d09b6c0d4bb37a49356 8fc781a59f6009fa64fbbf28f302b2e83b0f7fcbe0cf13d5236637248dcb6579 ql/lib/codeql/swift/elements/expr/BridgeToObjCExprConstructor.qll 7e51fef328ad149170f83664efd57de2b7058511934f3cf1a9d6cb4033562bed 34ab05bbdddc5477ba681cc89f03283057867116c83b3e57766c3b24f38ca7bf -ql/lib/codeql/swift/elements/expr/BuiltinLiteralExpr.qll 5455879c4f3aef960881da579007544e8f20a973d2fba0c58aa21705800a0c9d 9d9de530709c80cfe710a9e3d62a1b7cede61ba22da46365b1ba7766dbc48b44 -ql/lib/codeql/swift/elements/expr/CallExpr.qll 625c0e0866c1e6384591c5022952391d256b2366d1b83174c2d299ccca086d23 8040ab28b4e1630ff343ab77d10b2449e792908b55e683316f442d853eee6c0a +ql/lib/codeql/swift/elements/expr/BuiltinLiteralExpr.qll fb3c44075ab50713722dac76de4df6129038658bbcf155e52ffab0308b54b771 9d9de530709c80cfe710a9e3d62a1b7cede61ba22da46365b1ba7766dbc48b44 +ql/lib/codeql/swift/elements/expr/CallExpr.qll 3c481940ff9d176b86368dbc8c23a39193e5aa226797233f42d2ba47ad8c54f1 8040ab28b4e1630ff343ab77d10b2449e792908b55e683316f442d853eee6c0a ql/lib/codeql/swift/elements/expr/CallExprConstructor.qll 478caaaee61b5d83126da6de16ff21d11dc452428f15a879e1401d595b7bed75 7014f17d347b781e4c8211568954c2858ab2dcf37ef5dfd5ed36678415000009 ql/lib/codeql/swift/elements/expr/CaptureListExprConstructor.qll 03af12d1b10bdc2cc4ac2b0322c4cd7f68a77699f37315ddca97f1e99a770c93 0fc709cdca8935a3142f7718d660c932af65952db8603bd909087aa68eab9236 -ql/lib/codeql/swift/elements/expr/CheckedCastExpr.qll 766f2fc44952f34ac0609aa346a5fedf7eb9c1d7bf1393890a05cb5bda45725e e7c90a92829472335199fd7a8e4ba7b781fbbf7d18cf12d6c421ddb22c719a4b -ql/lib/codeql/swift/elements/expr/ClassMetatypeToObjectExpr.qll 36fd3daf20130882e26e0f301b02380219e67ed3fe8a1caaac3854789eb6bcad 4b5aca9fa4524dc25dc6d12eb32eeda179a7e7ec20f4504493cf7eb828a8e7be +ql/lib/codeql/swift/elements/expr/CheckedCastExpr.qll 440eeee832401584f46779389d93c2a4faa93f06bd5ea00a6f2049040ae53847 e7c90a92829472335199fd7a8e4ba7b781fbbf7d18cf12d6c421ddb22c719a4b +ql/lib/codeql/swift/elements/expr/ClassMetatypeToObjectExpr.qll 9830ef94d196c93e016237c330a21a9d935d49c3d0493e597c3e29804940b29e 4b5aca9fa4524dc25dc6d12eb32eeda179a7e7ec20f4504493cf7eb828a8e7be ql/lib/codeql/swift/elements/expr/ClassMetatypeToObjectExprConstructor.qll 369cecb4859164413d997ee4afba444853b77fb857fa2d82589603d88d01e1dc 3b4ebd1fb2e426cba21edd91b36e14dc3963a1ede8c482cdf04ef5003a290b28 ql/lib/codeql/swift/elements/expr/ClosureExprConstructor.qll cf2fa2dab328f6b98aeffcdc833de4d74f69d23779ac897f5ada9c2dca9ef093 13f85b735ebb56c361458baba45eb854e70b7987d5e1863e564084c1a6165cc5 -ql/lib/codeql/swift/elements/expr/CoerceExpr.qll efc1e3852212089d81b5c3d06ae74b0a36abf2dd8843689d50dcc22d3bed12ba eb13ef05c7436d039c1f8a4164b039bdbf12323310c249d7702291058f244d38 +ql/lib/codeql/swift/elements/expr/CoerceExpr.qll e68c125466a36af148f0e47ff1d22b13e9806a40f1ec5ddc540d020d2ab7c7dc eb13ef05c7436d039c1f8a4164b039bdbf12323310c249d7702291058f244d38 ql/lib/codeql/swift/elements/expr/CoerceExprConstructor.qll aa80ea0e6c904fab461c463137ce1e755089c3990f789fae6a0b29dea7013f6d 455f5184a3d2e2a6b9720a191f1f568699f598984779d923c2b28e8a3718fa9d -ql/lib/codeql/swift/elements/expr/CollectionExpr.qll 80fedf0757cd8024ebcadd0b82507cfd5cec57b4d7c53ff0f97357384f9d89c4 87977b7661bcd8212b07b36f45ff94f5e98513c6dddb4cca697d1d6b853dff72 -ql/lib/codeql/swift/elements/expr/CollectionUpcastConversionExpr.qll 37aa0e9e829a480a5db855a2d2617ace57ac8d89fe01ec11251aa9183ccbd0a1 ab8370b77f27ed658f58571638f96187746cbafdfdf86583caf807bf3910f8c2 +ql/lib/codeql/swift/elements/expr/CollectionExpr.qll ec0e46338e028821afe1bafb2bed4edc9c9a9f69b65b397c3c0914eb52851bb0 87977b7661bcd8212b07b36f45ff94f5e98513c6dddb4cca697d1d6b853dff72 +ql/lib/codeql/swift/elements/expr/CollectionUpcastConversionExpr.qll 8e5ec3b19aacef6a926e353ced1b42224e64bd699398b4bf6a5259e77214a671 ab8370b77f27ed658f58571638f96187746cbafdfdf86583caf807bf3910f8c2 ql/lib/codeql/swift/elements/expr/CollectionUpcastConversionExprConstructor.qll 4896b2ac56def7a428945c97cd5d5e44ca6378be96707baf1cb3a47c81ef9ca3 c8f1efdfcc67b5d631447ab2b87a0a70722bd52ef3282ad74d8de929c361f626 -ql/lib/codeql/swift/elements/expr/ConditionalBridgeFromObjCExpr.qll f9b1da899020c8dd9c0633376410f5b8b8d00f4df43d5da164e5e5696c813499 4013b1dcebbc873f337ee433042ad1e5d178b0afe2d62434fe235a234e9b8aa6 +ql/lib/codeql/swift/elements/expr/ConditionalBridgeFromObjCExpr.qll 4ff4d0e9f4afbf1317dd9b6b08c0456e5808e6f821d3e8fe2d401769eeefbbbd 4013b1dcebbc873f337ee433042ad1e5d178b0afe2d62434fe235a234e9b8aa6 ql/lib/codeql/swift/elements/expr/ConditionalBridgeFromObjCExprConstructor.qll 7350d9e279995181f08dcc931723d21a36aac17b3ea5b633c82bac5c7aeb733a dc6767f621bddcc22be8594b46b7d3170e5d7bfcee6f1e0279c26492fd88c81d -ql/lib/codeql/swift/elements/expr/ConditionalCheckedCastExpr.qll 527f8f1dd071e2647f6f86a6b204a082c7e9929f9a37f35b8dcd40e99e1064b2 a66a1e07b210a1e8d999380db04a8b3210b66049a876bd92c8f56eae66c5a062 +ql/lib/codeql/swift/elements/expr/ConditionalCheckedCastExpr.qll 3052583ee44e9c859dddefc2ee578710c7ac272ba82eb939e2299008da0c92db a66a1e07b210a1e8d999380db04a8b3210b66049a876bd92c8f56eae66c5a062 ql/lib/codeql/swift/elements/expr/ConditionalCheckedCastExprConstructor.qll 13a1032bfa1199245746d4aac2c54d3ba336d3580c2713a66a91ad47eb8648ca 2a7c66669551aaa3528d77a8525985b850acbc983fea6f076561709a076dadb7 -ql/lib/codeql/swift/elements/expr/ConstructorRefCallExpr.qll e8830d2c73a10d394495b8aa5bc68290f9524b0f09dba932d7cd7b533f149a1b fc4b855b27f7afefab8132bd2adc3567cceec6b2fd762bf1dc7463ce76421326 -ql/lib/codeql/swift/elements/expr/CovariantFunctionConversionExpr.qll 687065e8625a249d51e8e92136afacfd3c48f85f689d5aff077a5a9dac56272e 4510d77d211f4b6db9dd4c941706d7eb7579fe7311714758c9d1d24513bfbdc4 +ql/lib/codeql/swift/elements/expr/ConstructorRefCallExpr.qll 2d8709f776df9edda8f1c07884fc32d1d25306cc2e8029d7b0c74d91f3828fef fc4b855b27f7afefab8132bd2adc3567cceec6b2fd762bf1dc7463ce76421326 +ql/lib/codeql/swift/elements/expr/CovariantFunctionConversionExpr.qll 0d18efcc60908890fa4ebf3ef90b19b06a4140d06ec90053ab33db3ad864281a 4510d77d211f4b6db9dd4c941706d7eb7579fe7311714758c9d1d24513bfbdc4 ql/lib/codeql/swift/elements/expr/CovariantFunctionConversionExprConstructor.qll eac12524819e9fe29074f90ea89fea866023b5ed4a5494345f2b9d8eec531620 71a6eb320630f42403e1e67bb37c39a1bae1c9f6cc38c0f1688a31f3f206d83f -ql/lib/codeql/swift/elements/expr/CovariantReturnConversionExpr.qll e6a7a3ce538c068bd7ab0974b4615acbf00038d3b01dc594372152114559fa44 720fb172ebcb800c70810539c7a80dbdf61acb970277f2b6a54b9159ab4e016e +ql/lib/codeql/swift/elements/expr/CovariantReturnConversionExpr.qll baa7e9a3c2a2de383d55fac1741b8739c389b9c3cf7a0241d357d226364daaf3 720fb172ebcb800c70810539c7a80dbdf61acb970277f2b6a54b9159ab4e016e ql/lib/codeql/swift/elements/expr/CovariantReturnConversionExprConstructor.qll b32a9b3c067d09bd6350efe57215e3b3b9ae598631756878da4a1e474876fc3f bcc963ee556fdd5e1563c305d1bfc6a89e8953243f5dfa1b92144d280ccb3b1a ql/lib/codeql/swift/elements/expr/DeclRefExprConstructor.qll 1efd7b7de80bdff9c179cdb01777a85369497c5fd02cbdcf41dd9724a663a60b 63dd1e7049091e3e2158fb00498e7b3e82b38abbf5deee56abd00959527ba352 ql/lib/codeql/swift/elements/expr/DefaultArgumentExprConstructor.qll 013827d95e2a9d65830b748093fd8a02da6b6cae78729875f624bf71cc28a4fe 900879fd1c26cfbcea0cd0c3b8f95425644458a8a1dd6628a8bd4bc61bc45809 -ql/lib/codeql/swift/elements/expr/DerivedToBaseExpr.qll 782d47d73634aea8ee4ea991acde27180b77535d8e5112d40df77262d9e9a19e e12acd24f48b7b59009615af6a43e061ffc595f1edc55bfe01c1524f30d7be7c +ql/lib/codeql/swift/elements/expr/DerivedToBaseExpr.qll 93bd80de8627203f0e25759698e989ff9d2067a6e996b7e3b4fe221f3f0c2052 e12acd24f48b7b59009615af6a43e061ffc595f1edc55bfe01c1524f30d7be7c ql/lib/codeql/swift/elements/expr/DerivedToBaseExprConstructor.qll ca74471f6ac2500145de98bb75880450c9185f697f5ce25905271358182a29b3 797b9eaa9d3d56a963d584ba560a67ec94e1a1b10916f0d03f4ad4777e4984f9 -ql/lib/codeql/swift/elements/expr/DestructureTupleExpr.qll 618298ec50ac464268472bba7925695ba3d37bd3ae07b310a69724b396265554 8bc4a6238bec6dbdc2f91e2777cb00d86c63642bf3d2d9758a192d170cf6fcde +ql/lib/codeql/swift/elements/expr/DestructureTupleExpr.qll 2e5556786752b319f41d12e022723b90ddad4811e50f5b09136c7a7e9e65e3c6 8bc4a6238bec6dbdc2f91e2777cb00d86c63642bf3d2d9758a192d170cf6fcde ql/lib/codeql/swift/elements/expr/DestructureTupleExprConstructor.qll 7d844c6c4a0f9008e2fdf9a194621f09595e328a5f5c6f2f993b1a3cd2a74a03 e75d47955ae9a91c75fcb8e0bb12b6ed792c361645ee29bbcc37fa2ac27c4517 ql/lib/codeql/swift/elements/expr/DictionaryExprConstructor.qll 6bd61507158b62fd8d2f3a68c61cceff5926915bf71730c898cf6be402d1e426 37cfce5600dd047a65f1321709350eabae5846429a1940c6f8b27f601420a687 -ql/lib/codeql/swift/elements/expr/DifferentiableFunctionExpr.qll 32d59a601c7ee95715e09478561018788e8f10eca34c5637c94d7700a868636c 520f79dd2fd9b500c32fb31d578fffaec67d232690638746792417a0b80b98e6 +ql/lib/codeql/swift/elements/expr/DifferentiableFunctionExpr.qll 326aafc47dd426fbcf78830ce90ce267cc121d9d3adcacca231c8222d515f688 520f79dd2fd9b500c32fb31d578fffaec67d232690638746792417a0b80b98e6 ql/lib/codeql/swift/elements/expr/DifferentiableFunctionExprConstructor.qll 4ee532a020a6e75ba2971cee5724fcccc7e6b60530ec26385cbbda0b2626f9be 6c35cd2b0142b2c74e7d8a46cf3aebfcf92e5809e5c0c480a666d8a7dacdcfa2 ql/lib/codeql/swift/elements/expr/DifferentiableFunctionExtractOriginalExprConstructor.qll ce008cb7ce392277dd0678203f845f94a9933b9530c265a58a66c16542423495 4b4522c39929d062662b5e321371e76df5f2c9c8e5eebdf5c62e88b8eb84960b ql/lib/codeql/swift/elements/expr/DiscardAssignmentExprConstructor.qll cd814e77f82fac48949382335655f22b0d1d99ece04612f026aebc2bc60f0dc9 d1faa9e2d863175feb00cd2b503ac839e09744cbbfbe4c18b670416f9d50483c ql/lib/codeql/swift/elements/expr/DotSelfExprConstructor.qll 4b6956818dac5b460dfbe9878c2c5b6761fcf1c65556b38555f68de9cc6f2562 2ae26f5e7bde2f972cc5a63e4a3dca1698e3a7c75b06419bb7bb080cb8ce78d9 ql/lib/codeql/swift/elements/expr/DotSyntaxBaseIgnoredExprConstructor.qll 8ca889cc506cac0eeb35c246a3f317c9da8fe4dbfaf736a2056108b00b1c8521 9a20b12ad44f1dbf58d205a58cdfc1d63d2540353d8c8df48d87393d3b50d8b6 -ql/lib/codeql/swift/elements/expr/DotSyntaxCallExpr.qll f5048cff6fcdd298c8822ece1cd2042a61b40521dfc230f0f0e1798527010e58 5220861621d01b15ea0182bbb8358d700f842b94ec07745f77c5285d0e84a509 -ql/lib/codeql/swift/elements/expr/DynamicLookupExpr.qll cd5670379df14b7a765037378221e541dd93567c97729d6be24bbbbb9aacc054 89f564a793d1f09a8aeb2dd61c475df3e55a49f4f0b6094ceb9f0ebe6d42fa76 +ql/lib/codeql/swift/elements/expr/DotSyntaxCallExpr.qll d2209dafbe8cde6a8a850a96d21af91db4c5a0833bcdd4f14e4a8c137209a3a4 5220861621d01b15ea0182bbb8358d700f842b94ec07745f77c5285d0e84a509 +ql/lib/codeql/swift/elements/expr/DynamicLookupExpr.qll 58e3dfb7fea694653950d09ce00772847cc3f88f0cdbc81399d676f95d67ef62 89f564a793d1f09a8aeb2dd61c475df3e55a49f4f0b6094ceb9f0ebe6d42fa76 ql/lib/codeql/swift/elements/expr/DynamicMemberRefExprConstructor.qll 6bd769bdbb83999bfd94bf4d5a1b8a32cc045460183f5f2fcf7055257f6c3787 e2b72550a71f2f39bde171ada6e04c6bdbd797caa74813ea3c8070b93cefa25e ql/lib/codeql/swift/elements/expr/DynamicSubscriptExprConstructor.qll d40d88069371807c72445453f26e0777ac857e200c9c3e8a88cd55628ccb9230 6ff580bbc1b7f99c95145168f7099ab19b5d150e7d7e83747595ff2eb2c289c4 ql/lib/codeql/swift/elements/expr/DynamicTypeExprConstructor.qll 37066c57e8a9b7044b8b4ecf42a7bf079e3400dd02bf28a1d51abd5406391ba0 62cc0405ecfe4c8d5477957d8789a6b03a4e9eecabbb0f94e1bde5ce2adabb8c ql/lib/codeql/swift/elements/expr/EnumIsCaseExprConstructor.qll a02f992035c7ef7692c381377b1e594f0021025df6bcab23f149efeacd61c8e6 687df32678e1b3bcc4241270962593f7838e461970621f6e5b829321718ed257 -ql/lib/codeql/swift/elements/expr/ErasureExpr.qll 3549ee36cbca32207ec7a339de87e81126b0ca0e087e74a6f525c817b4dd15be 91a60971ff01d158f6358a6cb2e028234b66b3a75c851a3f5289af0aa8c16613 +ql/lib/codeql/swift/elements/expr/ErasureExpr.qll 6aca57c70706f6c26be28d47b2bcb20c6d5eb7104c6a8f1e5885d13fd2f17a48 91a60971ff01d158f6358a6cb2e028234b66b3a75c851a3f5289af0aa8c16613 ql/lib/codeql/swift/elements/expr/ErasureExprConstructor.qll 29e0ab9f363b6009f59a24b2b293d12b12c3cdea0f771952d1a57c693f4db4a3 c4bc12f016b792dff79e38b296ef58dba3370357d088fd63931a8af09c8444a9 -ql/lib/codeql/swift/elements/expr/ErrorExpr.qll 89468d8ed9c1cc69575cb9c890b8e424ec0c8495894f691a657774e9146a896d bc3e4a566bc37590929e90a72e383f9fbc446e4f955e07e83c1c59a86cee8215 +ql/lib/codeql/swift/elements/expr/ErrorExpr.qll 8a68131297e574625a22fbbb28f3f09097e3272b76caf3283d4afdb8a2c5fffd bc3e4a566bc37590929e90a72e383f9fbc446e4f955e07e83c1c59a86cee8215 ql/lib/codeql/swift/elements/expr/ErrorExprConstructor.qll dd2bec0e35121e0a65d47600100834963a7695c268e3832aad513e70b1b92a75 e85dcf686403511c5f72b25ae9cf62f77703575137c39610e61562efc988bbac -ql/lib/codeql/swift/elements/expr/ExistentialMetatypeToObjectExpr.qll cd5d01e8410ed65165bb4a1a570a63864b0a75c742ac9224cef8c2683d72f62d c0b5811c8665f3324b04d40f5952a62e631ec4b3f00db8e9cc13cb5d60028178 +ql/lib/codeql/swift/elements/expr/ExistentialMetatypeToObjectExpr.qll 420d534f76e192e89f29c71a7282e0697d259c00a7edc3e168ca895b0dc4f1d1 c0b5811c8665f3324b04d40f5952a62e631ec4b3f00db8e9cc13cb5d60028178 ql/lib/codeql/swift/elements/expr/ExistentialMetatypeToObjectExprConstructor.qll 1a735425a59f8a2bd208a845e3b4fc961632c82db3b69d0b71a1bc2875090f3b 769b6a80a451c64cbf9ce09729b34493a59330d4ef54ab0d51d8ff81305b680f ql/lib/codeql/swift/elements/expr/FloatLiteralExprConstructor.qll 4dfb34d32e4022b55caadcfbe147e94ebe771395c59f137228213a51a744ba10 1eb78fcda9e0b70d1993e02408fb6032035991bf937c4267149ab9c7c6a99d3a ql/lib/codeql/swift/elements/expr/ForceTryExprConstructor.qll 48cbc408bb34a50558d25aa092188e1ad0f68d83e98836e05072037f3d8b49af 62ce7b92410bf712ecd49d3eb7dd9b195b9157415713aaf59712542339f37e4c ql/lib/codeql/swift/elements/expr/ForceValueExprConstructor.qll 3b201ee2d70ab13ad7e3c52aad6f210385466ec4a60d03867808b4d3d97511a8 d5d9f0e7e7b4cae52f97e4681960fa36a0c59b47164868a4a099754f133e25af -ql/lib/codeql/swift/elements/expr/ForcedCheckedCastExpr.qll 27612d688194618da2403d9c913cb7fe0f423e099f0abdb9b54f4eb58b2767be a3bae0709caac887bec37c502f191ea51608006e719bb17550c3215f65b16f7f +ql/lib/codeql/swift/elements/expr/ForcedCheckedCastExpr.qll f42d96598ca09a014c43eae2fc96189c5279eab5adbebbaa6da386ffb08e7e5d a3bae0709caac887bec37c502f191ea51608006e719bb17550c3215f65b16f7f ql/lib/codeql/swift/elements/expr/ForcedCheckedCastExprConstructor.qll 3fdd87183e72c4b0ee927c5865c8cbadf4f133bd09441bf77324941c4057cbc8 a6e7dc34de8d1767512c2595121524bd8369bd21879857e13590cec87a4b0eeb -ql/lib/codeql/swift/elements/expr/ForeignObjectConversionExpr.qll fbffcd3bde46cd3e443ce583bf7bfb2d73b86e3d061465c7ddb4468be7447b72 7ea9aa492b2d37ad05d92421a92bb9b1786175b2f3b02867c1d39f1c67934f3d +ql/lib/codeql/swift/elements/expr/ForeignObjectConversionExpr.qll 4ca318937bcadd5a042b7f9ec6639144dc671a274d698506a408c94c8caceea0 7ea9aa492b2d37ad05d92421a92bb9b1786175b2f3b02867c1d39f1c67934f3d ql/lib/codeql/swift/elements/expr/ForeignObjectConversionExprConstructor.qll d90fdb1b4125299e45be4dead6831835e8d3cd7137c82143e687e1d0b0a0a3bc a2f38e36823a18d275e199c35a246a6bc5ec4a37bf8547a09a59fe5dd39a0b4e -ql/lib/codeql/swift/elements/expr/FunctionConversionExpr.qll e6dcf7fb3966d2ee5e4434221ec615b066da0e17ddc442692ca7936fcebec70b 87c1f5a44d9cc7dd10d05f17f5d4c718ecc5b673c7b7f4c1662b5d97e0177803 +ql/lib/codeql/swift/elements/expr/FunctionConversionExpr.qll 4685eae5030d599d5149557a1111c0426f944c4fce14edbf24d6b469cbde07bf 87c1f5a44d9cc7dd10d05f17f5d4c718ecc5b673c7b7f4c1662b5d97e0177803 ql/lib/codeql/swift/elements/expr/FunctionConversionExprConstructor.qll ff88509ae6754c622d5d020c0e92e0ea1efe2f7c54e59482366640b2100d187b fd640286e765dc00c4a6c87d766750cad0acd2544566ec9a21bc49c44cf09dba ql/lib/codeql/swift/elements/expr/IfExprConstructor.qll 19450ccaa41321db4114c2751e9083fbd6ceb9f6a68905e6dca5993f90dd567a 42605d9af0376e3e23b982716266f776d998d3073d228e2bf3b90705c7cb6c58 ql/lib/codeql/swift/elements/expr/InOutExprConstructor.qll c8c230f9a396acadca6df83aed6751ec1710a51575f85546c2664e5244b6c395 2e354aca8430185889e091ddaecd7d7df54da10706fe7fe11b4fa0ee04d892e0 -ql/lib/codeql/swift/elements/expr/InOutToPointerExpr.qll 60e70359ea6a433cac1b4d7afe27d739979176d2f881a8108e61fe7c1dea1a9a e9c7db3671cce65c775760c52d1e58e91903ad7be656457f096bfe2abab63d29 +ql/lib/codeql/swift/elements/expr/InOutToPointerExpr.qll 145616d30d299245701f15417d02e6e90a6aa61b33326bfd4bc2a2d69bed5551 e9c7db3671cce65c775760c52d1e58e91903ad7be656457f096bfe2abab63d29 ql/lib/codeql/swift/elements/expr/InOutToPointerExprConstructor.qll 06b1377d3d7399ef308ba3c7787192446452a4c2e80e4bb9e235267b765ae05d 969680fddeb48d9e97c05061ae9cbc56263e4c5ad7f4fad5ff34fdaa6c0010b4 -ql/lib/codeql/swift/elements/expr/InjectIntoOptionalExpr.qll d44e2ccede83bc55fb5fcd135d176a53be55783904be700e4b7bc6ca54f23499 6ec93a725c92a9abf62c39451eaf6435942b61b56bd06db0d494da0b5f407441 +ql/lib/codeql/swift/elements/expr/InjectIntoOptionalExpr.qll 79d859152f5fde76e28b8b01e3ba70ec481650b39e2a686fc6898759948bc716 6ec93a725c92a9abf62c39451eaf6435942b61b56bd06db0d494da0b5f407441 ql/lib/codeql/swift/elements/expr/InjectIntoOptionalExprConstructor.qll e25cee8b12b0640bfcc652973bbe677c93b4cb252feba46f9ffe3d822f9d97e0 4211336657fce1789dcdc97d9fe75e6bc5ab3e79ec9999733488e0be0ae52ca2 ql/lib/codeql/swift/elements/expr/IntegerLiteralExprConstructor.qll 779c97ef157265fa4e02dacc6ece40834d78e061a273d30773ac2a444cf099d0 d57c9e8bbb04d8c852906a099dc319473ae126b55145735b0c2dc2b671e1bcbd ql/lib/codeql/swift/elements/expr/InterpolatedStringLiteralExprConstructor.qll 2d288a4cbaa3d7e412543fe851bb8764c56f8ccd88dc9d3a22734e7aa8da3c1a dfa6bea9f18f17d548d8af0bb4cd15e9a327a8100349d2ecfce51908062b45c8 @@ -152,52 +152,52 @@ ql/lib/codeql/swift/elements/expr/KeyPathApplicationExprConstructor.qll c58c6812 ql/lib/codeql/swift/elements/expr/KeyPathDotExprConstructor.qll d112a3a1c1b421fc6901933685179232ac37134270482a5b18d96ba6f78a1fd1 abce0b957bdf2c4b7316f4041491d31735b6c893a38fbf8d96e700a377617b51 ql/lib/codeql/swift/elements/expr/KeyPathExprConstructor.qll 96f7bc80a1364b95f5a02526b3da4f937abe6d8672e2a324d57c1b036389e102 2f65b63e8eac280b338db29875f620751c8eb14fbdcf6864d852f332c9951dd7 ql/lib/codeql/swift/elements/expr/LazyInitializerExprConstructor.qll deba52e51f31504564adc33da079b70f1f2da1e3e6f9538cba8bf97be0c27c64 4499c688d86c08cb33a754ad86f6adbe47754aa0fc58a4d77dd7cbfa1ca1fa50 -ql/lib/codeql/swift/elements/expr/LinearFunctionExpr.qll bcdc3b7c9f854f622e087a16a892af677439fee023d29341be534d297596bd3e b3253571f09a743a235c0d27384e72cf66b26ba8aa5e34061956c63be4940f15 +ql/lib/codeql/swift/elements/expr/LinearFunctionExpr.qll 37fc05646e4fbce7332fb544e3c1d053a2f2b42acb8ce1f3a9bb19425f74ae34 b3253571f09a743a235c0d27384e72cf66b26ba8aa5e34061956c63be4940f15 ql/lib/codeql/swift/elements/expr/LinearFunctionExprConstructor.qll 18998356c31c95a9a706a62dd2db24b3751015878c354dc36aa4655e386f53c3 7e02b4801e624c50d880c2826ef7149ad609aa896d194d64f715c16cfbd11a7d -ql/lib/codeql/swift/elements/expr/LinearFunctionExtractOriginalExpr.qll fb5d879aa0dd3191dfc587926618b59f977914780c607c6c62c293ecc654b6fe bd9f3c1a5114cec5c360a1bb94fe2ffaa8559dfdd69d78bd1a1c039b9d0cab10 +ql/lib/codeql/swift/elements/expr/LinearFunctionExtractOriginalExpr.qll c968bca2c79985d8899e37a4015de2a6df6fd40f6e519f8f0601202c32c68f70 bd9f3c1a5114cec5c360a1bb94fe2ffaa8559dfdd69d78bd1a1c039b9d0cab10 ql/lib/codeql/swift/elements/expr/LinearFunctionExtractOriginalExprConstructor.qll 4cdacae7a04da12cd19a51ff6b8fa5d0a5fb40b915073a261c1b71a1a0586c90 b4f338fa97ff256a53932901cf209473af8c78c8da0ec7caa66335bfb2aabe1f -ql/lib/codeql/swift/elements/expr/LinearToDifferentiableFunctionExpr.qll c841a3a0d5deb1d0f8c26122270c10793f8d49d8a484ac0fb838ad0733619fb6 a002c9d1cfc933b45eecf317654c90727a2986fb6d3403fc541be431d7c6b901 +ql/lib/codeql/swift/elements/expr/LinearToDifferentiableFunctionExpr.qll 388f59eac6cb7a21ef0222f707f8793045999c3b5bbdc202cb23648dabbdd036 a002c9d1cfc933b45eecf317654c90727a2986fb6d3403fc541be431d7c6b901 ql/lib/codeql/swift/elements/expr/LinearToDifferentiableFunctionExprConstructor.qll 8a66e39915b4945bef0b1d5b31f4cbbf8149e1392ae42a29d661cfea9c0e3476 954242936f413271a64da2b8862168712ee7b3e0a31653344268f1d615e20fdf -ql/lib/codeql/swift/elements/expr/LiteralExpr.qll 8e39746df049b3598013901e5b5f9e5d328c22fb7893c273f1a8ab96ec8305fa a599db9010b51379172c400cbd28ab3ea0e893a2dd049e2af3ed1a5eb9329f73 -ql/lib/codeql/swift/elements/expr/LoadExpr.qll 74643292340ccd9ac1c6449faa65bb02ba86749ec6a4f64e7ff04572822a1acd 44b0d1213be692586ac2a2af025ed2c4c2c2f707d2d3e6abab11ee7a28083510 +ql/lib/codeql/swift/elements/expr/LiteralExpr.qll 505be8b4d5e7e2ce60bc5ef66d0198050c8cdc1429d837088ffa8e8fc6c440ce a599db9010b51379172c400cbd28ab3ea0e893a2dd049e2af3ed1a5eb9329f73 +ql/lib/codeql/swift/elements/expr/LoadExpr.qll e75bd0ffd2da6c0db724ee3c45b2cfbed7e129339e1a597f67689362929fb120 44b0d1213be692586ac2a2af025ed2c4c2c2f707d2d3e6abab11ee7a28083510 ql/lib/codeql/swift/elements/expr/LoadExprConstructor.qll 47e2766b4019cec454177db59429f66ff4cc5e6c2ba811b9afd6b651fb390c8d a37517b63ad9e83b18a6e03cad5a4b31bc58d471a078603e7346c2f52dbb5ef9 -ql/lib/codeql/swift/elements/expr/LookupExpr.qll 46ed9daef8b3fe31ad93bb7450b11d35dfae639a7803c24c999603f49517e1ef cf76a591d96ccd9f64f404332b1be1e0587a124e3de0f9ea978d819549f51582 +ql/lib/codeql/swift/elements/expr/LookupExpr.qll c9204e10adf7e71599422b140bdc3d6f78a9bd67d11d0282555c9584a3342267 cf76a591d96ccd9f64f404332b1be1e0587a124e3de0f9ea978d819549f51582 ql/lib/codeql/swift/elements/expr/MagicIdentifierLiteralExprConstructor.qll 9ac0c8296b8a0920782210520b1d55b780f037cd080bbd1332daddddc23dac97 d87f853e1a761f3986236c44937cbe21d233e821a9ad4739d98ec8255829eb32 ql/lib/codeql/swift/elements/expr/MakeTemporarilyEscapableExprConstructor.qll b291d55ccbdef0d783ba05c68f496c0a015a211c9e5067dc6e4e65b50292a358 1c2ee4068da4b6fc5f3671af5319a784c0d3e1aa715392f8416918738f3d3633 ql/lib/codeql/swift/elements/expr/MemberRefExprConstructor.qll 484391d318c767336ae0b1625e28adcc656cbfa6075a38732d92848aaf8fb25e 2907badc97b8aa8df10912fd116758ce4762940753d6fa66d61a557e9d76cde6 -ql/lib/codeql/swift/elements/expr/MetatypeConversionExpr.qll 50ee8a089204600476f1a629bdfc8efe7718a62806abcd81901df9c8b257797c f4debff6b8aab8ddf041f3d2a9a3d9e1432e77178b3d6128ebd9861c4fa73ac1 +ql/lib/codeql/swift/elements/expr/MetatypeConversionExpr.qll 2aa47134ef9e680333532d26a30fd77054f4aec92cd58f7f39b886378d374bd0 f4debff6b8aab8ddf041f3d2a9a3d9e1432e77178b3d6128ebd9861c4fa73ac1 ql/lib/codeql/swift/elements/expr/MetatypeConversionExprConstructor.qll 925f2a5c20517f60d6464f52fe1f2940ea1c46b418571d9050f387be51b36705 60063f936b7180aea9eba42a029202a362473c0bb620e880001f0b76d326b54a ql/lib/codeql/swift/elements/expr/NilLiteralExprConstructor.qll 483911d82316ea9c4fd29a46aa9e587e91ce51e78e6f55959aa6edafd5ae4c88 12ec784670587f43e793dd50e2bc47555897203dfa9bf3d8fc591ddeb39d3bb5 -ql/lib/codeql/swift/elements/expr/NumberLiteralExpr.qll 14e4dd1acbd947ccb86c1700ac0f0dd0830aee733da356b857d0efe612498fe3 abbe1abbabb1d0511429e2c25b7cbcfba524b9f8391f4d8a5aca079b2c1085e6 +ql/lib/codeql/swift/elements/expr/NumberLiteralExpr.qll c021069046f68c90096ba0af742fe4ff190423eb46a5ce1070cfa5928160b31a abbe1abbabb1d0511429e2c25b7cbcfba524b9f8391f4d8a5aca079b2c1085e6 ql/lib/codeql/swift/elements/expr/ObjCSelectorExprConstructor.qll f61b72989d2729e279b0e70343cf020e72de8daa530ef8f1e996816431720a50 37c5f7695da3a7db0f7281e06cc34328a5ae158a5c7a15e0ac64100e06beb7f9 ql/lib/codeql/swift/elements/expr/ObjectLiteralExprConstructor.qll a18863eb82d0615e631a3fd04343646a2d45f21c14e666d4425a139d333ec035 b41bed928509bd792ec619a08560f1b5c80fb75cec485648601d55b9d7c53d1c ql/lib/codeql/swift/elements/expr/OneWayExprConstructor.qll 1f6b634d0c211d4b2fb13b5ac3f9cf6af93c535f9b0d9b764feb36dbc11a252e a2f0660ac48420cfd73111b1100f7f4f6523140c5860e1e5489c105707106275 -ql/lib/codeql/swift/elements/expr/OpaqueValueExpr.qll 15e24ab58aa38242dcc01cce60fb006da3e1a1fd98d7d3a715af3c96d28f1efc 3bf654dc10e2057a92f5f6b727237ec0b0ec7f564a6cc6ef2027c20e8e23a1e9 +ql/lib/codeql/swift/elements/expr/OpaqueValueExpr.qll 004c10a1abd10fa1596368f53a57398d3b851086d4748f312a69ef457e5586fe 3bf654dc10e2057a92f5f6b727237ec0b0ec7f564a6cc6ef2027c20e8e23a1e9 ql/lib/codeql/swift/elements/expr/OpaqueValueExprConstructor.qll 35e8475fd6a83e3ef7678529465852de9fb60d129bb5db13a26380c1376ada8b c9c999cb816b948be266aaa83bc22fb9af11b104137b4da1d99f453759784a62 -ql/lib/codeql/swift/elements/expr/OpenExistentialExpr.qll d6187b0ccca6e84c502a4528dcaa0ada8ade1c96ba0a85c5fcd2d052ad291558 cfd96b626180ef3c63c2dbc17b13cd6f585515427f5c3beac48896cf98234a67 +ql/lib/codeql/swift/elements/expr/OpenExistentialExpr.qll cd3dca0f54a9d546166af755a6c108be9f11ef73f2bbd65a380223e57d2afc1c cfd96b626180ef3c63c2dbc17b13cd6f585515427f5c3beac48896cf98234a67 ql/lib/codeql/swift/elements/expr/OpenExistentialExprConstructor.qll c56e5e6f7ae59a089316cd66a9b03d2584024625c2c662e7f74526c0b15dbd60 ea3cc78dd1b1f8fb744258e1c2bf6a3ec09eb9c1181e1a502c6a9bc2cf449337 -ql/lib/codeql/swift/elements/expr/OptionalEvaluationExpr.qll 2f46c15d17a50b14e91552be8ac5b72dbdc9f39b8fac9fa068e519ae5c8aa99b 559902efedbf4c5ef24697267c7b48162129b4ab463b41d89bdfb8b94742fa9f +ql/lib/codeql/swift/elements/expr/OptionalEvaluationExpr.qll bba59c32fbe7e76ddf07b8bbe68ce09587f490687e6754c2210e13bda055ba25 559902efedbf4c5ef24697267c7b48162129b4ab463b41d89bdfb8b94742fa9f ql/lib/codeql/swift/elements/expr/OptionalEvaluationExprConstructor.qll 4ba0af8f8b4b7920bc1106d069455eb754b7404d9a4bfc361d2ea22e8763f4fe 6d07e7838339290d1a2aec88addd511f01224d7e1d485b08ef4793e01f4b4421 ql/lib/codeql/swift/elements/expr/OptionalTryExprConstructor.qll 60d2f88e2c6fc843353cc52ce1e1c9f7b80978750d0e780361f817b1b2fea895 4eabd9f03dc5c1f956e50e2a7af0535292484acc69692d7c7f771e213609fd04 ql/lib/codeql/swift/elements/expr/OtherConstructorDeclRefExprConstructor.qll cf726ed7ed830e17aaedf1acddf1edc4efc7d72ab9f9580bc89cc8eefbd54d8a 4ef3010dc5500bd503db8aa531d5455a9c80bc30172fb005abc6459b6f66ea00 -ql/lib/codeql/swift/elements/expr/OverloadedDeclRefExpr.qll adb49e25cdd87d2e6259399a7ce3a1fbe6eb345f9b8f4e34eb23cb39eb3555da 47b1c6df5397de490f62e96edc0656b1f97c0be73c6b99ecd78b62d46106ce61 +ql/lib/codeql/swift/elements/expr/OverloadedDeclRefExpr.qll 97e35eda07e243144652648342621a67745c0b3b324940777d38a4a293968cf6 47b1c6df5397de490f62e96edc0656b1f97c0be73c6b99ecd78b62d46106ce61 ql/lib/codeql/swift/elements/expr/OverloadedDeclRefExprConstructor.qll 2cf79b483f942fbf8aaf9956429b92bf9536e212bb7f7940c2bc1d30e8e8dfd5 f4c16a90e3ab944dded491887779f960e3077f0a8823f17f50f82cf5b9803737 ql/lib/codeql/swift/elements/expr/ParenExprConstructor.qll 6baaa592db57870f5ecd9be632bd3f653c44d72581efd41e8a837916e1590f9e 6f28988d04b2cb69ddcb63fba9ae3166b527803a61c250f97e48ff39a28379f6 -ql/lib/codeql/swift/elements/expr/PointerToPointerExpr.qll 921645a373443d050dbc29b9f6bc4a734163c75aeffce453a4f8334b34077d30 54089de77845f6b0e623c537bc25a010ecf1b5c7630b1b4060d2b378abc07f4e +ql/lib/codeql/swift/elements/expr/PointerToPointerExpr.qll dad0616bab644089837f2ee2c4118d012ab62e1c4a19e1fa28c9a3187bb1e710 54089de77845f6b0e623c537bc25a010ecf1b5c7630b1b4060d2b378abc07f4e ql/lib/codeql/swift/elements/expr/PointerToPointerExprConstructor.qll 95cc8003b9a3b2101afb8f110ec4cbd29e380fc048ee080f5047bcf0e14a06c7 114d487a1bb2cd33b27a9c3a47ad1d7254766e169512642f8b09b9c32cf3dc86 ql/lib/codeql/swift/elements/expr/PostfixUnaryExprConstructor.qll c26326e2703b9a8b077ea9f132ae86a76b4010a108b8dcde29864f4206096231 70e45fbe365b63226d0132158cdd453e2e00d740a31c1fb0f7bfb3b2dedfd928 ql/lib/codeql/swift/elements/expr/PrefixUnaryExprConstructor.qll 6d4c915baf460691cc22681154b1129852c26f1bd9fe3e27b4e162f819d934f5 7971698433bc03dbff2fec34426a96a969fab1a5a575aaf91f10044819e16f6d -ql/lib/codeql/swift/elements/expr/PropertyWrapperValuePlaceholderExpr.qll 35a61a7f68e71165690127b445fff39780028cb6be5e7b5eadaafa8aeb6b2321 f9e32f65e6d453d3fa857a4d3ca19700be1f8ea2f3d13534656bc21a2fc5f0b0 +ql/lib/codeql/swift/elements/expr/PropertyWrapperValuePlaceholderExpr.qll d4b6e3f96d79b999e8a83cfa20640ac72a1e99b91ea9a42f7dc29c9471e113b8 f9e32f65e6d453d3fa857a4d3ca19700be1f8ea2f3d13534656bc21a2fc5f0b0 ql/lib/codeql/swift/elements/expr/PropertyWrapperValuePlaceholderExprConstructor.qll 874da84b8ac2fbf6f44e5343e09629225f9196f0f1f3584e6bc314e5d01d8593 e01fc8f9a1d1cddab7c249437c13f63e8dc93e7892409791728f82f1111ac924 -ql/lib/codeql/swift/elements/expr/ProtocolMetatypeToObjectExpr.qll db0a35204b99aa6665d95461db0c5592739172d3def43d38461612622d39fea7 1f342dead634daf2cd77dd32a1e59546e8c2c073e997108e17eb2c3c832b3070 +ql/lib/codeql/swift/elements/expr/ProtocolMetatypeToObjectExpr.qll b43455289de611ba68870298e89ad6f94b5edbac69d3a22b3a91046e95020913 1f342dead634daf2cd77dd32a1e59546e8c2c073e997108e17eb2c3c832b3070 ql/lib/codeql/swift/elements/expr/ProtocolMetatypeToObjectExprConstructor.qll aaaf5fd2496e24b341345933a5c730bbfd4de31c5737e22269c3f6927f8ae733 bece45f59dc21e9deffc1632aae52c17cf41924f953afc31a1aa94149ecc1512 ql/lib/codeql/swift/elements/expr/RebindSelfInConstructorExprConstructor.qll 434e00b6e5d3ccf356dabb4a7d6574966676c32d4c257ad3606d5b9e2b715524 637a16d0f5f504bad4a04bb85d6491a94738781d3282bc27363cceafb3023408 ql/lib/codeql/swift/elements/expr/RegexLiteralExprConstructor.qll 7bf1bdba26d38e8397a9a489d05042ea2057f06e35f2a664876dc0225e45892d dcc697170a9fc03b708f4a13391395e3986d60eb482639e3f5a3ba0984b72349 -ql/lib/codeql/swift/elements/expr/SelfApplyExpr.qll 75a7f14daedd69803bbb2650e503c7db5589044347c3b783f8cd13130c7c508e f0349628f9ead822783e09e56e0721f939bfb7f59c8661e6155b5a7d113c26f3 -ql/lib/codeql/swift/elements/expr/SequenceExpr.qll b1269230db9782dacba9a61e60fb2b962b05d47048b205a5bcf89157fe475b82 3b2d06ac54746033a90319463243f2d0f17265c7f1573cbfedbdca3fb7063fd2 +ql/lib/codeql/swift/elements/expr/SelfApplyExpr.qll 986b3ff9833aac59facecea185517c006264c5011191b4c7f31317a20926467a f0349628f9ead822783e09e56e0721f939bfb7f59c8661e6155b5a7d113c26f3 +ql/lib/codeql/swift/elements/expr/SequenceExpr.qll 813360eff6a312e39c7b6c49928477679a3f32314badf3383bf6204690a280e4 3b2d06ac54746033a90319463243f2d0f17265c7f1573cbfedbdca3fb7063fd2 ql/lib/codeql/swift/elements/expr/SequenceExprConstructor.qll 5a15ede013bb017a85092aff35dd2f4f1fb025e0e4e9002ac6e65b8e27c27a0b 05d6c0e2fa80bbd088b67c039520fe74ef4aa7c946f75c86207af125e7e2e6b4 ql/lib/codeql/swift/elements/expr/StringLiteralExprConstructor.qll 49de92f9566459609f4a05b7bf9b776e3a420a7316151e1d3d4ec4c5471dcffb 4a7474d3782b74a098afe48599faee2c35c88c1c7a47d4b94f79d39921cd4a1f -ql/lib/codeql/swift/elements/expr/StringToPointerExpr.qll 8fcb58665cac6f01df36fbd4f3cd78f515ee57bc1a2bdf5f414174615442cf49 6f6710f7ac709102b0f3240dcd779baf5da00d2e7a547d19291600bc405c5a54 +ql/lib/codeql/swift/elements/expr/StringToPointerExpr.qll c30a9f184de3f395183751a826c59e5e3605560f738315cead3bf89a49cfe23c 6f6710f7ac709102b0f3240dcd779baf5da00d2e7a547d19291600bc405c5a54 ql/lib/codeql/swift/elements/expr/StringToPointerExprConstructor.qll 138dd290fff168d00af79f78d9d39a1940c2a1654afd0ec02e36be86cebef970 66f7385721789915b6d5311665b89feff9469707fab630a6dcbf742980857fd9 ql/lib/codeql/swift/elements/expr/SubscriptExprConstructor.qll dd2a249c6fb3a2ce2641929206df147167682c6294c9e5815dab7dddbac0d3bd ad382cbd793461f4b4b1979b93144b5e545ba91773f06957c8e1b4808113cd80 ql/lib/codeql/swift/elements/expr/SuperRefExprConstructor.qll 7d503393bddf5c32fb4af9b47e6d748d523fc4f3deb58b36a43d3c8c176c7233 86d2312a61ccb3661d899b90ac1f37a1079b5599782d52adaf48f773b7e7dd72 @@ -206,21 +206,21 @@ ql/lib/codeql/swift/elements/expr/TryExprConstructor.qll 786f2e720922c6d485a3e02 ql/lib/codeql/swift/elements/expr/TupleElementExprConstructor.qll d5677df4f573dd79af7636bf632f854e5fd1cbe05a42a5d141892be83550e655 5248a81d39ed60c663987463f1ce35f0d48b300cd8e9c1bcd2fdbf5a32db48dc ql/lib/codeql/swift/elements/expr/TupleExprConstructor.qll 0eec270bb267006b7cdb0579efe4c420e0b01d901254a4034c3d16f98dc18fc0 4dab110e17ff808e01e46fc33436ffd22ebf5644abcb92158b5b09a93c0b1c19 ql/lib/codeql/swift/elements/expr/TypeExprConstructor.qll d4cbe4ddbd7a43a67f9a9ca55081ae11c4a85aa1cc598bc31edd3ff975255c62 1ca407571c456237f3f4f212bbcfa821d96aac44c9e569c6e5a4929c144c4569 -ql/lib/codeql/swift/elements/expr/UnderlyingToOpaqueExpr.qll f8238439d553627d5b82f21fd906f602e2d1fc884d593209be00deb2fb85b8c7 f947161c8956113ff052743fea50645176959f2b04041cb30f4111c2569400be +ql/lib/codeql/swift/elements/expr/UnderlyingToOpaqueExpr.qll f008a4bb8362b237d35702702c388bcbf13878ee4d91e3a0d4cc30e90b627560 f947161c8956113ff052743fea50645176959f2b04041cb30f4111c2569400be ql/lib/codeql/swift/elements/expr/UnderlyingToOpaqueExprConstructor.qll 6b580c0c36a8c5497b3ec7c2b704c230de4529cfdeb44399184503048dc547d7 b896b2635319b2b2498eac7d22c98f1190ff7ba23a1e2e285c97a773860d9884 -ql/lib/codeql/swift/elements/expr/UnevaluatedInstanceExpr.qll 7d390adafff48b7365e4abe80e98a9367030ad62992b0ee8b17e16d140c0e673 a094972b3b30a8a5ead53e12ede960f637190f9fa7dd061f76b4a4ab1ff5282e +ql/lib/codeql/swift/elements/expr/UnevaluatedInstanceExpr.qll 6def5d71ecc3187a7786893d4ba38677757357f9d8ab3684b74351898a74ff7d a094972b3b30a8a5ead53e12ede960f637190f9fa7dd061f76b4a4ab1ff5282e ql/lib/codeql/swift/elements/expr/UnevaluatedInstanceExprConstructor.qll 9453bb0ae5e6b9f92c3c9ded75a6bbaff7a68f8770b160b3dd1e4c133b421a80 51ac38be089bbc98950e8175f8a2b0ab2a6b8e6dbb736c754b46bf3c21b7551e ql/lib/codeql/swift/elements/expr/UnresolvedDeclRefExprConstructor.qll 6f7498cf4edc48fa4c0184bb4068be63a88a0a5ab349bd54228f23d23df292cb b9e16dc1bd56535494a65f8faa780fca70a7eae1e04da132d99638ca2ee5e62c ql/lib/codeql/swift/elements/expr/UnresolvedDotExprConstructor.qll 11d54c61f34291a77e4de8d1d763de06da5933ab784f0ae6b4bf6798ab6e2297 78b01e12cd7f49dc71456419922cf972b322bd76554090bedeb4263a8701f1af -ql/lib/codeql/swift/elements/expr/UnresolvedMemberChainResultExpr.qll 0eaae416c14e9e6cb7319344509012a321587f96fcbd4f9c45002908450ff3d9 97362882ce004dce33e97a76f2857527925696f21ac5f1f1b285d57fea7e1d57 +ql/lib/codeql/swift/elements/expr/UnresolvedMemberChainResultExpr.qll bca5ed65b098dbf13cc655b9542292d745190512f588a24ada8d79747d7f6b14 97362882ce004dce33e97a76f2857527925696f21ac5f1f1b285d57fea7e1d57 ql/lib/codeql/swift/elements/expr/UnresolvedMemberChainResultExprConstructor.qll 3e76d7a004acd986c8d58ff399d6fb0510577b9a67e01a85294f89319038e895 e02f88167623ad78bc44f4682b87312bd3c44ddb1f0f85970e19fdbf4df3a4a8 -ql/lib/codeql/swift/elements/expr/UnresolvedMemberExpr.qll 4afc9da4eeb97f89adf31d3e04610d7df3437b66fe1c601507421fad7d3d3996 6591d38ddf3aa0e4db0fa7fdb28b8f70d8278ff96e8117c560ecb1bdf770bb2a +ql/lib/codeql/swift/elements/expr/UnresolvedMemberExpr.qll 922844a98f88bc6628a0d9c67d0f7f0b6b39490bfa66eaf4a8fc22f921034898 6591d38ddf3aa0e4db0fa7fdb28b8f70d8278ff96e8117c560ecb1bdf770bb2a ql/lib/codeql/swift/elements/expr/UnresolvedMemberExprConstructor.qll db3c55863184bd02e003bf159cab3d7f713a29749d35485473f727f3ccf801a8 ea74f8904d67ac3552d85c12a2b8a19d3e2edf216efccb4263a546501fd4eba2 -ql/lib/codeql/swift/elements/expr/UnresolvedPatternExpr.qll cb316e3bd39f7d558466f91428c5c8da7b3b07ea12e138c72fda33f3b4e3398a f3624cdd8025f1bb525cd0e9a85dc098ca8fa7876f1754849bade0d4e3840589 +ql/lib/codeql/swift/elements/expr/UnresolvedPatternExpr.qll 53c371fd057205d3005967f7d34001e7dafc83f0182875c00f16e7f90098e5aa f3624cdd8025f1bb525cd0e9a85dc098ca8fa7876f1754849bade0d4e3840589 ql/lib/codeql/swift/elements/expr/UnresolvedPatternExprConstructor.qll 7b7f834d2793c7e3d60fbd69cb989a170b0e62c2777d817d33a83110ca337e94 f4f8ee260274e547514f3a46ced487abe074409b209adb84f41dc9ebb3d67691 -ql/lib/codeql/swift/elements/expr/UnresolvedSpecializeExpr.qll 8b6975b0759e4a694d2b715f48b22af0b58b390c85ca1299e5a3aa5a687a61db c6fa963f07ed372dca97ea217a836f603c276ed309576b6a13e7cc75d13038c4 +ql/lib/codeql/swift/elements/expr/UnresolvedSpecializeExpr.qll 6c607ebd3570db81a7b4f2c57069717681ce0d75e5d166eb95d909e3e4dcb59a c6fa963f07ed372dca97ea217a836f603c276ed309576b6a13e7cc75d13038c4 ql/lib/codeql/swift/elements/expr/UnresolvedSpecializeExprConstructor.qll 1cbb484b72efa96b510103bea12247adfe31ec17f9d62b982868d4a5ca3e19b9 af57548a00010dc5e8a51342e85e0c7fc15a30068d7d68b082236cfc53b8c60b -ql/lib/codeql/swift/elements/expr/UnresolvedTypeConversionExpr.qll d7e889aa4c45ea8a7f171b0de7229cae8872f2f37dc2d5cdb458ffba66ef27b9 0270bc88ba7c53e443e35d04309fcff756f0afac0b3cd601779358b54f81e4a1 +ql/lib/codeql/swift/elements/expr/UnresolvedTypeConversionExpr.qll cf710b03294002bf964ea6ad6fc5d7f071296fd8d89718fbf5f4813d021c2002 0270bc88ba7c53e443e35d04309fcff756f0afac0b3cd601779358b54f81e4a1 ql/lib/codeql/swift/elements/expr/UnresolvedTypeConversionExprConstructor.qll 191cc2641ea735a72cedd50a1b4fcc66e0e42e3bdc5d1368003790d1621478f4 07384657c12f97d9cac284154a2bcff9c7bc4a745e705cbd7c1e2f0bc857ad48 ql/lib/codeql/swift/elements/expr/VarargExpansionExprConstructor.qll b3d9bb66747c3495a47f8d7ea27162a216124e94ceb4a0c403faf7c1ca0c1ea1 84cfb1600f461ddfe088b0028ca26b1e2708bd5b59e634eed2d8766817fa6906 ql/lib/codeql/swift/elements/pattern/AnyPatternConstructor.qll 9ce05c2c4c015a072f7ab5b0d1a15fa7c2666f252ae361164c59e90150338b2a 4a0d79d90e5392187cf631397b94a0e23bc6d661d381e880b129e4964e6468f2 @@ -232,7 +232,7 @@ ql/lib/codeql/swift/elements/pattern/IsPatternConstructor.qll 209ad40227f49dfe1b ql/lib/codeql/swift/elements/pattern/NamedPatternConstructor.qll 437ccf0a28c204a83861babc91e0e422846630f001554a3d7764b323c8632a26 91c52727ccf6b035cc1f0c2ca1eb91482ef28fa874bca382fb34f9226c31c84e ql/lib/codeql/swift/elements/pattern/OptionalSomePatternConstructor.qll bc33a81415edfa4294ad9dfb57f5aa929ea4d7f21a013f145949352009a93975 9fb2afa86dc9cedd28af9f27543ea8babf431a4ba48e9941bcd484b9aa0aeab5 ql/lib/codeql/swift/elements/pattern/ParenPatternConstructor.qll 7229439aac7010dbb82f2aaa48aedf47b189e21cc70cb926072e00faa8358369 341cfacd838185178e95a2a7bb29f198e46954098f6d13890351a82943969809 -ql/lib/codeql/swift/elements/pattern/Pattern.qll e2f802e788d00a9da18dd6b5d3536666972d9a6a87969b93f95174a922afbbac cbecbc4b2d9bea7b571b9d184a0bb8cf472f66106e96d4f70e0e98d627f269a5 +ql/lib/codeql/swift/elements/pattern/Pattern.qll a5cee4c72446f884107acc248a10b098871dc027513452c569294aaeecbc5890 cbecbc4b2d9bea7b571b9d184a0bb8cf472f66106e96d4f70e0e98d627f269a5 ql/lib/codeql/swift/elements/pattern/TuplePatternConstructor.qll 208fe1f6af1eb569ea4cd5f76e8fbe4dfab9a6264f6c12b762f074a237934bdc 174c55ad1bf3058059ed6c3c3502d6099cda95fbfce925cfd261705accbddbcd ql/lib/codeql/swift/elements/pattern/TypedPatternConstructor.qll 1befdd0455e94d4daa0332b644b74eae43f98bab6aab7491a37176a431c36c34 e574ecf38aac7d9381133bfb894da8cb96aec1c933093f4f7cc951dba8152570 ql/lib/codeql/swift/elements/stmt/BraceStmtConstructor.qll eb2b4817d84da4063eaa0b95fe22131cc980c761dcf41f1336566e95bc28aae4 c8e5f7fecd01a7724d8f58c2cd8c845264be91252281f37e3eb20f4a6f421c72 @@ -249,124 +249,124 @@ ql/lib/codeql/swift/elements/stmt/FallthroughStmtConstructor.qll 657f6a565884949 ql/lib/codeql/swift/elements/stmt/ForEachStmtConstructor.qll e21b78d279a072736b9e5ce14a1c5c68c6d4536f64093bf21f8c4e2103586105 02a28c4ef39f8e7efffb2e6d8dcfeccb6f0a0fc2889cbcda5dd971711ac0ff07 ql/lib/codeql/swift/elements/stmt/GuardStmtConstructor.qll 77ddea5f97777902854eec271811cd13f86d944bcc4df80a40ed19ad0ee9411e 1602e1209b64530ee0399536bff3c13dcecbccbc92cc1f46bc5bbb5edb4e7350 ql/lib/codeql/swift/elements/stmt/IfStmtConstructor.qll c65681a3e20e383173877720e1a8a5db141215158fffad87db0a5b9e4e76e394 104d1a33a5afb61543f7f76e60a51420599625e857151c02ac874c50c6985ee9 -ql/lib/codeql/swift/elements/stmt/LabeledConditionalStmt.qll 77c2dc7bfa551dd96109ee64ca9bbd5774a36762dd00cfad89a21eaf237e1f18 2b082cc547b431391f143d317c74fe7a3533f21cd422a6bd3c9ef617cacecc0f +ql/lib/codeql/swift/elements/stmt/LabeledConditionalStmt.qll 9b946c4573c053944ca11b9c1dbed73cf17e0553626f0267cd75947e5a835e0b 2b082cc547b431391f143d317c74fe7a3533f21cd422a6bd3c9ef617cacecc0f ql/lib/codeql/swift/elements/stmt/PoundAssertStmtConstructor.qll 70a0d22f81d7d7ce4b67cc22442beee681a64ac9d0b74108dfa2e8b109d7670e 08fee916772704f02c560b06b926cb4a56154d01d87166763b3179c5d4c85542 ql/lib/codeql/swift/elements/stmt/RepeatWhileStmtConstructor.qll e19d34dbf98501b60978db21c69abe2b77896b4b6379c6ff02b15c9f5c37270e a72db7c5cb0eb5be7b07cbddb17247d4d69d2bb8cbc957dc648c25fa6c0636ce ql/lib/codeql/swift/elements/stmt/ReturnStmtConstructor.qll ade838b3c154898f24a8e1d4ef547d460eac1cd6df81148ffb0f904d38855138 c00befd9ac0962172369319d7a791c44268413f760f2ac5e377fdee09c163101 -ql/lib/codeql/swift/elements/stmt/Stmt.qll 18aaec168417ad00fcb7fa120f9b4251b6a260ab7e31799687ac57b31c4a4819 014e29f6cc639359708f4416b1719823218efa0e92dc33630ecfc051144c7ac0 +ql/lib/codeql/swift/elements/stmt/Stmt.qll 205293fa5bb81dff4d7c6ec4016e1a2b319638931e94b4d65f17d2e292bb90c2 014e29f6cc639359708f4416b1719823218efa0e92dc33630ecfc051144c7ac0 ql/lib/codeql/swift/elements/stmt/StmtConditionConstructor.qll 599663e986ff31d0174500788d42a66180efb299769fc0f72a5c751621ddb9e2 8da4524319980f8039289165d01b53d588180cc1139b16ea7a6714b857086795 ql/lib/codeql/swift/elements/stmt/SwitchStmtConstructor.qll e55c4bda4e8c1b02e8bb00b546eca91b8797c9efb315d17aa9d7044bef0568b9 a8315347d620671ec752e7ff150faa6e6cbb2353773bc16f1d0162aa53f2c8ed ql/lib/codeql/swift/elements/stmt/ThrowStmtConstructor.qll 5a0905f1385b41e184c41d474a5d5fa031ed43e11c0f05b0411de097302cf81c 658daa8e97de69ed0c6bb79bc1e945c39bac9ff8d7530bd4aca5a5d3e3606a3a ql/lib/codeql/swift/elements/stmt/WhileStmtConstructor.qll 9b5711a82db7c4f2c01f124a1c787baa26fd038433979fd01e778b3326c2c357 4e89d6b2dfefd88b67ec7335376ea0cdccab047319a7ec23113728f937ff1c26 ql/lib/codeql/swift/elements/stmt/YieldStmtConstructor.qll c0aa7145a96c7ba46b904e39989f6ebf81b53239f84e5b96023ea84aef4b0195 50908d5ee60b7bc811ca1350eff5294e8426dbbab862e0866ef2df6e90c4859c -ql/lib/codeql/swift/elements/type/AnyBuiltinIntegerType.qll f89e8ede8fc455a74ad643521d3910dc27b29359f7e15b0333d823831b7cd20c bbd9611e593c95c7ddff9d648b06b236f1973759f5cd3783d359ddb7d2c7d29e -ql/lib/codeql/swift/elements/type/AnyFunctionType.qll 9a2f25f7f72aa80a2dcd936886dfda32f2b48ae44b79da58dbad5201ef4d7375 c7154b0018d161a6dcf461f351f37b2b4f6813968d2c2d0b1e357ea8c6f50710 -ql/lib/codeql/swift/elements/type/AnyGenericType.qll 9020d36bc6899c7f305cd99403d007c6d63fadfa080b4ec57372e7a76ca60975 4474fb21ac3f092f6c1e551cd9cf397abaa721ac2e30019b1d1a3974224d907d -ql/lib/codeql/swift/elements/type/AnyMetatypeType.qll d71d790b77c2d83f3637a1fbf2bae77ac5e95d8dc81a7fd662c22db586eea71c c73a76b03eee2faee33bb7e80ab057dbc6c302d9c8d5bfa452a7e919f86d942a -ql/lib/codeql/swift/elements/type/ArchetypeType.qll 5dba765115cc421e84c56e196d2a2d70310f3d8048aa78bd3b2042785aa5e880 28190086005e4e14b0556162d18aafe4d59eef0cb69e1a02bc440b27db012197 -ql/lib/codeql/swift/elements/type/ArraySliceType.qll 57184bc51fb02bc966d1ae143750a2a82e704dc52d20e314965420a83ebd9164 21d15a7dab938ce81de00b646b897e7348476da01096168430a4a19261b74f6d +ql/lib/codeql/swift/elements/type/AnyBuiltinIntegerType.qll 87eb8254d0cf194c173dd1572a2271874671b370b4e42a646959670877407d7a bbd9611e593c95c7ddff9d648b06b236f1973759f5cd3783d359ddb7d2c7d29e +ql/lib/codeql/swift/elements/type/AnyFunctionType.qll 41dc8ac19011f615f5f1e8cb0807ebe5147676e5fcbe2f56d8e560b893db7d2b c7154b0018d161a6dcf461f351f37b2b4f6813968d2c2d0b1e357ea8c6f50710 +ql/lib/codeql/swift/elements/type/AnyGenericType.qll d013979e58f7a18a719b312e29903ebb96a8f4da402477f1e2068f95f069efb9 4474fb21ac3f092f6c1e551cd9cf397abaa721ac2e30019b1d1a3974224d907d +ql/lib/codeql/swift/elements/type/AnyMetatypeType.qll 2bb251f092fe50d45735ce8fb48176bd38f4101ca01e2ac9ad4520f7b7000c66 c73a76b03eee2faee33bb7e80ab057dbc6c302d9c8d5bfa452a7e919f86d942a +ql/lib/codeql/swift/elements/type/ArchetypeType.qll 685ddff4c8246bdd4b64040daf3daee5745f13b479045da4d6394e52fb2f6ba9 28190086005e4e14b0556162d18aafe4d59eef0cb69e1a02bc440b27db012197 +ql/lib/codeql/swift/elements/type/ArraySliceType.qll b7d4e856836d2c7aa4a03aad1071824958f881ea8e1ff9e9cbce8f1e88d5a030 21d15a7dab938ce81de00b646b897e7348476da01096168430a4a19261b74f6d ql/lib/codeql/swift/elements/type/ArraySliceTypeConstructor.qll a1f1eb78e59c6ddf2c95a43908b11c25e2113c870a5b0b58e00b1ef5e89974c0 f0b4681e070343a13ee91b25aa20c0c6a474b701d1f7ea587ad72543a32dab72 -ql/lib/codeql/swift/elements/type/BoundGenericClassType.qll 7d02a471484de918f1395638f6e8017a3301f8953016c9ed62300308c6e2b6ac 284da181c967e57023009eb9e91ed4d26ae93925fea07e71d3af0d1b0c50f90a +ql/lib/codeql/swift/elements/type/BoundGenericClassType.qll a2f44b6bbe05c67d8656d389bf47a3f6892559814fbaed65939c5ea12fe98d59 284da181c967e57023009eb9e91ed4d26ae93925fea07e71d3af0d1b0c50f90a ql/lib/codeql/swift/elements/type/BoundGenericClassTypeConstructor.qll 1174753a0421f88abdca9f124768946d790f488554e9af3136bb0c08c5a6027f c6565c9f112f1297e12f025865d6b26c6622d25a8718de92222dd4fb64ede53e -ql/lib/codeql/swift/elements/type/BoundGenericEnumType.qll 685670068892a04cd20b718118c46c768488807a57cc75102b3d6be5b07e3c94 c394d8e963e2edec82b27368dc7832c033dbf56a8acd8990ff6cf825c29cc7d9 +ql/lib/codeql/swift/elements/type/BoundGenericEnumType.qll 3d7f91c9b052af2daf55369c6dfd6cbbe67f96a6595dd4e348a6bbd247dacb89 c394d8e963e2edec82b27368dc7832c033dbf56a8acd8990ff6cf825c29cc7d9 ql/lib/codeql/swift/elements/type/BoundGenericEnumTypeConstructor.qll 4faf2e4f76d446940d2801b457e8b24f5087494b145bae1e1e0a05ba2e8d4eee eda2bdd1b9f2176d8a6c78de68ae86148e35f5d75d96d78a84995ae99816f80e -ql/lib/codeql/swift/elements/type/BoundGenericStructType.qll 8e87dbeb3bad4c3b37a5260aadfac5b6c15c067a84be376ba8b5c3cf0794bd21 a3f7a3549ff7ab0bdbfda7da4c84b125c5b96073744ae62d719e9d3278e127cf +ql/lib/codeql/swift/elements/type/BoundGenericStructType.qll c136c557d506c143bacbab2096abc44463b59e8494e9ff41c04adb9a45a1baad a3f7a3549ff7ab0bdbfda7da4c84b125c5b96073744ae62d719e9d3278e127cf ql/lib/codeql/swift/elements/type/BoundGenericStructTypeConstructor.qll 9bc4dd0ffc865f0d2668e160fb0ce526bb4aa7e400ad20a10707aad839330d31 a0f28828125726f1e5d18ed7a2145ad133c3a2200523928b69abbdc1204e3349 -ql/lib/codeql/swift/elements/type/BoundGenericType.qll 1854ab70126e449cb64e9ac00b2eb465d1fac342e172a4eff6e7417a5d663d0e 86a3a2c73a837a4c58d104af5d473fe3171bd12b03d7a2862cc0ec6d2e85667f -ql/lib/codeql/swift/elements/type/BuiltinBridgeObjectType.qll 86971ec94ed0b5db7b33484d310c01e3b7d835e7845e7ec6f5f7a3e3df3bfe3d d5f2623c2742b9c123bd6789215f32dcb8035475c98b792e53c6ef583e245f65 +ql/lib/codeql/swift/elements/type/BoundGenericType.qll c1ed5f1dfb46528d410e600ddb243ef28fec4acbb3f61bbd41e3285dcb7efb41 86a3a2c73a837a4c58d104af5d473fe3171bd12b03d7a2862cc0ec6d2e85667f +ql/lib/codeql/swift/elements/type/BuiltinBridgeObjectType.qll 725db75405a3372d79ce90c174acd45a1ee7858808a6de8820bdaf094683c468 d5f2623c2742b9c123bd6789215f32dcb8035475c98b792e53c6ef583e245f65 ql/lib/codeql/swift/elements/type/BuiltinBridgeObjectTypeConstructor.qll e309fbf1bb61cc755fd0844697f8d587c63477fe11947f4af7d39b07fc731e8f 41acdb0acf0f2eb6b1b38fb57cbbf4dfcec46afc089798b829c1ffc0539cd0fc -ql/lib/codeql/swift/elements/type/BuiltinDefaultActorStorageType.qll 3f2a38da5222ebddcd9c0ef7ddccf84e26616a56e19978a2caa725ee6743e594 96777d099fe5e06a17e5770ce73fa4f50eefbe27703218871dc7dec4c2e8e11f +ql/lib/codeql/swift/elements/type/BuiltinDefaultActorStorageType.qll 15b5e290d132498c779f404253bae030070ce1f6863c04bf08b5aa63cb39e60b 96777d099fe5e06a17e5770ce73fa4f50eefbe27703218871dc7dec4c2e8e11f ql/lib/codeql/swift/elements/type/BuiltinDefaultActorStorageTypeConstructor.qll 645d8dd261fffb8b7f8d326bcdd0b153085c7cf45fe1cc50c8cb06dbe43a9d8d 0424cf62f6f0efb86a78ba55b2ef799caf04e63fdf15f3f8458108a93ee174b1 -ql/lib/codeql/swift/elements/type/BuiltinExecutorType.qll 226a09b42840529bd31c4e9795d570466462a8e5e1833edbcb36fc96458a33b3 bb2f7e62295b20fa07cc905ef0329293c932ab8ad115f8d37aa021e421b425c0 +ql/lib/codeql/swift/elements/type/BuiltinExecutorType.qll f63b4a0ea571d2561a262f1388123281222f85436332716be6b268180a349f30 bb2f7e62295b20fa07cc905ef0329293c932ab8ad115f8d37aa021e421b425c0 ql/lib/codeql/swift/elements/type/BuiltinExecutorTypeConstructor.qll 72545245dbf61a3ab298ece1de108950c063b146a585126753684218ad40ea10 b926c1688325022c98611b5e7c9747faf0faf8f9d301d976aa208a5aace46e0d -ql/lib/codeql/swift/elements/type/BuiltinFloatType.qll 7b307414ec4175d87ef715abe950830214785eca4728bfe32542f89f061cc3a6 3dfa2ed2e1f469e1f03dcc88b29cb2318a285051aa2941dcc29c7c925dad0d29 +ql/lib/codeql/swift/elements/type/BuiltinFloatType.qll f9fca26d0c875f6bc32f3a93f395ef8b4c5803eca89cfbefe32f1cdd12d21937 3dfa2ed2e1f469e1f03dcc88b29cb2318a285051aa2941dcc29c7c925dad0d29 ql/lib/codeql/swift/elements/type/BuiltinFloatTypeConstructor.qll 4254aa8c61c82fbea44d3ca1a94876546024600a56ac88d0e622c6126dfe6b9f 953f0fcb52668e1a435f6cabf01f9c96c5fc1645bf90b8257907218a4ce51e02 -ql/lib/codeql/swift/elements/type/BuiltinIntegerLiteralType.qll 5ca7d5b579924cd37d67703ce032fd626f6f2e53aecbd8246284471a7c766237 462bfc80eb0cfe478562fc5dcade8e6a1ecdd958b26481e4df19ecf632e72a7f +ql/lib/codeql/swift/elements/type/BuiltinIntegerLiteralType.qll 9c38b871442670d4c61f6b388f334f5013e7c6518d9461404d13ee9e7fbd75fb 462bfc80eb0cfe478562fc5dcade8e6a1ecdd958b26481e4df19ecf632e72a7f ql/lib/codeql/swift/elements/type/BuiltinIntegerLiteralTypeConstructor.qll 21c0ba7a316accd4197d57dafbeb7ce356ccef0a376e9188ec78b3e9a7d046bd 165f4a30ffb1fa34ee94c69975cbea57d940aea2e46558af7eff3a1941a269c2 -ql/lib/codeql/swift/elements/type/BuiltinIntegerType.qll ba9c4722bc8adcd3b81a516f228a2d1d6c6900a0a74c1586e6fda11fdc57cde9 2807cb11ca75f8d8cc3bc87159786528f7f28e6c594ee79bf0984d0dd960d524 +ql/lib/codeql/swift/elements/type/BuiltinIntegerType.qll 7204f4a0bd93886cf890c00285fc617d5b8e7236b564ad375ff2ff98a9b1cc58 2807cb11ca75f8d8cc3bc87159786528f7f28e6c594ee79bf0984d0dd960d524 ql/lib/codeql/swift/elements/type/BuiltinIntegerTypeConstructor.qll 8e738b8996c0b1612900dd40d6dd9ea395e7463a501feb04cc3c27e7fe73ee02 c517e29002513b5ae6d05d52bc3f7e8a85f33f6e9be0f56cdd53eb25de0c9cb9 -ql/lib/codeql/swift/elements/type/BuiltinJobType.qll 77ae06df788a1d6bdf060525f842408fb5ff773397862d30dfd46f80fe889c64 7c381ec2a6be2991518cfeef57be62238f50c27845cad8b72434c404ecc5c298 +ql/lib/codeql/swift/elements/type/BuiltinJobType.qll c216da7f6573f57fcfc72d930da56223b5561cbad9e2b069225183186ac58415 7c381ec2a6be2991518cfeef57be62238f50c27845cad8b72434c404ecc5c298 ql/lib/codeql/swift/elements/type/BuiltinJobTypeConstructor.qll a63724058d426fc38c092235adec6348aa9ea302aca408d4e9721d924ec28539 abf1263e6fad8f3de7692340399f013010f39c01f5fe93b92a491b7301be998c -ql/lib/codeql/swift/elements/type/BuiltinNativeObjectType.qll 5fddd40563fdff908bd357c5b34086b927f9e615554a8c0942a3bc24ee5936fc 3225e0b8e70f488b84d02b84ef02bf1a3ac879d8f442de2b6d2c3ae53445e8e8 +ql/lib/codeql/swift/elements/type/BuiltinNativeObjectType.qll d4d34922e2ace08e0b09cc542c161d9dadb044c1c5bf08519744f082c34ee606 3225e0b8e70f488b84d02b84ef02bf1a3ac879d8f442de2b6d2c3ae53445e8e8 ql/lib/codeql/swift/elements/type/BuiltinNativeObjectTypeConstructor.qll 9ec77aa1da74d7fe83a7c22e60a6b370d04c6859e59eed11b8dbc06a1ac8e68b bd9dcd8c5317d13a07695c51ff15f7d9cbf59ad7549301d42950caf5c6cc878f -ql/lib/codeql/swift/elements/type/BuiltinRawPointerType.qll 06ebac74cfcdc7195de3159d528288afb32786a071e42c2ede932666d89ea4d3 d2f6b327e6c5d4ff9382041bcebad2b9312eb86116c42b24b88c558b10a7561a +ql/lib/codeql/swift/elements/type/BuiltinRawPointerType.qll 1b67c5ccde71e14b30f1e2f636762fa2e21a492410015b4dc5a085b91499be23 d2f6b327e6c5d4ff9382041bcebad2b9312eb86116c42b24b88c558b10a7561a ql/lib/codeql/swift/elements/type/BuiltinRawPointerTypeConstructor.qll 7f77e1c768cb46b0eb8b08bb36e721417b95f1411bd200636ffdfc4e80c3c5c3 ce0916e95044ad74f5d7e762f3cc22065cc37e804f094e6067908bd635da6d97 -ql/lib/codeql/swift/elements/type/BuiltinRawUnsafeContinuationType.qll c91a28c12be5694004e02680d5d32bc3b67208ef6a7e0f9ab04cd4a7bb3a83ed 81682a768dcbcd72b2f13b5257e1f05b642e762de92bb3f0e275f863bad261c7 +ql/lib/codeql/swift/elements/type/BuiltinRawUnsafeContinuationType.qll 1db1db613e5c0c37cdc05347be6e386e65a1ad641d84ada08d074e2d64d09a61 81682a768dcbcd72b2f13b5257e1f05b642e762de92bb3f0e275f863bad261c7 ql/lib/codeql/swift/elements/type/BuiltinRawUnsafeContinuationTypeConstructor.qll f5a6c5ea5dd91c892f242b2a05837b2a4dd440365a33749994df8df30f393701 2eab1e5815c5f4854f310a2706482f1e7b401502291d0328d37184e50c0136b9 -ql/lib/codeql/swift/elements/type/BuiltinType.qll 6031ef4546c562d127d7c7120d12b9183021f2d9ff171ebf41ffa8491ce1a628 8e02dc1d67222a969ba563365897d93be105a64ec405fd0db367370624796db2 -ql/lib/codeql/swift/elements/type/BuiltinUnsafeValueBufferType.qll 2feff34c6e0c3cb22ff287b4b0fd7bac97ce796289175524a63c0a16258ef966 27a98fe13786b8d59d587ac042e440dec6699c76eb65288bbff6d374c28bfc53 +ql/lib/codeql/swift/elements/type/BuiltinType.qll 0db7c8fbeebf26beb7aa7d4b7aeed7de8e216fd90338c1c8e9324e88856afb2b 8e02dc1d67222a969ba563365897d93be105a64ec405fd0db367370624796db2 +ql/lib/codeql/swift/elements/type/BuiltinUnsafeValueBufferType.qll 83cb313f10a00430c2192cbc9c2df918ac847fa56af921cda916c505dcbc604f 27a98fe13786b8d59d587ac042e440dec6699c76eb65288bbff6d374c28bfc53 ql/lib/codeql/swift/elements/type/BuiltinUnsafeValueBufferTypeConstructor.qll 08a3a0f1ab53739a0db79a185a0e05538c1b7c7318b25bea93e0044ad98a3c6b fb8bb4ca4b20c6581d4419ac48581bf6e75b20e1612a953e31a7207c7dd0a0d8 -ql/lib/codeql/swift/elements/type/BuiltinVectorType.qll cfe1887a0f626704881622fb63287bc408fcf72022c8ba7f3bd14974068f36a5 df375c900db766f3f66dc022cb6302f2000bda90b5f2f023be992519948151f1 +ql/lib/codeql/swift/elements/type/BuiltinVectorType.qll c170367af631c35a4dfab970c4c098cd665de5c0a5089c6d2c4c2257c5b21dcd df375c900db766f3f66dc022cb6302f2000bda90b5f2f023be992519948151f1 ql/lib/codeql/swift/elements/type/BuiltinVectorTypeConstructor.qll 81d10e15693a33c51df659d4d8e8fa5dedea310415f580c6861e0043d36e83d3 3f60d067b860f3331edb5c0e67b2e9e469b78a9bcdb39a2f3a8724c6a6638f5e -ql/lib/codeql/swift/elements/type/ClassType.qll a69b0552206ca564124dfc9befd6288c0b84dcbadfd758baa85a33e0d8b820e8 a50d11cff50d948fcbbe3d27332f7e5842291844eaee9750d72063b7d2c0d7c2 +ql/lib/codeql/swift/elements/type/ClassType.qll a1ef05a05913dc14bc6a9f960b68429ba9f97e487eccac5ab0ca6efb6fa48892 a50d11cff50d948fcbbe3d27332f7e5842291844eaee9750d72063b7d2c0d7c2 ql/lib/codeql/swift/elements/type/ClassTypeConstructor.qll 0c462e43cc8139d666fe1d77b394f29f4141064c9295ec3581fe20f920cbbbe7 43cce957ebb274ff34f14ca8bdcf93ab9c81a27a204fa56e37d7d17c4a469600 -ql/lib/codeql/swift/elements/type/DependentMemberType.qll 5d57942f02b68fce9970176a15365cd5a4e7c8092f886781388098d53cdc8615 46b2e84f7731e2cc32b98c25b1c8794f0919fbd3c653ba9b2e82822ab351e164 +ql/lib/codeql/swift/elements/type/DependentMemberType.qll 91859dbfb738f24cf381f89493950dbf68591184c0b0a1c911c16e7abfd9f5a9 46b2e84f7731e2cc32b98c25b1c8794f0919fbd3c653ba9b2e82822ab351e164 ql/lib/codeql/swift/elements/type/DependentMemberTypeConstructor.qll 8580f6bbd73045908f33920cbd5a4406522dc57b5719e6034656eec0812d3754 fdeba4bfc25eecff972235d4d19305747eaa58963024735fd839b06b434ae9f2 -ql/lib/codeql/swift/elements/type/DictionaryType.qll b5b815ec4518781ccc600caaea81371e95fbee8a97803e5dce8e0bfc8789bae6 6b6901e8331ae2bd814a3011f057b12431f37b1ad57d3ecdaf7c2b599809060f +ql/lib/codeql/swift/elements/type/DictionaryType.qll a0f447b3bb321683f657a908cb255d565b51e4d0577691bb8293fa170bfbf871 6b6901e8331ae2bd814a3011f057b12431f37b1ad57d3ecdaf7c2b599809060f ql/lib/codeql/swift/elements/type/DictionaryTypeConstructor.qll 663bd10225565fab7ecd272b29356a89750e9fc57668b83bdb40bfb95b7b1fcb 5bfe2900eceee331765b15889357d3b45fc5b9ccaf034f13c76f51ad073c247f -ql/lib/codeql/swift/elements/type/DynamicSelfType.qll 7ba19e4fa1a8bbbc41fb08c16abbd1949feebe8ddadad7d3dfcb525f2abf5746 f9544f83ee11ae2317c7f67372a98eca904ea25667eeef4d0d21c5ef66fe6b28 +ql/lib/codeql/swift/elements/type/DynamicSelfType.qll 699680b118d85eacbbb5866674b894ba8ef1da735496577183a1cb45993487e9 f9544f83ee11ae2317c7f67372a98eca904ea25667eeef4d0d21c5ef66fe6b28 ql/lib/codeql/swift/elements/type/DynamicSelfTypeConstructor.qll f81ea2287fade045d164e6f14bf3f8a43d2bb7124e0ad6b7adf26e581acd58ff 73889ef1ac9a114a76a95708929185240fb1762c1fff8db9a77d3949d827599a -ql/lib/codeql/swift/elements/type/EnumType.qll d5428bcca8398cfbf706689b32390460d8c93cc2c733ceb10432ed496d11579d 7eb0dad9ffc7fad2a22e68710deac11d5e4dfa18698001f121c50850a758078f +ql/lib/codeql/swift/elements/type/EnumType.qll 660e18e8b8061af413ba0f46d4c7426a49c5294e006b21a82eff552c3bb6009b 7eb0dad9ffc7fad2a22e68710deac11d5e4dfa18698001f121c50850a758078f ql/lib/codeql/swift/elements/type/EnumTypeConstructor.qll aa9dbd67637aae078e3975328b383824a6ad0f0446d17b9c24939a95a0caf8df 1d697f400a5401c7962c09da430b8ce23be063aa1d83985d81bcdc947fd00b81 -ql/lib/codeql/swift/elements/type/ErrorType.qll ac897e297783736a984eb6168be9b300b7a2a536ae3988b6ec29426a38bc11f0 c02282abefeb4c93938cc398d4c06ccd2be2c64e45612f20eafc73783fa84486 +ql/lib/codeql/swift/elements/type/ErrorType.qll 5d76dafba387c6fd039717f2aa73e3976ae647e1abc86343f153ec6ce9221402 c02282abefeb4c93938cc398d4c06ccd2be2c64e45612f20eafc73783fa84486 ql/lib/codeql/swift/elements/type/ErrorTypeConstructor.qll b62dcd329e8bba82bd70aa439ed4d0ddb070da6fcd3ce5ce235e9c660ce5b5a8 43e3c4b7174bc17ca98c40554c2dbae281f1b66617d8ae59e8f970308fd24573 -ql/lib/codeql/swift/elements/type/ExistentialMetatypeType.qll 2b37fa25e3a06b42b3ecb211c1d4ca72f85a99474714811ef5e89d5c2e5e4592 e22e904092b9c5784aa2890968a27265df277c60f88d968e2546f39ab6454536 +ql/lib/codeql/swift/elements/type/ExistentialMetatypeType.qll a4adda440c77818b1bf9e6a749ff3cf8faf208111253277602f4181a41bff049 e22e904092b9c5784aa2890968a27265df277c60f88d968e2546f39ab6454536 ql/lib/codeql/swift/elements/type/ExistentialMetatypeTypeConstructor.qll a6b088425c0b0993b3ba3649a49c72c15c7bb3b369f610a7971d5cef858ed9b8 56e8663f9c50f5437b6f8269e41675e8832cfae7aa3b204fa03b86d4f35ce9ff -ql/lib/codeql/swift/elements/type/ExistentialType.qll 8cc0eb534ea2152dcd83e986103616c4f7aa31f0c0e23c73c1addcb39e3758b2 0d5ef028a6bd998fa2de2f4456bf7519202a2f0e66f2bc98bcb43c8af686cade +ql/lib/codeql/swift/elements/type/ExistentialType.qll 997436bc80cdc5bc383ead44f1ce84050fad048e04aeab2affafbec836eaf7a9 0d5ef028a6bd998fa2de2f4456bf7519202a2f0e66f2bc98bcb43c8af686cade ql/lib/codeql/swift/elements/type/ExistentialTypeConstructor.qll bc9bd26dc789fe389c5f9781a0d5465189c4b685ef29cd9ca3488c64b5423e45 d9977de27830d154e2afa34c3c69a7a02b750eda00a21a70554ca31c086cfe2e -ql/lib/codeql/swift/elements/type/FunctionType.qll e2d289fcb9e2fabfaef2a1265b29fa1595e3e188eec7d8d5847ad7d2862d4a6e 1bfc06f2ca2abf5861602fc45ab4531f69bf40646ac39a12f3b6dba8e43b0b21 +ql/lib/codeql/swift/elements/type/FunctionType.qll 0bb0fa2d0dac2159de262afa23950f4b10ee0c03b3ce4ea5ba3048e56623a797 1bfc06f2ca2abf5861602fc45ab4531f69bf40646ac39a12f3b6dba8e43b0b21 ql/lib/codeql/swift/elements/type/FunctionTypeConstructor.qll 1fa2829f1ee961a1ce1cfd8259a6cc88bedcbee0aad7aece207839b4066e73f4 8537e7e2f61998e5cf1920fb872089e68b81d67d5e9939611117e7e5a6d62eb5 -ql/lib/codeql/swift/elements/type/GenericFunctionType.qll 06446c074997ba2b99aa0f4f5d1928e01117e431326578e2ead6294abd90daf0 6d52f6ee2f3b6e9976d473d0d33ab1b9b3274f1e6b352f2d1e33215a27d68ad4 +ql/lib/codeql/swift/elements/type/GenericFunctionType.qll d25013c5db3796d21779998362fc7733e1d4f521a837db866b3ab12643da00d1 6d52f6ee2f3b6e9976d473d0d33ab1b9b3274f1e6b352f2d1e33215a27d68ad4 ql/lib/codeql/swift/elements/type/GenericFunctionTypeConstructor.qll cd3099dfa77dc5186c98e6323a0e02f6496e5b2ab131aab7b3dac403365607d0 cf6c83cef81a52c336e10f83f3eff265df34d97fbe5accdebaccfa24baefe07b -ql/lib/codeql/swift/elements/type/GenericTypeParamType.qll 6881305d3599d5a511561e4eae0664a5681d8cbb2aa6718dfffcde943474cef0 e1288015ff8a0261edc1876320ea475180d0e6e75f4b5565b1ccd1498949740f +ql/lib/codeql/swift/elements/type/GenericTypeParamType.qll 1e30358a2607f8955ec1a6a36fe896a48eb8d80f7b3f5e1b20757f948cfd4f69 e1288015ff8a0261edc1876320ea475180d0e6e75f4b5565b1ccd1498949740f ql/lib/codeql/swift/elements/type/GenericTypeParamTypeConstructor.qll 4265701fad1ad336be3e08e820946dcd1f119b4fa29132ae913318c784236172 d4bf5127edc0dfa4fb8758081a557b768c6e4854c9489184c7955f66b68d3148 -ql/lib/codeql/swift/elements/type/InOutType.qll d2f6be1da40e93a6d6745b467824b1e974bb64ec56378dc328cc3e864c54e433 942f46afd617151783c79c69d96234aa4ca5741084b12b3d8349338cebb99cc2 +ql/lib/codeql/swift/elements/type/InOutType.qll 4492731832cd19d9b789c91b28bb41a35943bae18116928f8b309db986b7f4c7 942f46afd617151783c79c69d96234aa4ca5741084b12b3d8349338cebb99cc2 ql/lib/codeql/swift/elements/type/InOutTypeConstructor.qll c4889f1009018a55d0ac18c5f2a006572ac6de1f57633adc904e8a2046c09e83 8a2496df02e9f5fcb07331165cee64f97dd40dc4b4f8f32eacaf395c7c014a99 ql/lib/codeql/swift/elements/type/LValueTypeConstructor.qll e426dac8fce60f9bbd6aa12b8e33230c405c9c773046226c948bc9791e03c911 4d495938b0eb604033cea8ff105854c0c9917dbad59bb47a8751fc12d7554bdd -ql/lib/codeql/swift/elements/type/MetatypeType.qll 5d2995b2269ec118daf81268cca62beaa4189e65cae32ef7ec83b9129858cef8 34c021dc051d5d80410cd7aa25b45ccd2d7b267b2bbcb92f4249f528f524c5d8 +ql/lib/codeql/swift/elements/type/MetatypeType.qll 9f35b4075ece8a688a6597a1e435d2b65b725b652deeeb24b3921ee1931c2c85 34c021dc051d5d80410cd7aa25b45ccd2d7b267b2bbcb92f4249f528f524c5d8 ql/lib/codeql/swift/elements/type/MetatypeTypeConstructor.qll 5dfa528a0c849afa46ad08c4c92e47c3bc3418abb7674e94a0d36bc0e45d5686 6b95579b99e4cdd53cc95d9288ecbdb07ef268e5344e467336d89adddb7cc853 -ql/lib/codeql/swift/elements/type/ModuleType.qll 5f7540f8520ee7e3c7c15c1f7da269e4acd4b02b57912902e3d334fc53a9ac76 2b6cec36c543c6319178415b9ccb29e4f840b1f6e8b760a83d0f9399722995da +ql/lib/codeql/swift/elements/type/ModuleType.qll 749d4513ec389745d2082ab67bc57ba39338c4ab2421520c61f9c5aa10dd3178 2b6cec36c543c6319178415b9ccb29e4f840b1f6e8b760a83d0f9399722995da ql/lib/codeql/swift/elements/type/ModuleTypeConstructor.qll da4d1836c7e453d67221f59d007b5aff113ee31b4c9ad9445c2a7726851acf9b c902ed1ffbde644498c987708b8a4ea06ab891ffd4656ab7eb5008420bd89273 -ql/lib/codeql/swift/elements/type/NominalOrBoundGenericNominalType.qll 76248640645cf2f6ad096a73189447b3b42565e91d8f85ee1a0e3922a231c1a5 bf7e4ff426288481e9b6b5c48be7ff10a69ace0f2d2a848462c21ad9ec3167b7 -ql/lib/codeql/swift/elements/type/OpaqueTypeArchetypeType.qll fe987d7f715f118695b43ceebd4ab6c7fc9eab1530fbb54f3b79b8edfb5666a2 73bf49c826d791678af964d51836c0e1693e994465af9531aa4d1a542455c93f +ql/lib/codeql/swift/elements/type/NominalOrBoundGenericNominalType.qll a5017d79e03cae5a5ef2754493c960ad4f2d5fe5304930bbfacdae5f0084e270 bf7e4ff426288481e9b6b5c48be7ff10a69ace0f2d2a848462c21ad9ec3167b7 +ql/lib/codeql/swift/elements/type/OpaqueTypeArchetypeType.qll a607eccaa3b13eb5733698cb7580248f07ff364e4c84cec6b7aa8e78415b52da 73bf49c826d791678af964d51836c0e1693e994465af9531aa4d1a542455c93f ql/lib/codeql/swift/elements/type/OpaqueTypeArchetypeTypeConstructor.qll 20c8aa032f25f2e9759d69849e943e7049a22f8b452c055591be982f8c1aee2b 17341a9c4ec4bbad59c82d217501c771df2a58cb6adb8f1d50cf4ec31e65f803 -ql/lib/codeql/swift/elements/type/OpenedArchetypeType.qll a69b4dc52f6e25014a0db401ca90a7f827c1c906cc91ab9dd18be6b3296acefe 49fd53e2f449da6b2f40bf16f3e8c394bf0f46e5d1e019b54b5a29a3ad964e2b +ql/lib/codeql/swift/elements/type/OpenedArchetypeType.qll 3af97aac92e30de46c02df1d5cc0aaa013157c8e7b918754de162edb7bdc7130 49fd53e2f449da6b2f40bf16f3e8c394bf0f46e5d1e019b54b5a29a3ad964e2b ql/lib/codeql/swift/elements/type/OpenedArchetypeTypeConstructor.qll cc114bee717de27c63efed38ddb9d8101e6ba96e91c358541625dc24eb0c6dd5 92c1f22b4c9e0486a2fd6eca7d43c7353ac265026de482235d2045f32473aeb7 -ql/lib/codeql/swift/elements/type/OptionalType.qll 27e81ae79cbfa22c8cda3839ebaac95d11abf68615caedc2bd8c0c3362cbc7c6 37be60f19fd806fa4e1c66d6bee4091e1fb605861d1f79aa428a1e7b6b991280 +ql/lib/codeql/swift/elements/type/OptionalType.qll 1a10dfe16e62c31570a88217922b00adb5a6476a6108ee0f153eedc8c2d808ac 37be60f19fd806fa4e1c66d6bee4091e1fb605861d1f79aa428a1e7b6b991280 ql/lib/codeql/swift/elements/type/OptionalTypeConstructor.qll 61219c8fa7226e782b36e1f5a2719272e532146004da9358e1b369e669760b7e 74621440a712a77f85678bc408e0f1dc3da4d0971e18ef70c4de112800fc48ac -ql/lib/codeql/swift/elements/type/ParameterizedProtocolType.qll 342a6a5bc7709d9de4819041e1b9b85caf8d716e4b817020d4eff12d8790006c 78b09022b0f9448d347c9faf7b8373ebae40c889428e342e0cefbd228ceff053 +ql/lib/codeql/swift/elements/type/ParameterizedProtocolType.qll c6f6200aca0b3fdd7bc4ed44b667b98f6d5e175ca825bf58ed89b7a68e10415b 78b09022b0f9448d347c9faf7b8373ebae40c889428e342e0cefbd228ceff053 ql/lib/codeql/swift/elements/type/ParameterizedProtocolTypeConstructor.qll 549649fd93b455bb6220677733a26539565240bc8b49163e934e9a42ebebd115 3886762d26172facf53a0baab2fe7b310a2f356cf9c30d325217ba2c51c136f4 -ql/lib/codeql/swift/elements/type/ParenType.qll 8a1aaf7c3e4c354a3848b3285d0261d1dc14324d65dfa64986cc9240f3869eed cde8c9488dfefbbdb177c6d37f7aa3f9c2f327e0d92383b294fbd2172bba2dff +ql/lib/codeql/swift/elements/type/ParenType.qll d4bbda58390f3da19cd7eca5a166c9b655c8182b95933379e1f14554e39d3d31 cde8c9488dfefbbdb177c6d37f7aa3f9c2f327e0d92383b294fbd2172bba2dff ql/lib/codeql/swift/elements/type/ParenTypeConstructor.qll a8dc27a9de0d1492ba3bab4bf87aa45e557eccf142cee12ffde224cd670d41df a08ce80fcd6255bc2492e2447c26210631ca09a30c4cc3874eb747ae1153bf66 -ql/lib/codeql/swift/elements/type/PrimaryArchetypeType.qll f9807812ae3827e0f195935b44528537ff91e769df131ac4755b0547c113834d c950a30ba14eaad1b72d944b5a65ba04dd064726cf65061b472fefdfa8828dbb +ql/lib/codeql/swift/elements/type/PrimaryArchetypeType.qll a23c97ee4f7a4f07c7f733e993172a0254e6a1685bcb688d96e93665efcdfefe c950a30ba14eaad1b72d944b5a65ba04dd064726cf65061b472fefdfa8828dbb ql/lib/codeql/swift/elements/type/PrimaryArchetypeTypeConstructor.qll a0d24202332449b15a1e804959896f045c123e2153291a7a2805473b8efbb347 1be1fbfbff1bb63f18402e4e082878b81d57708cfc20d1499f5fd91e8332b90b -ql/lib/codeql/swift/elements/type/ProtocolCompositionType.qll 97bdcfde6955bef578f121f803ce5cea42ebca80568ae6eb8d3451f079b8fd3d 3048be59e02ee821e8bf2d470b8901f61b18075696d598babda1964b2b00cbde +ql/lib/codeql/swift/elements/type/ProtocolCompositionType.qll 1b22a4ac7bd800c9d159f38c1b12230e54c0991abec8a578ec92e950c092f458 3048be59e02ee821e8bf2d470b8901f61b18075696d598babda1964b2b00cbde ql/lib/codeql/swift/elements/type/ProtocolCompositionTypeConstructor.qll b5f4d7e73ea9281874521acf0d91a1deb2f3744854531ee2026913e695d5090d be55225d2fd21e40d9cacb0ad52f5721fed47c36a559d859fba9c9f0cb3b73c3 -ql/lib/codeql/swift/elements/type/ProtocolType.qll 7f6806952e1fe87648516cdc310370ccd886a53f4a2014e9d62cd6ce14dbd7c3 527b2acdc24eca89847fa80deb84b9584d9c92fab333724f5994dfb5e475269d +ql/lib/codeql/swift/elements/type/ProtocolType.qll 7e1246c87e6119b14d31ae40b66e1ab049938ae6843f4e7831872b63066cac1a 527b2acdc24eca89847fa80deb84b9584d9c92fab333724f5994dfb5e475269d ql/lib/codeql/swift/elements/type/ProtocolTypeConstructor.qll c0252a9975f1a21e46969d03e608d2bd11f4d1f249406f263c34232d31c9574d 145e536a0836ed5047408f0f4cf79ab8855938e99927e458d3a893cd796fda74 -ql/lib/codeql/swift/elements/type/ReferenceStorageType.qll 12966c9aeaec22d3991ba970a314d8618971f7f6a579f249c88c47333fc518a2 5635deaf09199afe8fff909f34f989c864c65447c43edf8d8e2afdf0e89a7351 -ql/lib/codeql/swift/elements/type/StructType.qll 1b92a9a6107abd816d00193b910ab236de700299793b90fa50bfbea6e0055f45 07d5b0a29e946a7e5bf6dc131b6373745f75dbdbca6fe6a3843d4b0ba7ab0309 +ql/lib/codeql/swift/elements/type/ReferenceStorageType.qll 56572b3fb5d6824f915cab5a30dc9ef09e9aa3fff4e2063d52ad319f2d8f86c6 5635deaf09199afe8fff909f34f989c864c65447c43edf8d8e2afdf0e89a7351 +ql/lib/codeql/swift/elements/type/StructType.qll 27df69f9bd97539dbd434be8d72f60fc655b2ad3880975f42713e9ff1c066f20 07d5b0a29e946a7e5bf6dc131b6373745f75dbdbca6fe6a3843d4b0ba7ab0309 ql/lib/codeql/swift/elements/type/StructTypeConstructor.qll a784445a9bb98bb59b866aff23bbe4763e02a2dc4a268b84a72e6cd60da5b17d 8718e384a94fd23910f5d04e18f2a6f14b2148047244e485214b55ae7d28e877 -ql/lib/codeql/swift/elements/type/SubstitutableType.qll 2dc4774a5b6c941376e37785b34891e9311075715af840273322fd422e93e671 cdc27e531f61fb50aaa9a20f5bf05c081759ac27df35e16afcdd2d1ecdac5da0 -ql/lib/codeql/swift/elements/type/SugarType.qll d13faf1eb71d9fa1d6fd378455cbbcfea49029e94303e33f1d08bb03d115d654 cbcbd68098b76d99c09e7ee43c9e7d04e1b2e860df943a520bf793e835c4db81 -ql/lib/codeql/swift/elements/type/SyntaxSugarType.qll 0843801d8abcb3090a6dc8c41cce5d60bba47761aa68f3c89ce21cf659696af5 a7a002cf597c3e3d0fda67111116c61a80f1e66ab8db8ddb3e189c6f15cadda6 -ql/lib/codeql/swift/elements/type/TupleType.qll ef49280a8d01acf3ecba2d3c12b512d3d3480048c412d922a1997cb1ac76fc6b 0b34c17ce9db336d0be9a869da988f31f10f754d6ffab6fa88791e508044edd2 +ql/lib/codeql/swift/elements/type/SubstitutableType.qll 78a240c6226c2167a85dce325f0f3c552364daf879c0309ebefd4787d792df23 cdc27e531f61fb50aaa9a20f5bf05c081759ac27df35e16afcdd2d1ecdac5da0 +ql/lib/codeql/swift/elements/type/SugarType.qll 0833a0f1bd26b066817f55df7a58243dbd5da69051272c38effb45653170d5c1 cbcbd68098b76d99c09e7ee43c9e7d04e1b2e860df943a520bf793e835c4db81 +ql/lib/codeql/swift/elements/type/SyntaxSugarType.qll 699fe9b4805494b62416dc86098342a725020f59a649138e6f5ba405dd536db5 a7a002cf597c3e3d0fda67111116c61a80f1e66ab8db8ddb3e189c6f15cadda6 +ql/lib/codeql/swift/elements/type/TupleType.qll 1dc14882028be534d15e348fba318c0bb1b52e692ca833987e00c9a66a1921ad 0b34c17ce9db336d0be9a869da988f31f10f754d6ffab6fa88791e508044edd2 ql/lib/codeql/swift/elements/type/TupleTypeConstructor.qll 060633b22ee9884cb98103b380963fac62a02799461d342372cfb9cc6303d693 c9a89f695c85e7e22947287bcc32909b1f701168fd89c3598a45c97909e879f4 -ql/lib/codeql/swift/elements/type/TypeAliasType.qll 615273f833d588940a32e16adacdfa56b6ac480e1aca6ebd11adfaa878b6d19e 760c79b9b581cc645f1002ca892656d406d3d339267fd58e765738257dbb45ce +ql/lib/codeql/swift/elements/type/TypeAliasType.qll 8149cc01f6d47ab10c0e20f1892af5e5d778e11a76be5f4752ad349a4c5b4fa4 760c79b9b581cc645f1002ca892656d406d3d339267fd58e765738257dbb45ce ql/lib/codeql/swift/elements/type/TypeAliasTypeConstructor.qll f63ada921beb95d5f3484ab072aa4412e93adfc8e7c0b1637273f99356f5cb13 f90d2789f7c922bc8254a0d131e36b40db1e00f9b32518633520d5c3341cd70a ql/lib/codeql/swift/elements/type/TypeReprConstructor.qll 2bb9c5ece40c6caed9c3a614affc0efd47ad2309c09392800ad346bf369969bf 30429adc135eb8fc476bc9bc185cff0a4119ddc0e618368c44f4a43246b5287f -ql/lib/codeql/swift/elements/type/UnarySyntaxSugarType.qll 072fbc064fb059a49befab907dd6049b4bf1a28e4ba3fcddf3e73d7913bc3906 0b113b1a7834779fabfa046a64c6d256cde0f510edb84da253e89d36f41f8241 -ql/lib/codeql/swift/elements/type/UnboundGenericType.qll 21878a4bf3ad77085812ad55c85e3ed0257cad10e6d7c72e513aae81616ef405 cca58789f97e51acb9d873d826eb77eda793fc514db6656ee44d33180578680c +ql/lib/codeql/swift/elements/type/UnarySyntaxSugarType.qll 712c7e75b8169a80a44a6609da7f5a39cc4f36773eb520c8824ea09295c6929c 0b113b1a7834779fabfa046a64c6d256cde0f510edb84da253e89d36f41f8241 +ql/lib/codeql/swift/elements/type/UnboundGenericType.qll 5a74162b28290141d389562e3cb49237977c6d642a80ae634b57dc10e7c811b1 cca58789f97e51acb9d873d826eb77eda793fc514db6656ee44d33180578680c ql/lib/codeql/swift/elements/type/UnboundGenericTypeConstructor.qll 63462b24e0acceea0546ec04c808fb6cf33659c44ea26df1f407205e70b0243d d591e96f9831cce1ca6f776e2c324c8e0e1c4e37077f25f3457c885e29afbf3e -ql/lib/codeql/swift/elements/type/UnmanagedStorageType.qll 3e8276cc1bae19f448027d2a0629c95c0b58b3e096b898ef006cb5eaea613908 d32206af9bf319b4b0b826d91705dbd920073d6aaa002a21ec60175996ab9d1a +ql/lib/codeql/swift/elements/type/UnmanagedStorageType.qll e36e70fd22798af490cb2a5c3ca0bc6ae418831ae99cab1e0444e6e70808545d d32206af9bf319b4b0b826d91705dbd920073d6aaa002a21ec60175996ab9d1a ql/lib/codeql/swift/elements/type/UnmanagedStorageTypeConstructor.qll c5927ab988beb973785a840840647e47cc0fb6d51712bed796cb23de67b9d7d6 b9f0f451c58f70f54c47ad98d9421a187cf8bd52972e898c66988a9f49e4eda0 -ql/lib/codeql/swift/elements/type/UnownedStorageType.qll 18923326a76bcfa31697551fb001a06b2a38ea074fa312c47953dd9a7ac16604 3b5d90688070be5dc0b84ab29aed2439b734e65d57c7556c6d763f5714a466ba +ql/lib/codeql/swift/elements/type/UnownedStorageType.qll 2a8be26447acc1bcfddc186b955764cea7ef8e4d64068ec55d8759b6c59d30bf 3b5d90688070be5dc0b84ab29aed2439b734e65d57c7556c6d763f5714a466ba ql/lib/codeql/swift/elements/type/UnownedStorageTypeConstructor.qll 211c9f3a9d41d1c9e768aa8ece5c48cca37f7811c5daab8bf80fdc2bd663dd86 c4fb8b39d319e1c27175f96ceec9712f473e0df1597e801d5b475b4c5c9c6389 -ql/lib/codeql/swift/elements/type/UnresolvedType.qll d573017fef5394a11d43cdcbaad91060e0b1e4c9ba6f2a9e358f818176ca8f45 680dd2fc64eeec5f81d2c2a05221c56a1ef7004bdcb1a8517640caa5fba0890d +ql/lib/codeql/swift/elements/type/UnresolvedType.qll 9bdb52645208b186cd55dac91cdee50dc33fc49e10e49fadbfd1d21c33996460 680dd2fc64eeec5f81d2c2a05221c56a1ef7004bdcb1a8517640caa5fba0890d ql/lib/codeql/swift/elements/type/UnresolvedTypeConstructor.qll 76c34ca055a017a0fa7cfff93843392d0698657fbf864ac798e1ae98325b3556 d0770637ec9674f9e2a47ad5c59423b91d12bb22a9d35dcfa8afa65da9e6ed93 -ql/lib/codeql/swift/elements/type/VariadicSequenceType.qll 5bca77dd661d3b2653d31005c2341b408c86661e89ae0cab9539999ecac60eea 3ac870a1d6df1642fae26ccda6274a288524a5cf242fab6fac8705d70e3fca88 +ql/lib/codeql/swift/elements/type/VariadicSequenceType.qll 325e4c4481e9ac07acdc6aebbcfef618bcaeb420c026c62978a83cf8db4a2964 3ac870a1d6df1642fae26ccda6274a288524a5cf242fab6fac8705d70e3fca88 ql/lib/codeql/swift/elements/type/VariadicSequenceTypeConstructor.qll 0d1d2328a3b5e503a883e7e6d7efd0ca5e7f2633abead9e4c94a9f98ed3cb223 69bff81c1b9413949eacb9298d2efb718ea808e68364569a1090c9878c4af856 -ql/lib/codeql/swift/elements/type/WeakStorageType.qll 87a28616eea3600fb0156fffcd65eeddc1ea74ce9c0ba5886c6365b9359e00ce 9c968414d7cc8d672f3754bced5d4f83f43a6d7872d0d263d79ff60483e1f996 +ql/lib/codeql/swift/elements/type/WeakStorageType.qll 7c07739cfc1459f068f24fef74838428128054adf611504d22532e4a156073e7 9c968414d7cc8d672f3754bced5d4f83f43a6d7872d0d263d79ff60483e1f996 ql/lib/codeql/swift/elements/type/WeakStorageTypeConstructor.qll d88b031ef44d6de14b3ddcff2eb47b53dbd11550c37250ff2edb42e5d21ec3e9 26d855c33492cf7a118e439f7baeed0e5425cfaf058b1dcc007eca7ed765c897 ql/lib/codeql/swift/elements.qll 82b69a48b7afffeb97cafd9fdc57af96b672e21879580a6cfc3bae2a49bc2c40 82b69a48b7afffeb97cafd9fdc57af96b672e21879580a6cfc3bae2a49bc2c40 ql/lib/codeql/swift/generated/AstNode.qll 02ca56d82801f942ae6265c6079d92ccafdf6b532f6bcebd98a04029ddf696e4 6216fda240e45bd4302fa0cf0f08f5f945418b144659264cdda84622b0420aa2 @@ -800,6 +800,10 @@ ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOU ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr.ql 088e9955681f87045f77ce1acd8ccf24d9a418c0b200dc8936511776dda8c8dd a35eb69033c53fd4a986d02b10ec52ac192ea8a5ce7479f191427a329b4704df +ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr_getParsedPath.ql 5f88eaba63c02a42c6ed2093cba9d442f5a3595a5e0888312f51e196c0471cfc b30b8ca1894143a2e0c334e9c32b29c50d13ef5bc94d62d338e019d9e0caeca5 +ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr_getRoot.ql 61d8d0f50c62e6bdf98005609861f6f4fd16e59c439706abf03ba27f87ed3cb1 403ee884bb83b7a4207993afbda7964e676f5f64923ce11e65a0cf8bd199e01d +ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr_getType.ql 992497671107be454ffe1f42b513a5bca37bd31849587ad55f6bd87d8ac5d4a7 b51109f0d9e5e6238d8ab9e67f24d435a873a7884308c4f01ec4ecad51ed031d ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd From f1adb4319a389c7cc2dca282917ada2f42e0f02e Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Wed, 15 Feb 2023 16:25:20 +0000 Subject: [PATCH 273/415] Add C# integration test which uses MSBuild --- .../all-platforms/msbuild/Program.cs | 11 +++++++++++ .../all-platforms/msbuild/test.csproj | 9 +++++++++ .../integration-tests/all-platforms/msbuild/test.py | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 csharp/ql/integration-tests/all-platforms/msbuild/Program.cs create mode 100644 csharp/ql/integration-tests/all-platforms/msbuild/test.csproj create mode 100644 csharp/ql/integration-tests/all-platforms/msbuild/test.py diff --git a/csharp/ql/integration-tests/all-platforms/msbuild/Program.cs b/csharp/ql/integration-tests/all-platforms/msbuild/Program.cs new file mode 100644 index 00000000000..6f05128414c --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/msbuild/Program.cs @@ -0,0 +1,11 @@ +namespace Test +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("Hello world!"); + return 0; + } + } +} diff --git a/csharp/ql/integration-tests/all-platforms/msbuild/test.csproj b/csharp/ql/integration-tests/all-platforms/msbuild/test.csproj new file mode 100644 index 00000000000..867a51c7dcf --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/msbuild/test.csproj @@ -0,0 +1,9 @@ + + + + Exe + net7.0 + enable + enable + + diff --git a/csharp/ql/integration-tests/all-platforms/msbuild/test.py b/csharp/ql/integration-tests/all-platforms/msbuild/test.py new file mode 100644 index 00000000000..97682d28205 --- /dev/null +++ b/csharp/ql/integration-tests/all-platforms/msbuild/test.py @@ -0,0 +1,4 @@ +from create_database_utils import * + +# force CodeQL to use MSBuild by setting `LGTM_INDEX_MSBUILD_TARGET` +run_codeql_database_create([], test_db="default-db", db=None, lang="csharp", extra_env={ 'LGTM_INDEX_MSBUILD_TARGET': 'Build' }) From 9db1366e4b2f6041753984302c91d281a42dd72d Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 16 Feb 2023 09:25:07 +0000 Subject: [PATCH 274/415] Change target framework to 4.0 for mono --- csharp/ql/integration-tests/all-platforms/msbuild/Program.cs | 4 +++- csharp/ql/integration-tests/all-platforms/msbuild/test.csproj | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csharp/ql/integration-tests/all-platforms/msbuild/Program.cs b/csharp/ql/integration-tests/all-platforms/msbuild/Program.cs index 6f05128414c..66b32336aa3 100644 --- a/csharp/ql/integration-tests/all-platforms/msbuild/Program.cs +++ b/csharp/ql/integration-tests/all-platforms/msbuild/Program.cs @@ -1,4 +1,6 @@ -namespace Test +using System; + +namespace Test { public class Program { diff --git a/csharp/ql/integration-tests/all-platforms/msbuild/test.csproj b/csharp/ql/integration-tests/all-platforms/msbuild/test.csproj index 867a51c7dcf..88ed91975ce 100644 --- a/csharp/ql/integration-tests/all-platforms/msbuild/test.csproj +++ b/csharp/ql/integration-tests/all-platforms/msbuild/test.csproj @@ -2,8 +2,6 @@ Exe - net7.0 - enable - enable + net4.0 From 80f5342a6d840f78bea009d5a3211bd47453703c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 16 Feb 2023 11:08:43 +0100 Subject: [PATCH 275/415] Python: Add import regression for if-then-else definitions --- .../import-resolution/if_then_else.py | 16 ++++++++++++++++ .../test/experimental/import-resolution/main.py | 3 +++ 2 files changed, 19 insertions(+) create mode 100644 python/ql/test/experimental/import-resolution/if_then_else.py diff --git a/python/ql/test/experimental/import-resolution/if_then_else.py b/python/ql/test/experimental/import-resolution/if_then_else.py new file mode 100644 index 00000000000..147033089c0 --- /dev/null +++ b/python/ql/test/experimental/import-resolution/if_then_else.py @@ -0,0 +1,16 @@ +from trace import * +enter(__file__) + +# definition based on "random" choice in this case it will always go the the if-branch, +# but our analysis is not able to figure this out +if eval("True"): + if_then_else_defined = "if_defined" +else: + # we also check that nested if-then-else works, it would be easy to accidentally + # only support _one_ level of nesting. + if eval("True"): + if_then_else_defined = "else_defined_1" + else: + if_then_else_defined = "else_defined_2" + +exit(__file__) diff --git a/python/ql/test/experimental/import-resolution/main.py b/python/ql/test/experimental/import-resolution/main.py index 0dac9689d7f..fb1515cfeb0 100644 --- a/python/ql/test/experimental/import-resolution/main.py +++ b/python/ql/test/experimental/import-resolution/main.py @@ -89,6 +89,9 @@ check("non_clashing_submodule", non_clashing_submodule, " Date: Thu, 16 Feb 2023 11:17:10 +0100 Subject: [PATCH 276/415] Python: Handle if-then-else definitions in import resolution --- .../change-notes/2023-02-16-import-if-then-else.md | 4 ++++ .../dataflow/new/internal/ImportResolution.qll | 14 ++++++++++---- .../ql/test/experimental/import-resolution/main.py | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 python/ql/lib/change-notes/2023-02-16-import-if-then-else.md diff --git a/python/ql/lib/change-notes/2023-02-16-import-if-then-else.md b/python/ql/lib/change-notes/2023-02-16-import-if-then-else.md new file mode 100644 index 00000000000..c377014a32e --- /dev/null +++ b/python/ql/lib/change-notes/2023-02-16-import-if-then-else.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Fixed module resolution so we properly recognize definitions made within if-then-else statements. diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll index 5cfc28d0a5f..7af9ca524aa 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportResolution.qll @@ -71,13 +71,19 @@ module ImportResolution { */ pragma[nomagic] predicate module_export(Module m, string name, DataFlow::CfgNode defn) { - exists(EssaVariable v | + exists(EssaVariable v, EssaDefinition essaDef | v.getName() = name and - v.getAUse() = ImportStar::getStarImported*(m).getANormalExit() + v.getAUse() = ImportStar::getStarImported*(m).getANormalExit() and + ( + essaDef = v.getDefinition() + or + // to handle definitions guarded by if-then-else + essaDef = v.getDefinition().(PhiFunction).getAnInput() + ) | - defn.getNode() = v.getDefinition().(AssignmentDefinition).getValue() + defn.getNode() = essaDef.(AssignmentDefinition).getValue() or - defn.getNode() = v.getDefinition().(ArgumentRefinement).getArgument() + defn.getNode() = essaDef.(ArgumentRefinement).getArgument() ) or exists(Alias a | diff --git a/python/ql/test/experimental/import-resolution/main.py b/python/ql/test/experimental/import-resolution/main.py index fb1515cfeb0..840da95a03c 100644 --- a/python/ql/test/experimental/import-resolution/main.py +++ b/python/ql/test/experimental/import-resolution/main.py @@ -91,7 +91,7 @@ check("subpackage2_attr", subpackage2_attr, "subpackage2_attr", globals()) #$ pr # check that definitions from within if-then-else are found from if_then_else import if_then_else_defined -check("if_then_else_defined", if_then_else_defined, "if_defined", globals()) #$ MISSING: prints=if_defined prints=else_defined_1 prints=else_defined_2 +check("if_then_else_defined", if_then_else_defined, "if_defined", globals()) #$ prints=if_defined prints=else_defined_1 prints=else_defined_2 exit(__file__) From 3ec2a3c711e91ebc97459457f3cc7879036c57c8 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 16 Feb 2023 11:28:44 +0100 Subject: [PATCH 277/415] Swift: fix subtle codegen bug on missing files While the internal registry was being cleaned up from files removed by codegen itself, it was not dropping files removed outside of codegen. Because of this files removed by the user were not being regenerated again if no change was staged to them, unless `--force` was provided. This also fixes some such "ghost" entries in the registry and some missing generated files. --- swift/codegen/lib/render.py | 5 +++- swift/codegen/test/test_render.py | 25 ++++++++++++++++--- swift/ql/.generated.list | 4 --- .../OtherAvailabilitySpec/MISSING_SOURCE.txt | 4 +++ .../MISSING_SOURCE.txt | 4 +++ 5 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt create mode 100644 swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt diff --git a/swift/codegen/lib/render.py b/swift/codegen/lib/render.py index 65014a42fa2..06f62d54263 100644 --- a/swift/codegen/lib/render.py +++ b/swift/codegen/lib/render.py @@ -106,7 +106,6 @@ class RenderManager(Renderer): def __exit__(self, exc_type, exc_val, exc_tb): if exc_val is None: for f in self._existing - self._skipped - self.written: - self._hashes.pop(self._get_path(f), None) f.unlink(missing_ok=True) log.info(f"removed {f.name}") for f in self.written: @@ -116,6 +115,10 @@ class RenderManager(Renderer): # so that they get the chance to be regenerated again during the next run for f in self.written: self._hashes.pop(self._get_path(f), None) + # clean up the registry from files that do not exist any more + for f in list(self._hashes): + if not (self._swift_dir / f).exists(): + self._hashes.pop(f) self._dump_registry() def _do_write(self, mnemonic: str, contents: str, output: pathlib.Path): diff --git a/swift/codegen/test/test_render.py b/swift/codegen/test/test_render.py index 950ca385e2f..64a3c6eb831 100644 --- a/swift/codegen/test/test_render.py +++ b/swift/codegen/test/test_render.py @@ -214,23 +214,40 @@ class MyError(Exception): pass -def test_managed_render_exception_drops_written_from_registry(pystache_renderer, sut): +def test_managed_render_exception_drops_written_and_inexsistent_from_registry(pystache_renderer, sut): data = mock.Mock(spec=("template",)) text = "some text" pystache_renderer.render_name.side_effect = (text,) output = paths.swift_dir / "some/output.txt" - registry = paths.swift_dir / "a/registry.list" + registry = paths.swift_dir / "x/registry.list" write(output, text) + write(paths.swift_dir / "a") + write(paths.swift_dir / "c") write(registry, "a a a\n" f"some/output.txt whatever {hash(text)}\n" - "b b b") + "b b b\n" + "c c c") with pytest.raises(MyError): with sut.manage(generated=(), stubs=(), registry=registry) as renderer: renderer.render(data, output) raise MyError - assert_file(registry, "a a a\nb b b\n") + assert_file(registry, "a a a\nc c c\n") + + +def test_managed_render_drops_inexsistent_from_registry(pystache_renderer, sut): + registry = paths.swift_dir / "x/registry.list" + write(paths.swift_dir / "a") + write(paths.swift_dir / "c") + write(registry, f"a {hash('')} {hash('')}\n" + "b b b\n" + f"c {hash('')} {hash('')}") + + with sut.manage(generated=(), stubs=(), registry=registry): + pass + + assert_file(registry, f"a {hash('')} {hash('')}\nc {hash('')} {hash('')}\n") def test_managed_render_exception_does_not_erase(pystache_renderer, sut): diff --git a/swift/ql/.generated.list b/swift/ql/.generated.list index 666b78c05b2..5f8e2a27011 100644 --- a/swift/ql/.generated.list +++ b/swift/ql/.generated.list @@ -800,10 +800,6 @@ ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOU ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr.ql 088e9955681f87045f77ce1acd8ccf24d9a418c0b200dc8936511776dda8c8dd a35eb69033c53fd4a986d02b10ec52ac192ea8a5ce7479f191427a329b4704df -ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr_getParsedPath.ql 5f88eaba63c02a42c6ed2093cba9d442f5a3595a5e0888312f51e196c0471cfc b30b8ca1894143a2e0c334e9c32b29c50d13ef5bc94d62d338e019d9e0caeca5 -ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr_getRoot.ql 61d8d0f50c62e6bdf98005609861f6f4fd16e59c439706abf03ba27f87ed3cb1 403ee884bb83b7a4207993afbda7964e676f5f64923ce11e65a0cf8bd199e01d -ql/test/extractor-tests/generated/expr/KeyPathExpr/KeyPathExpr_getType.ql 992497671107be454ffe1f42b513a5bca37bd31849587ad55f6bd87d8ac5d4a7 b51109f0d9e5e6238d8ab9e67f24d435a873a7884308c4f01ec4ecad51ed031d ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd diff --git a/swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt new file mode 100644 index 00000000000..0d319d9a669 --- /dev/null +++ b/swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt @@ -0,0 +1,4 @@ +// generated by codegen/codegen.py + +After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt new file mode 100644 index 00000000000..0d319d9a669 --- /dev/null +++ b/swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt @@ -0,0 +1,4 @@ +// generated by codegen/codegen.py + +After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +will appear and this file will be deleted From 9cfd0f5f469bb8b0f74f8f17f08ab878305e4847 Mon Sep 17 00:00:00 2001 From: Alex Ford Date: Thu, 16 Feb 2023 11:00:37 +0000 Subject: [PATCH 278/415] JS: fix qldoc --- javascript/ql/lib/semmle/javascript/Concepts.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/Concepts.qll b/javascript/ql/lib/semmle/javascript/Concepts.qll index 831fd0fe145..67cf325eb11 100644 --- a/javascript/ql/lib/semmle/javascript/Concepts.qll +++ b/javascript/ql/lib/semmle/javascript/Concepts.qll @@ -121,8 +121,8 @@ module Cryptography { * A data-flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * - * Extend this class to model new APIs. If you want to refine existing API models, - * extend `CryptographicOperation` instead. + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CryptographicOperation::Range` instead. */ class CryptographicOperation extends SC::CryptographicOperation instanceof CryptographicOperation::Range { /** From 75c75ea49c2a59fa372b2edd519d32e9df7538a2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 10 Feb 2023 16:36:43 +0000 Subject: [PATCH 279/415] Correctly select dotnet platform on arm-based macs --- csharp/scripts/create-extractor-pack.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/csharp/scripts/create-extractor-pack.sh b/csharp/scripts/create-extractor-pack.sh index 2308ed7cd89..dbaf18b40c2 100755 --- a/csharp/scripts/create-extractor-pack.sh +++ b/csharp/scripts/create-extractor-pack.sh @@ -6,7 +6,11 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then dotnet_platform="linux-x64" elif [[ "$OSTYPE" == "darwin"* ]]; then platform="osx64" - dotnet_platform="osx-x64" + if [[ $(uname -m) == 'arm64' ]]; then + dotnet_platform="osx-arm64" + else + dotnet_platform="osx-x64" + fi else echo "Unknown OS" exit 1 From e28be5d98f2ace04756bdb83cacdc3bac6b106b2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 10 Feb 2023 17:01:07 +0000 Subject: [PATCH 280/415] Make `msbuild` work on Arm-based Macs --- .../BuildScripts.cs | 8 +++++ .../Semmle.Autobuild.Shared/BuildActions.cs | 19 +++++++++++ .../Semmle.Autobuild.Shared/MsBuildRule.cs | 32 +++++++++++++++---- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index df362c2a129..ec7c63a022d 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -145,6 +145,14 @@ namespace Semmle.Autobuild.CSharp.Tests bool IBuildActions.IsWindows() => IsWindows; + public bool IsMacOs { get; set; } + + bool IBuildActions.IsMacOs() => IsMacOs; + + public bool IsArm { get; set; } + + bool IBuildActions.IsArm() => IsArm; + public string PathCombine(params string[] parts) { return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs index 1cf1d6253a5..f3f9ae15da6 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs @@ -7,6 +7,7 @@ using System.Xml; using System.Net.Http; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using System.Runtime.InteropServices; namespace Semmle.Autobuild.Shared { @@ -98,6 +99,18 @@ namespace Semmle.Autobuild.Shared /// bool IsWindows(); + /// + /// Gets a value indicating whether we are running on macOS. + /// + /// True if we are running on macOS. + bool IsMacOs(); + + /// + /// Gets a value indicating whether we are running on arm. + /// + /// True if we are running on arm. + bool IsArm(); + /// /// Combine path segments, Path.Combine(). /// @@ -203,6 +216,12 @@ namespace Semmle.Autobuild.Shared bool IBuildActions.IsWindows() => Win32.IsWindows(); + bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + + bool IBuildActions.IsArm() => + RuntimeInformation.ProcessArchitecture == Architecture.Arm64 || + RuntimeInformation.ProcessArchitecture == Architecture.Arm; + string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts); void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents); diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs index 77f2f70f718..56858cc87a2 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs @@ -1,18 +1,36 @@ using Semmle.Util.Logging; +using System; using System.Linq; +using System.Runtime.InteropServices; namespace Semmle.Autobuild.Shared { + internal static class MsBuildCommandExtensions + { + /// + /// Appends a call to msbuild. + /// + /// + /// + /// + public static CommandBuilder MsBuildCommand(this CommandBuilder cmdBuilder, IAutobuilder builder) + { + var isArmMac = builder.Actions.IsMacOs() && builder.Actions.IsArm(); + + // mono doesn't ship with `msbuild` on Arm-based Macs, but we can fall back to + // msbuild that ships with `dotnet` which can be invoked with `dotnet msbuild` + // perhaps we should do this on all platforms? + return isArmMac ? + cmdBuilder.RunCommand("dotnet").Argument("msbuild") : + cmdBuilder.RunCommand("msbuild"); + } + } + /// /// A build rule using msbuild. /// public class MsBuildRule : IBuildRule { - /// - /// The name of the msbuild command. - /// - private const string msBuild = "msbuild"; - public BuildScript Analyse(IAutobuilder builder, bool auto) { if (!builder.ProjectsOrSolutionsToBuild.Any()) @@ -57,7 +75,7 @@ namespace Semmle.Autobuild.Shared Script; var nugetRestore = GetNugetRestoreScript(); var msbuildRestoreCommand = new CommandBuilder(builder.Actions). - RunCommand(msBuild). + MsBuildCommand(builder). Argument("/t:restore"). QuoteArgument(projectOrSolution.FullPath); @@ -95,7 +113,7 @@ namespace Semmle.Autobuild.Shared command.RunCommand("set Platform=&& type NUL", quoteExe: false); } - command.RunCommand(msBuild); + command.MsBuildCommand(builder); command.QuoteArgument(projectOrSolution.FullPath); var target = builder.Options.MsBuildTarget ?? "rebuild"; From eab3c6dd5e2de686a107dab144779abc4cde9f60 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Fri, 10 Feb 2023 17:20:12 +0000 Subject: [PATCH 281/415] Fix missing implementations for C++ tests --- .../Semmle.Autobuild.Cpp.Tests/BuildScripts.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs index def45890c9f..846d8333030 100644 --- a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/BuildScripts.cs @@ -131,6 +131,14 @@ namespace Semmle.Autobuild.Cpp.Tests bool IBuildActions.IsWindows() => IsWindows; + public bool IsMacOs { get; set; } + + bool IBuildActions.IsMacOs() => IsMacOs; + + public bool IsArm { get; set; } + + bool IBuildActions.IsArm() => IsArm; + string IBuildActions.PathCombine(params string[] parts) { return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); From b0315119c6e5894185b840136d9159dc0757a25d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 Feb 2023 11:49:06 +0000 Subject: [PATCH 282/415] Release preparation for version 2.12.3 --- cpp/ql/lib/CHANGELOG.md | 4 ++++ cpp/ql/lib/change-notes/released/0.5.3.md | 3 +++ cpp/ql/lib/codeql-pack.release.yml | 2 +- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/CHANGELOG.md | 4 ++++ cpp/ql/src/change-notes/released/0.5.3.md | 3 +++ cpp/ql/src/codeql-pack.release.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md | 4 ++++ .../Solorigate/lib/change-notes/released/1.4.3.md | 3 +++ .../Solorigate/lib/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/src/CHANGELOG.md | 4 ++++ .../Solorigate/src/change-notes/released/1.4.3.md | 3 +++ .../Solorigate/src/codeql-pack.release.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/CHANGELOG.md | 6 ++++++ .../lib/change-notes/2023-02-07-scoped-modifier.md | 4 ---- csharp/ql/lib/change-notes/released/0.5.3.md | 5 +++++ csharp/ql/lib/codeql-pack.release.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/CHANGELOG.md | 4 ++++ csharp/ql/src/change-notes/released/0.5.3.md | 3 +++ csharp/ql/src/codeql-pack.release.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/lib/CHANGELOG.md | 10 ++++++++++ .../2023-02-01--add-support-for-twirp-framework.md | 4 ---- .../{2023-02-15-golang-120.md => released/0.4.3.md} | 11 ++++++++--- go/ql/lib/codeql-pack.release.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/CHANGELOG.md | 10 ++++++++++ .../2023-02-06-unhandled-close-writable-handle.md | 4 ---- .../0.4.3.md} | 11 ++++++++--- go/ql/src/codeql-pack.release.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/CHANGELOG.md | 12 ++++++++++++ .../change-notes/2023-02-06-dataflow-deadcode.md | 4 ---- .../ql/lib/change-notes/2023-02-08-kotlin-1.8.20.md | 4 ---- .../2023-02-13-update-create-file-sinks.md | 5 ----- java/ql/lib/change-notes/released/0.5.3.md | 11 +++++++++++ java/ql/lib/codeql-pack.release.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/CHANGELOG.md | 10 ++++++++++ .../2023-02-06-index-out-of-bounds-constant.md | 4 ---- java/ql/src/change-notes/2023-02-09-xxe-local.md | 4 ---- java/ql/src/change-notes/released/0.5.3.md | 9 +++++++++ java/ql/src/codeql-pack.release.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/CHANGELOG.md | 6 ++++++ .../ql/lib/change-notes/2023-02-12-express-ws.md | 4 ---- javascript/ql/lib/change-notes/released/0.4.3.md | 5 +++++ javascript/ql/lib/codeql-pack.release.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/CHANGELOG.md | 4 ++++ javascript/ql/src/change-notes/released/0.5.3.md | 3 +++ javascript/ql/src/codeql-pack.release.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/CHANGELOG.md | 4 ++++ misc/suite-helpers/change-notes/released/0.4.3.md | 3 +++ misc/suite-helpers/codeql-pack.release.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/CHANGELOG.md | 13 +++++++++++++ .../change-notes/2023-02-15-import-star-package.md | 4 ---- .../0.8.0.md} | 11 ++++++++--- python/ql/lib/codeql-pack.release.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/CHANGELOG.md | 4 ++++ python/ql/src/change-notes/released/0.6.3.md | 3 +++ python/ql/src/codeql-pack.release.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/CHANGELOG.md | 6 ++++++ .../0.5.3.md} | 7 ++++--- ruby/ql/lib/codeql-pack.release.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/CHANGELOG.md | 11 +++++++++++ .../src/change-notes/2022-10-11-poly-redos-lib.md | 4 ---- .../0.5.3.md} | 11 ++++++++--- ruby/ql/src/codeql-pack.release.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- shared/regex/CHANGELOG.md | 4 ++++ shared/regex/change-notes/released/0.0.7.md | 3 +++ shared/regex/codeql-pack.release.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/CHANGELOG.md | 4 ++++ shared/ssa/change-notes/released/0.0.11.md | 3 +++ shared/ssa/codeql-pack.release.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/tutorial/CHANGELOG.md | 4 ++++ shared/tutorial/change-notes/released/0.0.4.md | 3 +++ shared/tutorial/codeql-pack.release.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typetracking/CHANGELOG.md | 4 ++++ shared/typetracking/change-notes/released/0.0.4.md | 3 +++ shared/typetracking/codeql-pack.release.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/CHANGELOG.md | 4 ++++ shared/typos/change-notes/released/0.0.11.md | 3 +++ shared/typos/codeql-pack.release.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/CHANGELOG.md | 4 ++++ shared/util/change-notes/released/0.0.4.md | 3 +++ shared/util/codeql-pack.release.yml | 2 +- shared/util/qlpack.yml | 2 +- 103 files changed, 294 insertions(+), 106 deletions(-) create mode 100644 cpp/ql/lib/change-notes/released/0.5.3.md create mode 100644 cpp/ql/src/change-notes/released/0.5.3.md create mode 100644 csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.4.3.md create mode 100644 csharp/ql/campaigns/Solorigate/src/change-notes/released/1.4.3.md delete mode 100644 csharp/ql/lib/change-notes/2023-02-07-scoped-modifier.md create mode 100644 csharp/ql/lib/change-notes/released/0.5.3.md create mode 100644 csharp/ql/src/change-notes/released/0.5.3.md delete mode 100644 go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md rename go/ql/lib/change-notes/{2023-02-15-golang-120.md => released/0.4.3.md} (71%) delete mode 100644 go/ql/src/change-notes/2023-02-06-unhandled-close-writable-handle.md rename go/ql/src/change-notes/{2023-02-09-log-injection-precision.md => released/0.4.3.md} (54%) delete mode 100644 java/ql/lib/change-notes/2023-02-06-dataflow-deadcode.md delete mode 100644 java/ql/lib/change-notes/2023-02-08-kotlin-1.8.20.md delete mode 100644 java/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md create mode 100644 java/ql/lib/change-notes/released/0.5.3.md delete mode 100644 java/ql/src/change-notes/2023-02-06-index-out-of-bounds-constant.md delete mode 100644 java/ql/src/change-notes/2023-02-09-xxe-local.md create mode 100644 java/ql/src/change-notes/released/0.5.3.md delete mode 100644 javascript/ql/lib/change-notes/2023-02-12-express-ws.md create mode 100644 javascript/ql/lib/change-notes/released/0.4.3.md create mode 100644 javascript/ql/src/change-notes/released/0.5.3.md create mode 100644 misc/suite-helpers/change-notes/released/0.4.3.md delete mode 100644 python/ql/lib/change-notes/2023-02-15-import-star-package.md rename python/ql/lib/change-notes/{2023-02-14-python-2-no-longer-supported.md => released/0.8.0.md} (59%) create mode 100644 python/ql/src/change-notes/released/0.6.3.md rename ruby/ql/lib/change-notes/{2023-02-06-one-line-matches.md => released/0.5.3.md} (78%) delete mode 100644 ruby/ql/src/change-notes/2022-10-11-poly-redos-lib.md rename ruby/ql/src/change-notes/{2023-01-06-badly-anchored-regex.md => released/0.5.3.md} (55%) create mode 100644 shared/regex/change-notes/released/0.0.7.md create mode 100644 shared/ssa/change-notes/released/0.0.11.md create mode 100644 shared/tutorial/change-notes/released/0.0.4.md create mode 100644 shared/typetracking/change-notes/released/0.0.4.md create mode 100644 shared/typos/change-notes/released/0.0.11.md create mode 100644 shared/util/change-notes/released/0.0.4.md diff --git a/cpp/ql/lib/CHANGELOG.md b/cpp/ql/lib/CHANGELOG.md index 387f55a3e2e..319e78ac20b 100644 --- a/cpp/ql/lib/CHANGELOG.md +++ b/cpp/ql/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +No user-facing changes. + ## 0.5.2 No user-facing changes. diff --git a/cpp/ql/lib/change-notes/released/0.5.3.md b/cpp/ql/lib/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e97503053f0 --- /dev/null +++ b/cpp/ql/lib/change-notes/released/0.5.3.md @@ -0,0 +1,3 @@ +## 0.5.3 + +No user-facing changes. diff --git a/cpp/ql/lib/codeql-pack.release.yml b/cpp/ql/lib/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/cpp/ql/lib/codeql-pack.release.yml +++ b/cpp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 239e5ad0055..4eff7132f6c 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 0.5.3-dev +version: 0.5.3 groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/CHANGELOG.md b/cpp/ql/src/CHANGELOG.md index 8b2bc6c1be0..f0364b77bab 100644 --- a/cpp/ql/src/CHANGELOG.md +++ b/cpp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +No user-facing changes. + ## 0.5.2 No user-facing changes. diff --git a/cpp/ql/src/change-notes/released/0.5.3.md b/cpp/ql/src/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e97503053f0 --- /dev/null +++ b/cpp/ql/src/change-notes/released/0.5.3.md @@ -0,0 +1,3 @@ +## 0.5.3 + +No user-facing changes. diff --git a/cpp/ql/src/codeql-pack.release.yml b/cpp/ql/src/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/cpp/ql/src/codeql-pack.release.yml +++ b/cpp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index fb977480f05..227e7e4036d 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 0.5.3-dev +version: 0.5.3 groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md index 3137a84a435..3d63162ca4d 100644 --- a/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/lib/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.3 + +No user-facing changes. + ## 1.4.2 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.4.3.md b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.4.3.md new file mode 100644 index 00000000000..abf2a0d4dcc --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/lib/change-notes/released/1.4.3.md @@ -0,0 +1,3 @@ +## 1.4.3 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml index a76cacdf799..08f88b689fb 100644 --- a/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.4.2 +lastReleaseVersion: 1.4.3 diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 4655f3d5939..8dea74ded80 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.4.3-dev +version: 1.4.3 groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md index 3137a84a435..3d63162ca4d 100644 --- a/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md +++ b/csharp/ql/campaigns/Solorigate/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.3 + +No user-facing changes. + ## 1.4.2 No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.4.3.md b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.4.3.md new file mode 100644 index 00000000000..abf2a0d4dcc --- /dev/null +++ b/csharp/ql/campaigns/Solorigate/src/change-notes/released/1.4.3.md @@ -0,0 +1,3 @@ +## 1.4.3 + +No user-facing changes. diff --git a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml index a76cacdf799..08f88b689fb 100644 --- a/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml +++ b/csharp/ql/campaigns/Solorigate/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 1.4.2 +lastReleaseVersion: 1.4.3 diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 813cb0d50ce..526b9726aac 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.4.3-dev +version: 1.4.3 groups: - csharp - solorigate diff --git a/csharp/ql/lib/CHANGELOG.md b/csharp/ql/lib/CHANGELOG.md index d31bad9b040..7d14d20ddbc 100644 --- a/csharp/ql/lib/CHANGELOG.md +++ b/csharp/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.5.3 + +### Minor Analysis Improvements + +* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables. + ## 0.5.2 ### Major Analysis Improvements diff --git a/csharp/ql/lib/change-notes/2023-02-07-scoped-modifier.md b/csharp/ql/lib/change-notes/2023-02-07-scoped-modifier.md deleted file mode 100644 index 93460b64184..00000000000 --- a/csharp/ql/lib/change-notes/2023-02-07-scoped-modifier.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables. \ No newline at end of file diff --git a/csharp/ql/lib/change-notes/released/0.5.3.md b/csharp/ql/lib/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..a4f605335ac --- /dev/null +++ b/csharp/ql/lib/change-notes/released/0.5.3.md @@ -0,0 +1,5 @@ +## 0.5.3 + +### Minor Analysis Improvements + +* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables. diff --git a/csharp/ql/lib/codeql-pack.release.yml b/csharp/ql/lib/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/csharp/ql/lib/codeql-pack.release.yml +++ b/csharp/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 106d566fefe..7b3d1f34c3d 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 0.5.3-dev +version: 0.5.3 groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/CHANGELOG.md b/csharp/ql/src/CHANGELOG.md index c9bdcf20c42..15b14e1e20d 100644 --- a/csharp/ql/src/CHANGELOG.md +++ b/csharp/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +No user-facing changes. + ## 0.5.2 No user-facing changes. diff --git a/csharp/ql/src/change-notes/released/0.5.3.md b/csharp/ql/src/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e97503053f0 --- /dev/null +++ b/csharp/ql/src/change-notes/released/0.5.3.md @@ -0,0 +1,3 @@ +## 0.5.3 + +No user-facing changes. diff --git a/csharp/ql/src/codeql-pack.release.yml b/csharp/ql/src/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/csharp/ql/src/codeql-pack.release.yml +++ b/csharp/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index b3c48bf29fe..74689657702 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 0.5.3-dev +version: 0.5.3 groups: - csharp - queries diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 687d1d2ca66..9e2d903eae8 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.4.3 + +### New Features + +* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed, the definitions of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules, and taint flow models have been added for relevant new standard library functions. + +### Minor Analysis Improvements + +* Support for the Twirp framework has been added. + ## 0.4.2 No user-facing changes. diff --git a/go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md b/go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md deleted file mode 100644 index a5e70658c4a..00000000000 --- a/go/ql/lib/change-notes/2023-02-01--add-support-for-twirp-framework.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Support for the Twirp framework has been added. diff --git a/go/ql/lib/change-notes/2023-02-15-golang-120.md b/go/ql/lib/change-notes/released/0.4.3.md similarity index 71% rename from go/ql/lib/change-notes/2023-02-15-golang-120.md rename to go/ql/lib/change-notes/released/0.4.3.md index 37e7433cbcb..095a5e4d788 100644 --- a/go/ql/lib/change-notes/2023-02-15-golang-120.md +++ b/go/ql/lib/change-notes/released/0.4.3.md @@ -1,4 +1,9 @@ ---- -category: feature ---- +## 0.4.3 + +### New Features + * Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed, the definitions of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules, and taint flow models have been added for relevant new standard library functions. + +### Minor Analysis Improvements + +* Support for the Twirp framework has been added. diff --git a/go/ql/lib/codeql-pack.release.yml b/go/ql/lib/codeql-pack.release.yml index 94c5b17423c..1ec9c4ea5d9 100644 --- a/go/ql/lib/codeql-pack.release.yml +++ b/go/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.2 +lastReleaseVersion: 0.4.3 diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index 7519fff5a28..c0f303848da 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 0.4.3-dev +version: 0.4.3 groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/CHANGELOG.md b/go/ql/src/CHANGELOG.md index 7271b252996..d7c6b659d23 100644 --- a/go/ql/src/CHANGELOG.md +++ b/go/ql/src/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.4.3 + +### New Queries + +* Added a new query, `go/unhandled-writable-file-close`, to detect instances where writable file handles are closed without appropriate checks for errors. + +### Query Metadata Changes + +* The precision of the `go/log-injection` query was decreased from `high` to `medium`, since it may not be able to identify every way in which log data may be sanitized. This also aligns it with the precision of comparable queries for other languages. + ## 0.4.2 No user-facing changes. diff --git a/go/ql/src/change-notes/2023-02-06-unhandled-close-writable-handle.md b/go/ql/src/change-notes/2023-02-06-unhandled-close-writable-handle.md deleted file mode 100644 index a759cd48517..00000000000 --- a/go/ql/src/change-notes/2023-02-06-unhandled-close-writable-handle.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: newQuery ---- -* Added a new query, `go/unhandled-writable-file-close`, to detect instances where writable file handles are closed without appropriate checks for errors. diff --git a/go/ql/src/change-notes/2023-02-09-log-injection-precision.md b/go/ql/src/change-notes/released/0.4.3.md similarity index 54% rename from go/ql/src/change-notes/2023-02-09-log-injection-precision.md rename to go/ql/src/change-notes/released/0.4.3.md index 668d06dbfb5..3a1f617387c 100644 --- a/go/ql/src/change-notes/2023-02-09-log-injection-precision.md +++ b/go/ql/src/change-notes/released/0.4.3.md @@ -1,4 +1,9 @@ ---- -category: queryMetadata ---- +## 0.4.3 + +### New Queries + +* Added a new query, `go/unhandled-writable-file-close`, to detect instances where writable file handles are closed without appropriate checks for errors. + +### Query Metadata Changes + * The precision of the `go/log-injection` query was decreased from `high` to `medium`, since it may not be able to identify every way in which log data may be sanitized. This also aligns it with the precision of comparable queries for other languages. diff --git a/go/ql/src/codeql-pack.release.yml b/go/ql/src/codeql-pack.release.yml index 94c5b17423c..1ec9c4ea5d9 100644 --- a/go/ql/src/codeql-pack.release.yml +++ b/go/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.2 +lastReleaseVersion: 0.4.3 diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 191e4d8f940..64d978e72af 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 0.4.3-dev +version: 0.4.3 groups: - go - queries diff --git a/java/ql/lib/CHANGELOG.md b/java/ql/lib/CHANGELOG.md index 1aa4de9efe6..a7710c105fd 100644 --- a/java/ql/lib/CHANGELOG.md +++ b/java/ql/lib/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.5.3 + +### New Features + +* Kotlin versions up to 1.8.20 are now supported. + +### Minor Analysis Improvements + +* Removed the first argument of `java.nio.file.Files#createTempDirectory(String,FileAttribute[])` as a "create-file" sink. +* Added the first argument of `java.nio.file.Files#copy` as a "read-file" sink for the `java/path-injection` query. +* The data flow library now disregards flow through code that is dead based on some basic constant propagation, for example, guards like `if (1+1>3)`. + ## 0.5.2 ### Minor Analysis Improvements diff --git a/java/ql/lib/change-notes/2023-02-06-dataflow-deadcode.md b/java/ql/lib/change-notes/2023-02-06-dataflow-deadcode.md deleted file mode 100644 index d802e802a18..00000000000 --- a/java/ql/lib/change-notes/2023-02-06-dataflow-deadcode.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The data flow library now disregards flow through code that is dead based on some basic constant propagation, for example, guards like `if (1+1>3)`. diff --git a/java/ql/lib/change-notes/2023-02-08-kotlin-1.8.20.md b/java/ql/lib/change-notes/2023-02-08-kotlin-1.8.20.md deleted file mode 100644 index f328dd7f05f..00000000000 --- a/java/ql/lib/change-notes/2023-02-08-kotlin-1.8.20.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: feature ---- -* Kotlin versions up to 1.8.20 are now supported. diff --git a/java/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md b/java/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md deleted file mode 100644 index ad4f35a6421..00000000000 --- a/java/ql/lib/change-notes/2023-02-13-update-create-file-sinks.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -category: minorAnalysis ---- -* Removed the first argument of `java.nio.file.Files#createTempDirectory(String,FileAttribute[])` as a "create-file" sink. -* Added the first argument of `java.nio.file.Files#copy` as a "read-file" sink for the `java/path-injection` query. diff --git a/java/ql/lib/change-notes/released/0.5.3.md b/java/ql/lib/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e16561a850d --- /dev/null +++ b/java/ql/lib/change-notes/released/0.5.3.md @@ -0,0 +1,11 @@ +## 0.5.3 + +### New Features + +* Kotlin versions up to 1.8.20 are now supported. + +### Minor Analysis Improvements + +* Removed the first argument of `java.nio.file.Files#createTempDirectory(String,FileAttribute[])` as a "create-file" sink. +* Added the first argument of `java.nio.file.Files#copy` as a "read-file" sink for the `java/path-injection` query. +* The data flow library now disregards flow through code that is dead based on some basic constant propagation, for example, guards like `if (1+1>3)`. diff --git a/java/ql/lib/codeql-pack.release.yml b/java/ql/lib/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/java/ql/lib/codeql-pack.release.yml +++ b/java/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 48043d91fb2..3688ef4a66c 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 0.5.3-dev +version: 0.5.3 groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/CHANGELOG.md b/java/ql/src/CHANGELOG.md index fe6ce573ada..0741ea4a1a3 100644 --- a/java/ql/src/CHANGELOG.md +++ b/java/ql/src/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.5.3 + +### New Queries + +* Added a new query, `java/xxe-local`, which is a version of the XXE query that uses local sources (for example, reads from a local file). + +### Minor Analysis Improvements + +* The `java/index-out-of-bounds` query has improved its handling of arrays of constant length, and may report additional results in those cases. + ## 0.5.2 ### New Queries diff --git a/java/ql/src/change-notes/2023-02-06-index-out-of-bounds-constant.md b/java/ql/src/change-notes/2023-02-06-index-out-of-bounds-constant.md deleted file mode 100644 index 364dfb1ab22..00000000000 --- a/java/ql/src/change-notes/2023-02-06-index-out-of-bounds-constant.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The `java/index-out-of-bounds` query has improved its handling of arrays of constant length, and may report additional results in those cases. diff --git a/java/ql/src/change-notes/2023-02-09-xxe-local.md b/java/ql/src/change-notes/2023-02-09-xxe-local.md deleted file mode 100644 index fd9d7209253..00000000000 --- a/java/ql/src/change-notes/2023-02-09-xxe-local.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: newQuery ---- -* Added a new query, `java/xxe-local`, which is a version of the XXE query that uses local sources (for example, reads from a local file). diff --git a/java/ql/src/change-notes/released/0.5.3.md b/java/ql/src/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..dfd7f6d2343 --- /dev/null +++ b/java/ql/src/change-notes/released/0.5.3.md @@ -0,0 +1,9 @@ +## 0.5.3 + +### New Queries + +* Added a new query, `java/xxe-local`, which is a version of the XXE query that uses local sources (for example, reads from a local file). + +### Minor Analysis Improvements + +* The `java/index-out-of-bounds` query has improved its handling of arrays of constant length, and may report additional results in those cases. diff --git a/java/ql/src/codeql-pack.release.yml b/java/ql/src/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/java/ql/src/codeql-pack.release.yml +++ b/java/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index f1efa658670..ac79303e9f2 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 0.5.3-dev +version: 0.5.3 groups: - java - queries diff --git a/javascript/ql/lib/CHANGELOG.md b/javascript/ql/lib/CHANGELOG.md index 81e26afe0ea..428036e9c45 100644 --- a/javascript/ql/lib/CHANGELOG.md +++ b/javascript/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.4.3 + +### Minor Analysis Improvements + +* Added dataflow sources for the [express-ws](https://www.npmjs.com/package/express-ws) library. + ## 0.4.2 ### Minor Analysis Improvements diff --git a/javascript/ql/lib/change-notes/2023-02-12-express-ws.md b/javascript/ql/lib/change-notes/2023-02-12-express-ws.md deleted file mode 100644 index f1e59ca7e1c..00000000000 --- a/javascript/ql/lib/change-notes/2023-02-12-express-ws.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Added dataflow sources for the [express-ws](https://www.npmjs.com/package/express-ws) library. \ No newline at end of file diff --git a/javascript/ql/lib/change-notes/released/0.4.3.md b/javascript/ql/lib/change-notes/released/0.4.3.md new file mode 100644 index 00000000000..03f2bdd2cf1 --- /dev/null +++ b/javascript/ql/lib/change-notes/released/0.4.3.md @@ -0,0 +1,5 @@ +## 0.4.3 + +### Minor Analysis Improvements + +* Added dataflow sources for the [express-ws](https://www.npmjs.com/package/express-ws) library. diff --git a/javascript/ql/lib/codeql-pack.release.yml b/javascript/ql/lib/codeql-pack.release.yml index 94c5b17423c..1ec9c4ea5d9 100644 --- a/javascript/ql/lib/codeql-pack.release.yml +++ b/javascript/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.2 +lastReleaseVersion: 0.4.3 diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index 8ce67542e11..a497a3694d1 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 0.4.3-dev +version: 0.4.3 groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/CHANGELOG.md b/javascript/ql/src/CHANGELOG.md index 192e7caf996..7eb1ebe12bd 100644 --- a/javascript/ql/src/CHANGELOG.md +++ b/javascript/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +No user-facing changes. + ## 0.5.2 No user-facing changes. diff --git a/javascript/ql/src/change-notes/released/0.5.3.md b/javascript/ql/src/change-notes/released/0.5.3.md new file mode 100644 index 00000000000..e97503053f0 --- /dev/null +++ b/javascript/ql/src/change-notes/released/0.5.3.md @@ -0,0 +1,3 @@ +## 0.5.3 + +No user-facing changes. diff --git a/javascript/ql/src/codeql-pack.release.yml b/javascript/ql/src/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/javascript/ql/src/codeql-pack.release.yml +++ b/javascript/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index 25edf011032..d890538b935 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 0.5.3-dev +version: 0.5.3 groups: - javascript - queries diff --git a/misc/suite-helpers/CHANGELOG.md b/misc/suite-helpers/CHANGELOG.md index 108c522a649..e6532a3f5d8 100644 --- a/misc/suite-helpers/CHANGELOG.md +++ b/misc/suite-helpers/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.3 + +No user-facing changes. + ## 0.4.2 No user-facing changes. diff --git a/misc/suite-helpers/change-notes/released/0.4.3.md b/misc/suite-helpers/change-notes/released/0.4.3.md new file mode 100644 index 00000000000..126fb622583 --- /dev/null +++ b/misc/suite-helpers/change-notes/released/0.4.3.md @@ -0,0 +1,3 @@ +## 0.4.3 + +No user-facing changes. diff --git a/misc/suite-helpers/codeql-pack.release.yml b/misc/suite-helpers/codeql-pack.release.yml index 94c5b17423c..1ec9c4ea5d9 100644 --- a/misc/suite-helpers/codeql-pack.release.yml +++ b/misc/suite-helpers/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.4.2 +lastReleaseVersion: 0.4.3 diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 6154a791ba2..58add65b183 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,3 +1,3 @@ name: codeql/suite-helpers -version: 0.4.3-dev +version: 0.4.3 groups: shared diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index 473d1ebc67e..c7ade22bbcb 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -1,3 +1,16 @@ +## 0.8.0 + +### Breaking Changes + +- Python 2 is no longer supported for extracting databases using the CodeQL CLI. As a consequence, + the previously deprecated support for `pyxl` and `spitfire` templates has also been removed. When + extracting Python 2 code, having Python 2 installed is still recommended, as this ensures the + correct version of the Python standard library is extracted. + +### Minor Analysis Improvements + +* Fixed module resolution so we properly recognize that in `from import *`, where `` is a package, the actual imports are made from the `/__init__.py` file. + ## 0.7.2 No user-facing changes. diff --git a/python/ql/lib/change-notes/2023-02-15-import-star-package.md b/python/ql/lib/change-notes/2023-02-15-import-star-package.md deleted file mode 100644 index c2f3e24cc2d..00000000000 --- a/python/ql/lib/change-notes/2023-02-15-import-star-package.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* Fixed module resolution so we properly recognize that in `from import *`, where `` is a package, the actual imports are made from the `/__init__.py` file. diff --git a/python/ql/lib/change-notes/2023-02-14-python-2-no-longer-supported.md b/python/ql/lib/change-notes/released/0.8.0.md similarity index 59% rename from python/ql/lib/change-notes/2023-02-14-python-2-no-longer-supported.md rename to python/ql/lib/change-notes/released/0.8.0.md index a15dda02da9..16533f766b6 100644 --- a/python/ql/lib/change-notes/2023-02-14-python-2-no-longer-supported.md +++ b/python/ql/lib/change-notes/released/0.8.0.md @@ -1,7 +1,12 @@ ---- -category: breaking ---- +## 0.8.0 + +### Breaking Changes + - Python 2 is no longer supported for extracting databases using the CodeQL CLI. As a consequence, the previously deprecated support for `pyxl` and `spitfire` templates has also been removed. When extracting Python 2 code, having Python 2 installed is still recommended, as this ensures the correct version of the Python standard library is extracted. + +### Minor Analysis Improvements + +* Fixed module resolution so we properly recognize that in `from import *`, where `` is a package, the actual imports are made from the `/__init__.py` file. diff --git a/python/ql/lib/codeql-pack.release.yml b/python/ql/lib/codeql-pack.release.yml index fee171e9685..37eab3197dc 100644 --- a/python/ql/lib/codeql-pack.release.yml +++ b/python/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.7.2 +lastReleaseVersion: 0.8.0 diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index cc59833287a..ca2bb693a35 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 0.7.3-dev +version: 0.8.0 groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/CHANGELOG.md b/python/ql/src/CHANGELOG.md index 6199749411d..eace5e34204 100644 --- a/python/ql/src/CHANGELOG.md +++ b/python/ql/src/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.3 + +No user-facing changes. + ## 0.6.2 No user-facing changes. diff --git a/python/ql/src/change-notes/released/0.6.3.md b/python/ql/src/change-notes/released/0.6.3.md new file mode 100644 index 00000000000..83374bcef56 --- /dev/null +++ b/python/ql/src/change-notes/released/0.6.3.md @@ -0,0 +1,3 @@ +## 0.6.3 + +No user-facing changes. diff --git a/python/ql/src/codeql-pack.release.yml b/python/ql/src/codeql-pack.release.yml index 5501a2a1cc5..b7dafe32c5d 100644 --- a/python/ql/src/codeql-pack.release.yml +++ b/python/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.6.2 +lastReleaseVersion: 0.6.3 diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index 8f91049c479..a29da011d40 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 0.6.3-dev +version: 0.6.3 groups: - python - queries diff --git a/ruby/ql/lib/CHANGELOG.md b/ruby/ql/lib/CHANGELOG.md index 9c0a2e31268..3aabcb81fa7 100644 --- a/ruby/ql/lib/CHANGELOG.md +++ b/ruby/ql/lib/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.5.3 + +### Minor Analysis Improvements + + * Ruby 3.1: one-line pattern matches are now supported. The AST nodes are named `TestPattern` (`expr in pattern`) and `MatchPattern` (`expr => pattern`). + ## 0.5.2 ### Minor Analysis Improvements diff --git a/ruby/ql/lib/change-notes/2023-02-06-one-line-matches.md b/ruby/ql/lib/change-notes/released/0.5.3.md similarity index 78% rename from ruby/ql/lib/change-notes/2023-02-06-one-line-matches.md rename to ruby/ql/lib/change-notes/released/0.5.3.md index 3eefba83c2d..3535d0a9fa7 100644 --- a/ruby/ql/lib/change-notes/2023-02-06-one-line-matches.md +++ b/ruby/ql/lib/change-notes/released/0.5.3.md @@ -1,4 +1,5 @@ ---- - category: minorAnalysis ---- +## 0.5.3 + +### Minor Analysis Improvements + * Ruby 3.1: one-line pattern matches are now supported. The AST nodes are named `TestPattern` (`expr in pattern`) and `MatchPattern` (`expr => pattern`). diff --git a/ruby/ql/lib/codeql-pack.release.yml b/ruby/ql/lib/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/ruby/ql/lib/codeql-pack.release.yml +++ b/ruby/ql/lib/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index b5932af8cca..7838a425ce3 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 0.5.3-dev +version: 0.5.3 groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/CHANGELOG.md b/ruby/ql/src/CHANGELOG.md index 0d0783ac735..c5329a4db5a 100644 --- a/ruby/ql/src/CHANGELOG.md +++ b/ruby/ql/src/CHANGELOG.md @@ -1,3 +1,14 @@ +## 0.5.3 + +### New Queries + +* Added a new query, `rb/regex/badly-anchored-regexp`, to detect regular expression validators that use `^` and `$` + as anchors and therefore might match only a single line of a multi-line string. + +### Minor Analysis Improvements + +* The `rb/polynomial-redos` query now considers the entrypoints of the API of a gem as sources. + ## 0.5.2 ### New Queries diff --git a/ruby/ql/src/change-notes/2022-10-11-poly-redos-lib.md b/ruby/ql/src/change-notes/2022-10-11-poly-redos-lib.md deleted file mode 100644 index 125f87378af..00000000000 --- a/ruby/ql/src/change-notes/2022-10-11-poly-redos-lib.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: minorAnalysis ---- -* The `rb/polynomial-redos` query now considers the entrypoints of the API of a gem as sources. diff --git a/ruby/ql/src/change-notes/2023-01-06-badly-anchored-regex.md b/ruby/ql/src/change-notes/released/0.5.3.md similarity index 55% rename from ruby/ql/src/change-notes/2023-01-06-badly-anchored-regex.md rename to ruby/ql/src/change-notes/released/0.5.3.md index ab694d3106f..e45205dbd41 100644 --- a/ruby/ql/src/change-notes/2023-01-06-badly-anchored-regex.md +++ b/ruby/ql/src/change-notes/released/0.5.3.md @@ -1,5 +1,10 @@ ---- -category: newQuery ---- +## 0.5.3 + +### New Queries + * Added a new query, `rb/regex/badly-anchored-regexp`, to detect regular expression validators that use `^` and `$` as anchors and therefore might match only a single line of a multi-line string. + +### Minor Analysis Improvements + +* The `rb/polynomial-redos` query now considers the entrypoints of the API of a gem as sources. diff --git a/ruby/ql/src/codeql-pack.release.yml b/ruby/ql/src/codeql-pack.release.yml index 2d9d3f587f8..2164e038a5d 100644 --- a/ruby/ql/src/codeql-pack.release.yml +++ b/ruby/ql/src/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.5.2 +lastReleaseVersion: 0.5.3 diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index e054a69c412..0c8fa047bd4 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 0.5.3-dev +version: 0.5.3 groups: - ruby - queries diff --git a/shared/regex/CHANGELOG.md b/shared/regex/CHANGELOG.md index 6fbffd820ce..122ab5362b6 100644 --- a/shared/regex/CHANGELOG.md +++ b/shared/regex/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.7 + +No user-facing changes. + ## 0.0.6 No user-facing changes. diff --git a/shared/regex/change-notes/released/0.0.7.md b/shared/regex/change-notes/released/0.0.7.md new file mode 100644 index 00000000000..84da6f18c42 --- /dev/null +++ b/shared/regex/change-notes/released/0.0.7.md @@ -0,0 +1,3 @@ +## 0.0.7 + +No user-facing changes. diff --git a/shared/regex/codeql-pack.release.yml b/shared/regex/codeql-pack.release.yml index cf398ce02aa..a2a5484910b 100644 --- a/shared/regex/codeql-pack.release.yml +++ b/shared/regex/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.6 +lastReleaseVersion: 0.0.7 diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index 12294207f32..4cbe36ea935 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 0.0.7-dev +version: 0.0.7 groups: shared library: true dependencies: diff --git a/shared/ssa/CHANGELOG.md b/shared/ssa/CHANGELOG.md index 59b8e47aca3..4f07ce5c1ec 100644 --- a/shared/ssa/CHANGELOG.md +++ b/shared/ssa/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.11 + +No user-facing changes. + ## 0.0.10 No user-facing changes. diff --git a/shared/ssa/change-notes/released/0.0.11.md b/shared/ssa/change-notes/released/0.0.11.md new file mode 100644 index 00000000000..19a2a55bd68 --- /dev/null +++ b/shared/ssa/change-notes/released/0.0.11.md @@ -0,0 +1,3 @@ +## 0.0.11 + +No user-facing changes. diff --git a/shared/ssa/codeql-pack.release.yml b/shared/ssa/codeql-pack.release.yml index b740014e5ae..e679dc42092 100644 --- a/shared/ssa/codeql-pack.release.yml +++ b/shared/ssa/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.10 +lastReleaseVersion: 0.0.11 diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index fee841c9975..754dd25d74b 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/ssa -version: 0.0.11-dev +version: 0.0.11 groups: shared library: true diff --git a/shared/tutorial/CHANGELOG.md b/shared/tutorial/CHANGELOG.md index 54503e1a481..3db1262ff44 100644 --- a/shared/tutorial/CHANGELOG.md +++ b/shared/tutorial/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4 + +No user-facing changes. + ## 0.0.3 No user-facing changes. diff --git a/shared/tutorial/change-notes/released/0.0.4.md b/shared/tutorial/change-notes/released/0.0.4.md new file mode 100644 index 00000000000..eefe286a4d8 --- /dev/null +++ b/shared/tutorial/change-notes/released/0.0.4.md @@ -0,0 +1,3 @@ +## 0.0.4 + +No user-facing changes. diff --git a/shared/tutorial/codeql-pack.release.yml b/shared/tutorial/codeql-pack.release.yml index a24b693d1e7..ec411a674bc 100644 --- a/shared/tutorial/codeql-pack.release.yml +++ b/shared/tutorial/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.3 +lastReleaseVersion: 0.0.4 diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index 9cc8b266cd1..ea8c77d9b9d 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 0.0.4-dev +version: 0.0.4 groups: shared library: true diff --git a/shared/typetracking/CHANGELOG.md b/shared/typetracking/CHANGELOG.md index a5e0d0a4ff3..203d814ee87 100644 --- a/shared/typetracking/CHANGELOG.md +++ b/shared/typetracking/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4 + +No user-facing changes. + ## 0.0.3 No user-facing changes. diff --git a/shared/typetracking/change-notes/released/0.0.4.md b/shared/typetracking/change-notes/released/0.0.4.md new file mode 100644 index 00000000000..eefe286a4d8 --- /dev/null +++ b/shared/typetracking/change-notes/released/0.0.4.md @@ -0,0 +1,3 @@ +## 0.0.4 + +No user-facing changes. diff --git a/shared/typetracking/codeql-pack.release.yml b/shared/typetracking/codeql-pack.release.yml index a24b693d1e7..ec411a674bc 100644 --- a/shared/typetracking/codeql-pack.release.yml +++ b/shared/typetracking/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.3 +lastReleaseVersion: 0.0.4 diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index 632e6e5afb3..74c76caf243 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 0.0.4-dev +version: 0.0.4 groups: shared library: true dependencies: diff --git a/shared/typos/CHANGELOG.md b/shared/typos/CHANGELOG.md index d00e75f5895..5bfc49ecc91 100644 --- a/shared/typos/CHANGELOG.md +++ b/shared/typos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.11 + +No user-facing changes. + ## 0.0.10 No user-facing changes. diff --git a/shared/typos/change-notes/released/0.0.11.md b/shared/typos/change-notes/released/0.0.11.md new file mode 100644 index 00000000000..19a2a55bd68 --- /dev/null +++ b/shared/typos/change-notes/released/0.0.11.md @@ -0,0 +1,3 @@ +## 0.0.11 + +No user-facing changes. diff --git a/shared/typos/codeql-pack.release.yml b/shared/typos/codeql-pack.release.yml index b740014e5ae..e679dc42092 100644 --- a/shared/typos/codeql-pack.release.yml +++ b/shared/typos/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.10 +lastReleaseVersion: 0.0.11 diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index af24ed34a09..bfcf30b6b72 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/typos -version: 0.0.11-dev +version: 0.0.11 groups: shared library: true diff --git a/shared/util/CHANGELOG.md b/shared/util/CHANGELOG.md index f7fa0fe0e40..60892d241a6 100644 --- a/shared/util/CHANGELOG.md +++ b/shared/util/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.4 + +No user-facing changes. + ## 0.0.3 No user-facing changes. diff --git a/shared/util/change-notes/released/0.0.4.md b/shared/util/change-notes/released/0.0.4.md new file mode 100644 index 00000000000..eefe286a4d8 --- /dev/null +++ b/shared/util/change-notes/released/0.0.4.md @@ -0,0 +1,3 @@ +## 0.0.4 + +No user-facing changes. diff --git a/shared/util/codeql-pack.release.yml b/shared/util/codeql-pack.release.yml index a24b693d1e7..ec411a674bc 100644 --- a/shared/util/codeql-pack.release.yml +++ b/shared/util/codeql-pack.release.yml @@ -1,2 +1,2 @@ --- -lastReleaseVersion: 0.0.3 +lastReleaseVersion: 0.0.4 diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index 469f40a4d3e..e84f606de69 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 0.0.4-dev +version: 0.0.4 groups: shared library: true dependencies: From b4d59ff9326ccbb2e37886cd29cf1e1e3ff990e1 Mon Sep 17 00:00:00 2001 From: Nick Rolfe Date: Thu, 16 Feb 2023 12:07:47 +0000 Subject: [PATCH 283/415] Go: changenote grammar tweaks --- go/ql/lib/CHANGELOG.md | 2 +- go/ql/lib/change-notes/released/0.4.3.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go/ql/lib/CHANGELOG.md b/go/ql/lib/CHANGELOG.md index 9e2d903eae8..1a5db51a5ee 100644 --- a/go/ql/lib/CHANGELOG.md +++ b/go/ql/lib/CHANGELOG.md @@ -2,7 +2,7 @@ ### New Features -* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed, the definitions of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules, and taint flow models have been added for relevant new standard library functions. +* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed; the definition of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules; and taint flow models have been added for relevant, new standard-library functions. ### Minor Analysis Improvements diff --git a/go/ql/lib/change-notes/released/0.4.3.md b/go/ql/lib/change-notes/released/0.4.3.md index 095a5e4d788..812c902d9bf 100644 --- a/go/ql/lib/change-notes/released/0.4.3.md +++ b/go/ql/lib/change-notes/released/0.4.3.md @@ -2,7 +2,7 @@ ### New Features -* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed, the definitions of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules, and taint flow models have been added for relevant new standard library functions. +* Go 1.20 is now supported. The extractor now functions as expected when Go 1.20 is installed; the definition of `implementsComparable` has been updated according to Go 1.20's new, more-liberal rules; and taint flow models have been added for relevant, new standard-library functions. ### Minor Analysis Improvements From 9ed021ad669064f566bb526b925f0eda11da9b81 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 16 Feb 2023 13:27:16 +0100 Subject: [PATCH 284/415] Python: Accept change to `WeakFilePermissions.expected` :muscle: --- .../CWE-732-WeakFilePermissions/WeakFilePermissions.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected index 762d2599c2d..3bfb6fe4f88 100644 --- a/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected +++ b/python/ql/test/query-tests/Security/CWE-732-WeakFilePermissions/WeakFilePermissions.expected @@ -2,5 +2,6 @@ | test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | | test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | | test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. | +| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | | test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | | test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. | From 45d00ae9dd6122e4f18570e65fab7d3bc5b1fb4c Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 16 Feb 2023 14:52:46 +0100 Subject: [PATCH 285/415] inline the move-caches script into the action --- .../cache-query-compilation/action.yml | 87 +++++++++++++++++-- .../cache-query-compilation/move-caches.js | 75 ---------------- 2 files changed, 79 insertions(+), 83 deletions(-) delete mode 100644 .github/actions/cache-query-compilation/move-caches.js diff --git a/.github/actions/cache-query-compilation/action.yml b/.github/actions/cache-query-compilation/action.yml index 2a0358ae63c..cd5c244f86a 100644 --- a/.github/actions/cache-query-compilation/action.yml +++ b/.github/actions/cache-query-compilation/action.yml @@ -43,12 +43,83 @@ runs: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}- codeql-compile-${{ inputs.key }}-main- - name: Fill compilation cache directory - id: fill-compilation-dir - shell: bash - run: | - # Move all the existing cache into another folder, so we only preserve the cache for the current queries. - node $GITHUB_WORKSPACE/.github/actions/cache-query-compilation/move-caches.js ${COMBINED_CACHE_DIR} - - echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT - env: + uses: actions/github-script@v6 + env: COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir + with: + script: | + // # Move all the existing cache into another folder, so we only preserve the cache for the current queries. + // mkdir -p ${COMBINED_CACHE_DIR} + // rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty. + // # copy the contents of the .cache folders into the combined cache folder. + // cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files + // # clean up the .cache folders + // rm -rf **/.cache/* + + const fs = require("fs"); + const path = require("path"); + + // the first argv is the cache folder to create. + const COMBINED_CACHE_DIR = process.env.COMBINED_CACHE_DIR; + + function* walkCaches(dir) { + const files = fs.readdirSync(dir, { withFileTypes: true }); + for (const file of files) { + if (file.isDirectory()) { + const filePath = path.join(dir, file.name); + yield* walkCaches(filePath); + if (file.name === ".cache") { + yield filePath; + } + } + } + } + + async function copyDir(src, dest) { + for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) { + const srcPath = path.join(src, file.name); + const destPath = path.join(dest, file.name); + if (file.isDirectory()) { + if (!fs.existsSync(destPath)) { + fs.mkdirSync(destPath); + } + await copyDir(srcPath, destPath); + } else { + await fs.promises.copyFile(srcPath, destPath); + } + } + } + + async function main() { + const cacheDirs = [...walkCaches(".")]; + + for (const dir of cacheDirs) { + console.log(`Found .cache dir at ${dir}`); + } + + // mkdir -p ${COMBINED_CACHE_DIR} + fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true }); + + // rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty. + await Promise.all( + cacheDirs.map((cacheDir) => + (async function () { + await fs.promises.rm(path.join(cacheDir, "lock"), { force: true }); + await fs.promises.rm(path.join(cacheDir, "size"), { force: true }); + })() + ) + ); + + // # copy the contents of the .cache folders into the combined cache folder. + // cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files + await Promise.all( + cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR)) + ); + + // # clean up the .cache folders + // rm -rf **/.cache/* + await Promise.all( + cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true })) + ); + } + main(); diff --git a/.github/actions/cache-query-compilation/move-caches.js b/.github/actions/cache-query-compilation/move-caches.js deleted file mode 100644 index 67fc503cdc0..00000000000 --- a/.github/actions/cache-query-compilation/move-caches.js +++ /dev/null @@ -1,75 +0,0 @@ -// # Move all the existing cache into another folder, so we only preserve the cache for the current queries. -// mkdir -p ${COMBINED_CACHE_DIR} -// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty. -// # copy the contents of the .cache folders into the combined cache folder. -// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files -// # clean up the .cache folders -// rm -rf **/.cache/* - -const fs = require("fs"); -const path = require("path"); - -// the first argv is the cache folder to create. -const COMBINED_CACHE_DIR = process.argv[2]; - -function* walkCaches(dir) { - const files = fs.readdirSync(dir, { withFileTypes: true }); - for (const file of files) { - if (file.isDirectory()) { - const filePath = path.join(dir, file.name); - yield* walkCaches(filePath); - if (file.name === ".cache") { - yield filePath; - } - } - } -} - -async function copyDir(src, dest) { - for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) { - const srcPath = path.join(src, file.name); - const destPath = path.join(dest, file.name); - if (file.isDirectory()) { - if (!fs.existsSync(destPath)) { - fs.mkdirSync(destPath); - } - await copyDir(srcPath, destPath); - } else { - await fs.promises.copyFile(srcPath, destPath); - } - } -} - -async function main() { - const cacheDirs = [...walkCaches(".")]; - - for (const dir of cacheDirs) { - console.log(`Found .cache dir at ${dir}`); - } - - // mkdir -p ${COMBINED_CACHE_DIR} - fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true }); - - // rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty. - await Promise.all( - cacheDirs.map((cacheDir) => - (async function () { - await fs.promises.rm(path.join(cacheDir, "lock"), { force: true }); - await fs.promises.rm(path.join(cacheDir, "size"), { force: true }); - })() - ) - ); - - // # copy the contents of the .cache folders into the combined cache folder. - // cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files - await Promise.all( - cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR)) - ); - - // # clean up the .cache folders - // rm -rf **/.cache/* - await Promise.all( - cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true })) - ); -} -main(); From f50382ba703a6e78fce5470e2ec3f733803a5303 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 16 Feb 2023 14:53:31 +0100 Subject: [PATCH 286/415] Swift: fix weird module naming in codegen --- swift/codegen/{schemadefs.py/defs.py => schemadefs.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename swift/codegen/{schemadefs.py/defs.py => schemadefs.py} (100%) diff --git a/swift/codegen/schemadefs.py/defs.py b/swift/codegen/schemadefs.py similarity index 100% rename from swift/codegen/schemadefs.py/defs.py rename to swift/codegen/schemadefs.py From 767da59397fb9917342b4c6ea10eade1d07d6787 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Thu, 16 Feb 2023 14:57:00 +0100 Subject: [PATCH 287/415] remove the paths requirement from running QL-for-QL --- .github/workflows/ql-for-ql-build.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml index 8b6e7a56946..f9a2f963c3f 100644 --- a/.github/workflows/ql-for-ql-build.yml +++ b/.github/workflows/ql-for-ql-build.yml @@ -5,13 +5,6 @@ on: branches: [main] pull_request: branches: [main] - paths: - - "ql/**" - - "**.qll" - - "**.ql" - - "**.dbscheme" - - "**/qlpack.yml" - - ".github/workflows/ql-for-ql-build.yml" env: CARGO_TERM_COLOR: always From 94fd4128097f17983b30b2e528dc635d2ad52e9b Mon Sep 17 00:00:00 2001 From: Jami Cogswell Date: Thu, 16 Feb 2023 09:02:41 -0500 Subject: [PATCH 288/415] Java: move awt and swing to isInfrequentlyUsed predicate --- .../modelgenerator/internal/CaptureModelsSpecific.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll b/java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll index d7c3a010bb3..879df6bb873 100644 --- a/java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll +++ b/java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll @@ -36,8 +36,6 @@ private predicate isInTestFile(J::File file) { private predicate isJdkInternal(J::CompilationUnit cu) { cu.getPackage().getName().matches("org.graalvm%") or cu.getPackage().getName().matches("com.sun%") or - cu.getPackage().getName().matches("javax.swing%") or - cu.getPackage().getName().matches("java.awt%") or cu.getPackage().getName().matches("sun%") or cu.getPackage().getName().matches("jdk%") or cu.getPackage().getName().matches("java2d%") or @@ -57,12 +55,18 @@ private predicate isJdkInternal(J::CompilationUnit cu) { cu.getPackage().getName() = "" } +private predicate isInfrequentlyUsed(J::CompilationUnit cu) { + cu.getPackage().getName().matches("javax.swing%") or + cu.getPackage().getName().matches("java.awt%") +} + /** * Holds if it is relevant to generate models for `api`. */ private predicate isRelevantForModels(J::Callable api) { not isInTestFile(api.getCompilationUnit().getFile()) and not isJdkInternal(api.getCompilationUnit()) and + not isInfrequentlyUsed(api.getCompilationUnit()) and not api instanceof J::MainMethod and not api instanceof J::StaticInitializer and not exists(J::FunctionalExpr funcExpr | api = funcExpr.asMethod()) and From 8eb8daa4d43fcdec1e718763e80fda4db842ff10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 16 Feb 2023 17:23:25 +0000 Subject: [PATCH 289/415] Post-release preparation for codeql-cli-2.12.3 --- cpp/ql/lib/qlpack.yml | 2 +- cpp/ql/src/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/lib/qlpack.yml | 2 +- csharp/ql/campaigns/Solorigate/src/qlpack.yml | 2 +- csharp/ql/lib/qlpack.yml | 2 +- csharp/ql/src/qlpack.yml | 2 +- go/ql/lib/qlpack.yml | 2 +- go/ql/src/qlpack.yml | 2 +- java/ql/lib/qlpack.yml | 2 +- java/ql/src/qlpack.yml | 2 +- javascript/ql/lib/qlpack.yml | 2 +- javascript/ql/src/qlpack.yml | 2 +- misc/suite-helpers/qlpack.yml | 2 +- python/ql/lib/qlpack.yml | 2 +- python/ql/src/qlpack.yml | 2 +- ruby/ql/lib/qlpack.yml | 2 +- ruby/ql/src/qlpack.yml | 2 +- shared/regex/qlpack.yml | 2 +- shared/ssa/qlpack.yml | 2 +- shared/tutorial/qlpack.yml | 2 +- shared/typetracking/qlpack.yml | 2 +- shared/typos/qlpack.yml | 2 +- shared/util/qlpack.yml | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/cpp/ql/lib/qlpack.yml b/cpp/ql/lib/qlpack.yml index 4eff7132f6c..ee8b5187961 100644 --- a/cpp/ql/lib/qlpack.yml +++ b/cpp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-all -version: 0.5.3 +version: 0.5.4-dev groups: cpp dbscheme: semmlecode.cpp.dbscheme extractor: cpp diff --git a/cpp/ql/src/qlpack.yml b/cpp/ql/src/qlpack.yml index 227e7e4036d..025587014e6 100644 --- a/cpp/ql/src/qlpack.yml +++ b/cpp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cpp-queries -version: 0.5.3 +version: 0.5.4-dev groups: - cpp - queries diff --git a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml index 8dea74ded80..7aa032fa92d 100644 --- a/csharp/ql/campaigns/Solorigate/lib/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-all -version: 1.4.3 +version: 1.4.4-dev groups: - csharp - solorigate diff --git a/csharp/ql/campaigns/Solorigate/src/qlpack.yml b/csharp/ql/campaigns/Solorigate/src/qlpack.yml index 526b9726aac..72f0256ef39 100644 --- a/csharp/ql/campaigns/Solorigate/src/qlpack.yml +++ b/csharp/ql/campaigns/Solorigate/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-solorigate-queries -version: 1.4.3 +version: 1.4.4-dev groups: - csharp - solorigate diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 7b3d1f34c3d..3e0b633019a 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-all -version: 0.5.3 +version: 0.5.4-dev groups: csharp dbscheme: semmlecode.csharp.dbscheme extractor: csharp diff --git a/csharp/ql/src/qlpack.yml b/csharp/ql/src/qlpack.yml index 74689657702..54179503685 100644 --- a/csharp/ql/src/qlpack.yml +++ b/csharp/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/csharp-queries -version: 0.5.3 +version: 0.5.4-dev groups: - csharp - queries diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml index c0f303848da..6d9f6fb8962 100644 --- a/go/ql/lib/qlpack.yml +++ b/go/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-all -version: 0.4.3 +version: 0.4.4-dev groups: go dbscheme: go.dbscheme extractor: go diff --git a/go/ql/src/qlpack.yml b/go/ql/src/qlpack.yml index 64d978e72af..a5a4c5de846 100644 --- a/go/ql/src/qlpack.yml +++ b/go/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/go-queries -version: 0.4.3 +version: 0.4.4-dev groups: - go - queries diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 3688ef4a66c..fb4ea6dca37 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-all -version: 0.5.3 +version: 0.5.4-dev groups: java dbscheme: config/semmlecode.dbscheme extractor: java diff --git a/java/ql/src/qlpack.yml b/java/ql/src/qlpack.yml index ac79303e9f2..7347b058157 100644 --- a/java/ql/src/qlpack.yml +++ b/java/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/java-queries -version: 0.5.3 +version: 0.5.4-dev groups: - java - queries diff --git a/javascript/ql/lib/qlpack.yml b/javascript/ql/lib/qlpack.yml index a497a3694d1..16aa05fb0ff 100644 --- a/javascript/ql/lib/qlpack.yml +++ b/javascript/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-all -version: 0.4.3 +version: 0.4.4-dev groups: javascript dbscheme: semmlecode.javascript.dbscheme extractor: javascript diff --git a/javascript/ql/src/qlpack.yml b/javascript/ql/src/qlpack.yml index d890538b935..0fa78fbcee3 100644 --- a/javascript/ql/src/qlpack.yml +++ b/javascript/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-queries -version: 0.5.3 +version: 0.5.4-dev groups: - javascript - queries diff --git a/misc/suite-helpers/qlpack.yml b/misc/suite-helpers/qlpack.yml index 58add65b183..8f380beb26b 100644 --- a/misc/suite-helpers/qlpack.yml +++ b/misc/suite-helpers/qlpack.yml @@ -1,3 +1,3 @@ name: codeql/suite-helpers -version: 0.4.3 +version: 0.4.4-dev groups: shared diff --git a/python/ql/lib/qlpack.yml b/python/ql/lib/qlpack.yml index ca2bb693a35..03b59d4771c 100644 --- a/python/ql/lib/qlpack.yml +++ b/python/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-all -version: 0.8.0 +version: 0.8.1-dev groups: python dbscheme: semmlecode.python.dbscheme extractor: python diff --git a/python/ql/src/qlpack.yml b/python/ql/src/qlpack.yml index a29da011d40..dc28c02032a 100644 --- a/python/ql/src/qlpack.yml +++ b/python/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/python-queries -version: 0.6.3 +version: 0.6.4-dev groups: - python - queries diff --git a/ruby/ql/lib/qlpack.yml b/ruby/ql/lib/qlpack.yml index 7838a425ce3..44bce4f5a2c 100644 --- a/ruby/ql/lib/qlpack.yml +++ b/ruby/ql/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-all -version: 0.5.3 +version: 0.5.4-dev groups: ruby extractor: ruby dbscheme: ruby.dbscheme diff --git a/ruby/ql/src/qlpack.yml b/ruby/ql/src/qlpack.yml index 0c8fa047bd4..448cb25519a 100644 --- a/ruby/ql/src/qlpack.yml +++ b/ruby/ql/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/ruby-queries -version: 0.5.3 +version: 0.5.4-dev groups: - ruby - queries diff --git a/shared/regex/qlpack.yml b/shared/regex/qlpack.yml index 4cbe36ea935..07b3584d50b 100644 --- a/shared/regex/qlpack.yml +++ b/shared/regex/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/regex -version: 0.0.7 +version: 0.0.8-dev groups: shared library: true dependencies: diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 754dd25d74b..9f2bad1207f 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/ssa -version: 0.0.11 +version: 0.0.12-dev groups: shared library: true diff --git a/shared/tutorial/qlpack.yml b/shared/tutorial/qlpack.yml index ea8c77d9b9d..0108cf86a00 100644 --- a/shared/tutorial/qlpack.yml +++ b/shared/tutorial/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/tutorial description: Library for the CodeQL detective tutorials, helping new users learn to write CodeQL queries. -version: 0.0.4 +version: 0.0.5-dev groups: shared library: true diff --git a/shared/typetracking/qlpack.yml b/shared/typetracking/qlpack.yml index 74c76caf243..aeae3429d62 100644 --- a/shared/typetracking/qlpack.yml +++ b/shared/typetracking/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/typetracking -version: 0.0.4 +version: 0.0.5-dev groups: shared library: true dependencies: diff --git a/shared/typos/qlpack.yml b/shared/typos/qlpack.yml index bfcf30b6b72..4358c859ee6 100644 --- a/shared/typos/qlpack.yml +++ b/shared/typos/qlpack.yml @@ -1,4 +1,4 @@ name: codeql/typos -version: 0.0.11 +version: 0.0.12-dev groups: shared library: true diff --git a/shared/util/qlpack.yml b/shared/util/qlpack.yml index e84f606de69..54aa156c0cd 100644 --- a/shared/util/qlpack.yml +++ b/shared/util/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/util -version: 0.0.4 +version: 0.0.5-dev groups: shared library: true dependencies: From f64cb2983ac6e570fbabb96e7045f6233a3a205b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:41:26 +0000 Subject: [PATCH 290/415] Swift: Add tests for a few models we didn't cover. --- .../dataflow/taint/LocalTaint.expected | 2180 +++++++++-------- .../dataflow/taint/Taint.expected | 1166 ++++----- .../library-tests/dataflow/taint/string.swift | 316 +-- 3 files changed, 1847 insertions(+), 1815 deletions(-) diff --git a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected index 05b72586dac..4738a7d3766 100644 --- a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected @@ -697,296 +697,218 @@ | string.swift:84:38:84:38 | &... | string.swift:84:3:84:50 | self[return] | | string.swift:84:38:84:38 | [post] &... | string.swift:84:3:84:50 | self[return] | | string.swift:84:38:84:38 | self | string.swift:84:38:84:38 | &... | -| string.swift:88:29:88:29 | SSA def(self) | string.swift:88:29:88:38 | self[return] | -| string.swift:88:29:88:29 | self | string.swift:88:29:88:29 | SSA def(self) | -| string.swift:89:38:89:38 | SSA def(self) | string.swift:89:38:89:47 | self[return] | -| string.swift:89:38:89:38 | self | string.swift:89:38:89:38 | SSA def(self) | -| string.swift:90:36:90:36 | SSA def(self) | string.swift:90:36:90:45 | self[return] | -| string.swift:90:36:90:36 | self | string.swift:90:36:90:36 | SSA def(self) | -| string.swift:91:36:91:36 | SSA def(self) | string.swift:91:36:91:45 | self[return] | -| string.swift:91:36:91:36 | self | string.swift:91:36:91:36 | SSA def(self) | -| string.swift:92:42:92:42 | SSA def(self) | string.swift:92:42:92:51 | self[return] | -| string.swift:92:42:92:42 | self | string.swift:92:42:92:42 | SSA def(self) | -| string.swift:93:54:93:54 | SSA def(self) | string.swift:93:54:93:63 | self[return] | -| string.swift:93:54:93:54 | self | string.swift:93:54:93:54 | SSA def(self) | -| string.swift:94:58:94:58 | SSA def(self) | string.swift:94:58:94:67 | self[return] | -| string.swift:94:58:94:58 | self | string.swift:94:58:94:58 | SSA def(self) | -| string.swift:95:55:95:55 | SSA def(self) | string.swift:95:55:95:64 | self[return] | -| string.swift:95:55:95:55 | self | string.swift:95:55:95:55 | SSA def(self) | -| string.swift:96:59:96:59 | SSA def(self) | string.swift:96:59:96:68 | self[return] | -| string.swift:96:59:96:59 | self | string.swift:96:59:96:59 | SSA def(self) | -| string.swift:98:8:98:8 | SSA def(self) | string.swift:98:3:98:63 | self[return] | -| string.swift:98:8:98:8 | self | string.swift:98:8:98:8 | SSA def(self) | -| string.swift:99:8:99:8 | SSA def(self) | string.swift:99:3:99:63 | self[return] | -| string.swift:99:8:99:8 | self | string.swift:99:8:99:8 | SSA def(self) | -| string.swift:100:8:100:8 | SSA def(self) | string.swift:100:3:100:64 | self[return] | -| string.swift:100:8:100:8 | self | string.swift:100:8:100:8 | SSA def(self) | -| string.swift:101:8:101:8 | SSA def(self) | string.swift:101:3:101:64 | self[return] | +| string.swift:86:17:86:17 | SSA def(self) | string.swift:86:12:87:51 | self[return] | +| string.swift:86:17:86:17 | self | string.swift:86:17:86:17 | SSA def(self) | +| string.swift:91:29:91:29 | SSA def(self) | string.swift:91:29:91:38 | self[return] | +| string.swift:91:29:91:29 | self | string.swift:91:29:91:29 | SSA def(self) | +| string.swift:92:38:92:38 | SSA def(self) | string.swift:92:38:92:47 | self[return] | +| string.swift:92:38:92:38 | self | string.swift:92:38:92:38 | SSA def(self) | +| string.swift:93:36:93:36 | SSA def(self) | string.swift:93:36:93:45 | self[return] | +| string.swift:93:36:93:36 | self | string.swift:93:36:93:36 | SSA def(self) | +| string.swift:94:36:94:36 | SSA def(self) | string.swift:94:36:94:45 | self[return] | +| string.swift:94:36:94:36 | self | string.swift:94:36:94:36 | SSA def(self) | +| string.swift:95:42:95:42 | SSA def(self) | string.swift:95:42:95:51 | self[return] | +| string.swift:95:42:95:42 | self | string.swift:95:42:95:42 | SSA def(self) | +| string.swift:96:54:96:54 | SSA def(self) | string.swift:96:54:96:63 | self[return] | +| string.swift:96:54:96:54 | self | string.swift:96:54:96:54 | SSA def(self) | +| string.swift:97:58:97:58 | SSA def(self) | string.swift:97:58:97:67 | self[return] | +| string.swift:97:58:97:58 | self | string.swift:97:58:97:58 | SSA def(self) | +| string.swift:98:55:98:55 | SSA def(self) | string.swift:98:55:98:64 | self[return] | +| string.swift:98:55:98:55 | self | string.swift:98:55:98:55 | SSA def(self) | +| string.swift:99:59:99:59 | SSA def(self) | string.swift:99:59:99:68 | self[return] | +| string.swift:99:59:99:59 | self | string.swift:99:59:99:59 | SSA def(self) | +| string.swift:101:8:101:8 | SSA def(self) | string.swift:101:3:101:63 | self[return] | | string.swift:101:8:101:8 | self | string.swift:101:8:101:8 | SSA def(self) | -| string.swift:102:8:102:8 | SSA def(self) | string.swift:102:3:102:71 | self[return] | +| string.swift:102:8:102:8 | SSA def(self) | string.swift:102:3:102:63 | self[return] | | string.swift:102:8:102:8 | self | string.swift:102:8:102:8 | SSA def(self) | -| string.swift:103:8:103:8 | SSA def(self) | string.swift:103:3:103:82 | self[return] | +| string.swift:103:8:103:8 | SSA def(self) | string.swift:103:3:103:64 | self[return] | | string.swift:103:8:103:8 | self | string.swift:103:8:103:8 | SSA def(self) | -| string.swift:104:8:104:8 | SSA def(self) | string.swift:104:3:104:138 | self[return] | +| string.swift:104:8:104:8 | SSA def(self) | string.swift:104:3:104:64 | self[return] | | string.swift:104:8:104:8 | self | string.swift:104:8:104:8 | SSA def(self) | -| string.swift:105:8:105:8 | SSA def(self) | string.swift:105:3:105:80 | self[return] | +| string.swift:105:8:105:8 | SSA def(self) | string.swift:105:3:105:71 | self[return] | | string.swift:105:8:105:8 | self | string.swift:105:8:105:8 | SSA def(self) | -| string.swift:106:8:106:8 | SSA def(self) | string.swift:106:3:106:92 | self[return] | +| string.swift:106:8:106:8 | SSA def(self) | string.swift:106:3:106:82 | self[return] | | string.swift:106:8:106:8 | self | string.swift:106:8:106:8 | SSA def(self) | -| string.swift:107:8:107:8 | SSA def(self) | string.swift:107:3:107:78 | self[return] | +| string.swift:107:8:107:8 | SSA def(self) | string.swift:107:3:107:138 | self[return] | | string.swift:107:8:107:8 | self | string.swift:107:8:107:8 | SSA def(self) | -| string.swift:108:8:108:8 | SSA def(self) | string.swift:108:3:108:74 | self[return] | +| string.swift:108:8:108:8 | SSA def(self) | string.swift:108:3:108:80 | self[return] | | string.swift:108:8:108:8 | self | string.swift:108:8:108:8 | SSA def(self) | -| string.swift:109:8:109:8 | SSA def(self) | string.swift:109:3:109:79 | self[return] | +| string.swift:109:8:109:8 | SSA def(self) | string.swift:109:3:109:92 | self[return] | | string.swift:109:8:109:8 | self | string.swift:109:8:109:8 | SSA def(self) | -| string.swift:112:7:112:7 | SSA def(self) | string.swift:112:7:112:7 | self[return] | -| string.swift:112:7:112:7 | self | string.swift:112:7:112:7 | SSA def(self) | -| string.swift:114:5:114:5 | SSA def(self) | string.swift:114:5:114:29 | self[return] | -| string.swift:114:5:114:5 | self | string.swift:114:5:114:5 | SSA def(self) | -| string.swift:120:32:120:32 | SSA def(self) | string.swift:120:32:120:47 | self[return] | -| string.swift:120:32:120:32 | self | string.swift:120:32:120:32 | SSA def(self) | -| string.swift:121:30:121:30 | SSA def(self) | string.swift:121:30:121:45 | self[return] | -| string.swift:121:30:121:30 | self | string.swift:121:30:121:30 | SSA def(self) | -| string.swift:122:43:122:43 | SSA def(self) | string.swift:122:43:122:58 | self[return] | -| string.swift:122:43:122:43 | self | string.swift:122:43:122:43 | SSA def(self) | -| string.swift:123:8:123:8 | SSA def(self) | string.swift:123:3:123:60 | self[return] | -| string.swift:123:8:123:8 | self | string.swift:123:8:123:8 | SSA def(self) | -| string.swift:132:7:132:7 | SSA def(x) | string.swift:134:16:134:16 | x | -| string.swift:132:11:132:18 | call to source() | string.swift:132:7:132:7 | SSA def(x) | -| string.swift:134:13:134:13 | | string.swift:134:13:134:13 | [post] | -| string.swift:134:13:134:13 | | string.swift:134:14:134:14 | [post] &... | -| string.swift:134:13:134:13 | SSA def($interpolation) | string.swift:134:14:134:14 | SSA phi($interpolation) | -| string.swift:134:13:134:13 | TapExpr | string.swift:134:13:134:13 | "..." | -| string.swift:134:14:134:14 | $interpolation | string.swift:134:14:134:14 | &... | -| string.swift:134:14:134:14 | &... | string.swift:134:13:134:13 | [post] | -| string.swift:134:14:134:14 | &... | string.swift:134:14:134:14 | [post] &... | -| string.swift:134:14:134:14 | &... | string.swift:134:15:134:15 | $interpolation | -| string.swift:134:14:134:14 | SSA phi($interpolation) | string.swift:134:14:134:14 | $interpolation | -| string.swift:134:14:134:14 | [post] &... | string.swift:134:15:134:15 | $interpolation | -| string.swift:134:15:134:15 | $interpolation | string.swift:134:15:134:15 | &... | -| string.swift:134:15:134:15 | &... | string.swift:134:15:134:15 | [post] &... | -| string.swift:134:15:134:15 | &... | string.swift:134:16:134:16 | [post] x | -| string.swift:134:15:134:15 | &... | string.swift:134:18:134:18 | $interpolation | -| string.swift:134:15:134:15 | [post] &... | string.swift:134:18:134:18 | $interpolation | -| string.swift:134:16:134:16 | [post] x | string.swift:136:16:136:16 | x | -| string.swift:134:16:134:16 | x | string.swift:134:15:134:15 | [post] &... | -| string.swift:134:16:134:16 | x | string.swift:134:16:134:16 | [post] x | -| string.swift:134:16:134:16 | x | string.swift:136:16:136:16 | x | -| string.swift:134:18:134:18 | | string.swift:134:18:134:18 | [post] | -| string.swift:134:18:134:18 | | string.swift:134:18:134:18 | [post] &... | -| string.swift:134:18:134:18 | $interpolation | string.swift:134:18:134:18 | &... | -| string.swift:134:18:134:18 | &... | string.swift:134:13:134:13 | TapExpr | -| string.swift:134:18:134:18 | &... | string.swift:134:18:134:18 | [post] | -| string.swift:134:18:134:18 | &... | string.swift:134:18:134:18 | [post] &... | -| string.swift:134:18:134:18 | [post] &... | string.swift:134:13:134:13 | TapExpr | -| string.swift:136:13:136:13 | | string.swift:136:13:136:13 | [post] | -| string.swift:136:13:136:13 | | string.swift:136:14:136:14 | [post] &... | -| string.swift:136:13:136:13 | SSA def($interpolation) | string.swift:136:14:136:14 | SSA phi($interpolation) | -| string.swift:136:13:136:13 | TapExpr | string.swift:136:13:136:13 | "..." | -| string.swift:136:14:136:14 | $interpolation | string.swift:136:14:136:14 | &... | -| string.swift:136:14:136:14 | &... | string.swift:136:13:136:13 | [post] | -| string.swift:136:14:136:14 | &... | string.swift:136:14:136:14 | [post] &... | -| string.swift:136:14:136:14 | &... | string.swift:136:15:136:15 | $interpolation | -| string.swift:136:14:136:14 | SSA phi($interpolation) | string.swift:136:14:136:14 | $interpolation | -| string.swift:136:14:136:14 | [post] &... | string.swift:136:15:136:15 | $interpolation | -| string.swift:136:15:136:15 | $interpolation | string.swift:136:15:136:15 | &... | -| string.swift:136:15:136:15 | &... | string.swift:136:15:136:15 | [post] &... | -| string.swift:136:15:136:15 | &... | string.swift:136:16:136:16 | [post] x | -| string.swift:136:15:136:15 | &... | string.swift:136:18:136:18 | $interpolation | -| string.swift:136:15:136:15 | [post] &... | string.swift:136:18:136:18 | $interpolation | -| string.swift:136:16:136:16 | [post] x | string.swift:136:21:136:21 | x | -| string.swift:136:16:136:16 | x | string.swift:136:15:136:15 | [post] &... | -| string.swift:136:16:136:16 | x | string.swift:136:16:136:16 | [post] x | -| string.swift:136:16:136:16 | x | string.swift:136:21:136:21 | x | -| string.swift:136:18:136:18 | | string.swift:136:18:136:18 | [post] | -| string.swift:136:18:136:18 | | string.swift:136:18:136:18 | [post] &... | -| string.swift:136:18:136:18 | $interpolation | string.swift:136:18:136:18 | &... | -| string.swift:136:18:136:18 | &... | string.swift:136:18:136:18 | [post] | -| string.swift:136:18:136:18 | &... | string.swift:136:18:136:18 | [post] &... | -| string.swift:136:18:136:18 | &... | string.swift:136:20:136:20 | $interpolation | -| string.swift:136:18:136:18 | [post] &... | string.swift:136:20:136:20 | $interpolation | -| string.swift:136:20:136:20 | $interpolation | string.swift:136:20:136:20 | &... | -| string.swift:136:20:136:20 | &... | string.swift:136:20:136:20 | [post] &... | -| string.swift:136:20:136:20 | &... | string.swift:136:21:136:21 | [post] x | -| string.swift:136:20:136:20 | &... | string.swift:136:23:136:23 | $interpolation | -| string.swift:136:20:136:20 | [post] &... | string.swift:136:23:136:23 | $interpolation | -| string.swift:136:21:136:21 | [post] x | string.swift:138:16:138:16 | x | -| string.swift:136:21:136:21 | x | string.swift:136:20:136:20 | [post] &... | -| string.swift:136:21:136:21 | x | string.swift:136:21:136:21 | [post] x | -| string.swift:136:21:136:21 | x | string.swift:138:16:138:16 | x | -| string.swift:136:23:136:23 | | string.swift:136:23:136:23 | [post] | -| string.swift:136:23:136:23 | | string.swift:136:23:136:23 | [post] &... | -| string.swift:136:23:136:23 | $interpolation | string.swift:136:23:136:23 | &... | -| string.swift:136:23:136:23 | &... | string.swift:136:13:136:13 | TapExpr | -| string.swift:136:23:136:23 | &... | string.swift:136:23:136:23 | [post] | -| string.swift:136:23:136:23 | &... | string.swift:136:23:136:23 | [post] &... | -| string.swift:136:23:136:23 | [post] &... | string.swift:136:13:136:13 | TapExpr | -| string.swift:138:13:138:13 | | string.swift:138:13:138:13 | [post] | -| string.swift:138:13:138:13 | | string.swift:138:14:138:14 | [post] &... | -| string.swift:138:13:138:13 | SSA def($interpolation) | string.swift:138:14:138:14 | SSA phi($interpolation) | -| string.swift:138:13:138:13 | TapExpr | string.swift:138:13:138:13 | "..." | -| string.swift:138:14:138:14 | $interpolation | string.swift:138:14:138:14 | &... | -| string.swift:138:14:138:14 | &... | string.swift:138:13:138:13 | [post] | -| string.swift:138:14:138:14 | &... | string.swift:138:14:138:14 | [post] &... | -| string.swift:138:14:138:14 | &... | string.swift:138:15:138:15 | $interpolation | -| string.swift:138:14:138:14 | SSA phi($interpolation) | string.swift:138:14:138:14 | $interpolation | -| string.swift:138:14:138:14 | [post] &... | string.swift:138:15:138:15 | $interpolation | -| string.swift:138:15:138:15 | $interpolation | string.swift:138:15:138:15 | &... | -| string.swift:138:15:138:15 | &... | string.swift:138:15:138:15 | [post] &... | -| string.swift:138:15:138:15 | &... | string.swift:138:16:138:16 | [post] x | -| string.swift:138:15:138:15 | &... | string.swift:138:18:138:18 | $interpolation | -| string.swift:138:15:138:15 | [post] &... | string.swift:138:18:138:18 | $interpolation | -| string.swift:138:16:138:16 | [post] x | string.swift:138:26:138:26 | x | -| string.swift:138:16:138:16 | x | string.swift:138:15:138:15 | [post] &... | -| string.swift:138:16:138:16 | x | string.swift:138:16:138:16 | [post] x | -| string.swift:138:16:138:16 | x | string.swift:138:26:138:26 | x | -| string.swift:138:18:138:18 | | string.swift:138:18:138:18 | [post] | -| string.swift:138:18:138:18 | | string.swift:138:18:138:18 | [post] &... | -| string.swift:138:18:138:18 | $interpolation | string.swift:138:18:138:18 | &... | -| string.swift:138:18:138:18 | &... | string.swift:138:18:138:18 | [post] | -| string.swift:138:18:138:18 | &... | string.swift:138:18:138:18 | [post] &... | -| string.swift:138:18:138:18 | &... | string.swift:138:20:138:20 | $interpolation | -| string.swift:138:18:138:18 | [post] &... | string.swift:138:20:138:20 | $interpolation | -| string.swift:138:20:138:20 | $interpolation | string.swift:138:20:138:20 | &... | -| string.swift:138:20:138:20 | &... | string.swift:138:20:138:20 | [post] &... | -| string.swift:138:20:138:20 | &... | string.swift:138:21:138:21 | [post] 0 | -| string.swift:138:20:138:20 | &... | string.swift:138:23:138:23 | $interpolation | -| string.swift:138:20:138:20 | [post] &... | string.swift:138:23:138:23 | $interpolation | -| string.swift:138:21:138:21 | 0 | string.swift:138:20:138:20 | [post] &... | -| string.swift:138:21:138:21 | 0 | string.swift:138:21:138:21 | [post] 0 | -| string.swift:138:23:138:23 | | string.swift:138:23:138:23 | [post] | -| string.swift:138:23:138:23 | | string.swift:138:23:138:23 | [post] &... | -| string.swift:138:23:138:23 | $interpolation | string.swift:138:23:138:23 | &... | -| string.swift:138:23:138:23 | &... | string.swift:138:23:138:23 | [post] | -| string.swift:138:23:138:23 | &... | string.swift:138:23:138:23 | [post] &... | -| string.swift:138:23:138:23 | &... | string.swift:138:25:138:25 | $interpolation | -| string.swift:138:23:138:23 | [post] &... | string.swift:138:25:138:25 | $interpolation | -| string.swift:138:25:138:25 | $interpolation | string.swift:138:25:138:25 | &... | -| string.swift:138:25:138:25 | &... | string.swift:138:25:138:25 | [post] &... | -| string.swift:138:25:138:25 | &... | string.swift:138:26:138:26 | [post] x | -| string.swift:138:25:138:25 | &... | string.swift:138:28:138:28 | $interpolation | -| string.swift:138:25:138:25 | [post] &... | string.swift:138:28:138:28 | $interpolation | -| string.swift:138:26:138:26 | [post] x | string.swift:144:16:144:16 | x | -| string.swift:138:26:138:26 | x | string.swift:138:25:138:25 | [post] &... | -| string.swift:138:26:138:26 | x | string.swift:138:26:138:26 | [post] x | -| string.swift:138:26:138:26 | x | string.swift:144:16:144:16 | x | -| string.swift:138:28:138:28 | | string.swift:138:28:138:28 | [post] | -| string.swift:138:28:138:28 | | string.swift:138:28:138:28 | [post] &... | -| string.swift:138:28:138:28 | $interpolation | string.swift:138:28:138:28 | &... | -| string.swift:138:28:138:28 | &... | string.swift:138:13:138:13 | TapExpr | -| string.swift:138:28:138:28 | &... | string.swift:138:28:138:28 | [post] | -| string.swift:138:28:138:28 | &... | string.swift:138:28:138:28 | [post] &... | -| string.swift:138:28:138:28 | [post] &... | string.swift:138:13:138:13 | TapExpr | -| string.swift:140:7:140:7 | SSA def(y) | string.swift:142:16:142:16 | y | -| string.swift:140:11:140:11 | 42 | string.swift:140:7:140:7 | SSA def(y) | -| string.swift:142:13:142:13 | | string.swift:142:13:142:13 | [post] | -| string.swift:142:13:142:13 | | string.swift:142:14:142:14 | [post] &... | -| string.swift:142:13:142:13 | SSA def($interpolation) | string.swift:142:14:142:14 | SSA phi($interpolation) | -| string.swift:142:13:142:13 | TapExpr | string.swift:142:13:142:13 | "..." | -| string.swift:142:14:142:14 | $interpolation | string.swift:142:14:142:14 | &... | -| string.swift:142:14:142:14 | &... | string.swift:142:13:142:13 | [post] | -| string.swift:142:14:142:14 | &... | string.swift:142:14:142:14 | [post] &... | -| string.swift:142:14:142:14 | &... | string.swift:142:15:142:15 | $interpolation | -| string.swift:142:14:142:14 | SSA phi($interpolation) | string.swift:142:14:142:14 | $interpolation | -| string.swift:142:14:142:14 | [post] &... | string.swift:142:15:142:15 | $interpolation | -| string.swift:142:15:142:15 | $interpolation | string.swift:142:15:142:15 | &... | -| string.swift:142:15:142:15 | &... | string.swift:142:15:142:15 | [post] &... | -| string.swift:142:15:142:15 | &... | string.swift:142:16:142:16 | [post] y | -| string.swift:142:15:142:15 | &... | string.swift:142:18:142:18 | $interpolation | -| string.swift:142:15:142:15 | [post] &... | string.swift:142:18:142:18 | $interpolation | -| string.swift:142:16:142:16 | [post] y | string.swift:144:27:144:27 | y | -| string.swift:142:16:142:16 | y | string.swift:142:15:142:15 | [post] &... | -| string.swift:142:16:142:16 | y | string.swift:142:16:142:16 | [post] y | -| string.swift:142:16:142:16 | y | string.swift:144:27:144:27 | y | -| string.swift:142:18:142:18 | | string.swift:142:18:142:18 | [post] | -| string.swift:142:18:142:18 | | string.swift:142:18:142:18 | [post] &... | -| string.swift:142:18:142:18 | $interpolation | string.swift:142:18:142:18 | &... | -| string.swift:142:18:142:18 | &... | string.swift:142:13:142:13 | TapExpr | -| string.swift:142:18:142:18 | &... | string.swift:142:18:142:18 | [post] | -| string.swift:142:18:142:18 | &... | string.swift:142:18:142:18 | [post] &... | -| string.swift:142:18:142:18 | [post] &... | string.swift:142:13:142:13 | TapExpr | -| string.swift:144:13:144:13 | | string.swift:144:13:144:13 | [post] | -| string.swift:144:13:144:13 | | string.swift:144:14:144:14 | [post] &... | -| string.swift:144:13:144:13 | SSA def($interpolation) | string.swift:144:14:144:14 | SSA phi($interpolation) | -| string.swift:144:13:144:13 | TapExpr | string.swift:144:13:144:13 | "..." | -| string.swift:144:14:144:14 | $interpolation | string.swift:144:14:144:14 | &... | -| string.swift:144:14:144:14 | &... | string.swift:144:13:144:13 | [post] | -| string.swift:144:14:144:14 | &... | string.swift:144:14:144:14 | [post] &... | -| string.swift:144:14:144:14 | &... | string.swift:144:15:144:15 | $interpolation | -| string.swift:144:14:144:14 | SSA phi($interpolation) | string.swift:144:14:144:14 | $interpolation | -| string.swift:144:14:144:14 | [post] &... | string.swift:144:15:144:15 | $interpolation | -| string.swift:144:15:144:15 | $interpolation | string.swift:144:15:144:15 | &... | -| string.swift:144:15:144:15 | &... | string.swift:144:15:144:15 | [post] &... | -| string.swift:144:15:144:15 | &... | string.swift:144:16:144:16 | [post] x | -| string.swift:144:15:144:15 | &... | string.swift:144:18:144:18 | $interpolation | -| string.swift:144:15:144:15 | [post] &... | string.swift:144:18:144:18 | $interpolation | -| string.swift:144:16:144:16 | [post] x | string.swift:146:27:146:27 | x | -| string.swift:144:16:144:16 | x | string.swift:144:15:144:15 | [post] &... | -| string.swift:144:16:144:16 | x | string.swift:144:16:144:16 | [post] x | -| string.swift:144:16:144:16 | x | string.swift:146:27:146:27 | x | -| string.swift:144:18:144:18 | hello | string.swift:144:18:144:18 | [post] hello | -| string.swift:144:18:144:18 | hello | string.swift:144:18:144:18 | [post] &... | -| string.swift:144:18:144:18 | $interpolation | string.swift:144:18:144:18 | &... | -| string.swift:144:18:144:18 | &... | string.swift:144:18:144:18 | [post] hello | -| string.swift:144:18:144:18 | &... | string.swift:144:18:144:18 | [post] &... | -| string.swift:144:18:144:18 | &... | string.swift:144:26:144:26 | $interpolation | -| string.swift:144:18:144:18 | [post] &... | string.swift:144:26:144:26 | $interpolation | -| string.swift:144:26:144:26 | $interpolation | string.swift:144:26:144:26 | &... | -| string.swift:144:26:144:26 | &... | string.swift:144:26:144:26 | [post] &... | -| string.swift:144:26:144:26 | &... | string.swift:144:27:144:27 | [post] y | -| string.swift:144:26:144:26 | &... | string.swift:144:29:144:29 | $interpolation | -| string.swift:144:26:144:26 | [post] &... | string.swift:144:29:144:29 | $interpolation | -| string.swift:144:27:144:27 | [post] y | string.swift:146:16:146:16 | y | -| string.swift:144:27:144:27 | y | string.swift:144:26:144:26 | [post] &... | -| string.swift:144:27:144:27 | y | string.swift:144:27:144:27 | [post] y | -| string.swift:144:27:144:27 | y | string.swift:146:16:146:16 | y | -| string.swift:144:29:144:29 | | string.swift:144:29:144:29 | [post] | -| string.swift:144:29:144:29 | | string.swift:144:29:144:29 | [post] &... | -| string.swift:144:29:144:29 | $interpolation | string.swift:144:29:144:29 | &... | -| string.swift:144:29:144:29 | &... | string.swift:144:13:144:13 | TapExpr | -| string.swift:144:29:144:29 | &... | string.swift:144:29:144:29 | [post] | -| string.swift:144:29:144:29 | &... | string.swift:144:29:144:29 | [post] &... | -| string.swift:144:29:144:29 | [post] &... | string.swift:144:13:144:13 | TapExpr | -| string.swift:146:13:146:13 | | string.swift:146:13:146:13 | [post] | -| string.swift:146:13:146:13 | | string.swift:146:14:146:14 | [post] &... | -| string.swift:146:13:146:13 | SSA def($interpolation) | string.swift:146:14:146:14 | SSA phi($interpolation) | -| string.swift:146:13:146:13 | TapExpr | string.swift:146:13:146:13 | "..." | -| string.swift:146:14:146:14 | $interpolation | string.swift:146:14:146:14 | &... | -| string.swift:146:14:146:14 | &... | string.swift:146:13:146:13 | [post] | -| string.swift:146:14:146:14 | &... | string.swift:146:14:146:14 | [post] &... | -| string.swift:146:14:146:14 | &... | string.swift:146:15:146:15 | $interpolation | -| string.swift:146:14:146:14 | SSA phi($interpolation) | string.swift:146:14:146:14 | $interpolation | -| string.swift:146:14:146:14 | [post] &... | string.swift:146:15:146:15 | $interpolation | -| string.swift:146:15:146:15 | $interpolation | string.swift:146:15:146:15 | &... | -| string.swift:146:15:146:15 | &... | string.swift:146:15:146:15 | [post] &... | -| string.swift:146:15:146:15 | &... | string.swift:146:16:146:16 | [post] y | -| string.swift:146:15:146:15 | &... | string.swift:146:18:146:18 | $interpolation | -| string.swift:146:15:146:15 | [post] &... | string.swift:146:18:146:18 | $interpolation | -| string.swift:146:16:146:16 | y | string.swift:146:15:146:15 | [post] &... | -| string.swift:146:16:146:16 | y | string.swift:146:16:146:16 | [post] y | -| string.swift:146:18:146:18 | world | string.swift:146:18:146:18 | [post] world | -| string.swift:146:18:146:18 | world | string.swift:146:18:146:18 | [post] &... | -| string.swift:146:18:146:18 | $interpolation | string.swift:146:18:146:18 | &... | -| string.swift:146:18:146:18 | &... | string.swift:146:18:146:18 | [post] world | -| string.swift:146:18:146:18 | &... | string.swift:146:18:146:18 | [post] &... | -| string.swift:146:18:146:18 | &... | string.swift:146:26:146:26 | $interpolation | -| string.swift:146:18:146:18 | [post] &... | string.swift:146:26:146:26 | $interpolation | -| string.swift:146:26:146:26 | $interpolation | string.swift:146:26:146:26 | &... | -| string.swift:146:26:146:26 | &... | string.swift:146:26:146:26 | [post] &... | -| string.swift:146:26:146:26 | &... | string.swift:146:27:146:27 | [post] x | -| string.swift:146:26:146:26 | &... | string.swift:146:29:146:29 | $interpolation | -| string.swift:146:26:146:26 | [post] &... | string.swift:146:29:146:29 | $interpolation | -| string.swift:146:27:146:27 | x | string.swift:146:26:146:26 | [post] &... | -| string.swift:146:27:146:27 | x | string.swift:146:27:146:27 | [post] x | -| string.swift:146:29:146:29 | | string.swift:146:29:146:29 | [post] | -| string.swift:146:29:146:29 | | string.swift:146:29:146:29 | [post] &... | -| string.swift:146:29:146:29 | $interpolation | string.swift:146:29:146:29 | &... | -| string.swift:146:29:146:29 | &... | string.swift:146:13:146:13 | TapExpr | -| string.swift:146:29:146:29 | &... | string.swift:146:29:146:29 | [post] | -| string.swift:146:29:146:29 | &... | string.swift:146:29:146:29 | [post] &... | -| string.swift:146:29:146:29 | [post] &... | string.swift:146:13:146:13 | TapExpr | -| string.swift:148:3:148:7 | SSA def(x) | string.swift:149:16:149:16 | x | -| string.swift:148:7:148:7 | 0 | string.swift:148:3:148:7 | SSA def(x) | +| string.swift:110:8:110:8 | SSA def(self) | string.swift:110:3:110:78 | self[return] | +| string.swift:110:8:110:8 | self | string.swift:110:8:110:8 | SSA def(self) | +| string.swift:111:8:111:8 | SSA def(self) | string.swift:111:3:111:74 | self[return] | +| string.swift:111:8:111:8 | self | string.swift:111:8:111:8 | SSA def(self) | +| string.swift:112:8:112:8 | SSA def(self) | string.swift:112:3:112:79 | self[return] | +| string.swift:112:8:112:8 | self | string.swift:112:8:112:8 | SSA def(self) | +| string.swift:113:8:113:8 | SSA def(self) | string.swift:113:3:114:77 | self[return] | +| string.swift:113:8:113:8 | self | string.swift:113:8:113:8 | SSA def(self) | +| string.swift:117:7:117:7 | SSA def(self) | string.swift:117:7:117:7 | self[return] | +| string.swift:117:7:117:7 | self | string.swift:117:7:117:7 | SSA def(self) | +| string.swift:119:5:119:5 | SSA def(self) | string.swift:119:5:119:29 | self[return] | +| string.swift:119:5:119:5 | self | string.swift:119:5:119:5 | SSA def(self) | +| string.swift:125:32:125:32 | SSA def(self) | string.swift:125:32:125:47 | self[return] | +| string.swift:125:32:125:32 | self | string.swift:125:32:125:32 | SSA def(self) | +| string.swift:126:30:126:30 | SSA def(self) | string.swift:126:30:126:45 | self[return] | +| string.swift:126:30:126:30 | self | string.swift:126:30:126:30 | SSA def(self) | +| string.swift:127:43:127:43 | SSA def(self) | string.swift:127:43:127:58 | self[return] | +| string.swift:127:43:127:43 | self | string.swift:127:43:127:43 | SSA def(self) | +| string.swift:128:8:128:8 | SSA def(self) | string.swift:128:3:128:60 | self[return] | +| string.swift:128:8:128:8 | self | string.swift:128:8:128:8 | SSA def(self) | +| string.swift:137:7:137:7 | SSA def(x) | string.swift:139:16:139:16 | x | +| string.swift:137:11:137:18 | call to source() | string.swift:137:7:137:7 | SSA def(x) | +| string.swift:139:13:139:13 | | string.swift:139:13:139:13 | [post] | +| string.swift:139:13:139:13 | | string.swift:139:14:139:14 | [post] &... | +| string.swift:139:13:139:13 | SSA def($interpolation) | string.swift:139:14:139:14 | SSA phi($interpolation) | +| string.swift:139:13:139:13 | TapExpr | string.swift:139:13:139:13 | "..." | +| string.swift:139:14:139:14 | $interpolation | string.swift:139:14:139:14 | &... | +| string.swift:139:14:139:14 | &... | string.swift:139:13:139:13 | [post] | +| string.swift:139:14:139:14 | &... | string.swift:139:14:139:14 | [post] &... | +| string.swift:139:14:139:14 | &... | string.swift:139:15:139:15 | $interpolation | +| string.swift:139:14:139:14 | SSA phi($interpolation) | string.swift:139:14:139:14 | $interpolation | +| string.swift:139:14:139:14 | [post] &... | string.swift:139:15:139:15 | $interpolation | +| string.swift:139:15:139:15 | $interpolation | string.swift:139:15:139:15 | &... | +| string.swift:139:15:139:15 | &... | string.swift:139:15:139:15 | [post] &... | +| string.swift:139:15:139:15 | &... | string.swift:139:16:139:16 | [post] x | +| string.swift:139:15:139:15 | &... | string.swift:139:18:139:18 | $interpolation | +| string.swift:139:15:139:15 | [post] &... | string.swift:139:18:139:18 | $interpolation | +| string.swift:139:16:139:16 | [post] x | string.swift:141:16:141:16 | x | +| string.swift:139:16:139:16 | x | string.swift:139:15:139:15 | [post] &... | +| string.swift:139:16:139:16 | x | string.swift:139:16:139:16 | [post] x | +| string.swift:139:16:139:16 | x | string.swift:141:16:141:16 | x | +| string.swift:139:18:139:18 | | string.swift:139:18:139:18 | [post] | +| string.swift:139:18:139:18 | | string.swift:139:18:139:18 | [post] &... | +| string.swift:139:18:139:18 | $interpolation | string.swift:139:18:139:18 | &... | +| string.swift:139:18:139:18 | &... | string.swift:139:13:139:13 | TapExpr | +| string.swift:139:18:139:18 | &... | string.swift:139:18:139:18 | [post] | +| string.swift:139:18:139:18 | &... | string.swift:139:18:139:18 | [post] &... | +| string.swift:139:18:139:18 | [post] &... | string.swift:139:13:139:13 | TapExpr | +| string.swift:141:13:141:13 | | string.swift:141:13:141:13 | [post] | +| string.swift:141:13:141:13 | | string.swift:141:14:141:14 | [post] &... | +| string.swift:141:13:141:13 | SSA def($interpolation) | string.swift:141:14:141:14 | SSA phi($interpolation) | +| string.swift:141:13:141:13 | TapExpr | string.swift:141:13:141:13 | "..." | +| string.swift:141:14:141:14 | $interpolation | string.swift:141:14:141:14 | &... | +| string.swift:141:14:141:14 | &... | string.swift:141:13:141:13 | [post] | +| string.swift:141:14:141:14 | &... | string.swift:141:14:141:14 | [post] &... | +| string.swift:141:14:141:14 | &... | string.swift:141:15:141:15 | $interpolation | +| string.swift:141:14:141:14 | SSA phi($interpolation) | string.swift:141:14:141:14 | $interpolation | +| string.swift:141:14:141:14 | [post] &... | string.swift:141:15:141:15 | $interpolation | +| string.swift:141:15:141:15 | $interpolation | string.swift:141:15:141:15 | &... | +| string.swift:141:15:141:15 | &... | string.swift:141:15:141:15 | [post] &... | +| string.swift:141:15:141:15 | &... | string.swift:141:16:141:16 | [post] x | +| string.swift:141:15:141:15 | &... | string.swift:141:18:141:18 | $interpolation | +| string.swift:141:15:141:15 | [post] &... | string.swift:141:18:141:18 | $interpolation | +| string.swift:141:16:141:16 | [post] x | string.swift:141:21:141:21 | x | +| string.swift:141:16:141:16 | x | string.swift:141:15:141:15 | [post] &... | +| string.swift:141:16:141:16 | x | string.swift:141:16:141:16 | [post] x | +| string.swift:141:16:141:16 | x | string.swift:141:21:141:21 | x | +| string.swift:141:18:141:18 | | string.swift:141:18:141:18 | [post] | +| string.swift:141:18:141:18 | | string.swift:141:18:141:18 | [post] &... | +| string.swift:141:18:141:18 | $interpolation | string.swift:141:18:141:18 | &... | +| string.swift:141:18:141:18 | &... | string.swift:141:18:141:18 | [post] | +| string.swift:141:18:141:18 | &... | string.swift:141:18:141:18 | [post] &... | +| string.swift:141:18:141:18 | &... | string.swift:141:20:141:20 | $interpolation | +| string.swift:141:18:141:18 | [post] &... | string.swift:141:20:141:20 | $interpolation | +| string.swift:141:20:141:20 | $interpolation | string.swift:141:20:141:20 | &... | +| string.swift:141:20:141:20 | &... | string.swift:141:20:141:20 | [post] &... | +| string.swift:141:20:141:20 | &... | string.swift:141:21:141:21 | [post] x | +| string.swift:141:20:141:20 | &... | string.swift:141:23:141:23 | $interpolation | +| string.swift:141:20:141:20 | [post] &... | string.swift:141:23:141:23 | $interpolation | +| string.swift:141:21:141:21 | [post] x | string.swift:143:16:143:16 | x | +| string.swift:141:21:141:21 | x | string.swift:141:20:141:20 | [post] &... | +| string.swift:141:21:141:21 | x | string.swift:141:21:141:21 | [post] x | +| string.swift:141:21:141:21 | x | string.swift:143:16:143:16 | x | +| string.swift:141:23:141:23 | | string.swift:141:23:141:23 | [post] | +| string.swift:141:23:141:23 | | string.swift:141:23:141:23 | [post] &... | +| string.swift:141:23:141:23 | $interpolation | string.swift:141:23:141:23 | &... | +| string.swift:141:23:141:23 | &... | string.swift:141:13:141:13 | TapExpr | +| string.swift:141:23:141:23 | &... | string.swift:141:23:141:23 | [post] | +| string.swift:141:23:141:23 | &... | string.swift:141:23:141:23 | [post] &... | +| string.swift:141:23:141:23 | [post] &... | string.swift:141:13:141:13 | TapExpr | +| string.swift:143:13:143:13 | | string.swift:143:13:143:13 | [post] | +| string.swift:143:13:143:13 | | string.swift:143:14:143:14 | [post] &... | +| string.swift:143:13:143:13 | SSA def($interpolation) | string.swift:143:14:143:14 | SSA phi($interpolation) | +| string.swift:143:13:143:13 | TapExpr | string.swift:143:13:143:13 | "..." | +| string.swift:143:14:143:14 | $interpolation | string.swift:143:14:143:14 | &... | +| string.swift:143:14:143:14 | &... | string.swift:143:13:143:13 | [post] | +| string.swift:143:14:143:14 | &... | string.swift:143:14:143:14 | [post] &... | +| string.swift:143:14:143:14 | &... | string.swift:143:15:143:15 | $interpolation | +| string.swift:143:14:143:14 | SSA phi($interpolation) | string.swift:143:14:143:14 | $interpolation | +| string.swift:143:14:143:14 | [post] &... | string.swift:143:15:143:15 | $interpolation | +| string.swift:143:15:143:15 | $interpolation | string.swift:143:15:143:15 | &... | +| string.swift:143:15:143:15 | &... | string.swift:143:15:143:15 | [post] &... | +| string.swift:143:15:143:15 | &... | string.swift:143:16:143:16 | [post] x | +| string.swift:143:15:143:15 | &... | string.swift:143:18:143:18 | $interpolation | +| string.swift:143:15:143:15 | [post] &... | string.swift:143:18:143:18 | $interpolation | +| string.swift:143:16:143:16 | [post] x | string.swift:143:26:143:26 | x | +| string.swift:143:16:143:16 | x | string.swift:143:15:143:15 | [post] &... | +| string.swift:143:16:143:16 | x | string.swift:143:16:143:16 | [post] x | +| string.swift:143:16:143:16 | x | string.swift:143:26:143:26 | x | +| string.swift:143:18:143:18 | | string.swift:143:18:143:18 | [post] | +| string.swift:143:18:143:18 | | string.swift:143:18:143:18 | [post] &... | +| string.swift:143:18:143:18 | $interpolation | string.swift:143:18:143:18 | &... | +| string.swift:143:18:143:18 | &... | string.swift:143:18:143:18 | [post] | +| string.swift:143:18:143:18 | &... | string.swift:143:18:143:18 | [post] &... | +| string.swift:143:18:143:18 | &... | string.swift:143:20:143:20 | $interpolation | +| string.swift:143:18:143:18 | [post] &... | string.swift:143:20:143:20 | $interpolation | +| string.swift:143:20:143:20 | $interpolation | string.swift:143:20:143:20 | &... | +| string.swift:143:20:143:20 | &... | string.swift:143:20:143:20 | [post] &... | +| string.swift:143:20:143:20 | &... | string.swift:143:21:143:21 | [post] 0 | +| string.swift:143:20:143:20 | &... | string.swift:143:23:143:23 | $interpolation | +| string.swift:143:20:143:20 | [post] &... | string.swift:143:23:143:23 | $interpolation | +| string.swift:143:21:143:21 | 0 | string.swift:143:20:143:20 | [post] &... | +| string.swift:143:21:143:21 | 0 | string.swift:143:21:143:21 | [post] 0 | +| string.swift:143:23:143:23 | | string.swift:143:23:143:23 | [post] | +| string.swift:143:23:143:23 | | string.swift:143:23:143:23 | [post] &... | +| string.swift:143:23:143:23 | $interpolation | string.swift:143:23:143:23 | &... | +| string.swift:143:23:143:23 | &... | string.swift:143:23:143:23 | [post] | +| string.swift:143:23:143:23 | &... | string.swift:143:23:143:23 | [post] &... | +| string.swift:143:23:143:23 | &... | string.swift:143:25:143:25 | $interpolation | +| string.swift:143:23:143:23 | [post] &... | string.swift:143:25:143:25 | $interpolation | +| string.swift:143:25:143:25 | $interpolation | string.swift:143:25:143:25 | &... | +| string.swift:143:25:143:25 | &... | string.swift:143:25:143:25 | [post] &... | +| string.swift:143:25:143:25 | &... | string.swift:143:26:143:26 | [post] x | +| string.swift:143:25:143:25 | &... | string.swift:143:28:143:28 | $interpolation | +| string.swift:143:25:143:25 | [post] &... | string.swift:143:28:143:28 | $interpolation | +| string.swift:143:26:143:26 | [post] x | string.swift:149:16:149:16 | x | +| string.swift:143:26:143:26 | x | string.swift:143:25:143:25 | [post] &... | +| string.swift:143:26:143:26 | x | string.swift:143:26:143:26 | [post] x | +| string.swift:143:26:143:26 | x | string.swift:149:16:149:16 | x | +| string.swift:143:28:143:28 | | string.swift:143:28:143:28 | [post] | +| string.swift:143:28:143:28 | | string.swift:143:28:143:28 | [post] &... | +| string.swift:143:28:143:28 | $interpolation | string.swift:143:28:143:28 | &... | +| string.swift:143:28:143:28 | &... | string.swift:143:13:143:13 | TapExpr | +| string.swift:143:28:143:28 | &... | string.swift:143:28:143:28 | [post] | +| string.swift:143:28:143:28 | &... | string.swift:143:28:143:28 | [post] &... | +| string.swift:143:28:143:28 | [post] &... | string.swift:143:13:143:13 | TapExpr | +| string.swift:145:7:145:7 | SSA def(y) | string.swift:147:16:147:16 | y | +| string.swift:145:11:145:11 | 42 | string.swift:145:7:145:7 | SSA def(y) | +| string.swift:147:13:147:13 | | string.swift:147:13:147:13 | [post] | +| string.swift:147:13:147:13 | | string.swift:147:14:147:14 | [post] &... | +| string.swift:147:13:147:13 | SSA def($interpolation) | string.swift:147:14:147:14 | SSA phi($interpolation) | +| string.swift:147:13:147:13 | TapExpr | string.swift:147:13:147:13 | "..." | +| string.swift:147:14:147:14 | $interpolation | string.swift:147:14:147:14 | &... | +| string.swift:147:14:147:14 | &... | string.swift:147:13:147:13 | [post] | +| string.swift:147:14:147:14 | &... | string.swift:147:14:147:14 | [post] &... | +| string.swift:147:14:147:14 | &... | string.swift:147:15:147:15 | $interpolation | +| string.swift:147:14:147:14 | SSA phi($interpolation) | string.swift:147:14:147:14 | $interpolation | +| string.swift:147:14:147:14 | [post] &... | string.swift:147:15:147:15 | $interpolation | +| string.swift:147:15:147:15 | $interpolation | string.swift:147:15:147:15 | &... | +| string.swift:147:15:147:15 | &... | string.swift:147:15:147:15 | [post] &... | +| string.swift:147:15:147:15 | &... | string.swift:147:16:147:16 | [post] y | +| string.swift:147:15:147:15 | &... | string.swift:147:18:147:18 | $interpolation | +| string.swift:147:15:147:15 | [post] &... | string.swift:147:18:147:18 | $interpolation | +| string.swift:147:16:147:16 | [post] y | string.swift:149:27:149:27 | y | +| string.swift:147:16:147:16 | y | string.swift:147:15:147:15 | [post] &... | +| string.swift:147:16:147:16 | y | string.swift:147:16:147:16 | [post] y | +| string.swift:147:16:147:16 | y | string.swift:149:27:149:27 | y | +| string.swift:147:18:147:18 | | string.swift:147:18:147:18 | [post] | +| string.swift:147:18:147:18 | | string.swift:147:18:147:18 | [post] &... | +| string.swift:147:18:147:18 | $interpolation | string.swift:147:18:147:18 | &... | +| string.swift:147:18:147:18 | &... | string.swift:147:13:147:13 | TapExpr | +| string.swift:147:18:147:18 | &... | string.swift:147:18:147:18 | [post] | +| string.swift:147:18:147:18 | &... | string.swift:147:18:147:18 | [post] &... | +| string.swift:147:18:147:18 | [post] &... | string.swift:147:13:147:13 | TapExpr | | string.swift:149:13:149:13 | | string.swift:149:13:149:13 | [post] | | string.swift:149:13:149:13 | | string.swift:149:14:149:14 | [post] &... | | string.swift:149:13:149:13 | SSA def($interpolation) | string.swift:149:14:149:14 | SSA phi($interpolation) | @@ -1002,824 +924,920 @@ | string.swift:149:15:149:15 | &... | string.swift:149:16:149:16 | [post] x | | string.swift:149:15:149:15 | &... | string.swift:149:18:149:18 | $interpolation | | string.swift:149:15:149:15 | [post] &... | string.swift:149:18:149:18 | $interpolation | +| string.swift:149:16:149:16 | [post] x | string.swift:151:27:151:27 | x | | string.swift:149:16:149:16 | x | string.swift:149:15:149:15 | [post] &... | | string.swift:149:16:149:16 | x | string.swift:149:16:149:16 | [post] x | -| string.swift:149:18:149:18 | | string.swift:149:18:149:18 | [post] | -| string.swift:149:18:149:18 | | string.swift:149:18:149:18 | [post] &... | +| string.swift:149:16:149:16 | x | string.swift:151:27:151:27 | x | +| string.swift:149:18:149:18 | hello | string.swift:149:18:149:18 | [post] hello | +| string.swift:149:18:149:18 | hello | string.swift:149:18:149:18 | [post] &... | | string.swift:149:18:149:18 | $interpolation | string.swift:149:18:149:18 | &... | -| string.swift:149:18:149:18 | &... | string.swift:149:13:149:13 | TapExpr | -| string.swift:149:18:149:18 | &... | string.swift:149:18:149:18 | [post] | +| string.swift:149:18:149:18 | &... | string.swift:149:18:149:18 | [post] hello | | string.swift:149:18:149:18 | &... | string.swift:149:18:149:18 | [post] &... | -| string.swift:149:18:149:18 | [post] &... | string.swift:149:13:149:13 | TapExpr | -| string.swift:155:7:155:7 | SSA def(clean) | string.swift:158:13:158:13 | clean | -| string.swift:155:15:155:15 | abcdef | string.swift:155:7:155:7 | SSA def(clean) | -| string.swift:156:7:156:7 | SSA def(tainted) | string.swift:159:13:159:13 | tainted | -| string.swift:156:17:156:25 | call to source2() | string.swift:156:7:156:7 | SSA def(tainted) | -| string.swift:158:13:158:13 | [post] clean | string.swift:161:13:161:13 | clean | -| string.swift:158:13:158:13 | clean | string.swift:161:13:161:13 | clean | -| string.swift:159:13:159:13 | [post] tainted | string.swift:162:21:162:21 | tainted | -| string.swift:159:13:159:13 | tainted | string.swift:162:21:162:21 | tainted | -| string.swift:161:13:161:13 | [post] clean | string.swift:161:21:161:21 | clean | -| string.swift:161:13:161:13 | clean | string.swift:161:13:161:21 | ... .+(_:_:) ... | -| string.swift:161:13:161:13 | clean | string.swift:161:21:161:21 | clean | -| string.swift:161:21:161:21 | [post] clean | string.swift:162:13:162:13 | clean | -| string.swift:161:21:161:21 | clean | string.swift:161:13:161:21 | ... .+(_:_:) ... | -| string.swift:161:21:161:21 | clean | string.swift:162:13:162:13 | clean | -| string.swift:162:13:162:13 | [post] clean | string.swift:163:23:163:23 | clean | -| string.swift:162:13:162:13 | clean | string.swift:162:13:162:21 | ... .+(_:_:) ... | -| string.swift:162:13:162:13 | clean | string.swift:163:23:163:23 | clean | -| string.swift:162:21:162:21 | [post] tainted | string.swift:163:13:163:13 | tainted | -| string.swift:162:21:162:21 | tainted | string.swift:162:13:162:21 | ... .+(_:_:) ... | -| string.swift:162:21:162:21 | tainted | string.swift:163:13:163:13 | tainted | -| string.swift:163:13:163:13 | [post] tainted | string.swift:164:13:164:13 | tainted | -| string.swift:163:13:163:13 | tainted | string.swift:163:13:163:23 | ... .+(_:_:) ... | -| string.swift:163:13:163:13 | tainted | string.swift:164:13:164:13 | tainted | -| string.swift:163:23:163:23 | [post] clean | string.swift:166:19:166:19 | clean | -| string.swift:163:23:163:23 | clean | string.swift:163:13:163:23 | ... .+(_:_:) ... | -| string.swift:163:23:163:23 | clean | string.swift:166:19:166:19 | clean | -| string.swift:164:13:164:13 | [post] tainted | string.swift:164:23:164:23 | tainted | -| string.swift:164:13:164:13 | tainted | string.swift:164:13:164:23 | ... .+(_:_:) ... | -| string.swift:164:13:164:13 | tainted | string.swift:164:23:164:23 | tainted | -| string.swift:164:23:164:23 | [post] tainted | string.swift:167:19:167:19 | tainted | -| string.swift:164:23:164:23 | tainted | string.swift:164:13:164:23 | ... .+(_:_:) ... | -| string.swift:164:23:164:23 | tainted | string.swift:167:19:167:19 | tainted | -| string.swift:166:13:166:13 | > | string.swift:166:13:166:19 | ... .+(_:_:) ... | -| string.swift:166:13:166:19 | ... .+(_:_:) ... | string.swift:166:13:166:27 | ... .+(_:_:) ... | -| string.swift:166:19:166:19 | [post] clean | string.swift:169:13:169:13 | clean | -| string.swift:166:19:166:19 | clean | string.swift:166:13:166:19 | ... .+(_:_:) ... | -| string.swift:166:19:166:19 | clean | string.swift:169:13:169:13 | clean | -| string.swift:166:27:166:27 | < | string.swift:166:13:166:27 | ... .+(_:_:) ... | -| string.swift:167:13:167:13 | > | string.swift:167:13:167:19 | ... .+(_:_:) ... | -| string.swift:167:13:167:19 | ... .+(_:_:) ... | string.swift:167:13:167:29 | ... .+(_:_:) ... | -| string.swift:167:19:167:19 | [post] tainted | string.swift:170:29:170:29 | tainted | -| string.swift:167:19:167:19 | tainted | string.swift:167:13:167:19 | ... .+(_:_:) ... | -| string.swift:167:19:167:19 | tainted | string.swift:170:29:170:29 | tainted | -| string.swift:167:29:167:29 | < | string.swift:167:13:167:29 | ... .+(_:_:) ... | -| string.swift:169:13:169:13 | [post] clean | string.swift:169:29:169:29 | clean | -| string.swift:169:13:169:13 | clean | string.swift:169:13:169:34 | call to appending(_:) | -| string.swift:169:13:169:13 | clean | string.swift:169:29:169:29 | clean | -| string.swift:169:29:169:29 | [post] clean | string.swift:170:13:170:13 | clean | -| string.swift:169:29:169:29 | clean | string.swift:169:13:169:34 | call to appending(_:) | -| string.swift:169:29:169:29 | clean | string.swift:170:13:170:13 | clean | -| string.swift:170:13:170:13 | [post] clean | string.swift:171:31:171:31 | clean | -| string.swift:170:13:170:13 | clean | string.swift:170:13:170:36 | call to appending(_:) | -| string.swift:170:13:170:13 | clean | string.swift:171:31:171:31 | clean | -| string.swift:170:29:170:29 | [post] tainted | string.swift:171:13:171:13 | tainted | -| string.swift:170:29:170:29 | tainted | string.swift:170:13:170:36 | call to appending(_:) | -| string.swift:170:29:170:29 | tainted | string.swift:171:13:171:13 | tainted | -| string.swift:171:13:171:13 | [post] tainted | string.swift:172:13:172:13 | tainted | -| string.swift:171:13:171:13 | tainted | string.swift:171:13:171:36 | call to appending(_:) | -| string.swift:171:13:171:13 | tainted | string.swift:172:13:172:13 | tainted | -| string.swift:171:31:171:31 | clean | string.swift:171:13:171:36 | call to appending(_:) | -| string.swift:172:13:172:13 | [post] tainted | string.swift:172:31:172:31 | tainted | -| string.swift:172:13:172:13 | tainted | string.swift:172:13:172:38 | call to appending(_:) | -| string.swift:172:13:172:13 | tainted | string.swift:172:31:172:31 | tainted | -| string.swift:172:31:172:31 | tainted | string.swift:172:13:172:38 | call to appending(_:) | -| string.swift:174:7:174:7 | SSA def(str) | string.swift:175:13:175:13 | str | -| string.swift:174:13:174:13 | abc | string.swift:174:7:174:7 | SSA def(str) | -| string.swift:175:13:175:13 | [post] str | string.swift:176:3:176:3 | str | -| string.swift:175:13:175:13 | str | string.swift:176:3:176:3 | str | -| string.swift:176:3:176:3 | &... | string.swift:177:13:177:13 | str | -| string.swift:176:3:176:3 | [post] &... | string.swift:177:13:177:13 | str | -| string.swift:176:3:176:3 | str | string.swift:176:3:176:3 | &... | -| string.swift:177:13:177:13 | [post] str | string.swift:178:3:178:3 | str | -| string.swift:177:13:177:13 | str | string.swift:178:3:178:3 | str | -| string.swift:178:3:178:3 | &... | string.swift:179:13:179:13 | str | -| string.swift:178:3:178:3 | [post] &... | string.swift:179:13:179:13 | str | -| string.swift:178:3:178:3 | str | string.swift:178:3:178:3 | &... | -| string.swift:181:7:181:7 | SSA def(str2) | string.swift:182:13:182:13 | str2 | -| string.swift:181:14:181:14 | abc | string.swift:181:7:181:7 | SSA def(str2) | -| string.swift:182:13:182:13 | [post] str2 | string.swift:183:3:183:3 | str2 | -| string.swift:182:13:182:13 | str2 | string.swift:183:3:183:3 | str2 | -| string.swift:183:3:183:3 | &... | string.swift:184:13:184:13 | str2 | -| string.swift:183:3:183:3 | [post] &... | string.swift:184:13:184:13 | str2 | -| string.swift:183:3:183:3 | str2 | string.swift:183:3:183:3 | &... | -| string.swift:183:15:183:15 | def | string.swift:183:3:183:3 | [post] &... | -| string.swift:184:13:184:13 | [post] str2 | string.swift:185:3:185:3 | str2 | -| string.swift:184:13:184:13 | str2 | string.swift:185:3:185:3 | str2 | -| string.swift:185:3:185:3 | &... | string.swift:186:13:186:13 | str2 | -| string.swift:185:3:185:3 | [post] &... | string.swift:186:13:186:13 | str2 | -| string.swift:185:3:185:3 | str2 | string.swift:185:3:185:3 | &... | -| string.swift:185:15:185:23 | call to source2() | string.swift:185:3:185:3 | [post] &... | -| string.swift:188:7:188:7 | SSA def(str3) | string.swift:189:13:189:13 | str3 | -| string.swift:188:14:188:14 | abc | string.swift:188:7:188:7 | SSA def(str3) | -| string.swift:189:13:189:13 | [post] str3 | string.swift:190:3:190:3 | str3 | -| string.swift:189:13:189:13 | str3 | string.swift:190:3:190:3 | str3 | -| string.swift:190:3:190:3 | &... | string.swift:191:13:191:13 | str3 | -| string.swift:190:3:190:3 | [post] &... | string.swift:191:13:191:13 | str3 | -| string.swift:190:3:190:3 | str3 | string.swift:190:3:190:3 | &... | -| string.swift:190:27:190:27 | def | string.swift:190:3:190:3 | [post] &... | -| string.swift:191:13:191:13 | [post] str3 | string.swift:192:3:192:3 | str3 | -| string.swift:191:13:191:13 | str3 | string.swift:192:3:192:3 | str3 | -| string.swift:192:3:192:3 | &... | string.swift:193:13:193:13 | str3 | -| string.swift:192:3:192:3 | [post] &... | string.swift:193:13:193:13 | str3 | -| string.swift:192:3:192:3 | str3 | string.swift:192:3:192:3 | &... | -| string.swift:192:27:192:35 | call to source2() | string.swift:192:3:192:3 | [post] &... | -| string.swift:195:7:195:7 | SSA def(str4) | string.swift:196:13:196:13 | str4 | -| string.swift:195:14:195:14 | abc | string.swift:195:7:195:7 | SSA def(str4) | -| string.swift:196:13:196:13 | [post] str4 | string.swift:197:3:197:3 | str4 | -| string.swift:196:13:196:13 | str4 | string.swift:197:3:197:3 | str4 | -| string.swift:197:3:197:3 | &... | string.swift:198:13:198:13 | str4 | -| string.swift:197:3:197:3 | [post] &... | string.swift:198:13:198:13 | str4 | -| string.swift:197:3:197:3 | str4 | string.swift:197:3:197:3 | &... | -| string.swift:197:14:197:14 | def | string.swift:197:3:197:3 | [post] &... | -| string.swift:198:13:198:13 | [post] str4 | string.swift:199:3:199:3 | str4 | -| string.swift:198:13:198:13 | str4 | string.swift:199:3:199:3 | str4 | -| string.swift:199:3:199:3 | &... | string.swift:200:13:200:13 | str4 | -| string.swift:199:3:199:3 | [post] &... | string.swift:200:13:200:13 | str4 | -| string.swift:199:3:199:3 | str4 | string.swift:199:3:199:3 | &... | -| string.swift:199:14:199:22 | call to source2() | string.swift:199:3:199:3 | [post] &... | -| string.swift:202:7:202:7 | SSA def(str5) | string.swift:203:13:203:13 | str5 | -| string.swift:202:14:202:14 | abc | string.swift:202:7:202:7 | SSA def(str5) | -| string.swift:203:13:203:13 | [post] str5 | string.swift:204:3:204:3 | str5 | -| string.swift:203:13:203:13 | str5 | string.swift:204:3:204:3 | str5 | -| string.swift:204:3:204:3 | &... | string.swift:204:38:204:38 | str5 | -| string.swift:204:3:204:3 | [post] &... | string.swift:204:38:204:38 | str5 | -| string.swift:204:3:204:3 | str5 | string.swift:204:3:204:3 | &... | -| string.swift:204:27:204:27 | abc | string.swift:204:3:204:3 | [post] &... | -| string.swift:204:38:204:38 | [post] str5 | string.swift:205:13:205:13 | str5 | -| string.swift:204:38:204:38 | str5 | string.swift:205:13:205:13 | str5 | -| string.swift:205:13:205:13 | [post] str5 | string.swift:206:3:206:3 | str5 | -| string.swift:205:13:205:13 | str5 | string.swift:206:3:206:3 | str5 | -| string.swift:206:3:206:3 | &... | string.swift:206:42:206:42 | str5 | -| string.swift:206:3:206:3 | [post] &... | string.swift:206:42:206:42 | str5 | -| string.swift:206:3:206:3 | str5 | string.swift:206:3:206:3 | &... | -| string.swift:206:27:206:35 | call to source2() | string.swift:206:3:206:3 | [post] &... | -| string.swift:206:42:206:42 | [post] str5 | string.swift:207:13:207:13 | str5 | -| string.swift:206:42:206:42 | str5 | string.swift:207:13:207:13 | str5 | -| string.swift:211:7:211:7 | SSA def(clean) | string.swift:215:20:215:20 | clean | -| string.swift:211:15:211:15 | | string.swift:211:7:211:7 | SSA def(clean) | -| string.swift:212:7:212:7 | SSA def(tainted) | string.swift:216:20:216:20 | tainted | -| string.swift:212:17:212:25 | call to source2() | string.swift:212:7:212:7 | SSA def(tainted) | -| string.swift:213:7:213:7 | SSA def(taintedInt) | string.swift:217:20:217:20 | taintedInt | -| string.swift:213:20:213:27 | call to source() | string.swift:213:7:213:7 | SSA def(taintedInt) | -| string.swift:215:20:215:20 | [post] clean | string.swift:227:31:227:31 | clean | -| string.swift:215:20:215:20 | clean | string.swift:215:13:215:25 | call to String.init(_:) | -| string.swift:215:20:215:20 | clean | string.swift:227:31:227:31 | clean | -| string.swift:216:20:216:20 | [post] tainted | string.swift:219:28:219:28 | tainted | -| string.swift:216:20:216:20 | tainted | string.swift:216:13:216:27 | call to String.init(_:) | -| string.swift:216:20:216:20 | tainted | string.swift:219:28:219:28 | tainted | -| string.swift:217:20:217:20 | [post] taintedInt | string.swift:225:46:225:46 | taintedInt | -| string.swift:217:20:217:20 | taintedInt | string.swift:217:13:217:30 | call to String.init(_:) | -| string.swift:217:20:217:20 | taintedInt | string.swift:225:46:225:46 | taintedInt | -| string.swift:219:28:219:28 | [post] tainted | string.swift:220:28:220:28 | tainted | -| string.swift:219:28:219:28 | tainted | string.swift:219:13:219:44 | call to String.init(format:_:) | -| string.swift:219:28:219:28 | tainted | string.swift:220:28:220:28 | tainted | -| string.swift:220:28:220:28 | [post] tainted | string.swift:221:28:221:28 | tainted | -| string.swift:220:28:220:28 | tainted | string.swift:220:13:220:50 | call to String.init(format:arguments:) | -| string.swift:220:28:220:28 | tainted | string.swift:221:28:221:28 | tainted | -| string.swift:220:48:220:49 | [...] | string.swift:220:13:220:50 | call to String.init(format:arguments:) | -| string.swift:221:28:221:28 | [post] tainted | string.swift:222:28:222:28 | tainted | -| string.swift:221:28:221:28 | tainted | string.swift:221:13:221:57 | call to String.init(format:locale:_:) | -| string.swift:221:28:221:28 | tainted | string.swift:222:28:222:28 | tainted | -| string.swift:222:28:222:28 | [post] tainted | string.swift:223:46:223:46 | tainted | -| string.swift:222:28:222:28 | tainted | string.swift:222:13:222:63 | call to String.init(format:locale:arguments:) | -| string.swift:222:28:222:28 | tainted | string.swift:223:46:223:46 | tainted | -| string.swift:223:46:223:46 | [post] tainted | string.swift:224:34:224:34 | tainted | -| string.swift:223:46:223:46 | tainted | string.swift:223:13:223:62 | call to localizedStringWithFormat(_:_:) | -| string.swift:223:46:223:46 | tainted | string.swift:224:34:224:34 | tainted | -| string.swift:223:55:223:61 | [...] | string.swift:223:13:223:62 | call to localizedStringWithFormat(_:_:) | -| string.swift:224:28:224:28 | %s | string.swift:224:13:224:41 | call to String.init(format:_:) | -| string.swift:224:34:224:34 | tainted | string.swift:228:31:228:31 | tainted | -| string.swift:225:28:225:28 | %i %i %i | string.swift:225:13:225:56 | call to String.init(format:_:) | -| string.swift:227:31:227:31 | [post] clean | string.swift:253:13:253:13 | clean | -| string.swift:227:31:227:31 | clean | string.swift:227:13:227:46 | call to String.init(repeating:count:) | -| string.swift:227:31:227:31 | clean | string.swift:253:13:253:13 | clean | -| string.swift:228:31:228:31 | [post] tainted | string.swift:230:13:230:13 | tainted | -| string.swift:228:31:228:31 | tainted | string.swift:228:13:228:48 | call to String.init(repeating:count:) | -| string.swift:228:31:228:31 | tainted | string.swift:230:13:230:13 | tainted | -| string.swift:230:13:230:13 | [post] tainted | string.swift:231:13:231:13 | tainted | -| string.swift:230:13:230:13 | tainted | string.swift:230:13:230:33 | call to dropFirst(_:) | -| string.swift:230:13:230:13 | tainted | string.swift:231:13:231:13 | tainted | -| string.swift:231:13:231:13 | [post] tainted | string.swift:232:13:232:13 | tainted | -| string.swift:231:13:231:13 | tainted | string.swift:231:13:231:32 | call to dropLast(_:) | -| string.swift:231:13:231:13 | tainted | string.swift:232:13:232:13 | tainted | -| string.swift:232:13:232:13 | [post] tainted | string.swift:232:37:232:37 | tainted | -| string.swift:232:13:232:13 | tainted | string.swift:232:13:232:55 | call to substring(from:) | -| string.swift:232:13:232:13 | tainted | string.swift:232:37:232:37 | tainted | -| string.swift:232:37:232:37 | [post] tainted | string.swift:234:13:234:13 | tainted | -| string.swift:232:37:232:37 | tainted | string.swift:234:13:234:13 | tainted | -| string.swift:234:13:234:13 | [post] tainted | string.swift:235:13:235:13 | tainted | -| string.swift:234:13:234:13 | tainted | string.swift:234:13:234:32 | call to lowercased() | -| string.swift:234:13:234:13 | tainted | string.swift:235:13:235:13 | tainted | +| string.swift:149:18:149:18 | &... | string.swift:149:26:149:26 | $interpolation | +| string.swift:149:18:149:18 | [post] &... | string.swift:149:26:149:26 | $interpolation | +| string.swift:149:26:149:26 | $interpolation | string.swift:149:26:149:26 | &... | +| string.swift:149:26:149:26 | &... | string.swift:149:26:149:26 | [post] &... | +| string.swift:149:26:149:26 | &... | string.swift:149:27:149:27 | [post] y | +| string.swift:149:26:149:26 | &... | string.swift:149:29:149:29 | $interpolation | +| string.swift:149:26:149:26 | [post] &... | string.swift:149:29:149:29 | $interpolation | +| string.swift:149:27:149:27 | [post] y | string.swift:151:16:151:16 | y | +| string.swift:149:27:149:27 | y | string.swift:149:26:149:26 | [post] &... | +| string.swift:149:27:149:27 | y | string.swift:149:27:149:27 | [post] y | +| string.swift:149:27:149:27 | y | string.swift:151:16:151:16 | y | +| string.swift:149:29:149:29 | | string.swift:149:29:149:29 | [post] | +| string.swift:149:29:149:29 | | string.swift:149:29:149:29 | [post] &... | +| string.swift:149:29:149:29 | $interpolation | string.swift:149:29:149:29 | &... | +| string.swift:149:29:149:29 | &... | string.swift:149:13:149:13 | TapExpr | +| string.swift:149:29:149:29 | &... | string.swift:149:29:149:29 | [post] | +| string.swift:149:29:149:29 | &... | string.swift:149:29:149:29 | [post] &... | +| string.swift:149:29:149:29 | [post] &... | string.swift:149:13:149:13 | TapExpr | +| string.swift:151:13:151:13 | | string.swift:151:13:151:13 | [post] | +| string.swift:151:13:151:13 | | string.swift:151:14:151:14 | [post] &... | +| string.swift:151:13:151:13 | SSA def($interpolation) | string.swift:151:14:151:14 | SSA phi($interpolation) | +| string.swift:151:13:151:13 | TapExpr | string.swift:151:13:151:13 | "..." | +| string.swift:151:14:151:14 | $interpolation | string.swift:151:14:151:14 | &... | +| string.swift:151:14:151:14 | &... | string.swift:151:13:151:13 | [post] | +| string.swift:151:14:151:14 | &... | string.swift:151:14:151:14 | [post] &... | +| string.swift:151:14:151:14 | &... | string.swift:151:15:151:15 | $interpolation | +| string.swift:151:14:151:14 | SSA phi($interpolation) | string.swift:151:14:151:14 | $interpolation | +| string.swift:151:14:151:14 | [post] &... | string.swift:151:15:151:15 | $interpolation | +| string.swift:151:15:151:15 | $interpolation | string.swift:151:15:151:15 | &... | +| string.swift:151:15:151:15 | &... | string.swift:151:15:151:15 | [post] &... | +| string.swift:151:15:151:15 | &... | string.swift:151:16:151:16 | [post] y | +| string.swift:151:15:151:15 | &... | string.swift:151:18:151:18 | $interpolation | +| string.swift:151:15:151:15 | [post] &... | string.swift:151:18:151:18 | $interpolation | +| string.swift:151:16:151:16 | y | string.swift:151:15:151:15 | [post] &... | +| string.swift:151:16:151:16 | y | string.swift:151:16:151:16 | [post] y | +| string.swift:151:18:151:18 | world | string.swift:151:18:151:18 | [post] world | +| string.swift:151:18:151:18 | world | string.swift:151:18:151:18 | [post] &... | +| string.swift:151:18:151:18 | $interpolation | string.swift:151:18:151:18 | &... | +| string.swift:151:18:151:18 | &... | string.swift:151:18:151:18 | [post] world | +| string.swift:151:18:151:18 | &... | string.swift:151:18:151:18 | [post] &... | +| string.swift:151:18:151:18 | &... | string.swift:151:26:151:26 | $interpolation | +| string.swift:151:18:151:18 | [post] &... | string.swift:151:26:151:26 | $interpolation | +| string.swift:151:26:151:26 | $interpolation | string.swift:151:26:151:26 | &... | +| string.swift:151:26:151:26 | &... | string.swift:151:26:151:26 | [post] &... | +| string.swift:151:26:151:26 | &... | string.swift:151:27:151:27 | [post] x | +| string.swift:151:26:151:26 | &... | string.swift:151:29:151:29 | $interpolation | +| string.swift:151:26:151:26 | [post] &... | string.swift:151:29:151:29 | $interpolation | +| string.swift:151:27:151:27 | x | string.swift:151:26:151:26 | [post] &... | +| string.swift:151:27:151:27 | x | string.swift:151:27:151:27 | [post] x | +| string.swift:151:29:151:29 | | string.swift:151:29:151:29 | [post] | +| string.swift:151:29:151:29 | | string.swift:151:29:151:29 | [post] &... | +| string.swift:151:29:151:29 | $interpolation | string.swift:151:29:151:29 | &... | +| string.swift:151:29:151:29 | &... | string.swift:151:13:151:13 | TapExpr | +| string.swift:151:29:151:29 | &... | string.swift:151:29:151:29 | [post] | +| string.swift:151:29:151:29 | &... | string.swift:151:29:151:29 | [post] &... | +| string.swift:151:29:151:29 | [post] &... | string.swift:151:13:151:13 | TapExpr | +| string.swift:153:3:153:7 | SSA def(x) | string.swift:154:16:154:16 | x | +| string.swift:153:7:153:7 | 0 | string.swift:153:3:153:7 | SSA def(x) | +| string.swift:154:13:154:13 | | string.swift:154:13:154:13 | [post] | +| string.swift:154:13:154:13 | | string.swift:154:14:154:14 | [post] &... | +| string.swift:154:13:154:13 | SSA def($interpolation) | string.swift:154:14:154:14 | SSA phi($interpolation) | +| string.swift:154:13:154:13 | TapExpr | string.swift:154:13:154:13 | "..." | +| string.swift:154:14:154:14 | $interpolation | string.swift:154:14:154:14 | &... | +| string.swift:154:14:154:14 | &... | string.swift:154:13:154:13 | [post] | +| string.swift:154:14:154:14 | &... | string.swift:154:14:154:14 | [post] &... | +| string.swift:154:14:154:14 | &... | string.swift:154:15:154:15 | $interpolation | +| string.swift:154:14:154:14 | SSA phi($interpolation) | string.swift:154:14:154:14 | $interpolation | +| string.swift:154:14:154:14 | [post] &... | string.swift:154:15:154:15 | $interpolation | +| string.swift:154:15:154:15 | $interpolation | string.swift:154:15:154:15 | &... | +| string.swift:154:15:154:15 | &... | string.swift:154:15:154:15 | [post] &... | +| string.swift:154:15:154:15 | &... | string.swift:154:16:154:16 | [post] x | +| string.swift:154:15:154:15 | &... | string.swift:154:18:154:18 | $interpolation | +| string.swift:154:15:154:15 | [post] &... | string.swift:154:18:154:18 | $interpolation | +| string.swift:154:16:154:16 | x | string.swift:154:15:154:15 | [post] &... | +| string.swift:154:16:154:16 | x | string.swift:154:16:154:16 | [post] x | +| string.swift:154:18:154:18 | | string.swift:154:18:154:18 | [post] | +| string.swift:154:18:154:18 | | string.swift:154:18:154:18 | [post] &... | +| string.swift:154:18:154:18 | $interpolation | string.swift:154:18:154:18 | &... | +| string.swift:154:18:154:18 | &... | string.swift:154:13:154:13 | TapExpr | +| string.swift:154:18:154:18 | &... | string.swift:154:18:154:18 | [post] | +| string.swift:154:18:154:18 | &... | string.swift:154:18:154:18 | [post] &... | +| string.swift:154:18:154:18 | [post] &... | string.swift:154:13:154:13 | TapExpr | +| string.swift:160:7:160:7 | SSA def(clean) | string.swift:163:13:163:13 | clean | +| string.swift:160:15:160:15 | abcdef | string.swift:160:7:160:7 | SSA def(clean) | +| string.swift:161:7:161:7 | SSA def(tainted) | string.swift:164:13:164:13 | tainted | +| string.swift:161:17:161:25 | call to source2() | string.swift:161:7:161:7 | SSA def(tainted) | +| string.swift:163:13:163:13 | [post] clean | string.swift:166:13:166:13 | clean | +| string.swift:163:13:163:13 | clean | string.swift:166:13:166:13 | clean | +| string.swift:164:13:164:13 | [post] tainted | string.swift:167:21:167:21 | tainted | +| string.swift:164:13:164:13 | tainted | string.swift:167:21:167:21 | tainted | +| string.swift:166:13:166:13 | [post] clean | string.swift:166:21:166:21 | clean | +| string.swift:166:13:166:13 | clean | string.swift:166:13:166:21 | ... .+(_:_:) ... | +| string.swift:166:13:166:13 | clean | string.swift:166:21:166:21 | clean | +| string.swift:166:21:166:21 | [post] clean | string.swift:167:13:167:13 | clean | +| string.swift:166:21:166:21 | clean | string.swift:166:13:166:21 | ... .+(_:_:) ... | +| string.swift:166:21:166:21 | clean | string.swift:167:13:167:13 | clean | +| string.swift:167:13:167:13 | [post] clean | string.swift:168:23:168:23 | clean | +| string.swift:167:13:167:13 | clean | string.swift:167:13:167:21 | ... .+(_:_:) ... | +| string.swift:167:13:167:13 | clean | string.swift:168:23:168:23 | clean | +| string.swift:167:21:167:21 | [post] tainted | string.swift:168:13:168:13 | tainted | +| string.swift:167:21:167:21 | tainted | string.swift:167:13:167:21 | ... .+(_:_:) ... | +| string.swift:167:21:167:21 | tainted | string.swift:168:13:168:13 | tainted | +| string.swift:168:13:168:13 | [post] tainted | string.swift:169:13:169:13 | tainted | +| string.swift:168:13:168:13 | tainted | string.swift:168:13:168:23 | ... .+(_:_:) ... | +| string.swift:168:13:168:13 | tainted | string.swift:169:13:169:13 | tainted | +| string.swift:168:23:168:23 | [post] clean | string.swift:171:19:171:19 | clean | +| string.swift:168:23:168:23 | clean | string.swift:168:13:168:23 | ... .+(_:_:) ... | +| string.swift:168:23:168:23 | clean | string.swift:171:19:171:19 | clean | +| string.swift:169:13:169:13 | [post] tainted | string.swift:169:23:169:23 | tainted | +| string.swift:169:13:169:13 | tainted | string.swift:169:13:169:23 | ... .+(_:_:) ... | +| string.swift:169:13:169:13 | tainted | string.swift:169:23:169:23 | tainted | +| string.swift:169:23:169:23 | [post] tainted | string.swift:172:19:172:19 | tainted | +| string.swift:169:23:169:23 | tainted | string.swift:169:13:169:23 | ... .+(_:_:) ... | +| string.swift:169:23:169:23 | tainted | string.swift:172:19:172:19 | tainted | +| string.swift:171:13:171:13 | > | string.swift:171:13:171:19 | ... .+(_:_:) ... | +| string.swift:171:13:171:19 | ... .+(_:_:) ... | string.swift:171:13:171:27 | ... .+(_:_:) ... | +| string.swift:171:19:171:19 | [post] clean | string.swift:174:13:174:13 | clean | +| string.swift:171:19:171:19 | clean | string.swift:171:13:171:19 | ... .+(_:_:) ... | +| string.swift:171:19:171:19 | clean | string.swift:174:13:174:13 | clean | +| string.swift:171:27:171:27 | < | string.swift:171:13:171:27 | ... .+(_:_:) ... | +| string.swift:172:13:172:13 | > | string.swift:172:13:172:19 | ... .+(_:_:) ... | +| string.swift:172:13:172:19 | ... .+(_:_:) ... | string.swift:172:13:172:29 | ... .+(_:_:) ... | +| string.swift:172:19:172:19 | [post] tainted | string.swift:175:29:175:29 | tainted | +| string.swift:172:19:172:19 | tainted | string.swift:172:13:172:19 | ... .+(_:_:) ... | +| string.swift:172:19:172:19 | tainted | string.swift:175:29:175:29 | tainted | +| string.swift:172:29:172:29 | < | string.swift:172:13:172:29 | ... .+(_:_:) ... | +| string.swift:174:13:174:13 | [post] clean | string.swift:174:29:174:29 | clean | +| string.swift:174:13:174:13 | clean | string.swift:174:13:174:34 | call to appending(_:) | +| string.swift:174:13:174:13 | clean | string.swift:174:29:174:29 | clean | +| string.swift:174:29:174:29 | [post] clean | string.swift:175:13:175:13 | clean | +| string.swift:174:29:174:29 | clean | string.swift:174:13:174:34 | call to appending(_:) | +| string.swift:174:29:174:29 | clean | string.swift:175:13:175:13 | clean | +| string.swift:175:13:175:13 | [post] clean | string.swift:176:31:176:31 | clean | +| string.swift:175:13:175:13 | clean | string.swift:175:13:175:36 | call to appending(_:) | +| string.swift:175:13:175:13 | clean | string.swift:176:31:176:31 | clean | +| string.swift:175:29:175:29 | [post] tainted | string.swift:176:13:176:13 | tainted | +| string.swift:175:29:175:29 | tainted | string.swift:175:13:175:36 | call to appending(_:) | +| string.swift:175:29:175:29 | tainted | string.swift:176:13:176:13 | tainted | +| string.swift:176:13:176:13 | [post] tainted | string.swift:177:13:177:13 | tainted | +| string.swift:176:13:176:13 | tainted | string.swift:176:13:176:36 | call to appending(_:) | +| string.swift:176:13:176:13 | tainted | string.swift:177:13:177:13 | tainted | +| string.swift:176:31:176:31 | clean | string.swift:176:13:176:36 | call to appending(_:) | +| string.swift:177:13:177:13 | [post] tainted | string.swift:177:31:177:31 | tainted | +| string.swift:177:13:177:13 | tainted | string.swift:177:13:177:38 | call to appending(_:) | +| string.swift:177:13:177:13 | tainted | string.swift:177:31:177:31 | tainted | +| string.swift:177:31:177:31 | tainted | string.swift:177:13:177:38 | call to appending(_:) | +| string.swift:179:7:179:7 | SSA def(str) | string.swift:180:13:180:13 | str | +| string.swift:179:13:179:13 | abc | string.swift:179:7:179:7 | SSA def(str) | +| string.swift:180:13:180:13 | [post] str | string.swift:181:3:181:3 | str | +| string.swift:180:13:180:13 | str | string.swift:181:3:181:3 | str | +| string.swift:181:3:181:3 | &... | string.swift:182:13:182:13 | str | +| string.swift:181:3:181:3 | [post] &... | string.swift:182:13:182:13 | str | +| string.swift:181:3:181:3 | str | string.swift:181:3:181:3 | &... | +| string.swift:182:13:182:13 | [post] str | string.swift:183:3:183:3 | str | +| string.swift:182:13:182:13 | str | string.swift:183:3:183:3 | str | +| string.swift:183:3:183:3 | &... | string.swift:184:13:184:13 | str | +| string.swift:183:3:183:3 | [post] &... | string.swift:184:13:184:13 | str | +| string.swift:183:3:183:3 | str | string.swift:183:3:183:3 | &... | +| string.swift:186:7:186:7 | SSA def(str2) | string.swift:187:13:187:13 | str2 | +| string.swift:186:14:186:14 | abc | string.swift:186:7:186:7 | SSA def(str2) | +| string.swift:187:13:187:13 | [post] str2 | string.swift:188:3:188:3 | str2 | +| string.swift:187:13:187:13 | str2 | string.swift:188:3:188:3 | str2 | +| string.swift:188:3:188:3 | &... | string.swift:189:13:189:13 | str2 | +| string.swift:188:3:188:3 | [post] &... | string.swift:189:13:189:13 | str2 | +| string.swift:188:3:188:3 | str2 | string.swift:188:3:188:3 | &... | +| string.swift:188:15:188:15 | def | string.swift:188:3:188:3 | [post] &... | +| string.swift:189:13:189:13 | [post] str2 | string.swift:190:3:190:3 | str2 | +| string.swift:189:13:189:13 | str2 | string.swift:190:3:190:3 | str2 | +| string.swift:190:3:190:3 | &... | string.swift:191:13:191:13 | str2 | +| string.swift:190:3:190:3 | [post] &... | string.swift:191:13:191:13 | str2 | +| string.swift:190:3:190:3 | str2 | string.swift:190:3:190:3 | &... | +| string.swift:190:15:190:23 | call to source2() | string.swift:190:3:190:3 | [post] &... | +| string.swift:193:7:193:7 | SSA def(str3) | string.swift:194:13:194:13 | str3 | +| string.swift:193:14:193:14 | abc | string.swift:193:7:193:7 | SSA def(str3) | +| string.swift:194:13:194:13 | [post] str3 | string.swift:195:3:195:3 | str3 | +| string.swift:194:13:194:13 | str3 | string.swift:195:3:195:3 | str3 | +| string.swift:195:3:195:3 | &... | string.swift:196:13:196:13 | str3 | +| string.swift:195:3:195:3 | [post] &... | string.swift:196:13:196:13 | str3 | +| string.swift:195:3:195:3 | str3 | string.swift:195:3:195:3 | &... | +| string.swift:195:27:195:27 | def | string.swift:195:3:195:3 | [post] &... | +| string.swift:196:13:196:13 | [post] str3 | string.swift:197:3:197:3 | str3 | +| string.swift:196:13:196:13 | str3 | string.swift:197:3:197:3 | str3 | +| string.swift:197:3:197:3 | &... | string.swift:198:13:198:13 | str3 | +| string.swift:197:3:197:3 | [post] &... | string.swift:198:13:198:13 | str3 | +| string.swift:197:3:197:3 | str3 | string.swift:197:3:197:3 | &... | +| string.swift:197:27:197:35 | call to source2() | string.swift:197:3:197:3 | [post] &... | +| string.swift:200:7:200:7 | SSA def(str4) | string.swift:201:13:201:13 | str4 | +| string.swift:200:14:200:14 | abc | string.swift:200:7:200:7 | SSA def(str4) | +| string.swift:201:13:201:13 | [post] str4 | string.swift:202:3:202:3 | str4 | +| string.swift:201:13:201:13 | str4 | string.swift:202:3:202:3 | str4 | +| string.swift:202:3:202:3 | &... | string.swift:203:13:203:13 | str4 | +| string.swift:202:3:202:3 | [post] &... | string.swift:203:13:203:13 | str4 | +| string.swift:202:3:202:3 | str4 | string.swift:202:3:202:3 | &... | +| string.swift:202:14:202:14 | def | string.swift:202:3:202:3 | [post] &... | +| string.swift:203:13:203:13 | [post] str4 | string.swift:204:3:204:3 | str4 | +| string.swift:203:13:203:13 | str4 | string.swift:204:3:204:3 | str4 | +| string.swift:204:3:204:3 | &... | string.swift:205:13:205:13 | str4 | +| string.swift:204:3:204:3 | [post] &... | string.swift:205:13:205:13 | str4 | +| string.swift:204:3:204:3 | str4 | string.swift:204:3:204:3 | &... | +| string.swift:204:14:204:22 | call to source2() | string.swift:204:3:204:3 | [post] &... | +| string.swift:207:7:207:7 | SSA def(str5) | string.swift:208:13:208:13 | str5 | +| string.swift:207:14:207:14 | abc | string.swift:207:7:207:7 | SSA def(str5) | +| string.swift:208:13:208:13 | [post] str5 | string.swift:209:3:209:3 | str5 | +| string.swift:208:13:208:13 | str5 | string.swift:209:3:209:3 | str5 | +| string.swift:209:3:209:3 | &... | string.swift:209:38:209:38 | str5 | +| string.swift:209:3:209:3 | [post] &... | string.swift:209:38:209:38 | str5 | +| string.swift:209:3:209:3 | str5 | string.swift:209:3:209:3 | &... | +| string.swift:209:27:209:27 | abc | string.swift:209:3:209:3 | [post] &... | +| string.swift:209:38:209:38 | [post] str5 | string.swift:210:13:210:13 | str5 | +| string.swift:209:38:209:38 | str5 | string.swift:210:13:210:13 | str5 | +| string.swift:210:13:210:13 | [post] str5 | string.swift:211:3:211:3 | str5 | +| string.swift:210:13:210:13 | str5 | string.swift:211:3:211:3 | str5 | +| string.swift:211:3:211:3 | &... | string.swift:211:42:211:42 | str5 | +| string.swift:211:3:211:3 | [post] &... | string.swift:211:42:211:42 | str5 | +| string.swift:211:3:211:3 | str5 | string.swift:211:3:211:3 | &... | +| string.swift:211:27:211:35 | call to source2() | string.swift:211:3:211:3 | [post] &... | +| string.swift:211:42:211:42 | [post] str5 | string.swift:212:13:212:13 | str5 | +| string.swift:211:42:211:42 | str5 | string.swift:212:13:212:13 | str5 | +| string.swift:216:7:216:7 | SSA def(clean) | string.swift:220:20:220:20 | clean | +| string.swift:216:15:216:15 | | string.swift:216:7:216:7 | SSA def(clean) | +| string.swift:217:7:217:7 | SSA def(tainted) | string.swift:221:20:221:20 | tainted | +| string.swift:217:17:217:25 | call to source2() | string.swift:217:7:217:7 | SSA def(tainted) | +| string.swift:218:7:218:7 | SSA def(taintedInt) | string.swift:222:20:222:20 | taintedInt | +| string.swift:218:20:218:27 | call to source() | string.swift:218:7:218:7 | SSA def(taintedInt) | +| string.swift:220:20:220:20 | [post] clean | string.swift:232:31:232:31 | clean | +| string.swift:220:20:220:20 | clean | string.swift:220:13:220:25 | call to String.init(_:) | +| string.swift:220:20:220:20 | clean | string.swift:232:31:232:31 | clean | +| string.swift:221:20:221:20 | [post] tainted | string.swift:224:28:224:28 | tainted | +| string.swift:221:20:221:20 | tainted | string.swift:221:13:221:27 | call to String.init(_:) | +| string.swift:221:20:221:20 | tainted | string.swift:224:28:224:28 | tainted | +| string.swift:222:20:222:20 | [post] taintedInt | string.swift:230:46:230:46 | taintedInt | +| string.swift:222:20:222:20 | taintedInt | string.swift:222:13:222:30 | call to String.init(_:) | +| string.swift:222:20:222:20 | taintedInt | string.swift:230:46:230:46 | taintedInt | +| string.swift:224:28:224:28 | [post] tainted | string.swift:225:28:225:28 | tainted | +| string.swift:224:28:224:28 | tainted | string.swift:224:13:224:44 | call to String.init(format:_:) | +| string.swift:224:28:224:28 | tainted | string.swift:225:28:225:28 | tainted | +| string.swift:225:28:225:28 | [post] tainted | string.swift:226:28:226:28 | tainted | +| string.swift:225:28:225:28 | tainted | string.swift:225:13:225:50 | call to String.init(format:arguments:) | +| string.swift:225:28:225:28 | tainted | string.swift:226:28:226:28 | tainted | +| string.swift:225:48:225:49 | [...] | string.swift:225:13:225:50 | call to String.init(format:arguments:) | +| string.swift:226:28:226:28 | [post] tainted | string.swift:227:28:227:28 | tainted | +| string.swift:226:28:226:28 | tainted | string.swift:226:13:226:57 | call to String.init(format:locale:_:) | +| string.swift:226:28:226:28 | tainted | string.swift:227:28:227:28 | tainted | +| string.swift:227:28:227:28 | [post] tainted | string.swift:228:46:228:46 | tainted | +| string.swift:227:28:227:28 | tainted | string.swift:227:13:227:63 | call to String.init(format:locale:arguments:) | +| string.swift:227:28:227:28 | tainted | string.swift:228:46:228:46 | tainted | +| string.swift:228:46:228:46 | [post] tainted | string.swift:229:34:229:34 | tainted | +| string.swift:228:46:228:46 | tainted | string.swift:228:13:228:62 | call to localizedStringWithFormat(_:_:) | +| string.swift:228:46:228:46 | tainted | string.swift:229:34:229:34 | tainted | +| string.swift:228:55:228:61 | [...] | string.swift:228:13:228:62 | call to localizedStringWithFormat(_:_:) | +| string.swift:229:28:229:28 | %s | string.swift:229:13:229:41 | call to String.init(format:_:) | +| string.swift:229:34:229:34 | tainted | string.swift:233:31:233:31 | tainted | +| string.swift:230:28:230:28 | %i %i %i | string.swift:230:13:230:56 | call to String.init(format:_:) | +| string.swift:232:31:232:31 | [post] clean | string.swift:258:13:258:13 | clean | +| string.swift:232:31:232:31 | clean | string.swift:232:13:232:46 | call to String.init(repeating:count:) | +| string.swift:232:31:232:31 | clean | string.swift:258:13:258:13 | clean | +| string.swift:233:31:233:31 | [post] tainted | string.swift:235:13:235:13 | tainted | +| string.swift:233:31:233:31 | tainted | string.swift:233:13:233:48 | call to String.init(repeating:count:) | +| string.swift:233:31:233:31 | tainted | string.swift:235:13:235:13 | tainted | | string.swift:235:13:235:13 | [post] tainted | string.swift:236:13:236:13 | tainted | -| string.swift:235:13:235:13 | tainted | string.swift:235:13:235:32 | call to uppercased() | +| string.swift:235:13:235:13 | tainted | string.swift:235:13:235:33 | call to dropFirst(_:) | | string.swift:235:13:235:13 | tainted | string.swift:236:13:236:13 | tainted | | string.swift:236:13:236:13 | [post] tainted | string.swift:237:13:237:13 | tainted | -| string.swift:236:13:236:13 | tainted | string.swift:236:13:236:41 | call to lowercased(with:) | +| string.swift:236:13:236:13 | tainted | string.swift:236:13:236:32 | call to dropLast(_:) | | string.swift:236:13:236:13 | tainted | string.swift:237:13:237:13 | tainted | -| string.swift:237:13:237:13 | [post] tainted | string.swift:238:13:238:13 | tainted | -| string.swift:237:13:237:13 | tainted | string.swift:237:13:237:41 | call to uppercased(with:) | -| string.swift:237:13:237:13 | tainted | string.swift:238:13:238:13 | tainted | -| string.swift:238:13:238:13 | [post] tainted | string.swift:239:13:239:13 | tainted | -| string.swift:238:13:238:13 | tainted | string.swift:238:13:238:42 | call to capitalized(with:) | -| string.swift:238:13:238:13 | tainted | string.swift:239:13:239:13 | tainted | -| string.swift:239:13:239:13 | [post] tainted | string.swift:241:13:241:13 | tainted | -| string.swift:239:13:239:13 | tainted | string.swift:239:13:239:30 | call to reversed() | -| string.swift:239:13:239:13 | tainted | string.swift:241:13:241:13 | tainted | +| string.swift:237:13:237:13 | [post] tainted | string.swift:237:37:237:37 | tainted | +| string.swift:237:13:237:13 | tainted | string.swift:237:13:237:55 | call to substring(from:) | +| string.swift:237:13:237:13 | tainted | string.swift:237:37:237:37 | tainted | +| string.swift:237:37:237:37 | [post] tainted | string.swift:239:13:239:13 | tainted | +| string.swift:237:37:237:37 | tainted | string.swift:239:13:239:13 | tainted | +| string.swift:239:13:239:13 | [post] tainted | string.swift:240:13:240:13 | tainted | +| string.swift:239:13:239:13 | tainted | string.swift:239:13:239:32 | call to lowercased() | +| string.swift:239:13:239:13 | tainted | string.swift:240:13:240:13 | tainted | +| string.swift:240:13:240:13 | [post] tainted | string.swift:241:13:241:13 | tainted | +| string.swift:240:13:240:13 | tainted | string.swift:240:13:240:32 | call to uppercased() | +| string.swift:240:13:240:13 | tainted | string.swift:241:13:241:13 | tainted | | string.swift:241:13:241:13 | [post] tainted | string.swift:242:13:242:13 | tainted | -| string.swift:241:13:241:13 | tainted | string.swift:241:13:241:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | +| string.swift:241:13:241:13 | tainted | string.swift:241:13:241:41 | call to lowercased(with:) | | string.swift:241:13:241:13 | tainted | string.swift:242:13:242:13 | tainted | -| string.swift:242:13:242:13 | [post] tainted | string.swift:245:13:245:13 | tainted | -| string.swift:242:13:242:13 | tainted | string.swift:242:13:244:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | -| string.swift:242:13:242:13 | tainted | string.swift:245:13:245:13 | tainted | -| string.swift:243:5:243:5 | SSA def(c) | string.swift:243:18:243:18 | c | -| string.swift:243:5:243:5 | c | string.swift:243:5:243:5 | SSA def(c) | -| string.swift:245:13:245:13 | [post] tainted | string.swift:246:13:246:13 | tainted | -| string.swift:245:13:245:13 | tainted | string.swift:245:13:245:68 | call to trimmingCharacters(in:) | -| string.swift:245:13:245:13 | tainted | string.swift:246:13:246:13 | tainted | +| string.swift:242:13:242:13 | [post] tainted | string.swift:243:13:243:13 | tainted | +| string.swift:242:13:242:13 | tainted | string.swift:242:13:242:41 | call to uppercased(with:) | +| string.swift:242:13:242:13 | tainted | string.swift:243:13:243:13 | tainted | +| string.swift:243:13:243:13 | [post] tainted | string.swift:244:13:244:13 | tainted | +| string.swift:243:13:243:13 | tainted | string.swift:243:13:243:42 | call to capitalized(with:) | +| string.swift:243:13:243:13 | tainted | string.swift:244:13:244:13 | tainted | +| string.swift:244:13:244:13 | [post] tainted | string.swift:246:13:246:13 | tainted | +| string.swift:244:13:244:13 | tainted | string.swift:244:13:244:30 | call to reversed() | +| string.swift:244:13:244:13 | tainted | string.swift:246:13:246:13 | tainted | | string.swift:246:13:246:13 | [post] tainted | string.swift:247:13:247:13 | tainted | -| string.swift:246:13:246:13 | tainted | string.swift:246:13:246:70 | call to padding(toLength:withPad:startingAt:) | +| string.swift:246:13:246:13 | tainted | string.swift:246:13:246:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | | string.swift:246:13:246:13 | tainted | string.swift:247:13:247:13 | tainted | -| string.swift:246:52:246:52 | | string.swift:246:13:246:70 | call to padding(toLength:withPad:startingAt:) | -| string.swift:247:13:247:13 | [post] tainted | string.swift:248:13:248:13 | tainted | -| string.swift:247:13:247:13 | tainted | string.swift:247:13:247:69 | call to components(separatedBy:) | -| string.swift:247:13:247:13 | tainted | string.swift:248:13:248:13 | tainted | -| string.swift:248:13:248:13 | [post] tainted | string.swift:249:13:249:13 | tainted | -| string.swift:248:13:248:13 | tainted | string.swift:248:13:248:69 | call to components(separatedBy:) | -| string.swift:248:13:248:13 | tainted | string.swift:249:13:249:13 | tainted | -| string.swift:248:13:248:69 | call to components(separatedBy:) | string.swift:248:13:248:72 | ...[...] | -| string.swift:249:13:249:13 | [post] tainted | string.swift:250:13:250:13 | tainted | -| string.swift:249:13:249:13 | tainted | string.swift:249:13:249:40 | call to folding(options:locale:) | -| string.swift:249:13:249:13 | tainted | string.swift:250:13:250:13 | tainted | +| string.swift:247:13:247:13 | [post] tainted | string.swift:250:13:250:13 | tainted | +| string.swift:247:13:247:13 | tainted | string.swift:247:13:249:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | +| string.swift:247:13:247:13 | tainted | string.swift:250:13:250:13 | tainted | +| string.swift:248:5:248:5 | SSA def(c) | string.swift:248:18:248:18 | c | +| string.swift:248:5:248:5 | c | string.swift:248:5:248:5 | SSA def(c) | | string.swift:250:13:250:13 | [post] tainted | string.swift:251:13:251:13 | tainted | -| string.swift:250:13:250:13 | tainted | string.swift:250:13:250:55 | call to propertyListFromStringsFileFormat() | +| string.swift:250:13:250:13 | tainted | string.swift:250:13:250:68 | call to trimmingCharacters(in:) | | string.swift:250:13:250:13 | tainted | string.swift:251:13:251:13 | tainted | -| string.swift:251:13:251:13 | [post] tainted | string.swift:258:13:258:13 | tainted | -| string.swift:251:13:251:13 | tainted | string.swift:251:13:251:55 | call to propertyListFromStringsFileFormat() | -| string.swift:251:13:251:13 | tainted | string.swift:258:13:258:13 | tainted | -| string.swift:251:13:251:55 | call to propertyListFromStringsFileFormat() | string.swift:251:13:251:62 | ...[...] | -| string.swift:251:13:251:62 | ...[...] | string.swift:251:13:251:63 | ...! | -| string.swift:253:13:253:13 | [post] clean | string.swift:264:14:264:14 | clean | -| string.swift:253:13:253:13 | clean | string.swift:264:14:264:14 | clean | -| string.swift:254:5:254:5 | SSA def(line) | string.swift:255:15:255:15 | line | -| string.swift:254:5:254:5 | line | string.swift:254:5:254:5 | SSA def(line) | -| string.swift:254:11:254:11 | SSA def(stop) | string.swift:256:15:256:15 | stop | -| string.swift:254:11:254:11 | stop | string.swift:254:11:254:11 | SSA def(stop) | -| string.swift:258:13:258:13 | [post] tainted | string.swift:265:14:265:14 | tainted | -| string.swift:258:13:258:13 | tainted | string.swift:265:14:265:14 | tainted | +| string.swift:251:13:251:13 | [post] tainted | string.swift:252:13:252:13 | tainted | +| string.swift:251:13:251:13 | tainted | string.swift:251:13:251:70 | call to padding(toLength:withPad:startingAt:) | +| string.swift:251:13:251:13 | tainted | string.swift:252:13:252:13 | tainted | +| string.swift:251:52:251:52 | | string.swift:251:13:251:70 | call to padding(toLength:withPad:startingAt:) | +| string.swift:252:13:252:13 | [post] tainted | string.swift:253:13:253:13 | tainted | +| string.swift:252:13:252:13 | tainted | string.swift:252:13:252:69 | call to components(separatedBy:) | +| string.swift:252:13:252:13 | tainted | string.swift:253:13:253:13 | tainted | +| string.swift:253:13:253:13 | [post] tainted | string.swift:254:13:254:13 | tainted | +| string.swift:253:13:253:13 | tainted | string.swift:253:13:253:69 | call to components(separatedBy:) | +| string.swift:253:13:253:13 | tainted | string.swift:254:13:254:13 | tainted | +| string.swift:253:13:253:69 | call to components(separatedBy:) | string.swift:253:13:253:72 | ...[...] | +| string.swift:254:13:254:13 | [post] tainted | string.swift:255:13:255:13 | tainted | +| string.swift:254:13:254:13 | tainted | string.swift:254:13:254:40 | call to folding(options:locale:) | +| string.swift:254:13:254:13 | tainted | string.swift:255:13:255:13 | tainted | +| string.swift:255:13:255:13 | [post] tainted | string.swift:256:13:256:13 | tainted | +| string.swift:255:13:255:13 | tainted | string.swift:255:13:255:55 | call to propertyListFromStringsFileFormat() | +| string.swift:255:13:255:13 | tainted | string.swift:256:13:256:13 | tainted | +| string.swift:256:13:256:13 | [post] tainted | string.swift:263:13:263:13 | tainted | +| string.swift:256:13:256:13 | tainted | string.swift:256:13:256:55 | call to propertyListFromStringsFileFormat() | +| string.swift:256:13:256:13 | tainted | string.swift:263:13:263:13 | tainted | +| string.swift:256:13:256:55 | call to propertyListFromStringsFileFormat() | string.swift:256:13:256:62 | ...[...] | +| string.swift:256:13:256:62 | ...[...] | string.swift:256:13:256:63 | ...! | +| string.swift:258:13:258:13 | [post] clean | string.swift:269:14:269:14 | clean | +| string.swift:258:13:258:13 | clean | string.swift:269:14:269:14 | clean | | string.swift:259:5:259:5 | SSA def(line) | string.swift:260:15:260:15 | line | | string.swift:259:5:259:5 | line | string.swift:259:5:259:5 | SSA def(line) | | string.swift:259:11:259:11 | SSA def(stop) | string.swift:261:15:261:15 | stop | | string.swift:259:11:259:11 | stop | string.swift:259:11:259:11 | SSA def(stop) | -| string.swift:264:13:264:26 | [...] | string.swift:264:13:264:35 | call to joined(separator:) | -| string.swift:264:14:264:14 | clean | string.swift:264:21:264:21 | clean | -| string.swift:264:21:264:21 | clean | string.swift:265:23:265:23 | clean | -| string.swift:264:34:264:34 | default separator | string.swift:264:13:264:35 | call to joined(separator:) | -| string.swift:265:13:265:28 | [...] | string.swift:265:13:265:37 | call to joined(separator:) | -| string.swift:265:14:265:14 | tainted | string.swift:266:21:266:21 | tainted | -| string.swift:265:23:265:23 | clean | string.swift:266:14:266:14 | clean | -| string.swift:265:36:265:36 | default separator | string.swift:265:13:265:37 | call to joined(separator:) | -| string.swift:266:13:266:28 | [...] | string.swift:266:13:266:37 | call to joined(separator:) | -| string.swift:266:14:266:14 | clean | string.swift:269:13:269:13 | clean | -| string.swift:266:21:266:21 | tainted | string.swift:267:14:267:14 | tainted | -| string.swift:266:36:266:36 | default separator | string.swift:266:13:266:37 | call to joined(separator:) | -| string.swift:267:13:267:30 | [...] | string.swift:267:13:267:39 | call to joined(separator:) | -| string.swift:267:14:267:14 | tainted | string.swift:267:23:267:23 | tainted | -| string.swift:267:23:267:23 | tainted | string.swift:270:13:270:13 | tainted | -| string.swift:267:38:267:38 | default separator | string.swift:267:13:267:39 | call to joined(separator:) | -| string.swift:269:13:269:13 | [post] clean | string.swift:271:13:271:13 | clean | -| string.swift:269:13:269:13 | clean | string.swift:269:13:269:19 | .description | -| string.swift:269:13:269:13 | clean | string.swift:271:13:271:13 | clean | -| string.swift:270:13:270:13 | [post] tainted | string.swift:272:13:272:13 | tainted | -| string.swift:270:13:270:13 | tainted | string.swift:270:13:270:21 | .description | -| string.swift:270:13:270:13 | tainted | string.swift:272:13:272:13 | tainted | -| string.swift:271:13:271:13 | [post] clean | string.swift:273:13:273:13 | clean | -| string.swift:271:13:271:13 | clean | string.swift:271:13:271:19 | .debugDescription | -| string.swift:271:13:271:13 | clean | string.swift:273:13:273:13 | clean | -| string.swift:272:13:272:13 | [post] tainted | string.swift:274:13:274:13 | tainted | -| string.swift:272:13:272:13 | tainted | string.swift:272:13:272:21 | .debugDescription | -| string.swift:272:13:272:13 | tainted | string.swift:274:13:274:13 | tainted | -| string.swift:273:13:273:13 | [post] clean | string.swift:275:13:275:13 | clean | -| string.swift:273:13:273:13 | clean | string.swift:273:13:273:19 | .utf8 | -| string.swift:273:13:273:13 | clean | string.swift:275:13:275:13 | clean | -| string.swift:274:13:274:13 | [post] tainted | string.swift:276:13:276:13 | tainted | -| string.swift:274:13:274:13 | tainted | string.swift:274:13:274:21 | .utf8 | -| string.swift:274:13:274:13 | tainted | string.swift:276:13:276:13 | tainted | -| string.swift:275:13:275:13 | [post] clean | string.swift:277:13:277:13 | clean | -| string.swift:275:13:275:13 | clean | string.swift:275:13:275:19 | .utf16 | -| string.swift:275:13:275:13 | clean | string.swift:277:13:277:13 | clean | -| string.swift:276:13:276:13 | [post] tainted | string.swift:278:13:278:13 | tainted | -| string.swift:276:13:276:13 | tainted | string.swift:276:13:276:21 | .utf16 | -| string.swift:276:13:276:13 | tainted | string.swift:278:13:278:13 | tainted | -| string.swift:277:13:277:13 | [post] clean | string.swift:279:13:279:13 | clean | -| string.swift:277:13:277:13 | clean | string.swift:277:13:277:19 | .unicodeScalars | -| string.swift:277:13:277:13 | clean | string.swift:279:13:279:13 | clean | -| string.swift:278:13:278:13 | [post] tainted | string.swift:280:13:280:13 | tainted | -| string.swift:278:13:278:13 | tainted | string.swift:278:13:278:21 | .unicodeScalars | -| string.swift:278:13:278:13 | tainted | string.swift:280:13:280:13 | tainted | -| string.swift:279:13:279:13 | [post] clean | string.swift:281:13:281:13 | clean | -| string.swift:279:13:279:13 | clean | string.swift:279:13:279:19 | .utf8CString | -| string.swift:279:13:279:13 | clean | string.swift:281:13:281:13 | clean | -| string.swift:280:13:280:13 | [post] tainted | string.swift:282:13:282:13 | tainted | -| string.swift:280:13:280:13 | tainted | string.swift:280:13:280:21 | .utf8CString | -| string.swift:280:13:280:13 | tainted | string.swift:282:13:282:13 | tainted | -| string.swift:281:13:281:13 | [post] clean | string.swift:283:13:283:13 | clean | -| string.swift:281:13:281:13 | clean | string.swift:281:13:281:19 | .lazy | -| string.swift:281:13:281:13 | clean | string.swift:283:13:283:13 | clean | -| string.swift:282:13:282:13 | [post] tainted | string.swift:284:13:284:13 | tainted | -| string.swift:282:13:282:13 | tainted | string.swift:282:13:282:21 | .lazy | -| string.swift:282:13:282:13 | tainted | string.swift:284:13:284:13 | tainted | -| string.swift:283:13:283:13 | [post] clean | string.swift:285:13:285:13 | clean | -| string.swift:283:13:283:13 | clean | string.swift:283:13:283:19 | .capitalized | -| string.swift:283:13:283:13 | clean | string.swift:285:13:285:13 | clean | -| string.swift:284:13:284:13 | [post] tainted | string.swift:286:13:286:13 | tainted | -| string.swift:284:13:284:13 | tainted | string.swift:284:13:284:21 | .capitalized | -| string.swift:284:13:284:13 | tainted | string.swift:286:13:286:13 | tainted | -| string.swift:285:13:285:13 | [post] clean | string.swift:287:13:287:13 | clean | -| string.swift:285:13:285:13 | clean | string.swift:285:13:285:19 | .localizedCapitalized | -| string.swift:285:13:285:13 | clean | string.swift:287:13:287:13 | clean | -| string.swift:286:13:286:13 | [post] tainted | string.swift:288:13:288:13 | tainted | -| string.swift:286:13:286:13 | tainted | string.swift:286:13:286:21 | .localizedCapitalized | -| string.swift:286:13:286:13 | tainted | string.swift:288:13:288:13 | tainted | -| string.swift:287:13:287:13 | [post] clean | string.swift:289:13:289:13 | clean | -| string.swift:287:13:287:13 | clean | string.swift:287:13:287:19 | .localizedLowercase | -| string.swift:287:13:287:13 | clean | string.swift:289:13:289:13 | clean | -| string.swift:288:13:288:13 | [post] tainted | string.swift:290:13:290:13 | tainted | -| string.swift:288:13:288:13 | tainted | string.swift:288:13:288:21 | .localizedLowercase | -| string.swift:288:13:288:13 | tainted | string.swift:290:13:290:13 | tainted | -| string.swift:289:13:289:13 | [post] clean | string.swift:291:13:291:13 | clean | -| string.swift:289:13:289:13 | clean | string.swift:289:13:289:19 | .localizedUppercase | -| string.swift:289:13:289:13 | clean | string.swift:291:13:291:13 | clean | -| string.swift:290:13:290:13 | [post] tainted | string.swift:292:13:292:13 | tainted | -| string.swift:290:13:290:13 | tainted | string.swift:290:13:290:21 | .localizedUppercase | -| string.swift:290:13:290:13 | tainted | string.swift:292:13:292:13 | tainted | -| string.swift:291:13:291:13 | [post] clean | string.swift:293:13:293:13 | clean | -| string.swift:291:13:291:13 | clean | string.swift:291:13:291:19 | .decomposedStringWithCanonicalMapping | -| string.swift:291:13:291:13 | clean | string.swift:293:13:293:13 | clean | -| string.swift:292:13:292:13 | [post] tainted | string.swift:294:13:294:13 | tainted | -| string.swift:292:13:292:13 | tainted | string.swift:292:13:292:21 | .decomposedStringWithCanonicalMapping | -| string.swift:292:13:292:13 | tainted | string.swift:294:13:294:13 | tainted | -| string.swift:293:13:293:13 | [post] clean | string.swift:295:13:295:13 | clean | -| string.swift:293:13:293:13 | clean | string.swift:293:13:293:19 | .precomposedStringWithCompatibilityMapping | -| string.swift:293:13:293:13 | clean | string.swift:295:13:295:13 | clean | -| string.swift:294:13:294:13 | [post] tainted | string.swift:296:13:296:13 | tainted | -| string.swift:294:13:294:13 | tainted | string.swift:294:13:294:21 | .precomposedStringWithCompatibilityMapping | -| string.swift:294:13:294:13 | tainted | string.swift:296:13:296:13 | tainted | -| string.swift:295:13:295:13 | clean | string.swift:295:13:295:19 | .removingPercentEncoding | -| string.swift:295:13:295:19 | .removingPercentEncoding | string.swift:295:13:295:42 | ...! | -| string.swift:296:13:296:13 | tainted | string.swift:296:13:296:21 | .removingPercentEncoding | -| string.swift:296:13:296:21 | .removingPercentEncoding | string.swift:296:13:296:44 | ...! | -| string.swift:300:7:300:7 | SSA def(str1) | string.swift:301:13:301:13 | str1 | -| string.swift:300:14:300:22 | call to source2() | string.swift:300:7:300:7 | SSA def(str1) | -| string.swift:301:13:301:13 | [post] str1 | string.swift:302:13:302:13 | str1 | -| string.swift:301:13:301:13 | str1 | string.swift:302:13:302:13 | str1 | -| string.swift:302:13:302:13 | &... | string.swift:302:13:302:44 | call to remove(at:) | -| string.swift:302:13:302:13 | &... | string.swift:302:29:302:29 | str1 | -| string.swift:302:13:302:13 | [post] &... | string.swift:302:29:302:29 | str1 | -| string.swift:302:13:302:13 | str1 | string.swift:302:13:302:13 | &... | -| string.swift:302:29:302:29 | [post] str1 | string.swift:303:13:303:13 | str1 | -| string.swift:302:29:302:29 | str1 | string.swift:303:13:303:13 | str1 | -| string.swift:305:7:305:7 | SSA def(str2) | string.swift:306:13:306:13 | str2 | -| string.swift:305:14:305:22 | call to source2() | string.swift:305:7:305:7 | SSA def(str2) | -| string.swift:306:13:306:13 | [post] str2 | string.swift:307:3:307:3 | str2 | -| string.swift:306:13:306:13 | str2 | string.swift:307:3:307:3 | str2 | -| string.swift:307:3:307:3 | &... | string.swift:308:13:308:13 | str2 | -| string.swift:307:3:307:3 | [post] &... | string.swift:308:13:308:13 | str2 | -| string.swift:307:3:307:3 | str2 | string.swift:307:3:307:3 | &... | -| string.swift:310:7:310:7 | SSA def(str3) | string.swift:311:13:311:13 | str3 | -| string.swift:310:14:310:22 | call to source2() | string.swift:310:7:310:7 | SSA def(str3) | -| string.swift:311:13:311:13 | [post] str3 | string.swift:312:3:312:3 | str3 | -| string.swift:311:13:311:13 | str3 | string.swift:312:3:312:3 | str3 | -| string.swift:312:3:312:3 | &... | string.swift:313:13:313:13 | str3 | -| string.swift:312:3:312:3 | [post] &... | string.swift:313:13:313:13 | str3 | -| string.swift:312:3:312:3 | str3 | string.swift:312:3:312:3 | &... | -| string.swift:315:7:315:7 | SSA def(str4) | string.swift:316:13:316:13 | str4 | -| string.swift:315:14:315:22 | call to source2() | string.swift:315:7:315:7 | SSA def(str4) | -| string.swift:316:13:316:13 | [post] str4 | string.swift:317:13:317:13 | str4 | -| string.swift:316:13:316:13 | str4 | string.swift:317:13:317:13 | str4 | -| string.swift:317:13:317:13 | &... | string.swift:317:13:317:30 | call to removeFirst() | -| string.swift:317:13:317:13 | &... | string.swift:318:13:318:13 | str4 | -| string.swift:317:13:317:13 | [post] &... | string.swift:318:13:318:13 | str4 | -| string.swift:317:13:317:13 | str4 | string.swift:317:13:317:13 | &... | -| string.swift:318:13:318:13 | [post] str4 | string.swift:319:3:319:3 | str4 | -| string.swift:318:13:318:13 | str4 | string.swift:319:3:319:3 | str4 | -| string.swift:319:3:319:3 | &... | string.swift:320:13:320:13 | str4 | -| string.swift:319:3:319:3 | [post] &... | string.swift:320:13:320:13 | str4 | -| string.swift:319:3:319:3 | str4 | string.swift:319:3:319:3 | &... | -| string.swift:320:13:320:13 | [post] str4 | string.swift:321:13:321:13 | str4 | -| string.swift:320:13:320:13 | str4 | string.swift:321:13:321:13 | str4 | -| string.swift:321:13:321:13 | &... | string.swift:321:13:321:29 | call to removeLast() | -| string.swift:321:13:321:13 | &... | string.swift:322:13:322:13 | str4 | -| string.swift:321:13:321:13 | [post] &... | string.swift:322:13:322:13 | str4 | -| string.swift:321:13:321:13 | str4 | string.swift:321:13:321:13 | &... | -| string.swift:322:13:322:13 | [post] str4 | string.swift:323:3:323:3 | str4 | -| string.swift:322:13:322:13 | str4 | string.swift:323:3:323:3 | str4 | -| string.swift:323:3:323:3 | &... | string.swift:324:13:324:13 | str4 | -| string.swift:323:3:323:3 | [post] &... | string.swift:324:13:324:13 | str4 | -| string.swift:323:3:323:3 | str4 | string.swift:323:3:323:3 | &... | -| string.swift:326:7:326:7 | SSA def(str5) | string.swift:327:13:327:13 | str5 | -| string.swift:326:14:326:22 | call to source2() | string.swift:326:7:326:7 | SSA def(str5) | -| string.swift:327:13:327:13 | [post] str5 | string.swift:328:3:328:3 | str5 | -| string.swift:327:13:327:13 | str5 | string.swift:328:3:328:3 | str5 | -| string.swift:328:3:328:3 | &... | string.swift:328:23:328:23 | str5 | -| string.swift:328:3:328:3 | [post] &... | string.swift:328:23:328:23 | str5 | -| string.swift:328:3:328:3 | str5 | string.swift:328:3:328:3 | &... | -| string.swift:328:23:328:23 | [post] str5 | string.swift:328:43:328:43 | str5 | -| string.swift:328:23:328:23 | str5 | string.swift:328:43:328:43 | str5 | -| string.swift:328:43:328:43 | [post] str5 | string.swift:328:54:328:54 | str5 | -| string.swift:328:43:328:43 | str5 | string.swift:328:54:328:54 | str5 | -| string.swift:328:54:328:54 | [post] str5 | string.swift:329:13:329:13 | str5 | -| string.swift:328:54:328:54 | str5 | string.swift:329:13:329:13 | str5 | -| string.swift:331:7:331:7 | SSA def(str6) | string.swift:332:13:332:13 | str6 | -| string.swift:331:14:331:22 | call to source2() | string.swift:331:7:331:7 | SSA def(str6) | -| string.swift:332:13:332:13 | [post] str6 | string.swift:333:3:333:3 | str6 | -| string.swift:332:13:332:13 | str6 | string.swift:333:3:333:3 | str6 | -| string.swift:333:3:333:3 | &... | string.swift:334:13:334:13 | str6 | -| string.swift:333:3:333:3 | [post] &... | string.swift:334:13:334:13 | str6 | -| string.swift:333:3:333:3 | str6 | string.swift:333:3:333:3 | &... | -| string.swift:337:38:337:38 | | string.swift:337:33:337:40 | call to Data.init(_:) | -| string.swift:340:7:340:7 | SSA def(stringClean) | string.swift:343:12:343:12 | stringClean | -| string.swift:340:21:340:74 | call to String.init(data:encoding:) | string.swift:340:7:340:7 | SSA def(stringClean) | -| string.swift:340:34:340:41 | call to Data.init(_:) | string.swift:340:21:340:74 | call to String.init(data:encoding:) | -| string.swift:340:39:340:39 | | string.swift:340:34:340:41 | call to Data.init(_:) | -| string.swift:341:7:341:7 | SSA def(stringTainted) | string.swift:344:12:344:12 | stringTainted | -| string.swift:341:23:341:77 | call to String.init(data:encoding:) | string.swift:341:7:341:7 | SSA def(stringTainted) | -| string.swift:341:36:341:44 | call to source3() | string.swift:341:23:341:77 | call to String.init(data:encoding:) | -| string.swift:343:12:343:12 | stringClean | string.swift:343:12:343:23 | ...! | -| string.swift:344:12:344:12 | stringTainted | string.swift:344:12:344:25 | ...! | -| string.swift:346:30:346:37 | call to Data.init(_:) | string.swift:346:13:346:53 | call to String.init(decoding:as:) | -| string.swift:346:35:346:35 | | string.swift:346:30:346:37 | call to Data.init(_:) | -| string.swift:347:30:347:38 | call to source3() | string.swift:347:13:347:54 | call to String.init(decoding:as:) | -| string.swift:351:7:351:7 | SSA def(clean) | string.swift:354:3:354:3 | clean | -| string.swift:351:15:351:15 | | string.swift:351:7:351:7 | SSA def(clean) | -| string.swift:352:7:352:7 | SSA def(tainted) | string.swift:359:3:359:3 | tainted | -| string.swift:352:17:352:25 | call to source2() | string.swift:352:7:352:7 | SSA def(tainted) | -| string.swift:354:3:354:3 | &... | string.swift:365:3:365:3 | clean | -| string.swift:354:3:354:3 | [post] &... | string.swift:365:3:365:3 | clean | -| string.swift:354:3:354:3 | clean | string.swift:354:3:354:3 | &... | -| string.swift:355:5:355:5 | SSA def(buffer) | string.swift:356:15:356:15 | buffer | -| string.swift:355:5:355:5 | buffer | string.swift:355:5:355:5 | SSA def(buffer) | -| string.swift:356:15:356:15 | buffer | string.swift:357:15:357:15 | buffer | -| string.swift:357:15:357:22 | .baseAddress | string.swift:357:15:357:33 | ...! | -| string.swift:359:3:359:3 | &... | string.swift:369:3:369:3 | tainted | -| string.swift:359:3:359:3 | [post] &... | string.swift:369:3:369:3 | tainted | -| string.swift:359:3:359:3 | tainted | string.swift:359:3:359:3 | &... | -| string.swift:360:5:360:5 | SSA def(buffer) | string.swift:361:15:361:15 | buffer | -| string.swift:360:5:360:5 | buffer | string.swift:360:5:360:5 | SSA def(buffer) | -| string.swift:361:15:361:15 | buffer | string.swift:362:15:362:15 | buffer | -| string.swift:362:15:362:22 | .baseAddress | string.swift:362:15:362:33 | ...! | -| string.swift:365:3:365:3 | [post] clean | string.swift:373:3:373:3 | clean | -| string.swift:365:3:365:3 | clean | string.swift:373:3:373:3 | clean | -| string.swift:366:5:366:5 | SSA def(ptr) | string.swift:367:15:367:15 | ptr | -| string.swift:366:5:366:5 | ptr | string.swift:366:5:366:5 | SSA def(ptr) | -| string.swift:369:3:369:3 | [post] tainted | string.swift:377:3:377:3 | tainted | -| string.swift:369:3:369:3 | tainted | string.swift:377:3:377:3 | tainted | -| string.swift:370:5:370:5 | SSA def(ptr) | string.swift:371:15:371:15 | ptr | -| string.swift:370:5:370:5 | ptr | string.swift:370:5:370:5 | SSA def(ptr) | -| string.swift:373:3:373:3 | [post] clean | string.swift:382:22:382:22 | clean | -| string.swift:373:3:373:3 | clean | string.swift:382:22:382:22 | clean | -| string.swift:374:5:374:5 | SSA def(ptr) | string.swift:375:15:375:15 | ptr | -| string.swift:374:5:374:5 | ptr | string.swift:374:5:374:5 | SSA def(ptr) | -| string.swift:377:3:377:3 | [post] tainted | string.swift:389:22:389:22 | tainted | -| string.swift:377:3:377:3 | tainted | string.swift:389:22:389:22 | tainted | -| string.swift:378:5:378:5 | SSA def(ptr) | string.swift:379:15:379:15 | ptr | -| string.swift:378:5:378:5 | ptr | string.swift:378:5:378:5 | SSA def(ptr) | -| string.swift:382:7:382:7 | SSA def(arrayString1) | string.swift:383:13:383:13 | arrayString1 | -| string.swift:382:22:382:22 | [post] clean | string.swift:397:3:397:3 | clean | -| string.swift:382:22:382:22 | clean | string.swift:382:22:382:63 | call to cString(using:) | -| string.swift:382:22:382:22 | clean | string.swift:397:3:397:3 | clean | -| string.swift:382:22:382:63 | call to cString(using:) | string.swift:382:22:382:64 | ...! | -| string.swift:382:22:382:64 | ...! | string.swift:382:7:382:7 | SSA def(arrayString1) | -| string.swift:383:13:383:13 | arrayString1 | string.swift:384:3:384:3 | arrayString1 | -| string.swift:384:3:384:3 | [post] arrayString1 | string.swift:391:3:391:3 | arrayString1 | -| string.swift:384:3:384:3 | arrayString1 | string.swift:391:3:391:3 | arrayString1 | -| string.swift:385:5:385:5 | SSA def(buffer) | string.swift:386:15:386:15 | buffer | -| string.swift:385:5:385:5 | buffer | string.swift:385:5:385:5 | SSA def(buffer) | -| string.swift:386:15:386:15 | buffer | string.swift:387:31:387:31 | buffer | -| string.swift:387:31:387:38 | .baseAddress | string.swift:387:31:387:49 | ...! | -| string.swift:387:31:387:49 | ...! | string.swift:387:15:387:50 | call to String.init(cString:) | -| string.swift:389:7:389:7 | SSA def(arrayString2) | string.swift:390:13:390:13 | arrayString2 | -| string.swift:389:22:389:22 | [post] tainted | string.swift:408:3:408:3 | tainted | -| string.swift:389:22:389:22 | tainted | string.swift:389:22:389:65 | call to cString(using:) | -| string.swift:389:22:389:22 | tainted | string.swift:408:3:408:3 | tainted | -| string.swift:389:22:389:65 | call to cString(using:) | string.swift:389:22:389:66 | ...! | -| string.swift:389:22:389:66 | ...! | string.swift:389:7:389:7 | SSA def(arrayString2) | -| string.swift:392:5:392:5 | SSA def(buffer) | string.swift:393:15:393:15 | buffer | -| string.swift:392:5:392:5 | buffer | string.swift:392:5:392:5 | SSA def(buffer) | -| string.swift:393:15:393:15 | buffer | string.swift:394:31:394:31 | buffer | -| string.swift:394:31:394:38 | .baseAddress | string.swift:394:31:394:49 | ...! | -| string.swift:394:31:394:49 | ...! | string.swift:394:15:394:50 | call to String.init(cString:) | -| string.swift:397:3:397:3 | [post] clean | string.swift:420:3:420:3 | clean | -| string.swift:397:3:397:3 | clean | string.swift:420:3:420:3 | clean | -| string.swift:398:5:398:5 | SSA def(ptr) | string.swift:399:15:399:15 | ptr | -| string.swift:398:5:398:5 | ptr | string.swift:398:5:398:5 | SSA def(ptr) | -| string.swift:399:15:399:15 | ptr | string.swift:400:38:400:38 | ptr | -| string.swift:400:38:400:38 | ptr | string.swift:400:15:400:41 | call to String.init(platformString:) | -| string.swift:400:38:400:38 | ptr | string.swift:402:45:402:45 | ptr | -| string.swift:402:9:402:9 | SSA def(buffer) | string.swift:403:29:403:29 | buffer | -| string.swift:402:18:402:59 | call to UnsafeBufferPointer.init(start:count:) | string.swift:402:9:402:9 | SSA def(buffer) | -| string.swift:403:9:403:9 | SSA def(arrayString) | string.swift:405:15:405:15 | arrayString | -| string.swift:403:23:403:35 | call to Array.init(_:) | string.swift:403:9:403:9 | SSA def(arrayString) | -| string.swift:403:29:403:29 | buffer | string.swift:404:15:404:15 | buffer | -| string.swift:405:15:405:15 | arrayString | string.swift:406:38:406:38 | arrayString | -| string.swift:406:38:406:38 | arrayString | string.swift:406:15:406:49 | call to String.init(platformString:) | -| string.swift:408:3:408:3 | [post] tainted | string.swift:425:3:425:3 | tainted | -| string.swift:408:3:408:3 | tainted | string.swift:425:3:425:3 | tainted | -| string.swift:409:5:409:5 | SSA def(ptr) | string.swift:410:15:410:15 | ptr | -| string.swift:409:5:409:5 | ptr | string.swift:409:5:409:5 | SSA def(ptr) | -| string.swift:410:15:410:15 | ptr | string.swift:411:38:411:38 | ptr | -| string.swift:411:38:411:38 | ptr | string.swift:411:15:411:41 | call to String.init(platformString:) | -| string.swift:411:38:411:38 | ptr | string.swift:413:45:413:45 | ptr | -| string.swift:413:9:413:9 | SSA def(buffer) | string.swift:414:29:414:29 | buffer | -| string.swift:413:18:413:59 | call to UnsafeBufferPointer.init(start:count:) | string.swift:413:9:413:9 | SSA def(buffer) | -| string.swift:414:9:414:9 | SSA def(arrayString) | string.swift:416:15:416:15 | arrayString | -| string.swift:414:23:414:35 | call to Array.init(_:) | string.swift:414:9:414:9 | SSA def(arrayString) | -| string.swift:414:29:414:29 | buffer | string.swift:415:15:415:15 | buffer | -| string.swift:416:15:416:15 | arrayString | string.swift:417:38:417:38 | arrayString | -| string.swift:417:38:417:38 | arrayString | string.swift:417:15:417:49 | call to String.init(platformString:) | -| string.swift:421:5:421:5 | SSA def(ptr) | string.swift:422:15:422:15 | ptr | -| string.swift:421:5:421:5 | ptr | string.swift:421:5:421:5 | SSA def(ptr) | -| string.swift:422:15:422:15 | ptr | string.swift:423:15:423:15 | ptr | -| string.swift:423:15:423:19 | .baseAddress | string.swift:423:15:423:30 | ...! | -| string.swift:426:5:426:5 | SSA def(ptr) | string.swift:427:15:427:15 | ptr | -| string.swift:426:5:426:5 | ptr | string.swift:426:5:426:5 | SSA def(ptr) | -| string.swift:427:15:427:15 | ptr | string.swift:428:15:428:15 | ptr | -| string.swift:428:15:428:19 | .baseAddress | string.swift:428:15:428:30 | ...! | -| string.swift:435:7:435:31 | SSA def(cleanUInt8Values) | string.swift:455:27:455:27 | cleanUInt8Values | -| string.swift:435:35:435:55 | [...] | string.swift:435:7:435:31 | SSA def(cleanUInt8Values) | -| string.swift:436:7:436:7 | SSA def(taintedUInt8Values) | string.swift:456:27:456:27 | taintedUInt8Values | -| string.swift:436:28:436:36 | call to source4() | string.swift:436:7:436:7 | SSA def(taintedUInt8Values) | -| string.swift:439:6:439:46 | SSA def(buffer) | string.swift:440:17:440:17 | buffer | -| string.swift:439:6:439:46 | buffer | string.swift:439:6:439:46 | SSA def(buffer) | -| string.swift:440:17:440:17 | buffer | string.swift:441:15:441:15 | buffer | -| string.swift:441:15:441:15 | [post] buffer | string.swift:442:17:442:17 | buffer | -| string.swift:441:15:441:15 | buffer | string.swift:442:17:442:17 | buffer | -| string.swift:447:6:447:46 | SSA def(buffer) | string.swift:448:17:448:17 | buffer | -| string.swift:447:6:447:46 | buffer | string.swift:447:6:447:46 | SSA def(buffer) | -| string.swift:448:17:448:17 | buffer | string.swift:449:15:449:15 | buffer | -| string.swift:449:15:449:15 | [post] buffer | string.swift:450:17:450:17 | buffer | -| string.swift:449:15:449:15 | buffer | string.swift:450:17:450:17 | buffer | -| string.swift:455:13:455:75 | call to String.init(bytes:encoding:) | string.swift:455:13:455:76 | ...! | -| string.swift:455:27:455:27 | cleanUInt8Values | string.swift:455:13:455:75 | call to String.init(bytes:encoding:) | -| string.swift:455:27:455:27 | cleanUInt8Values | string.swift:458:29:458:29 | cleanUInt8Values | -| string.swift:456:13:456:77 | call to String.init(bytes:encoding:) | string.swift:456:13:456:78 | ...! | -| string.swift:456:27:456:27 | taintedUInt8Values | string.swift:456:13:456:77 | call to String.init(bytes:encoding:) | -| string.swift:456:27:456:27 | taintedUInt8Values | string.swift:459:29:459:29 | taintedUInt8Values | -| string.swift:458:29:458:29 | cleanUInt8Values | string.swift:458:13:458:45 | call to String.init(cString:) | -| string.swift:458:29:458:29 | cleanUInt8Values | string.swift:461:8:461:8 | cleanUInt8Values | -| string.swift:459:29:459:29 | taintedUInt8Values | string.swift:459:13:459:47 | call to String.init(cString:) | -| string.swift:459:29:459:29 | taintedUInt8Values | string.swift:467:8:467:8 | taintedUInt8Values | -| string.swift:461:8:461:8 | [post] cleanUInt8Values | string.swift:474:8:474:8 | cleanUInt8Values | -| string.swift:461:8:461:8 | cleanUInt8Values | string.swift:474:8:474:8 | cleanUInt8Values | -| string.swift:461:8:466:4 | call to withUnsafeBufferPointer(_:) | string.swift:461:3:466:4 | try! ... | -| string.swift:462:6:462:39 | SSA def(buffer) | string.swift:463:15:463:15 | buffer | -| string.swift:462:6:462:39 | buffer | string.swift:462:6:462:39 | SSA def(buffer) | -| string.swift:463:15:463:15 | buffer | string.swift:464:15:464:15 | buffer | -| string.swift:464:15:464:15 | [post] buffer | string.swift:465:31:465:31 | buffer | -| string.swift:464:15:464:15 | buffer | string.swift:465:31:465:31 | buffer | -| string.swift:464:15:464:22 | .baseAddress | string.swift:464:15:464:33 | ...! | -| string.swift:465:31:465:38 | .baseAddress | string.swift:465:31:465:49 | ...! | -| string.swift:465:31:465:49 | ...! | string.swift:465:15:465:50 | call to String.init(cString:) | -| string.swift:467:8:467:8 | [post] taintedUInt8Values | string.swift:480:8:480:8 | taintedUInt8Values | -| string.swift:467:8:467:8 | taintedUInt8Values | string.swift:480:8:480:8 | taintedUInt8Values | -| string.swift:467:8:472:4 | call to withUnsafeBufferPointer(_:) | string.swift:467:3:472:4 | try! ... | -| string.swift:468:6:468:39 | SSA def(buffer) | string.swift:469:15:469:15 | buffer | -| string.swift:468:6:468:39 | buffer | string.swift:468:6:468:39 | SSA def(buffer) | -| string.swift:469:15:469:15 | buffer | string.swift:470:15:470:15 | buffer | -| string.swift:470:15:470:15 | [post] buffer | string.swift:471:31:471:31 | buffer | -| string.swift:470:15:470:15 | buffer | string.swift:471:31:471:31 | buffer | -| string.swift:470:15:470:22 | .baseAddress | string.swift:470:15:470:33 | ...! | -| string.swift:471:31:471:38 | .baseAddress | string.swift:471:31:471:49 | ...! | -| string.swift:471:31:471:49 | ...! | string.swift:471:15:471:50 | call to String.init(cString:) | -| string.swift:474:8:474:8 | cleanUInt8Values | string.swift:474:8:474:8 | &... | -| string.swift:474:8:479:4 | call to withUnsafeMutableBytes(_:) | string.swift:474:3:479:4 | try! ... | -| string.swift:475:6:475:14 | SSA def(buffer) | string.swift:476:15:476:15 | buffer | -| string.swift:475:6:475:14 | buffer | string.swift:475:6:475:14 | SSA def(buffer) | -| string.swift:476:15:476:15 | [post] buffer | string.swift:477:15:477:15 | buffer | -| string.swift:476:15:476:15 | buffer | string.swift:477:15:477:15 | buffer | -| string.swift:477:15:477:15 | [post] buffer | string.swift:478:35:478:35 | buffer | -| string.swift:477:15:477:15 | buffer | string.swift:478:35:478:35 | buffer | -| string.swift:477:15:477:22 | .baseAddress | string.swift:477:15:477:33 | ...! | -| string.swift:478:15:478:129 | call to String.init(bytesNoCopy:length:encoding:freeWhenDone:) | string.swift:478:15:478:130 | ...! | -| string.swift:478:35:478:35 | [post] buffer | string.swift:478:64:478:64 | buffer | -| string.swift:478:35:478:35 | buffer | string.swift:478:64:478:64 | buffer | -| string.swift:478:35:478:42 | .baseAddress | string.swift:478:35:478:53 | ...! | -| string.swift:480:8:480:8 | taintedUInt8Values | string.swift:480:8:480:8 | &... | -| string.swift:480:8:485:4 | call to withUnsafeMutableBytes(_:) | string.swift:480:3:485:4 | try! ... | -| string.swift:481:6:481:14 | SSA def(buffer) | string.swift:482:15:482:15 | buffer | -| string.swift:481:6:481:14 | buffer | string.swift:481:6:481:14 | SSA def(buffer) | -| string.swift:482:15:482:15 | [post] buffer | string.swift:483:15:483:15 | buffer | -| string.swift:482:15:482:15 | buffer | string.swift:483:15:483:15 | buffer | -| string.swift:483:15:483:15 | [post] buffer | string.swift:484:35:484:35 | buffer | -| string.swift:483:15:483:15 | buffer | string.swift:484:35:484:35 | buffer | -| string.swift:483:15:483:22 | .baseAddress | string.swift:483:15:483:33 | ...! | -| string.swift:484:15:484:129 | call to String.init(bytesNoCopy:length:encoding:freeWhenDone:) | string.swift:484:15:484:130 | ...! | -| string.swift:484:35:484:35 | [post] buffer | string.swift:484:64:484:64 | buffer | -| string.swift:484:35:484:35 | buffer | string.swift:484:64:484:64 | buffer | -| string.swift:484:35:484:42 | .baseAddress | string.swift:484:35:484:53 | ...! | -| string.swift:491:7:491:31 | SSA def(cleanCCharValues) | string.swift:494:3:494:3 | cleanCCharValues | -| string.swift:491:35:491:55 | [...] | string.swift:491:7:491:31 | SSA def(cleanCCharValues) | -| string.swift:492:7:492:33 | SSA def(taintedCCharValues) | string.swift:502:3:502:3 | taintedCCharValues | -| string.swift:492:37:492:45 | call to source5() | string.swift:492:7:492:33 | SSA def(taintedCCharValues) | -| string.swift:494:3:494:3 | [post] cleanCCharValues | string.swift:511:29:511:29 | cleanCCharValues | -| string.swift:494:3:494:3 | cleanCCharValues | string.swift:511:29:511:29 | cleanCCharValues | -| string.swift:495:5:495:5 | SSA def(ptr) | string.swift:496:15:496:15 | ptr | -| string.swift:495:5:495:5 | ptr | string.swift:495:5:495:5 | SSA def(ptr) | -| string.swift:496:15:496:15 | ptr | string.swift:497:15:497:15 | ptr | -| string.swift:497:15:497:15 | [post] ptr | string.swift:498:34:498:34 | ptr | -| string.swift:497:15:497:15 | ptr | string.swift:498:34:498:34 | ptr | -| string.swift:497:15:497:19 | .baseAddress | string.swift:497:15:497:30 | ...! | -| string.swift:498:15:498:50 | call to String.init(utf8String:) | string.swift:498:15:498:51 | ...! | -| string.swift:498:34:498:34 | [post] ptr | string.swift:499:38:499:38 | ptr | -| string.swift:498:34:498:34 | ptr | string.swift:499:38:499:38 | ptr | -| string.swift:498:34:498:38 | .baseAddress | string.swift:498:34:498:49 | ...! | -| string.swift:498:34:498:49 | ...! | string.swift:498:15:498:50 | call to String.init(utf8String:) | -| string.swift:499:15:499:54 | call to String.init(validatingUTF8:) | string.swift:499:15:499:55 | ...! | -| string.swift:499:38:499:38 | [post] ptr | string.swift:500:31:500:31 | ptr | -| string.swift:499:38:499:38 | ptr | string.swift:500:31:500:31 | ptr | -| string.swift:499:38:499:42 | .baseAddress | string.swift:499:38:499:53 | ...! | -| string.swift:499:38:499:53 | ...! | string.swift:499:15:499:54 | call to String.init(validatingUTF8:) | -| string.swift:500:31:500:35 | .baseAddress | string.swift:500:31:500:46 | ...! | -| string.swift:500:31:500:46 | ...! | string.swift:500:15:500:47 | call to String.init(cString:) | -| string.swift:502:3:502:3 | [post] taintedCCharValues | string.swift:512:29:512:29 | taintedCCharValues | -| string.swift:502:3:502:3 | taintedCCharValues | string.swift:512:29:512:29 | taintedCCharValues | -| string.swift:503:5:503:5 | SSA def(ptr) | string.swift:504:15:504:15 | ptr | -| string.swift:503:5:503:5 | ptr | string.swift:503:5:503:5 | SSA def(ptr) | -| string.swift:504:15:504:15 | ptr | string.swift:505:15:505:15 | ptr | -| string.swift:505:15:505:15 | [post] ptr | string.swift:506:34:506:34 | ptr | -| string.swift:505:15:505:15 | ptr | string.swift:506:34:506:34 | ptr | -| string.swift:505:15:505:19 | .baseAddress | string.swift:505:15:505:30 | ...! | -| string.swift:506:15:506:50 | call to String.init(utf8String:) | string.swift:506:15:506:51 | ...! | -| string.swift:506:34:506:34 | [post] ptr | string.swift:507:38:507:38 | ptr | -| string.swift:506:34:506:34 | ptr | string.swift:507:38:507:38 | ptr | -| string.swift:506:34:506:38 | .baseAddress | string.swift:506:34:506:49 | ...! | -| string.swift:506:34:506:49 | ...! | string.swift:506:15:506:50 | call to String.init(utf8String:) | -| string.swift:507:15:507:54 | call to String.init(validatingUTF8:) | string.swift:507:15:507:55 | ...! | -| string.swift:507:38:507:38 | [post] ptr | string.swift:508:31:508:31 | ptr | -| string.swift:507:38:507:38 | ptr | string.swift:508:31:508:31 | ptr | -| string.swift:507:38:507:42 | .baseAddress | string.swift:507:38:507:53 | ...! | -| string.swift:507:38:507:53 | ...! | string.swift:507:15:507:54 | call to String.init(validatingUTF8:) | -| string.swift:508:31:508:35 | .baseAddress | string.swift:508:31:508:46 | ...! | -| string.swift:508:31:508:46 | ...! | string.swift:508:15:508:47 | call to String.init(cString:) | -| string.swift:511:29:511:29 | cleanCCharValues | string.swift:511:13:511:45 | call to String.init(cString:) | -| string.swift:512:29:512:29 | taintedCCharValues | string.swift:512:13:512:47 | call to String.init(cString:) | -| string.swift:518:7:518:35 | SSA def(cleanUnicharValues) | string.swift:521:3:521:3 | cleanUnicharValues | -| string.swift:518:39:518:59 | [...] | string.swift:518:7:518:35 | SSA def(cleanUnicharValues) | -| string.swift:519:7:519:37 | SSA def(taintedUnicharValues) | string.swift:528:3:528:3 | taintedUnicharValues | -| string.swift:519:41:519:49 | call to source6() | string.swift:519:7:519:37 | SSA def(taintedUnicharValues) | -| string.swift:522:5:522:5 | SSA def(ptr) | string.swift:523:15:523:15 | ptr | -| string.swift:522:5:522:5 | ptr | string.swift:522:5:522:5 | SSA def(ptr) | -| string.swift:523:15:523:15 | ptr | string.swift:524:15:524:15 | ptr | -| string.swift:524:15:524:15 | [post] ptr | string.swift:525:38:525:38 | ptr | -| string.swift:524:15:524:15 | ptr | string.swift:525:38:525:38 | ptr | -| string.swift:524:15:524:19 | .baseAddress | string.swift:524:15:524:30 | ...! | -| string.swift:525:38:525:38 | [post] ptr | string.swift:525:63:525:63 | ptr | -| string.swift:525:38:525:38 | ptr | string.swift:525:63:525:63 | ptr | -| string.swift:525:38:525:42 | .baseAddress | string.swift:525:38:525:53 | ...! | -| string.swift:525:38:525:53 | ...! | string.swift:525:15:525:72 | call to String.init(utf16CodeUnits:count:) | -| string.swift:525:63:525:63 | [post] ptr | string.swift:526:44:526:44 | ptr | -| string.swift:525:63:525:63 | ptr | string.swift:526:44:526:44 | ptr | -| string.swift:526:44:526:44 | [post] ptr | string.swift:526:69:526:69 | ptr | -| string.swift:526:44:526:44 | ptr | string.swift:526:69:526:69 | ptr | -| string.swift:526:44:526:48 | .baseAddress | string.swift:526:44:526:59 | ...! | -| string.swift:526:44:526:59 | ...! | string.swift:526:15:526:99 | call to String.init(utf16CodeUnitsNoCopy:count:freeWhenDone:) | -| string.swift:529:5:529:5 | SSA def(ptr) | string.swift:530:15:530:15 | ptr | -| string.swift:529:5:529:5 | ptr | string.swift:529:5:529:5 | SSA def(ptr) | -| string.swift:530:15:530:15 | ptr | string.swift:531:15:531:15 | ptr | -| string.swift:531:15:531:15 | [post] ptr | string.swift:532:38:532:38 | ptr | -| string.swift:531:15:531:15 | ptr | string.swift:532:38:532:38 | ptr | -| string.swift:531:15:531:19 | .baseAddress | string.swift:531:15:531:30 | ...! | -| string.swift:532:38:532:38 | [post] ptr | string.swift:532:63:532:63 | ptr | -| string.swift:532:38:532:38 | ptr | string.swift:532:63:532:63 | ptr | -| string.swift:532:38:532:42 | .baseAddress | string.swift:532:38:532:53 | ...! | -| string.swift:532:38:532:53 | ...! | string.swift:532:15:532:72 | call to String.init(utf16CodeUnits:count:) | -| string.swift:532:63:532:63 | [post] ptr | string.swift:533:44:533:44 | ptr | -| string.swift:532:63:532:63 | ptr | string.swift:533:44:533:44 | ptr | -| string.swift:533:44:533:44 | [post] ptr | string.swift:533:69:533:69 | ptr | -| string.swift:533:44:533:44 | ptr | string.swift:533:69:533:69 | ptr | -| string.swift:533:44:533:48 | .baseAddress | string.swift:533:44:533:59 | ...! | -| string.swift:533:44:533:59 | ...! | string.swift:533:15:533:99 | call to String.init(utf16CodeUnitsNoCopy:count:freeWhenDone:) | -| string.swift:540:7:540:7 | SSA def(tainted) | string.swift:544:14:544:14 | tainted | -| string.swift:540:17:540:25 | call to source2() | string.swift:540:7:540:7 | SSA def(tainted) | -| string.swift:544:7:544:7 | SSA def(sub1) | string.swift:545:13:545:13 | sub1 | -| string.swift:544:14:544:14 | [post] tainted | string.swift:544:22:544:22 | tainted | -| string.swift:544:14:544:14 | tainted | string.swift:544:14:544:61 | ...[...] | -| string.swift:544:14:544:14 | tainted | string.swift:544:22:544:22 | tainted | -| string.swift:544:14:544:61 | ...[...] | string.swift:544:7:544:7 | SSA def(sub1) | -| string.swift:544:22:544:22 | [post] tainted | string.swift:544:45:544:45 | tainted | -| string.swift:544:22:544:22 | tainted | string.swift:544:45:544:45 | tainted | -| string.swift:544:45:544:45 | [post] tainted | string.swift:548:14:548:14 | tainted | -| string.swift:544:45:544:45 | tainted | string.swift:548:14:548:14 | tainted | -| string.swift:545:13:545:13 | [post] sub1 | string.swift:546:20:546:20 | sub1 | -| string.swift:545:13:545:13 | sub1 | string.swift:546:20:546:20 | sub1 | -| string.swift:546:20:546:20 | sub1 | string.swift:546:13:546:24 | call to String.init(_:) | -| string.swift:548:7:548:7 | SSA def(sub2) | string.swift:549:13:549:13 | sub2 | -| string.swift:548:14:548:14 | [post] tainted | string.swift:552:14:552:14 | tainted | -| string.swift:548:14:548:14 | tainted | string.swift:548:14:548:31 | call to prefix(_:) | -| string.swift:548:14:548:14 | tainted | string.swift:552:14:552:14 | tainted | -| string.swift:548:14:548:31 | call to prefix(_:) | string.swift:548:7:548:7 | SSA def(sub2) | -| string.swift:549:13:549:13 | sub2 | string.swift:550:20:550:20 | sub2 | -| string.swift:550:20:550:20 | sub2 | string.swift:550:13:550:24 | call to String.init(_:) | -| string.swift:552:7:552:7 | SSA def(sub3) | string.swift:553:13:553:13 | sub3 | -| string.swift:552:14:552:14 | [post] tainted | string.swift:552:38:552:38 | tainted | -| string.swift:552:14:552:14 | tainted | string.swift:552:14:552:54 | call to prefix(through:) | -| string.swift:552:14:552:14 | tainted | string.swift:552:38:552:38 | tainted | -| string.swift:552:14:552:54 | call to prefix(through:) | string.swift:552:7:552:7 | SSA def(sub3) | -| string.swift:552:38:552:38 | [post] tainted | string.swift:556:14:556:14 | tainted | -| string.swift:552:38:552:38 | tainted | string.swift:556:14:556:14 | tainted | -| string.swift:553:13:553:13 | sub3 | string.swift:554:20:554:20 | sub3 | -| string.swift:554:20:554:20 | sub3 | string.swift:554:13:554:24 | call to String.init(_:) | -| string.swift:556:7:556:7 | SSA def(sub4) | string.swift:557:13:557:13 | sub4 | -| string.swift:556:14:556:14 | [post] tainted | string.swift:556:35:556:35 | tainted | -| string.swift:556:14:556:14 | tainted | string.swift:556:14:556:51 | call to prefix(upTo:) | -| string.swift:556:14:556:14 | tainted | string.swift:556:35:556:35 | tainted | -| string.swift:556:14:556:51 | call to prefix(upTo:) | string.swift:556:7:556:7 | SSA def(sub4) | -| string.swift:556:35:556:35 | [post] tainted | string.swift:560:14:560:14 | tainted | -| string.swift:556:35:556:35 | tainted | string.swift:560:14:560:14 | tainted | -| string.swift:557:13:557:13 | sub4 | string.swift:558:20:558:20 | sub4 | -| string.swift:558:20:558:20 | sub4 | string.swift:558:13:558:24 | call to String.init(_:) | -| string.swift:560:7:560:7 | SSA def(sub5) | string.swift:561:13:561:13 | sub5 | -| string.swift:560:14:560:14 | [post] tainted | string.swift:564:14:564:14 | tainted | -| string.swift:560:14:560:14 | tainted | string.swift:560:14:560:31 | call to suffix(_:) | -| string.swift:560:14:560:14 | tainted | string.swift:564:14:564:14 | tainted | -| string.swift:560:14:560:31 | call to suffix(_:) | string.swift:560:7:560:7 | SSA def(sub5) | -| string.swift:561:13:561:13 | sub5 | string.swift:562:20:562:20 | sub5 | -| string.swift:562:20:562:20 | sub5 | string.swift:562:13:562:24 | call to String.init(_:) | -| string.swift:564:7:564:7 | SSA def(sub6) | string.swift:565:13:565:13 | sub6 | -| string.swift:564:14:564:14 | [post] tainted | string.swift:564:35:564:35 | tainted | -| string.swift:564:14:564:14 | tainted | string.swift:564:14:564:53 | call to suffix(from:) | -| string.swift:564:14:564:14 | tainted | string.swift:564:35:564:35 | tainted | -| string.swift:564:14:564:53 | call to suffix(from:) | string.swift:564:7:564:7 | SSA def(sub6) | -| string.swift:565:13:565:13 | sub6 | string.swift:566:20:566:20 | sub6 | -| string.swift:566:20:566:20 | sub6 | string.swift:566:13:566:24 | call to String.init(_:) | -| string.swift:570:7:570:7 | SSA def(clean) | string.swift:573:13:573:13 | clean | -| string.swift:570:15:570:26 | call to FilePath.init(_:) | string.swift:570:7:570:7 | SSA def(clean) | -| string.swift:571:7:571:7 | SSA def(tainted) | string.swift:574:13:574:13 | tainted | -| string.swift:571:17:571:35 | call to FilePath.init(_:) | string.swift:571:7:571:7 | SSA def(tainted) | -| string.swift:573:13:573:13 | [post] clean | string.swift:585:11:585:11 | clean | -| string.swift:573:13:573:13 | clean | string.swift:585:11:585:11 | clean | -| string.swift:574:13:574:13 | [post] tainted | string.swift:576:13:576:13 | tainted | -| string.swift:574:13:574:13 | tainted | string.swift:576:13:576:13 | tainted | -| string.swift:576:13:576:13 | [post] tainted | string.swift:577:13:577:13 | tainted | -| string.swift:576:13:576:13 | tainted | string.swift:577:13:577:13 | tainted | -| string.swift:576:13:576:21 | .extension | string.swift:576:13:576:30 | ...! | -| string.swift:577:13:577:13 | [post] tainted | string.swift:578:13:578:13 | tainted | -| string.swift:577:13:577:13 | tainted | string.swift:578:13:578:13 | tainted | -| string.swift:577:13:577:21 | .stem | string.swift:577:13:577:25 | ...! | -| string.swift:578:13:578:13 | [post] tainted | string.swift:579:13:579:13 | tainted | -| string.swift:578:13:578:13 | tainted | string.swift:579:13:579:13 | tainted | -| string.swift:579:13:579:13 | [post] tainted | string.swift:580:13:580:13 | tainted | -| string.swift:579:13:579:13 | tainted | string.swift:580:13:580:13 | tainted | -| string.swift:580:13:580:13 | [post] tainted | string.swift:582:30:582:30 | tainted | -| string.swift:580:13:580:13 | tainted | string.swift:582:30:582:30 | tainted | -| string.swift:582:30:582:30 | [post] tainted | string.swift:583:32:583:32 | tainted | -| string.swift:582:30:582:30 | tainted | string.swift:582:13:582:37 | call to String.init(decoding:) | -| string.swift:582:30:582:30 | tainted | string.swift:583:32:583:32 | tainted | -| string.swift:583:13:583:39 | call to String.init(validating:) | string.swift:583:13:583:40 | ...! | -| string.swift:583:32:583:32 | [post] tainted | string.swift:589:11:589:11 | tainted | -| string.swift:583:32:583:32 | tainted | string.swift:583:13:583:39 | call to String.init(validating:) | -| string.swift:583:32:583:32 | tainted | string.swift:589:11:589:11 | tainted | -| string.swift:585:11:585:11 | [post] clean | string.swift:594:11:594:11 | clean | -| string.swift:585:11:585:11 | clean | string.swift:594:11:594:11 | clean | -| string.swift:586:5:586:5 | SSA def(ptr) | string.swift:587:15:587:15 | ptr | -| string.swift:586:5:586:5 | ptr | string.swift:586:5:586:5 | SSA def(ptr) | -| string.swift:589:11:589:11 | [post] tainted | string.swift:600:11:600:11 | tainted | -| string.swift:589:11:589:11 | tainted | string.swift:600:11:600:11 | tainted | -| string.swift:590:5:590:5 | SSA def(ptr) | string.swift:591:15:591:15 | ptr | -| string.swift:590:5:590:5 | ptr | string.swift:590:5:590:5 | SSA def(ptr) | -| string.swift:594:11:594:11 | [post] clean | string.swift:614:13:614:13 | clean | -| string.swift:594:11:594:11 | clean | string.swift:614:13:614:13 | clean | -| string.swift:595:5:595:5 | SSA def(ptr) | string.swift:596:15:596:15 | ptr | -| string.swift:595:5:595:5 | ptr | string.swift:595:5:595:5 | SSA def(ptr) | -| string.swift:596:15:596:15 | ptr | string.swift:597:38:597:38 | ptr | -| string.swift:597:38:597:38 | ptr | string.swift:597:15:597:41 | call to String.init(platformString:) | -| string.swift:597:38:597:38 | ptr | string.swift:598:48:598:48 | ptr | -| string.swift:598:15:598:51 | call to String.init(validatingPlatformString:) | string.swift:598:15:598:52 | ...! | -| string.swift:598:48:598:48 | ptr | string.swift:598:15:598:51 | call to String.init(validatingPlatformString:) | -| string.swift:600:11:600:11 | [post] tainted | string.swift:616:13:616:13 | tainted | -| string.swift:600:11:600:11 | tainted | string.swift:616:13:616:13 | tainted | -| string.swift:601:5:601:5 | SSA def(ptr) | string.swift:602:15:602:15 | ptr | -| string.swift:601:5:601:5 | ptr | string.swift:601:5:601:5 | SSA def(ptr) | -| string.swift:602:15:602:15 | ptr | string.swift:603:38:603:38 | ptr | -| string.swift:603:38:603:38 | ptr | string.swift:603:15:603:41 | call to String.init(platformString:) | -| string.swift:603:38:603:38 | ptr | string.swift:604:48:604:48 | ptr | -| string.swift:604:15:604:51 | call to String.init(validatingPlatformString:) | string.swift:604:15:604:52 | ...! | -| string.swift:604:48:604:48 | ptr | string.swift:604:15:604:51 | call to String.init(validatingPlatformString:) | -| string.swift:607:7:607:7 | SSA def(fp1) | string.swift:608:13:608:13 | fp1 | -| string.swift:607:13:607:24 | call to FilePath.init(_:) | string.swift:607:7:607:7 | SSA def(fp1) | -| string.swift:608:13:608:13 | [post] fp1 | string.swift:609:3:609:3 | fp1 | -| string.swift:608:13:608:13 | fp1 | string.swift:609:3:609:3 | fp1 | -| string.swift:609:3:609:3 | &... | string.swift:610:13:610:13 | fp1 | -| string.swift:609:3:609:3 | [post] &... | string.swift:610:13:610:13 | fp1 | -| string.swift:609:3:609:3 | fp1 | string.swift:609:3:609:3 | &... | -| string.swift:610:13:610:13 | [post] fp1 | string.swift:611:3:611:3 | fp1 | -| string.swift:610:13:610:13 | fp1 | string.swift:611:3:611:3 | fp1 | -| string.swift:611:3:611:3 | &... | string.swift:612:13:612:13 | fp1 | -| string.swift:611:3:611:3 | [post] &... | string.swift:612:13:612:13 | fp1 | -| string.swift:611:3:611:3 | fp1 | string.swift:611:3:611:3 | &... | -| string.swift:614:13:614:13 | [post] clean | string.swift:615:13:615:13 | clean | -| string.swift:614:13:614:13 | clean | string.swift:615:13:615:13 | clean | -| string.swift:616:13:616:13 | [post] tainted | string.swift:617:13:617:13 | tainted | -| string.swift:616:13:616:13 | tainted | string.swift:617:13:617:13 | tainted | -| string.swift:621:20:621:20 | 0 | string.swift:621:13:621:21 | call to String.init(_:) | -| string.swift:622:20:622:27 | call to source() | string.swift:622:13:622:28 | call to String.init(_:) | -| string.swift:625:32:625:32 | 0 | string.swift:625:13:625:33 | call to String.init(describing:) | -| string.swift:626:32:626:39 | call to source() | string.swift:626:13:626:40 | call to String.init(describing:) | -| string.swift:628:13:628:22 | call to Self.init(_:) | string.swift:628:13:628:23 | ...! | -| string.swift:629:13:629:26 | call to Self.init(_:) | string.swift:629:13:629:27 | ...! | -| string.swift:633:7:633:7 | SSA def(tainted) | string.swift:637:13:637:13 | tainted | -| string.swift:633:17:633:25 | call to source2() | string.swift:633:7:633:7 | SSA def(tainted) | +| string.swift:263:13:263:13 | [post] tainted | string.swift:270:14:270:14 | tainted | +| string.swift:263:13:263:13 | tainted | string.swift:270:14:270:14 | tainted | +| string.swift:264:5:264:5 | SSA def(line) | string.swift:265:15:265:15 | line | +| string.swift:264:5:264:5 | line | string.swift:264:5:264:5 | SSA def(line) | +| string.swift:264:11:264:11 | SSA def(stop) | string.swift:266:15:266:15 | stop | +| string.swift:264:11:264:11 | stop | string.swift:264:11:264:11 | SSA def(stop) | +| string.swift:269:13:269:26 | [...] | string.swift:269:13:269:35 | call to joined(separator:) | +| string.swift:269:14:269:14 | clean | string.swift:269:21:269:21 | clean | +| string.swift:269:21:269:21 | clean | string.swift:270:23:270:23 | clean | +| string.swift:269:34:269:34 | default separator | string.swift:269:13:269:35 | call to joined(separator:) | +| string.swift:270:13:270:28 | [...] | string.swift:270:13:270:37 | call to joined(separator:) | +| string.swift:270:14:270:14 | tainted | string.swift:271:21:271:21 | tainted | +| string.swift:270:23:270:23 | clean | string.swift:271:14:271:14 | clean | +| string.swift:270:36:270:36 | default separator | string.swift:270:13:270:37 | call to joined(separator:) | +| string.swift:271:13:271:28 | [...] | string.swift:271:13:271:37 | call to joined(separator:) | +| string.swift:271:14:271:14 | clean | string.swift:274:13:274:13 | clean | +| string.swift:271:21:271:21 | tainted | string.swift:272:14:272:14 | tainted | +| string.swift:271:36:271:36 | default separator | string.swift:271:13:271:37 | call to joined(separator:) | +| string.swift:272:13:272:30 | [...] | string.swift:272:13:272:39 | call to joined(separator:) | +| string.swift:272:14:272:14 | tainted | string.swift:272:23:272:23 | tainted | +| string.swift:272:23:272:23 | tainted | string.swift:275:13:275:13 | tainted | +| string.swift:272:38:272:38 | default separator | string.swift:272:13:272:39 | call to joined(separator:) | +| string.swift:274:13:274:13 | [post] clean | string.swift:276:13:276:13 | clean | +| string.swift:274:13:274:13 | clean | string.swift:274:13:274:19 | .description | +| string.swift:274:13:274:13 | clean | string.swift:276:13:276:13 | clean | +| string.swift:275:13:275:13 | [post] tainted | string.swift:277:13:277:13 | tainted | +| string.swift:275:13:275:13 | tainted | string.swift:275:13:275:21 | .description | +| string.swift:275:13:275:13 | tainted | string.swift:277:13:277:13 | tainted | +| string.swift:276:13:276:13 | [post] clean | string.swift:278:13:278:13 | clean | +| string.swift:276:13:276:13 | clean | string.swift:276:13:276:19 | .debugDescription | +| string.swift:276:13:276:13 | clean | string.swift:278:13:278:13 | clean | +| string.swift:277:13:277:13 | [post] tainted | string.swift:279:13:279:13 | tainted | +| string.swift:277:13:277:13 | tainted | string.swift:277:13:277:21 | .debugDescription | +| string.swift:277:13:277:13 | tainted | string.swift:279:13:279:13 | tainted | +| string.swift:278:13:278:13 | [post] clean | string.swift:280:13:280:13 | clean | +| string.swift:278:13:278:13 | clean | string.swift:278:13:278:19 | .utf8 | +| string.swift:278:13:278:13 | clean | string.swift:280:13:280:13 | clean | +| string.swift:279:13:279:13 | [post] tainted | string.swift:281:13:281:13 | tainted | +| string.swift:279:13:279:13 | tainted | string.swift:279:13:279:21 | .utf8 | +| string.swift:279:13:279:13 | tainted | string.swift:281:13:281:13 | tainted | +| string.swift:280:13:280:13 | [post] clean | string.swift:282:13:282:13 | clean | +| string.swift:280:13:280:13 | clean | string.swift:280:13:280:19 | .utf16 | +| string.swift:280:13:280:13 | clean | string.swift:282:13:282:13 | clean | +| string.swift:281:13:281:13 | [post] tainted | string.swift:283:13:283:13 | tainted | +| string.swift:281:13:281:13 | tainted | string.swift:281:13:281:21 | .utf16 | +| string.swift:281:13:281:13 | tainted | string.swift:283:13:283:13 | tainted | +| string.swift:282:13:282:13 | [post] clean | string.swift:284:13:284:13 | clean | +| string.swift:282:13:282:13 | clean | string.swift:282:13:282:19 | .unicodeScalars | +| string.swift:282:13:282:13 | clean | string.swift:284:13:284:13 | clean | +| string.swift:283:13:283:13 | [post] tainted | string.swift:285:13:285:13 | tainted | +| string.swift:283:13:283:13 | tainted | string.swift:283:13:283:21 | .unicodeScalars | +| string.swift:283:13:283:13 | tainted | string.swift:285:13:285:13 | tainted | +| string.swift:284:13:284:13 | [post] clean | string.swift:286:13:286:13 | clean | +| string.swift:284:13:284:13 | clean | string.swift:284:13:284:19 | .utf8CString | +| string.swift:284:13:284:13 | clean | string.swift:286:13:286:13 | clean | +| string.swift:285:13:285:13 | [post] tainted | string.swift:287:13:287:13 | tainted | +| string.swift:285:13:285:13 | tainted | string.swift:285:13:285:21 | .utf8CString | +| string.swift:285:13:285:13 | tainted | string.swift:287:13:287:13 | tainted | +| string.swift:286:13:286:13 | [post] clean | string.swift:288:13:288:13 | clean | +| string.swift:286:13:286:13 | clean | string.swift:286:13:286:19 | .lazy | +| string.swift:286:13:286:13 | clean | string.swift:288:13:288:13 | clean | +| string.swift:287:13:287:13 | [post] tainted | string.swift:289:13:289:13 | tainted | +| string.swift:287:13:287:13 | tainted | string.swift:287:13:287:21 | .lazy | +| string.swift:287:13:287:13 | tainted | string.swift:289:13:289:13 | tainted | +| string.swift:288:13:288:13 | [post] clean | string.swift:290:13:290:13 | clean | +| string.swift:288:13:288:13 | clean | string.swift:288:13:288:19 | .capitalized | +| string.swift:288:13:288:13 | clean | string.swift:290:13:290:13 | clean | +| string.swift:289:13:289:13 | [post] tainted | string.swift:291:13:291:13 | tainted | +| string.swift:289:13:289:13 | tainted | string.swift:289:13:289:21 | .capitalized | +| string.swift:289:13:289:13 | tainted | string.swift:291:13:291:13 | tainted | +| string.swift:290:13:290:13 | [post] clean | string.swift:292:13:292:13 | clean | +| string.swift:290:13:290:13 | clean | string.swift:290:13:290:19 | .localizedCapitalized | +| string.swift:290:13:290:13 | clean | string.swift:292:13:292:13 | clean | +| string.swift:291:13:291:13 | [post] tainted | string.swift:293:13:293:13 | tainted | +| string.swift:291:13:291:13 | tainted | string.swift:291:13:291:21 | .localizedCapitalized | +| string.swift:291:13:291:13 | tainted | string.swift:293:13:293:13 | tainted | +| string.swift:292:13:292:13 | [post] clean | string.swift:294:13:294:13 | clean | +| string.swift:292:13:292:13 | clean | string.swift:292:13:292:19 | .localizedLowercase | +| string.swift:292:13:292:13 | clean | string.swift:294:13:294:13 | clean | +| string.swift:293:13:293:13 | [post] tainted | string.swift:295:13:295:13 | tainted | +| string.swift:293:13:293:13 | tainted | string.swift:293:13:293:21 | .localizedLowercase | +| string.swift:293:13:293:13 | tainted | string.swift:295:13:295:13 | tainted | +| string.swift:294:13:294:13 | [post] clean | string.swift:296:13:296:13 | clean | +| string.swift:294:13:294:13 | clean | string.swift:294:13:294:19 | .localizedUppercase | +| string.swift:294:13:294:13 | clean | string.swift:296:13:296:13 | clean | +| string.swift:295:13:295:13 | [post] tainted | string.swift:297:13:297:13 | tainted | +| string.swift:295:13:295:13 | tainted | string.swift:295:13:295:21 | .localizedUppercase | +| string.swift:295:13:295:13 | tainted | string.swift:297:13:297:13 | tainted | +| string.swift:296:13:296:13 | [post] clean | string.swift:298:13:298:13 | clean | +| string.swift:296:13:296:13 | clean | string.swift:296:13:296:19 | .decomposedStringWithCanonicalMapping | +| string.swift:296:13:296:13 | clean | string.swift:298:13:298:13 | clean | +| string.swift:297:13:297:13 | [post] tainted | string.swift:299:13:299:13 | tainted | +| string.swift:297:13:297:13 | tainted | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | +| string.swift:297:13:297:13 | tainted | string.swift:299:13:299:13 | tainted | +| string.swift:298:13:298:13 | [post] clean | string.swift:300:13:300:13 | clean | +| string.swift:298:13:298:13 | clean | string.swift:298:13:298:19 | .precomposedStringWithCompatibilityMapping | +| string.swift:298:13:298:13 | clean | string.swift:300:13:300:13 | clean | +| string.swift:299:13:299:13 | [post] tainted | string.swift:301:13:301:13 | tainted | +| string.swift:299:13:299:13 | tainted | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | +| string.swift:299:13:299:13 | tainted | string.swift:301:13:301:13 | tainted | +| string.swift:300:13:300:13 | [post] clean | string.swift:303:13:303:13 | clean | +| string.swift:300:13:300:13 | clean | string.swift:300:13:300:19 | .removingPercentEncoding | +| string.swift:300:13:300:13 | clean | string.swift:303:13:303:13 | clean | +| string.swift:300:13:300:19 | .removingPercentEncoding | string.swift:300:13:300:42 | ...! | +| string.swift:301:13:301:13 | [post] tainted | string.swift:304:13:304:13 | tainted | +| string.swift:301:13:301:13 | tainted | string.swift:301:13:301:21 | .removingPercentEncoding | +| string.swift:301:13:301:13 | tainted | string.swift:304:13:304:13 | tainted | +| string.swift:301:13:301:21 | .removingPercentEncoding | string.swift:301:13:301:44 | ...! | +| string.swift:303:13:303:13 | [post] clean | string.swift:305:13:305:13 | clean | +| string.swift:303:13:303:13 | clean | string.swift:305:13:305:13 | clean | +| string.swift:309:7:309:7 | SSA def(str1) | string.swift:310:13:310:13 | str1 | +| string.swift:309:14:309:22 | call to source2() | string.swift:309:7:309:7 | SSA def(str1) | +| string.swift:310:13:310:13 | [post] str1 | string.swift:311:13:311:13 | str1 | +| string.swift:310:13:310:13 | str1 | string.swift:311:13:311:13 | str1 | +| string.swift:311:13:311:13 | &... | string.swift:311:13:311:44 | call to remove(at:) | +| string.swift:311:13:311:13 | &... | string.swift:311:29:311:29 | str1 | +| string.swift:311:13:311:13 | [post] &... | string.swift:311:29:311:29 | str1 | +| string.swift:311:13:311:13 | str1 | string.swift:311:13:311:13 | &... | +| string.swift:311:29:311:29 | [post] str1 | string.swift:312:13:312:13 | str1 | +| string.swift:311:29:311:29 | str1 | string.swift:312:13:312:13 | str1 | +| string.swift:314:7:314:7 | SSA def(str2) | string.swift:315:13:315:13 | str2 | +| string.swift:314:14:314:22 | call to source2() | string.swift:314:7:314:7 | SSA def(str2) | +| string.swift:315:13:315:13 | [post] str2 | string.swift:316:3:316:3 | str2 | +| string.swift:315:13:315:13 | str2 | string.swift:316:3:316:3 | str2 | +| string.swift:316:3:316:3 | &... | string.swift:317:13:317:13 | str2 | +| string.swift:316:3:316:3 | [post] &... | string.swift:317:13:317:13 | str2 | +| string.swift:316:3:316:3 | str2 | string.swift:316:3:316:3 | &... | +| string.swift:319:7:319:7 | SSA def(str3) | string.swift:320:13:320:13 | str3 | +| string.swift:319:14:319:22 | call to source2() | string.swift:319:7:319:7 | SSA def(str3) | +| string.swift:320:13:320:13 | [post] str3 | string.swift:321:3:321:3 | str3 | +| string.swift:320:13:320:13 | str3 | string.swift:321:3:321:3 | str3 | +| string.swift:321:3:321:3 | &... | string.swift:322:13:322:13 | str3 | +| string.swift:321:3:321:3 | [post] &... | string.swift:322:13:322:13 | str3 | +| string.swift:321:3:321:3 | str3 | string.swift:321:3:321:3 | &... | +| string.swift:324:7:324:7 | SSA def(str4) | string.swift:325:13:325:13 | str4 | +| string.swift:324:14:324:22 | call to source2() | string.swift:324:7:324:7 | SSA def(str4) | +| string.swift:325:13:325:13 | [post] str4 | string.swift:326:13:326:13 | str4 | +| string.swift:325:13:325:13 | str4 | string.swift:326:13:326:13 | str4 | +| string.swift:326:13:326:13 | &... | string.swift:326:13:326:30 | call to removeFirst() | +| string.swift:326:13:326:13 | &... | string.swift:327:13:327:13 | str4 | +| string.swift:326:13:326:13 | [post] &... | string.swift:327:13:327:13 | str4 | +| string.swift:326:13:326:13 | str4 | string.swift:326:13:326:13 | &... | +| string.swift:327:13:327:13 | [post] str4 | string.swift:328:3:328:3 | str4 | +| string.swift:327:13:327:13 | str4 | string.swift:328:3:328:3 | str4 | +| string.swift:328:3:328:3 | &... | string.swift:329:13:329:13 | str4 | +| string.swift:328:3:328:3 | [post] &... | string.swift:329:13:329:13 | str4 | +| string.swift:328:3:328:3 | str4 | string.swift:328:3:328:3 | &... | +| string.swift:329:13:329:13 | [post] str4 | string.swift:330:13:330:13 | str4 | +| string.swift:329:13:329:13 | str4 | string.swift:330:13:330:13 | str4 | +| string.swift:330:13:330:13 | &... | string.swift:330:13:330:29 | call to removeLast() | +| string.swift:330:13:330:13 | &... | string.swift:331:13:331:13 | str4 | +| string.swift:330:13:330:13 | [post] &... | string.swift:331:13:331:13 | str4 | +| string.swift:330:13:330:13 | str4 | string.swift:330:13:330:13 | &... | +| string.swift:331:13:331:13 | [post] str4 | string.swift:332:3:332:3 | str4 | +| string.swift:331:13:331:13 | str4 | string.swift:332:3:332:3 | str4 | +| string.swift:332:3:332:3 | &... | string.swift:333:13:333:13 | str4 | +| string.swift:332:3:332:3 | [post] &... | string.swift:333:13:333:13 | str4 | +| string.swift:332:3:332:3 | str4 | string.swift:332:3:332:3 | &... | +| string.swift:335:7:335:7 | SSA def(str5) | string.swift:336:13:336:13 | str5 | +| string.swift:335:14:335:22 | call to source2() | string.swift:335:7:335:7 | SSA def(str5) | +| string.swift:336:13:336:13 | [post] str5 | string.swift:337:3:337:3 | str5 | +| string.swift:336:13:336:13 | str5 | string.swift:337:3:337:3 | str5 | +| string.swift:337:3:337:3 | &... | string.swift:337:23:337:23 | str5 | +| string.swift:337:3:337:3 | [post] &... | string.swift:337:23:337:23 | str5 | +| string.swift:337:3:337:3 | str5 | string.swift:337:3:337:3 | &... | +| string.swift:337:23:337:23 | [post] str5 | string.swift:337:43:337:43 | str5 | +| string.swift:337:23:337:23 | str5 | string.swift:337:43:337:43 | str5 | +| string.swift:337:43:337:43 | [post] str5 | string.swift:337:54:337:54 | str5 | +| string.swift:337:43:337:43 | str5 | string.swift:337:54:337:54 | str5 | +| string.swift:337:54:337:54 | [post] str5 | string.swift:338:13:338:13 | str5 | +| string.swift:337:54:337:54 | str5 | string.swift:338:13:338:13 | str5 | +| string.swift:340:7:340:7 | SSA def(str6) | string.swift:341:13:341:13 | str6 | +| string.swift:340:14:340:22 | call to source2() | string.swift:340:7:340:7 | SSA def(str6) | +| string.swift:341:13:341:13 | [post] str6 | string.swift:342:3:342:3 | str6 | +| string.swift:341:13:341:13 | str6 | string.swift:342:3:342:3 | str6 | +| string.swift:342:3:342:3 | &... | string.swift:343:13:343:13 | str6 | +| string.swift:342:3:342:3 | [post] &... | string.swift:343:13:343:13 | str6 | +| string.swift:342:3:342:3 | str6 | string.swift:342:3:342:3 | &... | +| string.swift:345:7:345:7 | SSA def(str7) | string.swift:346:13:346:13 | str7 | +| string.swift:345:14:345:14 | | string.swift:345:7:345:7 | SSA def(str7) | +| string.swift:346:13:346:13 | [post] str7 | string.swift:347:3:347:3 | str7 | +| string.swift:346:13:346:13 | str7 | string.swift:347:3:347:3 | str7 | +| string.swift:347:3:347:3 | &... | string.swift:348:13:348:13 | str7 | +| string.swift:347:3:347:3 | [post] &... | string.swift:348:13:348:13 | str7 | +| string.swift:347:3:347:3 | str7 | string.swift:347:3:347:3 | &... | +| string.swift:347:25:347:25 | nil | string.swift:347:24:347:53 | ...! | +| string.swift:351:38:351:38 | | string.swift:351:33:351:40 | call to Data.init(_:) | +| string.swift:354:7:354:7 | SSA def(stringClean) | string.swift:357:12:357:12 | stringClean | +| string.swift:354:21:354:74 | call to String.init(data:encoding:) | string.swift:354:7:354:7 | SSA def(stringClean) | +| string.swift:354:34:354:41 | call to Data.init(_:) | string.swift:354:21:354:74 | call to String.init(data:encoding:) | +| string.swift:354:39:354:39 | | string.swift:354:34:354:41 | call to Data.init(_:) | +| string.swift:355:7:355:7 | SSA def(stringTainted) | string.swift:358:12:358:12 | stringTainted | +| string.swift:355:23:355:77 | call to String.init(data:encoding:) | string.swift:355:7:355:7 | SSA def(stringTainted) | +| string.swift:355:36:355:44 | call to source3() | string.swift:355:23:355:77 | call to String.init(data:encoding:) | +| string.swift:357:12:357:12 | stringClean | string.swift:357:12:357:23 | ...! | +| string.swift:358:12:358:12 | stringTainted | string.swift:358:12:358:25 | ...! | +| string.swift:360:30:360:37 | call to Data.init(_:) | string.swift:360:13:360:53 | call to String.init(decoding:as:) | +| string.swift:360:35:360:35 | | string.swift:360:30:360:37 | call to Data.init(_:) | +| string.swift:361:30:361:38 | call to source3() | string.swift:361:13:361:54 | call to String.init(decoding:as:) | +| string.swift:365:7:365:7 | SSA def(clean) | string.swift:368:3:368:3 | clean | +| string.swift:365:15:365:15 | | string.swift:365:7:365:7 | SSA def(clean) | +| string.swift:366:7:366:7 | SSA def(tainted) | string.swift:373:3:373:3 | tainted | +| string.swift:366:17:366:25 | call to source2() | string.swift:366:7:366:7 | SSA def(tainted) | +| string.swift:368:3:368:3 | &... | string.swift:379:3:379:3 | clean | +| string.swift:368:3:368:3 | [post] &... | string.swift:379:3:379:3 | clean | +| string.swift:368:3:368:3 | clean | string.swift:368:3:368:3 | &... | +| string.swift:369:5:369:5 | SSA def(buffer) | string.swift:370:15:370:15 | buffer | +| string.swift:369:5:369:5 | buffer | string.swift:369:5:369:5 | SSA def(buffer) | +| string.swift:370:15:370:15 | buffer | string.swift:371:15:371:15 | buffer | +| string.swift:371:15:371:22 | .baseAddress | string.swift:371:15:371:33 | ...! | +| string.swift:373:3:373:3 | &... | string.swift:383:3:383:3 | tainted | +| string.swift:373:3:373:3 | [post] &... | string.swift:383:3:383:3 | tainted | +| string.swift:373:3:373:3 | tainted | string.swift:373:3:373:3 | &... | +| string.swift:374:5:374:5 | SSA def(buffer) | string.swift:375:15:375:15 | buffer | +| string.swift:374:5:374:5 | buffer | string.swift:374:5:374:5 | SSA def(buffer) | +| string.swift:375:15:375:15 | buffer | string.swift:376:15:376:15 | buffer | +| string.swift:376:15:376:22 | .baseAddress | string.swift:376:15:376:33 | ...! | +| string.swift:379:3:379:3 | [post] clean | string.swift:387:3:387:3 | clean | +| string.swift:379:3:379:3 | clean | string.swift:387:3:387:3 | clean | +| string.swift:380:5:380:5 | SSA def(ptr) | string.swift:381:15:381:15 | ptr | +| string.swift:380:5:380:5 | ptr | string.swift:380:5:380:5 | SSA def(ptr) | +| string.swift:383:3:383:3 | [post] tainted | string.swift:391:3:391:3 | tainted | +| string.swift:383:3:383:3 | tainted | string.swift:391:3:391:3 | tainted | +| string.swift:384:5:384:5 | SSA def(ptr) | string.swift:385:15:385:15 | ptr | +| string.swift:384:5:384:5 | ptr | string.swift:384:5:384:5 | SSA def(ptr) | +| string.swift:387:3:387:3 | [post] clean | string.swift:396:22:396:22 | clean | +| string.swift:387:3:387:3 | clean | string.swift:396:22:396:22 | clean | +| string.swift:388:5:388:5 | SSA def(ptr) | string.swift:389:15:389:15 | ptr | +| string.swift:388:5:388:5 | ptr | string.swift:388:5:388:5 | SSA def(ptr) | +| string.swift:391:3:391:3 | [post] tainted | string.swift:403:22:403:22 | tainted | +| string.swift:391:3:391:3 | tainted | string.swift:403:22:403:22 | tainted | +| string.swift:392:5:392:5 | SSA def(ptr) | string.swift:393:15:393:15 | ptr | +| string.swift:392:5:392:5 | ptr | string.swift:392:5:392:5 | SSA def(ptr) | +| string.swift:396:7:396:7 | SSA def(arrayString1) | string.swift:397:13:397:13 | arrayString1 | +| string.swift:396:22:396:22 | [post] clean | string.swift:411:3:411:3 | clean | +| string.swift:396:22:396:22 | clean | string.swift:396:22:396:63 | call to cString(using:) | +| string.swift:396:22:396:22 | clean | string.swift:411:3:411:3 | clean | +| string.swift:396:22:396:63 | call to cString(using:) | string.swift:396:22:396:64 | ...! | +| string.swift:396:22:396:64 | ...! | string.swift:396:7:396:7 | SSA def(arrayString1) | +| string.swift:397:13:397:13 | arrayString1 | string.swift:398:3:398:3 | arrayString1 | +| string.swift:398:3:398:3 | [post] arrayString1 | string.swift:405:3:405:3 | arrayString1 | +| string.swift:398:3:398:3 | arrayString1 | string.swift:405:3:405:3 | arrayString1 | +| string.swift:399:5:399:5 | SSA def(buffer) | string.swift:400:15:400:15 | buffer | +| string.swift:399:5:399:5 | buffer | string.swift:399:5:399:5 | SSA def(buffer) | +| string.swift:400:15:400:15 | buffer | string.swift:401:31:401:31 | buffer | +| string.swift:401:31:401:38 | .baseAddress | string.swift:401:31:401:49 | ...! | +| string.swift:401:31:401:49 | ...! | string.swift:401:15:401:50 | call to String.init(cString:) | +| string.swift:403:7:403:7 | SSA def(arrayString2) | string.swift:404:13:404:13 | arrayString2 | +| string.swift:403:22:403:22 | [post] tainted | string.swift:422:3:422:3 | tainted | +| string.swift:403:22:403:22 | tainted | string.swift:403:22:403:65 | call to cString(using:) | +| string.swift:403:22:403:22 | tainted | string.swift:422:3:422:3 | tainted | +| string.swift:403:22:403:65 | call to cString(using:) | string.swift:403:22:403:66 | ...! | +| string.swift:403:22:403:66 | ...! | string.swift:403:7:403:7 | SSA def(arrayString2) | +| string.swift:406:5:406:5 | SSA def(buffer) | string.swift:407:15:407:15 | buffer | +| string.swift:406:5:406:5 | buffer | string.swift:406:5:406:5 | SSA def(buffer) | +| string.swift:407:15:407:15 | buffer | string.swift:408:31:408:31 | buffer | +| string.swift:408:31:408:38 | .baseAddress | string.swift:408:31:408:49 | ...! | +| string.swift:408:31:408:49 | ...! | string.swift:408:15:408:50 | call to String.init(cString:) | +| string.swift:411:3:411:3 | [post] clean | string.swift:434:3:434:3 | clean | +| string.swift:411:3:411:3 | clean | string.swift:434:3:434:3 | clean | +| string.swift:412:5:412:5 | SSA def(ptr) | string.swift:413:15:413:15 | ptr | +| string.swift:412:5:412:5 | ptr | string.swift:412:5:412:5 | SSA def(ptr) | +| string.swift:413:15:413:15 | ptr | string.swift:414:38:414:38 | ptr | +| string.swift:414:38:414:38 | ptr | string.swift:414:15:414:41 | call to String.init(platformString:) | +| string.swift:414:38:414:38 | ptr | string.swift:416:45:416:45 | ptr | +| string.swift:416:9:416:9 | SSA def(buffer) | string.swift:417:29:417:29 | buffer | +| string.swift:416:18:416:59 | call to UnsafeBufferPointer.init(start:count:) | string.swift:416:9:416:9 | SSA def(buffer) | +| string.swift:417:9:417:9 | SSA def(arrayString) | string.swift:419:15:419:15 | arrayString | +| string.swift:417:23:417:35 | call to Array.init(_:) | string.swift:417:9:417:9 | SSA def(arrayString) | +| string.swift:417:29:417:29 | buffer | string.swift:418:15:418:15 | buffer | +| string.swift:419:15:419:15 | arrayString | string.swift:420:38:420:38 | arrayString | +| string.swift:420:38:420:38 | arrayString | string.swift:420:15:420:49 | call to String.init(platformString:) | +| string.swift:422:3:422:3 | [post] tainted | string.swift:439:3:439:3 | tainted | +| string.swift:422:3:422:3 | tainted | string.swift:439:3:439:3 | tainted | +| string.swift:423:5:423:5 | SSA def(ptr) | string.swift:424:15:424:15 | ptr | +| string.swift:423:5:423:5 | ptr | string.swift:423:5:423:5 | SSA def(ptr) | +| string.swift:424:15:424:15 | ptr | string.swift:425:38:425:38 | ptr | +| string.swift:425:38:425:38 | ptr | string.swift:425:15:425:41 | call to String.init(platformString:) | +| string.swift:425:38:425:38 | ptr | string.swift:427:45:427:45 | ptr | +| string.swift:427:9:427:9 | SSA def(buffer) | string.swift:428:29:428:29 | buffer | +| string.swift:427:18:427:59 | call to UnsafeBufferPointer.init(start:count:) | string.swift:427:9:427:9 | SSA def(buffer) | +| string.swift:428:9:428:9 | SSA def(arrayString) | string.swift:430:15:430:15 | arrayString | +| string.swift:428:23:428:35 | call to Array.init(_:) | string.swift:428:9:428:9 | SSA def(arrayString) | +| string.swift:428:29:428:29 | buffer | string.swift:429:15:429:15 | buffer | +| string.swift:430:15:430:15 | arrayString | string.swift:431:38:431:38 | arrayString | +| string.swift:431:38:431:38 | arrayString | string.swift:431:15:431:49 | call to String.init(platformString:) | +| string.swift:435:5:435:5 | SSA def(ptr) | string.swift:436:15:436:15 | ptr | +| string.swift:435:5:435:5 | ptr | string.swift:435:5:435:5 | SSA def(ptr) | +| string.swift:436:15:436:15 | ptr | string.swift:437:15:437:15 | ptr | +| string.swift:437:15:437:19 | .baseAddress | string.swift:437:15:437:30 | ...! | +| string.swift:440:5:440:5 | SSA def(ptr) | string.swift:441:15:441:15 | ptr | +| string.swift:440:5:440:5 | ptr | string.swift:440:5:440:5 | SSA def(ptr) | +| string.swift:441:15:441:15 | ptr | string.swift:442:15:442:15 | ptr | +| string.swift:442:15:442:19 | .baseAddress | string.swift:442:15:442:30 | ...! | +| string.swift:449:7:449:31 | SSA def(cleanUInt8Values) | string.swift:469:27:469:27 | cleanUInt8Values | +| string.swift:449:35:449:55 | [...] | string.swift:449:7:449:31 | SSA def(cleanUInt8Values) | +| string.swift:450:7:450:7 | SSA def(taintedUInt8Values) | string.swift:470:27:470:27 | taintedUInt8Values | +| string.swift:450:28:450:36 | call to source4() | string.swift:450:7:450:7 | SSA def(taintedUInt8Values) | +| string.swift:453:6:453:46 | SSA def(buffer) | string.swift:454:17:454:17 | buffer | +| string.swift:453:6:453:46 | buffer | string.swift:453:6:453:46 | SSA def(buffer) | +| string.swift:454:17:454:17 | buffer | string.swift:455:15:455:15 | buffer | +| string.swift:455:15:455:15 | [post] buffer | string.swift:456:17:456:17 | buffer | +| string.swift:455:15:455:15 | buffer | string.swift:456:17:456:17 | buffer | +| string.swift:461:6:461:46 | SSA def(buffer) | string.swift:462:17:462:17 | buffer | +| string.swift:461:6:461:46 | buffer | string.swift:461:6:461:46 | SSA def(buffer) | +| string.swift:462:17:462:17 | buffer | string.swift:463:15:463:15 | buffer | +| string.swift:463:15:463:15 | [post] buffer | string.swift:464:17:464:17 | buffer | +| string.swift:463:15:463:15 | buffer | string.swift:464:17:464:17 | buffer | +| string.swift:469:13:469:75 | call to String.init(bytes:encoding:) | string.swift:469:13:469:76 | ...! | +| string.swift:469:27:469:27 | cleanUInt8Values | string.swift:469:13:469:75 | call to String.init(bytes:encoding:) | +| string.swift:469:27:469:27 | cleanUInt8Values | string.swift:472:29:472:29 | cleanUInt8Values | +| string.swift:470:13:470:77 | call to String.init(bytes:encoding:) | string.swift:470:13:470:78 | ...! | +| string.swift:470:27:470:27 | taintedUInt8Values | string.swift:470:13:470:77 | call to String.init(bytes:encoding:) | +| string.swift:470:27:470:27 | taintedUInt8Values | string.swift:473:29:473:29 | taintedUInt8Values | +| string.swift:472:29:472:29 | cleanUInt8Values | string.swift:472:13:472:45 | call to String.init(cString:) | +| string.swift:472:29:472:29 | cleanUInt8Values | string.swift:475:8:475:8 | cleanUInt8Values | +| string.swift:473:29:473:29 | taintedUInt8Values | string.swift:473:13:473:47 | call to String.init(cString:) | +| string.swift:473:29:473:29 | taintedUInt8Values | string.swift:481:8:481:8 | taintedUInt8Values | +| string.swift:475:8:475:8 | [post] cleanUInt8Values | string.swift:488:8:488:8 | cleanUInt8Values | +| string.swift:475:8:475:8 | cleanUInt8Values | string.swift:488:8:488:8 | cleanUInt8Values | +| string.swift:475:8:480:4 | call to withUnsafeBufferPointer(_:) | string.swift:475:3:480:4 | try! ... | +| string.swift:476:6:476:39 | SSA def(buffer) | string.swift:477:15:477:15 | buffer | +| string.swift:476:6:476:39 | buffer | string.swift:476:6:476:39 | SSA def(buffer) | +| string.swift:477:15:477:15 | buffer | string.swift:478:15:478:15 | buffer | +| string.swift:478:15:478:15 | [post] buffer | string.swift:479:31:479:31 | buffer | +| string.swift:478:15:478:15 | buffer | string.swift:479:31:479:31 | buffer | +| string.swift:478:15:478:22 | .baseAddress | string.swift:478:15:478:33 | ...! | +| string.swift:479:31:479:38 | .baseAddress | string.swift:479:31:479:49 | ...! | +| string.swift:479:31:479:49 | ...! | string.swift:479:15:479:50 | call to String.init(cString:) | +| string.swift:481:8:481:8 | [post] taintedUInt8Values | string.swift:494:8:494:8 | taintedUInt8Values | +| string.swift:481:8:481:8 | taintedUInt8Values | string.swift:494:8:494:8 | taintedUInt8Values | +| string.swift:481:8:486:4 | call to withUnsafeBufferPointer(_:) | string.swift:481:3:486:4 | try! ... | +| string.swift:482:6:482:39 | SSA def(buffer) | string.swift:483:15:483:15 | buffer | +| string.swift:482:6:482:39 | buffer | string.swift:482:6:482:39 | SSA def(buffer) | +| string.swift:483:15:483:15 | buffer | string.swift:484:15:484:15 | buffer | +| string.swift:484:15:484:15 | [post] buffer | string.swift:485:31:485:31 | buffer | +| string.swift:484:15:484:15 | buffer | string.swift:485:31:485:31 | buffer | +| string.swift:484:15:484:22 | .baseAddress | string.swift:484:15:484:33 | ...! | +| string.swift:485:31:485:38 | .baseAddress | string.swift:485:31:485:49 | ...! | +| string.swift:485:31:485:49 | ...! | string.swift:485:15:485:50 | call to String.init(cString:) | +| string.swift:488:8:488:8 | cleanUInt8Values | string.swift:488:8:488:8 | &... | +| string.swift:488:8:493:4 | call to withUnsafeMutableBytes(_:) | string.swift:488:3:493:4 | try! ... | +| string.swift:489:6:489:14 | SSA def(buffer) | string.swift:490:15:490:15 | buffer | +| string.swift:489:6:489:14 | buffer | string.swift:489:6:489:14 | SSA def(buffer) | +| string.swift:490:15:490:15 | [post] buffer | string.swift:491:15:491:15 | buffer | +| string.swift:490:15:490:15 | buffer | string.swift:491:15:491:15 | buffer | +| string.swift:491:15:491:15 | [post] buffer | string.swift:492:35:492:35 | buffer | +| string.swift:491:15:491:15 | buffer | string.swift:492:35:492:35 | buffer | +| string.swift:491:15:491:22 | .baseAddress | string.swift:491:15:491:33 | ...! | +| string.swift:492:15:492:129 | call to String.init(bytesNoCopy:length:encoding:freeWhenDone:) | string.swift:492:15:492:130 | ...! | +| string.swift:492:35:492:35 | [post] buffer | string.swift:492:64:492:64 | buffer | +| string.swift:492:35:492:35 | buffer | string.swift:492:64:492:64 | buffer | +| string.swift:492:35:492:42 | .baseAddress | string.swift:492:35:492:53 | ...! | +| string.swift:494:8:494:8 | taintedUInt8Values | string.swift:494:8:494:8 | &... | +| string.swift:494:8:499:4 | call to withUnsafeMutableBytes(_:) | string.swift:494:3:499:4 | try! ... | +| string.swift:495:6:495:14 | SSA def(buffer) | string.swift:496:15:496:15 | buffer | +| string.swift:495:6:495:14 | buffer | string.swift:495:6:495:14 | SSA def(buffer) | +| string.swift:496:15:496:15 | [post] buffer | string.swift:497:15:497:15 | buffer | +| string.swift:496:15:496:15 | buffer | string.swift:497:15:497:15 | buffer | +| string.swift:497:15:497:15 | [post] buffer | string.swift:498:35:498:35 | buffer | +| string.swift:497:15:497:15 | buffer | string.swift:498:35:498:35 | buffer | +| string.swift:497:15:497:22 | .baseAddress | string.swift:497:15:497:33 | ...! | +| string.swift:498:15:498:129 | call to String.init(bytesNoCopy:length:encoding:freeWhenDone:) | string.swift:498:15:498:130 | ...! | +| string.swift:498:35:498:35 | [post] buffer | string.swift:498:64:498:64 | buffer | +| string.swift:498:35:498:35 | buffer | string.swift:498:64:498:64 | buffer | +| string.swift:498:35:498:42 | .baseAddress | string.swift:498:35:498:53 | ...! | +| string.swift:505:7:505:31 | SSA def(cleanCCharValues) | string.swift:508:3:508:3 | cleanCCharValues | +| string.swift:505:35:505:55 | [...] | string.swift:505:7:505:31 | SSA def(cleanCCharValues) | +| string.swift:506:7:506:33 | SSA def(taintedCCharValues) | string.swift:516:3:516:3 | taintedCCharValues | +| string.swift:506:37:506:45 | call to source5() | string.swift:506:7:506:33 | SSA def(taintedCCharValues) | +| string.swift:508:3:508:3 | [post] cleanCCharValues | string.swift:525:29:525:29 | cleanCCharValues | +| string.swift:508:3:508:3 | cleanCCharValues | string.swift:525:29:525:29 | cleanCCharValues | +| string.swift:509:5:509:5 | SSA def(ptr) | string.swift:510:15:510:15 | ptr | +| string.swift:509:5:509:5 | ptr | string.swift:509:5:509:5 | SSA def(ptr) | +| string.swift:510:15:510:15 | ptr | string.swift:511:15:511:15 | ptr | +| string.swift:511:15:511:15 | [post] ptr | string.swift:512:34:512:34 | ptr | +| string.swift:511:15:511:15 | ptr | string.swift:512:34:512:34 | ptr | +| string.swift:511:15:511:19 | .baseAddress | string.swift:511:15:511:30 | ...! | +| string.swift:512:15:512:50 | call to String.init(utf8String:) | string.swift:512:15:512:51 | ...! | +| string.swift:512:34:512:34 | [post] ptr | string.swift:513:38:513:38 | ptr | +| string.swift:512:34:512:34 | ptr | string.swift:513:38:513:38 | ptr | +| string.swift:512:34:512:38 | .baseAddress | string.swift:512:34:512:49 | ...! | +| string.swift:512:34:512:49 | ...! | string.swift:512:15:512:50 | call to String.init(utf8String:) | +| string.swift:513:15:513:54 | call to String.init(validatingUTF8:) | string.swift:513:15:513:55 | ...! | +| string.swift:513:38:513:38 | [post] ptr | string.swift:514:31:514:31 | ptr | +| string.swift:513:38:513:38 | ptr | string.swift:514:31:514:31 | ptr | +| string.swift:513:38:513:42 | .baseAddress | string.swift:513:38:513:53 | ...! | +| string.swift:513:38:513:53 | ...! | string.swift:513:15:513:54 | call to String.init(validatingUTF8:) | +| string.swift:514:31:514:35 | .baseAddress | string.swift:514:31:514:46 | ...! | +| string.swift:514:31:514:46 | ...! | string.swift:514:15:514:47 | call to String.init(cString:) | +| string.swift:516:3:516:3 | [post] taintedCCharValues | string.swift:526:29:526:29 | taintedCCharValues | +| string.swift:516:3:516:3 | taintedCCharValues | string.swift:526:29:526:29 | taintedCCharValues | +| string.swift:517:5:517:5 | SSA def(ptr) | string.swift:518:15:518:15 | ptr | +| string.swift:517:5:517:5 | ptr | string.swift:517:5:517:5 | SSA def(ptr) | +| string.swift:518:15:518:15 | ptr | string.swift:519:15:519:15 | ptr | +| string.swift:519:15:519:15 | [post] ptr | string.swift:520:34:520:34 | ptr | +| string.swift:519:15:519:15 | ptr | string.swift:520:34:520:34 | ptr | +| string.swift:519:15:519:19 | .baseAddress | string.swift:519:15:519:30 | ...! | +| string.swift:520:15:520:50 | call to String.init(utf8String:) | string.swift:520:15:520:51 | ...! | +| string.swift:520:34:520:34 | [post] ptr | string.swift:521:38:521:38 | ptr | +| string.swift:520:34:520:34 | ptr | string.swift:521:38:521:38 | ptr | +| string.swift:520:34:520:38 | .baseAddress | string.swift:520:34:520:49 | ...! | +| string.swift:520:34:520:49 | ...! | string.swift:520:15:520:50 | call to String.init(utf8String:) | +| string.swift:521:15:521:54 | call to String.init(validatingUTF8:) | string.swift:521:15:521:55 | ...! | +| string.swift:521:38:521:38 | [post] ptr | string.swift:522:31:522:31 | ptr | +| string.swift:521:38:521:38 | ptr | string.swift:522:31:522:31 | ptr | +| string.swift:521:38:521:42 | .baseAddress | string.swift:521:38:521:53 | ...! | +| string.swift:521:38:521:53 | ...! | string.swift:521:15:521:54 | call to String.init(validatingUTF8:) | +| string.swift:522:31:522:35 | .baseAddress | string.swift:522:31:522:46 | ...! | +| string.swift:522:31:522:46 | ...! | string.swift:522:15:522:47 | call to String.init(cString:) | +| string.swift:525:29:525:29 | cleanCCharValues | string.swift:525:13:525:45 | call to String.init(cString:) | +| string.swift:526:29:526:29 | taintedCCharValues | string.swift:526:13:526:47 | call to String.init(cString:) | +| string.swift:532:7:532:35 | SSA def(cleanUnicharValues) | string.swift:535:3:535:3 | cleanUnicharValues | +| string.swift:532:39:532:59 | [...] | string.swift:532:7:532:35 | SSA def(cleanUnicharValues) | +| string.swift:533:7:533:37 | SSA def(taintedUnicharValues) | string.swift:542:3:542:3 | taintedUnicharValues | +| string.swift:533:41:533:49 | call to source6() | string.swift:533:7:533:37 | SSA def(taintedUnicharValues) | +| string.swift:536:5:536:5 | SSA def(ptr) | string.swift:537:15:537:15 | ptr | +| string.swift:536:5:536:5 | ptr | string.swift:536:5:536:5 | SSA def(ptr) | +| string.swift:537:15:537:15 | ptr | string.swift:538:15:538:15 | ptr | +| string.swift:538:15:538:15 | [post] ptr | string.swift:539:38:539:38 | ptr | +| string.swift:538:15:538:15 | ptr | string.swift:539:38:539:38 | ptr | +| string.swift:538:15:538:19 | .baseAddress | string.swift:538:15:538:30 | ...! | +| string.swift:539:38:539:38 | [post] ptr | string.swift:539:63:539:63 | ptr | +| string.swift:539:38:539:38 | ptr | string.swift:539:63:539:63 | ptr | +| string.swift:539:38:539:42 | .baseAddress | string.swift:539:38:539:53 | ...! | +| string.swift:539:38:539:53 | ...! | string.swift:539:15:539:72 | call to String.init(utf16CodeUnits:count:) | +| string.swift:539:63:539:63 | [post] ptr | string.swift:540:44:540:44 | ptr | +| string.swift:539:63:539:63 | ptr | string.swift:540:44:540:44 | ptr | +| string.swift:540:44:540:44 | [post] ptr | string.swift:540:69:540:69 | ptr | +| string.swift:540:44:540:44 | ptr | string.swift:540:69:540:69 | ptr | +| string.swift:540:44:540:48 | .baseAddress | string.swift:540:44:540:59 | ...! | +| string.swift:540:44:540:59 | ...! | string.swift:540:15:540:99 | call to String.init(utf16CodeUnitsNoCopy:count:freeWhenDone:) | +| string.swift:543:5:543:5 | SSA def(ptr) | string.swift:544:15:544:15 | ptr | +| string.swift:543:5:543:5 | ptr | string.swift:543:5:543:5 | SSA def(ptr) | +| string.swift:544:15:544:15 | ptr | string.swift:545:15:545:15 | ptr | +| string.swift:545:15:545:15 | [post] ptr | string.swift:546:38:546:38 | ptr | +| string.swift:545:15:545:15 | ptr | string.swift:546:38:546:38 | ptr | +| string.swift:545:15:545:19 | .baseAddress | string.swift:545:15:545:30 | ...! | +| string.swift:546:38:546:38 | [post] ptr | string.swift:546:63:546:63 | ptr | +| string.swift:546:38:546:38 | ptr | string.swift:546:63:546:63 | ptr | +| string.swift:546:38:546:42 | .baseAddress | string.swift:546:38:546:53 | ...! | +| string.swift:546:38:546:53 | ...! | string.swift:546:15:546:72 | call to String.init(utf16CodeUnits:count:) | +| string.swift:546:63:546:63 | [post] ptr | string.swift:547:44:547:44 | ptr | +| string.swift:546:63:546:63 | ptr | string.swift:547:44:547:44 | ptr | +| string.swift:547:44:547:44 | [post] ptr | string.swift:547:69:547:69 | ptr | +| string.swift:547:44:547:44 | ptr | string.swift:547:69:547:69 | ptr | +| string.swift:547:44:547:48 | .baseAddress | string.swift:547:44:547:59 | ...! | +| string.swift:547:44:547:59 | ...! | string.swift:547:15:547:99 | call to String.init(utf16CodeUnitsNoCopy:count:freeWhenDone:) | +| string.swift:554:7:554:7 | SSA def(tainted) | string.swift:558:14:558:14 | tainted | +| string.swift:554:17:554:25 | call to source2() | string.swift:554:7:554:7 | SSA def(tainted) | +| string.swift:558:7:558:7 | SSA def(sub1) | string.swift:559:13:559:13 | sub1 | +| string.swift:558:14:558:14 | [post] tainted | string.swift:558:22:558:22 | tainted | +| string.swift:558:14:558:14 | tainted | string.swift:558:14:558:61 | ...[...] | +| string.swift:558:14:558:14 | tainted | string.swift:558:22:558:22 | tainted | +| string.swift:558:14:558:61 | ...[...] | string.swift:558:7:558:7 | SSA def(sub1) | +| string.swift:558:22:558:22 | [post] tainted | string.swift:558:45:558:45 | tainted | +| string.swift:558:22:558:22 | tainted | string.swift:558:45:558:45 | tainted | +| string.swift:558:45:558:45 | [post] tainted | string.swift:562:14:562:14 | tainted | +| string.swift:558:45:558:45 | tainted | string.swift:562:14:562:14 | tainted | +| string.swift:559:13:559:13 | [post] sub1 | string.swift:560:20:560:20 | sub1 | +| string.swift:559:13:559:13 | sub1 | string.swift:560:20:560:20 | sub1 | +| string.swift:560:20:560:20 | sub1 | string.swift:560:13:560:24 | call to String.init(_:) | +| string.swift:562:7:562:7 | SSA def(sub2) | string.swift:563:13:563:13 | sub2 | +| string.swift:562:14:562:14 | [post] tainted | string.swift:566:14:566:14 | tainted | +| string.swift:562:14:562:14 | tainted | string.swift:562:14:562:31 | call to prefix(_:) | +| string.swift:562:14:562:14 | tainted | string.swift:566:14:566:14 | tainted | +| string.swift:562:14:562:31 | call to prefix(_:) | string.swift:562:7:562:7 | SSA def(sub2) | +| string.swift:563:13:563:13 | sub2 | string.swift:564:20:564:20 | sub2 | +| string.swift:564:20:564:20 | sub2 | string.swift:564:13:564:24 | call to String.init(_:) | +| string.swift:566:7:566:7 | SSA def(sub3) | string.swift:567:13:567:13 | sub3 | +| string.swift:566:14:566:14 | [post] tainted | string.swift:566:38:566:38 | tainted | +| string.swift:566:14:566:14 | tainted | string.swift:566:14:566:54 | call to prefix(through:) | +| string.swift:566:14:566:14 | tainted | string.swift:566:38:566:38 | tainted | +| string.swift:566:14:566:54 | call to prefix(through:) | string.swift:566:7:566:7 | SSA def(sub3) | +| string.swift:566:38:566:38 | [post] tainted | string.swift:570:14:570:14 | tainted | +| string.swift:566:38:566:38 | tainted | string.swift:570:14:570:14 | tainted | +| string.swift:567:13:567:13 | sub3 | string.swift:568:20:568:20 | sub3 | +| string.swift:568:20:568:20 | sub3 | string.swift:568:13:568:24 | call to String.init(_:) | +| string.swift:570:7:570:7 | SSA def(sub4) | string.swift:571:13:571:13 | sub4 | +| string.swift:570:14:570:14 | [post] tainted | string.swift:570:35:570:35 | tainted | +| string.swift:570:14:570:14 | tainted | string.swift:570:14:570:51 | call to prefix(upTo:) | +| string.swift:570:14:570:14 | tainted | string.swift:570:35:570:35 | tainted | +| string.swift:570:14:570:51 | call to prefix(upTo:) | string.swift:570:7:570:7 | SSA def(sub4) | +| string.swift:570:35:570:35 | [post] tainted | string.swift:574:14:574:14 | tainted | +| string.swift:570:35:570:35 | tainted | string.swift:574:14:574:14 | tainted | +| string.swift:571:13:571:13 | sub4 | string.swift:572:20:572:20 | sub4 | +| string.swift:572:20:572:20 | sub4 | string.swift:572:13:572:24 | call to String.init(_:) | +| string.swift:574:7:574:7 | SSA def(sub5) | string.swift:575:13:575:13 | sub5 | +| string.swift:574:14:574:14 | [post] tainted | string.swift:578:14:578:14 | tainted | +| string.swift:574:14:574:14 | tainted | string.swift:574:14:574:31 | call to suffix(_:) | +| string.swift:574:14:574:14 | tainted | string.swift:578:14:578:14 | tainted | +| string.swift:574:14:574:31 | call to suffix(_:) | string.swift:574:7:574:7 | SSA def(sub5) | +| string.swift:575:13:575:13 | sub5 | string.swift:576:20:576:20 | sub5 | +| string.swift:576:20:576:20 | sub5 | string.swift:576:13:576:24 | call to String.init(_:) | +| string.swift:578:7:578:7 | SSA def(sub6) | string.swift:579:13:579:13 | sub6 | +| string.swift:578:14:578:14 | [post] tainted | string.swift:578:35:578:35 | tainted | +| string.swift:578:14:578:14 | tainted | string.swift:578:14:578:53 | call to suffix(from:) | +| string.swift:578:14:578:14 | tainted | string.swift:578:35:578:35 | tainted | +| string.swift:578:14:578:53 | call to suffix(from:) | string.swift:578:7:578:7 | SSA def(sub6) | +| string.swift:579:13:579:13 | sub6 | string.swift:580:20:580:20 | sub6 | +| string.swift:580:20:580:20 | sub6 | string.swift:580:13:580:24 | call to String.init(_:) | +| string.swift:584:7:584:7 | SSA def(clean) | string.swift:587:13:587:13 | clean | +| string.swift:584:15:584:26 | call to FilePath.init(_:) | string.swift:584:7:584:7 | SSA def(clean) | +| string.swift:585:7:585:7 | SSA def(tainted) | string.swift:588:13:588:13 | tainted | +| string.swift:585:17:585:35 | call to FilePath.init(_:) | string.swift:585:7:585:7 | SSA def(tainted) | +| string.swift:587:13:587:13 | [post] clean | string.swift:599:11:599:11 | clean | +| string.swift:587:13:587:13 | clean | string.swift:599:11:599:11 | clean | +| string.swift:588:13:588:13 | [post] tainted | string.swift:590:13:590:13 | tainted | +| string.swift:588:13:588:13 | tainted | string.swift:590:13:590:13 | tainted | +| string.swift:590:13:590:13 | [post] tainted | string.swift:591:13:591:13 | tainted | +| string.swift:590:13:590:13 | tainted | string.swift:591:13:591:13 | tainted | +| string.swift:590:13:590:21 | .extension | string.swift:590:13:590:30 | ...! | +| string.swift:591:13:591:13 | [post] tainted | string.swift:592:13:592:13 | tainted | +| string.swift:591:13:591:13 | tainted | string.swift:592:13:592:13 | tainted | +| string.swift:591:13:591:21 | .stem | string.swift:591:13:591:25 | ...! | +| string.swift:592:13:592:13 | [post] tainted | string.swift:593:13:593:13 | tainted | +| string.swift:592:13:592:13 | tainted | string.swift:593:13:593:13 | tainted | +| string.swift:593:13:593:13 | [post] tainted | string.swift:594:13:594:13 | tainted | +| string.swift:593:13:593:13 | tainted | string.swift:594:13:594:13 | tainted | +| string.swift:594:13:594:13 | [post] tainted | string.swift:596:30:596:30 | tainted | +| string.swift:594:13:594:13 | tainted | string.swift:596:30:596:30 | tainted | +| string.swift:596:30:596:30 | [post] tainted | string.swift:597:32:597:32 | tainted | +| string.swift:596:30:596:30 | tainted | string.swift:596:13:596:37 | call to String.init(decoding:) | +| string.swift:596:30:596:30 | tainted | string.swift:597:32:597:32 | tainted | +| string.swift:597:13:597:39 | call to String.init(validating:) | string.swift:597:13:597:40 | ...! | +| string.swift:597:32:597:32 | [post] tainted | string.swift:603:11:603:11 | tainted | +| string.swift:597:32:597:32 | tainted | string.swift:597:13:597:39 | call to String.init(validating:) | +| string.swift:597:32:597:32 | tainted | string.swift:603:11:603:11 | tainted | +| string.swift:599:11:599:11 | [post] clean | string.swift:608:11:608:11 | clean | +| string.swift:599:11:599:11 | clean | string.swift:608:11:608:11 | clean | +| string.swift:600:5:600:5 | SSA def(ptr) | string.swift:601:15:601:15 | ptr | +| string.swift:600:5:600:5 | ptr | string.swift:600:5:600:5 | SSA def(ptr) | +| string.swift:603:11:603:11 | [post] tainted | string.swift:614:11:614:11 | tainted | +| string.swift:603:11:603:11 | tainted | string.swift:614:11:614:11 | tainted | +| string.swift:604:5:604:5 | SSA def(ptr) | string.swift:605:15:605:15 | ptr | +| string.swift:604:5:604:5 | ptr | string.swift:604:5:604:5 | SSA def(ptr) | +| string.swift:608:11:608:11 | [post] clean | string.swift:628:13:628:13 | clean | +| string.swift:608:11:608:11 | clean | string.swift:628:13:628:13 | clean | +| string.swift:609:5:609:5 | SSA def(ptr) | string.swift:610:15:610:15 | ptr | +| string.swift:609:5:609:5 | ptr | string.swift:609:5:609:5 | SSA def(ptr) | +| string.swift:610:15:610:15 | ptr | string.swift:611:38:611:38 | ptr | +| string.swift:611:38:611:38 | ptr | string.swift:611:15:611:41 | call to String.init(platformString:) | +| string.swift:611:38:611:38 | ptr | string.swift:612:48:612:48 | ptr | +| string.swift:612:15:612:51 | call to String.init(validatingPlatformString:) | string.swift:612:15:612:52 | ...! | +| string.swift:612:48:612:48 | ptr | string.swift:612:15:612:51 | call to String.init(validatingPlatformString:) | +| string.swift:614:11:614:11 | [post] tainted | string.swift:630:13:630:13 | tainted | +| string.swift:614:11:614:11 | tainted | string.swift:630:13:630:13 | tainted | +| string.swift:615:5:615:5 | SSA def(ptr) | string.swift:616:15:616:15 | ptr | +| string.swift:615:5:615:5 | ptr | string.swift:615:5:615:5 | SSA def(ptr) | +| string.swift:616:15:616:15 | ptr | string.swift:617:38:617:38 | ptr | +| string.swift:617:38:617:38 | ptr | string.swift:617:15:617:41 | call to String.init(platformString:) | +| string.swift:617:38:617:38 | ptr | string.swift:618:48:618:48 | ptr | +| string.swift:618:15:618:51 | call to String.init(validatingPlatformString:) | string.swift:618:15:618:52 | ...! | +| string.swift:618:48:618:48 | ptr | string.swift:618:15:618:51 | call to String.init(validatingPlatformString:) | +| string.swift:621:7:621:7 | SSA def(fp1) | string.swift:622:13:622:13 | fp1 | +| string.swift:621:13:621:24 | call to FilePath.init(_:) | string.swift:621:7:621:7 | SSA def(fp1) | +| string.swift:622:13:622:13 | [post] fp1 | string.swift:623:3:623:3 | fp1 | +| string.swift:622:13:622:13 | fp1 | string.swift:623:3:623:3 | fp1 | +| string.swift:623:3:623:3 | &... | string.swift:624:13:624:13 | fp1 | +| string.swift:623:3:623:3 | [post] &... | string.swift:624:13:624:13 | fp1 | +| string.swift:623:3:623:3 | fp1 | string.swift:623:3:623:3 | &... | +| string.swift:624:13:624:13 | [post] fp1 | string.swift:625:3:625:3 | fp1 | +| string.swift:624:13:624:13 | fp1 | string.swift:625:3:625:3 | fp1 | +| string.swift:625:3:625:3 | &... | string.swift:626:13:626:13 | fp1 | +| string.swift:625:3:625:3 | [post] &... | string.swift:626:13:626:13 | fp1 | +| string.swift:625:3:625:3 | fp1 | string.swift:625:3:625:3 | &... | +| string.swift:628:13:628:13 | [post] clean | string.swift:629:13:629:13 | clean | +| string.swift:628:13:628:13 | clean | string.swift:629:13:629:13 | clean | +| string.swift:630:13:630:13 | [post] tainted | string.swift:631:13:631:13 | tainted | +| string.swift:630:13:630:13 | tainted | string.swift:631:13:631:13 | tainted | +| string.swift:635:20:635:20 | 0 | string.swift:635:13:635:21 | call to String.init(_:) | +| string.swift:636:20:636:27 | call to source() | string.swift:636:13:636:28 | call to String.init(_:) | +| string.swift:639:32:639:32 | 0 | string.swift:639:13:639:33 | call to String.init(describing:) | +| string.swift:640:32:640:39 | call to source() | string.swift:640:13:640:40 | call to String.init(describing:) | +| string.swift:642:13:642:22 | call to Self.init(_:) | string.swift:642:13:642:23 | ...! | +| string.swift:643:13:643:26 | call to Self.init(_:) | string.swift:643:13:643:27 | ...! | +| string.swift:647:7:647:7 | SSA def(tainted) | string.swift:651:13:651:13 | tainted | +| string.swift:647:17:647:25 | call to source2() | string.swift:647:7:647:7 | SSA def(tainted) | | subscript.swift:1:7:1:7 | SSA def(self) | subscript.swift:1:7:1:7 | self[return] | | subscript.swift:1:7:1:7 | SSA def(self) | subscript.swift:1:7:1:7 | self[return] | | subscript.swift:1:7:1:7 | self | subscript.swift:1:7:1:7 | SSA def(self) | diff --git a/swift/ql/test/library-tests/dataflow/taint/Taint.expected b/swift/ql/test/library-tests/dataflow/taint/Taint.expected index 462ad33a929..bd558a8ad63 100644 --- a/swift/ql/test/library-tests/dataflow/taint/Taint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/Taint.expected @@ -338,250 +338,250 @@ edges | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:locale:arguments:) : | | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in localizedStringWithFormat(_:_:) : | | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(bytes:encoding:) : | -| string.swift:98:3:98:63 | [summary param] this in lowercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in lowercased(with:) : | -| string.swift:99:3:99:63 | [summary param] this in uppercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in uppercased(with:) : | -| string.swift:100:3:100:64 | [summary param] this in capitalized(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in capitalized(with:) : | -| string.swift:101:3:101:64 | [summary param] this in substring(from:) : | file://:0:0:0:0 | [summary] to write: return (return) in substring(from:) : | -| string.swift:102:3:102:71 | [summary param] this in trimmingCharacters(in:) : | file://:0:0:0:0 | [summary] to write: return (return) in trimmingCharacters(in:) : | -| string.swift:103:3:103:82 | [summary param] 0 in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | -| string.swift:103:3:103:82 | [summary param] this in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | -| string.swift:104:3:104:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | file://:0:0:0:0 | [summary] to write: return (return) in padding(toLength:withPad:startingAt:) : | -| string.swift:105:3:105:80 | [summary param] this in components(separatedBy:) : | file://:0:0:0:0 | [summary] to write: return (return) in components(separatedBy:) : | -| string.swift:106:3:106:92 | [summary param] this in folding(options:locale:) : | file://:0:0:0:0 | [summary] to write: return (return) in folding(options:locale:) : | -| string.swift:107:3:107:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | -| string.swift:108:3:108:74 | [summary param] this in cString(using:) : | file://:0:0:0:0 | [summary] to write: return (return) in cString(using:) : | -| string.swift:109:8:109:8 | self : | string.swift:109:3:109:79 | self[return] : | -| string.swift:132:11:132:18 | call to source() : | string.swift:134:13:134:13 | "..." | -| string.swift:132:11:132:18 | call to source() : | string.swift:136:13:136:13 | "..." | -| string.swift:132:11:132:18 | call to source() : | string.swift:138:13:138:13 | "..." | -| string.swift:132:11:132:18 | call to source() : | string.swift:144:13:144:13 | "..." | -| string.swift:132:11:132:18 | call to source() : | string.swift:146:13:146:13 | "..." | -| string.swift:156:17:156:25 | call to source2() : | string.swift:159:13:159:13 | tainted | -| string.swift:156:17:156:25 | call to source2() : | string.swift:162:13:162:21 | ... .+(_:_:) ... | -| string.swift:156:17:156:25 | call to source2() : | string.swift:163:13:163:23 | ... .+(_:_:) ... | -| string.swift:156:17:156:25 | call to source2() : | string.swift:164:13:164:23 | ... .+(_:_:) ... | -| string.swift:156:17:156:25 | call to source2() : | string.swift:167:13:167:29 | ... .+(_:_:) ... | -| string.swift:156:17:156:25 | call to source2() : | string.swift:170:29:170:29 | tainted : | -| string.swift:156:17:156:25 | call to source2() : | string.swift:171:13:171:13 | tainted : | -| string.swift:156:17:156:25 | call to source2() : | string.swift:172:13:172:13 | tainted : | -| string.swift:156:17:156:25 | call to source2() : | string.swift:172:31:172:31 | tainted : | -| string.swift:170:29:170:29 | tainted : | string.swift:103:3:103:82 | [summary param] 0 in appending(_:) : | -| string.swift:170:29:170:29 | tainted : | string.swift:170:13:170:36 | call to appending(_:) | -| string.swift:171:13:171:13 | tainted : | string.swift:103:3:103:82 | [summary param] this in appending(_:) : | -| string.swift:171:13:171:13 | tainted : | string.swift:171:13:171:36 | call to appending(_:) | -| string.swift:172:13:172:13 | tainted : | string.swift:103:3:103:82 | [summary param] this in appending(_:) : | -| string.swift:172:13:172:13 | tainted : | string.swift:172:13:172:38 | call to appending(_:) | -| string.swift:172:31:172:31 | tainted : | string.swift:103:3:103:82 | [summary param] 0 in appending(_:) : | -| string.swift:172:31:172:31 | tainted : | string.swift:172:13:172:38 | call to appending(_:) | -| string.swift:185:3:185:3 | [post] &... : | string.swift:186:13:186:13 | str2 | -| string.swift:185:15:185:23 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(_:) : | -| string.swift:185:15:185:23 | call to source2() : | string.swift:185:3:185:3 | [post] &... : | -| string.swift:192:3:192:3 | [post] &... : | string.swift:193:13:193:13 | str3 | -| string.swift:192:27:192:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(contentsOf:) : | -| string.swift:192:27:192:35 | call to source2() : | string.swift:192:3:192:3 | [post] &... : | -| string.swift:199:3:199:3 | [post] &... : | string.swift:200:13:200:13 | str4 | -| string.swift:199:14:199:22 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in write(_:) : | -| string.swift:199:14:199:22 | call to source2() : | string.swift:199:3:199:3 | [post] &... : | -| string.swift:206:3:206:3 | [post] &... : | string.swift:207:13:207:13 | str5 | -| string.swift:206:27:206:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in insert(contentsOf:at:) : | -| string.swift:206:27:206:35 | call to source2() : | string.swift:206:3:206:3 | [post] &... : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:216:20:216:20 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:219:28:219:28 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:220:28:220:28 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:221:28:221:28 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:222:28:222:28 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:223:46:223:46 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:228:31:228:31 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:230:13:230:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:231:13:231:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:232:13:232:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:234:13:234:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:235:13:235:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:236:13:236:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:237:13:237:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:238:13:238:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:239:13:239:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:241:13:241:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:242:13:242:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:245:13:245:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:246:13:246:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:247:13:247:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:248:13:248:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:249:13:249:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:250:13:250:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:251:13:251:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:258:13:258:13 | tainted : | -| string.swift:212:17:212:25 | call to source2() : | string.swift:270:13:270:21 | .description | -| string.swift:212:17:212:25 | call to source2() : | string.swift:272:13:272:21 | .debugDescription | -| string.swift:212:17:212:25 | call to source2() : | string.swift:274:13:274:21 | .utf8 | -| string.swift:212:17:212:25 | call to source2() : | string.swift:276:13:276:21 | .utf16 | -| string.swift:212:17:212:25 | call to source2() : | string.swift:278:13:278:21 | .unicodeScalars | -| string.swift:212:17:212:25 | call to source2() : | string.swift:280:13:280:21 | .utf8CString | -| string.swift:212:17:212:25 | call to source2() : | string.swift:282:13:282:21 | .lazy | -| string.swift:212:17:212:25 | call to source2() : | string.swift:284:13:284:21 | .capitalized | -| string.swift:212:17:212:25 | call to source2() : | string.swift:286:13:286:21 | .localizedCapitalized | -| string.swift:212:17:212:25 | call to source2() : | string.swift:288:13:288:21 | .localizedLowercase | -| string.swift:212:17:212:25 | call to source2() : | string.swift:290:13:290:21 | .localizedUppercase | -| string.swift:212:17:212:25 | call to source2() : | string.swift:292:13:292:21 | .decomposedStringWithCanonicalMapping | -| string.swift:212:17:212:25 | call to source2() : | string.swift:294:13:294:21 | .precomposedStringWithCompatibilityMapping | -| string.swift:212:17:212:25 | call to source2() : | string.swift:296:13:296:44 | ...! | -| string.swift:213:20:213:27 | call to source() : | string.swift:217:20:217:20 | taintedInt : | -| string.swift:216:20:216:20 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:216:20:216:20 | tainted : | string.swift:216:13:216:27 | call to String.init(_:) | -| string.swift:217:20:217:20 | taintedInt : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:217:20:217:20 | taintedInt : | string.swift:217:13:217:30 | call to String.init(_:) | -| string.swift:219:28:219:28 | tainted : | string.swift:64:3:64:63 | [summary param] 0 in String.init(format:_:) : | -| string.swift:219:28:219:28 | tainted : | string.swift:219:13:219:44 | call to String.init(format:_:) | -| string.swift:220:28:220:28 | tainted : | string.swift:65:3:65:60 | [summary param] 0 in String.init(format:arguments:) : | -| string.swift:220:28:220:28 | tainted : | string.swift:220:13:220:50 | call to String.init(format:arguments:) | -| string.swift:221:28:221:28 | tainted : | string.swift:66:3:66:75 | [summary param] 0 in String.init(format:locale:_:) : | -| string.swift:221:28:221:28 | tainted : | string.swift:221:13:221:57 | call to String.init(format:locale:_:) | -| string.swift:222:28:222:28 | tainted : | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | -| string.swift:222:28:222:28 | tainted : | string.swift:222:13:222:63 | call to String.init(format:locale:arguments:) | -| string.swift:223:46:223:46 | tainted : | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | -| string.swift:223:46:223:46 | tainted : | string.swift:223:13:223:62 | call to localizedStringWithFormat(_:_:) | -| string.swift:228:31:228:31 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(repeating:count:) : | -| string.swift:228:31:228:31 | tainted : | string.swift:228:13:228:48 | call to String.init(repeating:count:) | -| string.swift:230:13:230:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropFirst(_:) : | -| string.swift:230:13:230:13 | tainted : | string.swift:230:13:230:33 | call to dropFirst(_:) | -| string.swift:231:13:231:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropLast(_:) : | -| string.swift:231:13:231:13 | tainted : | string.swift:231:13:231:32 | call to dropLast(_:) | -| string.swift:232:13:232:13 | tainted : | string.swift:101:3:101:64 | [summary param] this in substring(from:) : | -| string.swift:232:13:232:13 | tainted : | string.swift:232:13:232:55 | call to substring(from:) | -| string.swift:234:13:234:13 | tainted : | file://:0:0:0:0 | [summary param] this in lowercased() : | -| string.swift:234:13:234:13 | tainted : | string.swift:234:13:234:32 | call to lowercased() | -| string.swift:235:13:235:13 | tainted : | file://:0:0:0:0 | [summary param] this in uppercased() : | -| string.swift:235:13:235:13 | tainted : | string.swift:235:13:235:32 | call to uppercased() | -| string.swift:236:13:236:13 | tainted : | string.swift:98:3:98:63 | [summary param] this in lowercased(with:) : | -| string.swift:236:13:236:13 | tainted : | string.swift:236:13:236:41 | call to lowercased(with:) | -| string.swift:237:13:237:13 | tainted : | string.swift:99:3:99:63 | [summary param] this in uppercased(with:) : | -| string.swift:237:13:237:13 | tainted : | string.swift:237:13:237:41 | call to uppercased(with:) | -| string.swift:238:13:238:13 | tainted : | string.swift:100:3:100:64 | [summary param] this in capitalized(with:) : | -| string.swift:238:13:238:13 | tainted : | string.swift:238:13:238:42 | call to capitalized(with:) | -| string.swift:239:13:239:13 | tainted : | file://:0:0:0:0 | [summary param] this in reversed() : | -| string.swift:239:13:239:13 | tainted : | string.swift:239:13:239:30 | call to reversed() | -| string.swift:241:13:241:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(separator:maxSplits:omittingEmptySubsequences:) : | -| string.swift:241:13:241:13 | tainted : | string.swift:241:13:241:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | -| string.swift:242:13:242:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(maxSplits:omittingEmptySubsequences:whereSeparator:) : | -| string.swift:242:13:242:13 | tainted : | string.swift:242:13:244:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | -| string.swift:245:13:245:13 | tainted : | string.swift:102:3:102:71 | [summary param] this in trimmingCharacters(in:) : | -| string.swift:245:13:245:13 | tainted : | string.swift:245:13:245:68 | call to trimmingCharacters(in:) | -| string.swift:246:13:246:13 | tainted : | string.swift:104:3:104:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | -| string.swift:246:13:246:13 | tainted : | string.swift:246:13:246:70 | call to padding(toLength:withPad:startingAt:) | -| string.swift:247:13:247:13 | tainted : | string.swift:105:3:105:80 | [summary param] this in components(separatedBy:) : | -| string.swift:247:13:247:13 | tainted : | string.swift:247:13:247:69 | call to components(separatedBy:) | -| string.swift:248:13:248:13 | tainted : | string.swift:105:3:105:80 | [summary param] this in components(separatedBy:) : | -| string.swift:248:13:248:13 | tainted : | string.swift:248:13:248:69 | call to components(separatedBy:) : | -| string.swift:248:13:248:69 | call to components(separatedBy:) : | string.swift:248:13:248:72 | ...[...] | -| string.swift:249:13:249:13 | tainted : | string.swift:106:3:106:92 | [summary param] this in folding(options:locale:) : | -| string.swift:249:13:249:13 | tainted : | string.swift:249:13:249:40 | call to folding(options:locale:) | -| string.swift:250:13:250:13 | tainted : | string.swift:107:3:107:78 | [summary param] this in propertyListFromStringsFileFormat() : | -| string.swift:250:13:250:13 | tainted : | string.swift:250:13:250:55 | call to propertyListFromStringsFileFormat() | -| string.swift:251:13:251:13 | tainted : | string.swift:107:3:107:78 | [summary param] this in propertyListFromStringsFileFormat() : | -| string.swift:251:13:251:13 | tainted : | string.swift:251:13:251:55 | call to propertyListFromStringsFileFormat() : | -| string.swift:251:13:251:55 | call to propertyListFromStringsFileFormat() : | string.swift:251:13:251:63 | ...! | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:270:13:270:21 | .description | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:272:13:272:21 | .debugDescription | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:274:13:274:21 | .utf8 | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:276:13:276:21 | .utf16 | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:278:13:278:21 | .unicodeScalars | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:280:13:280:21 | .utf8CString | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:282:13:282:21 | .lazy | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:284:13:284:21 | .capitalized | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:286:13:286:21 | .localizedCapitalized | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:288:13:288:21 | .localizedLowercase | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:290:13:290:21 | .localizedUppercase | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:292:13:292:21 | .decomposedStringWithCanonicalMapping | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:294:13:294:21 | .precomposedStringWithCompatibilityMapping | -| string.swift:258:13:258:13 | [post] tainted : | string.swift:296:13:296:44 | ...! | -| string.swift:258:13:258:13 | tainted : | string.swift:109:8:109:8 | self : | -| string.swift:258:13:258:13 | tainted : | string.swift:258:13:258:13 | [post] tainted : | -| string.swift:300:14:300:22 | call to source2() : | string.swift:301:13:301:13 | str1 | -| string.swift:300:14:300:22 | call to source2() : | string.swift:302:13:302:13 | &... : | -| string.swift:300:14:300:22 | call to source2() : | string.swift:303:13:303:13 | str1 | -| string.swift:302:13:302:13 | &... : | file://:0:0:0:0 | [summary param] this in remove(at:) : | -| string.swift:302:13:302:13 | &... : | string.swift:302:13:302:44 | call to remove(at:) | -| string.swift:305:14:305:22 | call to source2() : | string.swift:306:13:306:13 | str2 | -| string.swift:305:14:305:22 | call to source2() : | string.swift:308:13:308:13 | str2 | -| string.swift:310:14:310:22 | call to source2() : | string.swift:311:13:311:13 | str3 | -| string.swift:310:14:310:22 | call to source2() : | string.swift:313:13:313:13 | str3 | -| string.swift:315:14:315:22 | call to source2() : | string.swift:316:13:316:13 | str4 | -| string.swift:315:14:315:22 | call to source2() : | string.swift:317:13:317:13 | &... : | -| string.swift:315:14:315:22 | call to source2() : | string.swift:318:13:318:13 | str4 | -| string.swift:315:14:315:22 | call to source2() : | string.swift:320:13:320:13 | str4 | -| string.swift:315:14:315:22 | call to source2() : | string.swift:321:13:321:13 | &... : | -| string.swift:315:14:315:22 | call to source2() : | string.swift:322:13:322:13 | str4 | -| string.swift:315:14:315:22 | call to source2() : | string.swift:324:13:324:13 | str4 | -| string.swift:317:13:317:13 | &... : | file://:0:0:0:0 | [summary param] this in removeFirst() : | -| string.swift:317:13:317:13 | &... : | string.swift:317:13:317:30 | call to removeFirst() | -| string.swift:321:13:321:13 | &... : | file://:0:0:0:0 | [summary param] this in removeLast() : | -| string.swift:321:13:321:13 | &... : | string.swift:321:13:321:29 | call to removeLast() | -| string.swift:326:14:326:22 | call to source2() : | string.swift:327:13:327:13 | str5 | -| string.swift:326:14:326:22 | call to source2() : | string.swift:329:13:329:13 | str5 | -| string.swift:331:14:331:22 | call to source2() : | string.swift:332:13:332:13 | str6 | -| string.swift:331:14:331:22 | call to source2() : | string.swift:334:13:334:13 | str6 | -| string.swift:341:23:341:77 | call to String.init(data:encoding:) : | string.swift:344:12:344:25 | ...! | -| string.swift:341:36:341:44 | call to source3() : | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | -| string.swift:341:36:341:44 | call to source3() : | string.swift:341:23:341:77 | call to String.init(data:encoding:) : | -| string.swift:347:30:347:38 | call to source3() : | file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) : | -| string.swift:347:30:347:38 | call to source3() : | string.swift:347:13:347:54 | call to String.init(decoding:as:) | -| string.swift:352:17:352:25 | call to source2() : | string.swift:389:22:389:22 | tainted : | -| string.swift:389:22:389:22 | tainted : | string.swift:108:3:108:74 | [summary param] this in cString(using:) : | -| string.swift:389:22:389:22 | tainted : | string.swift:389:22:389:65 | call to cString(using:) : | -| string.swift:389:22:389:65 | call to cString(using:) : | string.swift:390:13:390:13 | arrayString2 | -| string.swift:436:28:436:36 | call to source4() : | string.swift:456:27:456:27 | taintedUInt8Values : | -| string.swift:436:28:436:36 | call to source4() : | string.swift:459:29:459:29 | taintedUInt8Values : | -| string.swift:456:13:456:77 | call to String.init(bytes:encoding:) : | string.swift:456:13:456:78 | ...! | -| string.swift:456:27:456:27 | taintedUInt8Values : | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | -| string.swift:456:27:456:27 | taintedUInt8Values : | string.swift:456:13:456:77 | call to String.init(bytes:encoding:) : | -| string.swift:459:29:459:29 | taintedUInt8Values : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | -| string.swift:459:29:459:29 | taintedUInt8Values : | string.swift:459:13:459:47 | call to String.init(cString:) | -| string.swift:492:37:492:45 | call to source5() : | string.swift:512:29:512:29 | taintedCCharValues : | -| string.swift:512:29:512:29 | taintedCCharValues : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | -| string.swift:512:29:512:29 | taintedCCharValues : | string.swift:512:13:512:47 | call to String.init(cString:) | -| string.swift:540:17:540:25 | call to source2() : | string.swift:545:13:545:13 | sub1 | -| string.swift:540:17:540:25 | call to source2() : | string.swift:546:20:546:20 | sub1 : | -| string.swift:540:17:540:25 | call to source2() : | string.swift:548:14:548:14 | tainted : | -| string.swift:540:17:540:25 | call to source2() : | string.swift:552:14:552:14 | tainted : | -| string.swift:540:17:540:25 | call to source2() : | string.swift:556:14:556:14 | tainted : | -| string.swift:540:17:540:25 | call to source2() : | string.swift:560:14:560:14 | tainted : | -| string.swift:540:17:540:25 | call to source2() : | string.swift:564:14:564:14 | tainted : | -| string.swift:546:20:546:20 | sub1 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:546:20:546:20 | sub1 : | string.swift:546:13:546:24 | call to String.init(_:) | -| string.swift:548:14:548:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(_:) : | -| string.swift:548:14:548:14 | tainted : | string.swift:548:14:548:31 | call to prefix(_:) : | -| string.swift:548:14:548:31 | call to prefix(_:) : | string.swift:549:13:549:13 | sub2 | -| string.swift:548:14:548:31 | call to prefix(_:) : | string.swift:550:20:550:20 | sub2 : | -| string.swift:550:20:550:20 | sub2 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:550:20:550:20 | sub2 : | string.swift:550:13:550:24 | call to String.init(_:) | -| string.swift:552:14:552:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(through:) : | -| string.swift:552:14:552:14 | tainted : | string.swift:552:14:552:54 | call to prefix(through:) : | -| string.swift:552:14:552:54 | call to prefix(through:) : | string.swift:553:13:553:13 | sub3 | -| string.swift:552:14:552:54 | call to prefix(through:) : | string.swift:554:20:554:20 | sub3 : | -| string.swift:554:20:554:20 | sub3 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:554:20:554:20 | sub3 : | string.swift:554:13:554:24 | call to String.init(_:) | -| string.swift:556:14:556:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(upTo:) : | -| string.swift:556:14:556:14 | tainted : | string.swift:556:14:556:51 | call to prefix(upTo:) : | -| string.swift:556:14:556:51 | call to prefix(upTo:) : | string.swift:557:13:557:13 | sub4 | -| string.swift:556:14:556:51 | call to prefix(upTo:) : | string.swift:558:20:558:20 | sub4 : | -| string.swift:558:20:558:20 | sub4 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:558:20:558:20 | sub4 : | string.swift:558:13:558:24 | call to String.init(_:) | -| string.swift:560:14:560:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(_:) : | -| string.swift:560:14:560:14 | tainted : | string.swift:560:14:560:31 | call to suffix(_:) : | -| string.swift:560:14:560:31 | call to suffix(_:) : | string.swift:561:13:561:13 | sub5 | -| string.swift:560:14:560:31 | call to suffix(_:) : | string.swift:562:20:562:20 | sub5 : | -| string.swift:562:20:562:20 | sub5 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:562:20:562:20 | sub5 : | string.swift:562:13:562:24 | call to String.init(_:) | -| string.swift:564:14:564:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(from:) : | -| string.swift:564:14:564:14 | tainted : | string.swift:564:14:564:53 | call to suffix(from:) : | -| string.swift:564:14:564:53 | call to suffix(from:) : | string.swift:565:13:565:13 | sub6 | -| string.swift:564:14:564:53 | call to suffix(from:) : | string.swift:566:20:566:20 | sub6 : | -| string.swift:566:20:566:20 | sub6 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:566:20:566:20 | sub6 : | string.swift:566:13:566:24 | call to String.init(_:) | -| string.swift:622:20:622:27 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | -| string.swift:622:20:622:27 | call to source() : | string.swift:622:13:622:28 | call to String.init(_:) | -| string.swift:626:32:626:39 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(describing:) : | -| string.swift:626:32:626:39 | call to source() : | string.swift:626:13:626:40 | call to String.init(describing:) | +| string.swift:101:3:101:63 | [summary param] this in lowercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in lowercased(with:) : | +| string.swift:102:3:102:63 | [summary param] this in uppercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in uppercased(with:) : | +| string.swift:103:3:103:64 | [summary param] this in capitalized(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in capitalized(with:) : | +| string.swift:104:3:104:64 | [summary param] this in substring(from:) : | file://:0:0:0:0 | [summary] to write: return (return) in substring(from:) : | +| string.swift:105:3:105:71 | [summary param] this in trimmingCharacters(in:) : | file://:0:0:0:0 | [summary] to write: return (return) in trimmingCharacters(in:) : | +| string.swift:106:3:106:82 | [summary param] 0 in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | +| string.swift:106:3:106:82 | [summary param] this in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | +| string.swift:107:3:107:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | file://:0:0:0:0 | [summary] to write: return (return) in padding(toLength:withPad:startingAt:) : | +| string.swift:108:3:108:80 | [summary param] this in components(separatedBy:) : | file://:0:0:0:0 | [summary] to write: return (return) in components(separatedBy:) : | +| string.swift:109:3:109:92 | [summary param] this in folding(options:locale:) : | file://:0:0:0:0 | [summary] to write: return (return) in folding(options:locale:) : | +| string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | +| string.swift:111:3:111:74 | [summary param] this in cString(using:) : | file://:0:0:0:0 | [summary] to write: return (return) in cString(using:) : | +| string.swift:112:8:112:8 | self : | string.swift:112:3:112:79 | self[return] : | +| string.swift:137:11:137:18 | call to source() : | string.swift:139:13:139:13 | "..." | +| string.swift:137:11:137:18 | call to source() : | string.swift:141:13:141:13 | "..." | +| string.swift:137:11:137:18 | call to source() : | string.swift:143:13:143:13 | "..." | +| string.swift:137:11:137:18 | call to source() : | string.swift:149:13:149:13 | "..." | +| string.swift:137:11:137:18 | call to source() : | string.swift:151:13:151:13 | "..." | +| string.swift:161:17:161:25 | call to source2() : | string.swift:164:13:164:13 | tainted | +| string.swift:161:17:161:25 | call to source2() : | string.swift:167:13:167:21 | ... .+(_:_:) ... | +| string.swift:161:17:161:25 | call to source2() : | string.swift:168:13:168:23 | ... .+(_:_:) ... | +| string.swift:161:17:161:25 | call to source2() : | string.swift:169:13:169:23 | ... .+(_:_:) ... | +| string.swift:161:17:161:25 | call to source2() : | string.swift:172:13:172:29 | ... .+(_:_:) ... | +| string.swift:161:17:161:25 | call to source2() : | string.swift:175:29:175:29 | tainted : | +| string.swift:161:17:161:25 | call to source2() : | string.swift:176:13:176:13 | tainted : | +| string.swift:161:17:161:25 | call to source2() : | string.swift:177:13:177:13 | tainted : | +| string.swift:161:17:161:25 | call to source2() : | string.swift:177:31:177:31 | tainted : | +| string.swift:175:29:175:29 | tainted : | string.swift:106:3:106:82 | [summary param] 0 in appending(_:) : | +| string.swift:175:29:175:29 | tainted : | string.swift:175:13:175:36 | call to appending(_:) | +| string.swift:176:13:176:13 | tainted : | string.swift:106:3:106:82 | [summary param] this in appending(_:) : | +| string.swift:176:13:176:13 | tainted : | string.swift:176:13:176:36 | call to appending(_:) | +| string.swift:177:13:177:13 | tainted : | string.swift:106:3:106:82 | [summary param] this in appending(_:) : | +| string.swift:177:13:177:13 | tainted : | string.swift:177:13:177:38 | call to appending(_:) | +| string.swift:177:31:177:31 | tainted : | string.swift:106:3:106:82 | [summary param] 0 in appending(_:) : | +| string.swift:177:31:177:31 | tainted : | string.swift:177:13:177:38 | call to appending(_:) | +| string.swift:190:3:190:3 | [post] &... : | string.swift:191:13:191:13 | str2 | +| string.swift:190:15:190:23 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(_:) : | +| string.swift:190:15:190:23 | call to source2() : | string.swift:190:3:190:3 | [post] &... : | +| string.swift:197:3:197:3 | [post] &... : | string.swift:198:13:198:13 | str3 | +| string.swift:197:27:197:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(contentsOf:) : | +| string.swift:197:27:197:35 | call to source2() : | string.swift:197:3:197:3 | [post] &... : | +| string.swift:204:3:204:3 | [post] &... : | string.swift:205:13:205:13 | str4 | +| string.swift:204:14:204:22 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in write(_:) : | +| string.swift:204:14:204:22 | call to source2() : | string.swift:204:3:204:3 | [post] &... : | +| string.swift:211:3:211:3 | [post] &... : | string.swift:212:13:212:13 | str5 | +| string.swift:211:27:211:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in insert(contentsOf:at:) : | +| string.swift:211:27:211:35 | call to source2() : | string.swift:211:3:211:3 | [post] &... : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:221:20:221:20 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:224:28:224:28 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:225:28:225:28 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:226:28:226:28 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:227:28:227:28 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:228:46:228:46 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:233:31:233:31 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:235:13:235:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:236:13:236:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:237:13:237:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:239:13:239:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:240:13:240:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:241:13:241:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:242:13:242:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:243:13:243:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:244:13:244:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:246:13:246:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:247:13:247:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:250:13:250:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:251:13:251:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:252:13:252:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:253:13:253:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:254:13:254:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:255:13:255:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:256:13:256:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:263:13:263:13 | tainted : | +| string.swift:217:17:217:25 | call to source2() : | string.swift:275:13:275:21 | .description | +| string.swift:217:17:217:25 | call to source2() : | string.swift:277:13:277:21 | .debugDescription | +| string.swift:217:17:217:25 | call to source2() : | string.swift:279:13:279:21 | .utf8 | +| string.swift:217:17:217:25 | call to source2() : | string.swift:281:13:281:21 | .utf16 | +| string.swift:217:17:217:25 | call to source2() : | string.swift:283:13:283:21 | .unicodeScalars | +| string.swift:217:17:217:25 | call to source2() : | string.swift:285:13:285:21 | .utf8CString | +| string.swift:217:17:217:25 | call to source2() : | string.swift:287:13:287:21 | .lazy | +| string.swift:217:17:217:25 | call to source2() : | string.swift:289:13:289:21 | .capitalized | +| string.swift:217:17:217:25 | call to source2() : | string.swift:291:13:291:21 | .localizedCapitalized | +| string.swift:217:17:217:25 | call to source2() : | string.swift:293:13:293:21 | .localizedLowercase | +| string.swift:217:17:217:25 | call to source2() : | string.swift:295:13:295:21 | .localizedUppercase | +| string.swift:217:17:217:25 | call to source2() : | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | +| string.swift:217:17:217:25 | call to source2() : | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | +| string.swift:217:17:217:25 | call to source2() : | string.swift:301:13:301:44 | ...! | +| string.swift:218:20:218:27 | call to source() : | string.swift:222:20:222:20 | taintedInt : | +| string.swift:221:20:221:20 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:221:20:221:20 | tainted : | string.swift:221:13:221:27 | call to String.init(_:) | +| string.swift:222:20:222:20 | taintedInt : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:222:20:222:20 | taintedInt : | string.swift:222:13:222:30 | call to String.init(_:) | +| string.swift:224:28:224:28 | tainted : | string.swift:64:3:64:63 | [summary param] 0 in String.init(format:_:) : | +| string.swift:224:28:224:28 | tainted : | string.swift:224:13:224:44 | call to String.init(format:_:) | +| string.swift:225:28:225:28 | tainted : | string.swift:65:3:65:60 | [summary param] 0 in String.init(format:arguments:) : | +| string.swift:225:28:225:28 | tainted : | string.swift:225:13:225:50 | call to String.init(format:arguments:) | +| string.swift:226:28:226:28 | tainted : | string.swift:66:3:66:75 | [summary param] 0 in String.init(format:locale:_:) : | +| string.swift:226:28:226:28 | tainted : | string.swift:226:13:226:57 | call to String.init(format:locale:_:) | +| string.swift:227:28:227:28 | tainted : | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | +| string.swift:227:28:227:28 | tainted : | string.swift:227:13:227:63 | call to String.init(format:locale:arguments:) | +| string.swift:228:46:228:46 | tainted : | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | +| string.swift:228:46:228:46 | tainted : | string.swift:228:13:228:62 | call to localizedStringWithFormat(_:_:) | +| string.swift:233:31:233:31 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(repeating:count:) : | +| string.swift:233:31:233:31 | tainted : | string.swift:233:13:233:48 | call to String.init(repeating:count:) | +| string.swift:235:13:235:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropFirst(_:) : | +| string.swift:235:13:235:13 | tainted : | string.swift:235:13:235:33 | call to dropFirst(_:) | +| string.swift:236:13:236:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropLast(_:) : | +| string.swift:236:13:236:13 | tainted : | string.swift:236:13:236:32 | call to dropLast(_:) | +| string.swift:237:13:237:13 | tainted : | string.swift:104:3:104:64 | [summary param] this in substring(from:) : | +| string.swift:237:13:237:13 | tainted : | string.swift:237:13:237:55 | call to substring(from:) | +| string.swift:239:13:239:13 | tainted : | file://:0:0:0:0 | [summary param] this in lowercased() : | +| string.swift:239:13:239:13 | tainted : | string.swift:239:13:239:32 | call to lowercased() | +| string.swift:240:13:240:13 | tainted : | file://:0:0:0:0 | [summary param] this in uppercased() : | +| string.swift:240:13:240:13 | tainted : | string.swift:240:13:240:32 | call to uppercased() | +| string.swift:241:13:241:13 | tainted : | string.swift:101:3:101:63 | [summary param] this in lowercased(with:) : | +| string.swift:241:13:241:13 | tainted : | string.swift:241:13:241:41 | call to lowercased(with:) | +| string.swift:242:13:242:13 | tainted : | string.swift:102:3:102:63 | [summary param] this in uppercased(with:) : | +| string.swift:242:13:242:13 | tainted : | string.swift:242:13:242:41 | call to uppercased(with:) | +| string.swift:243:13:243:13 | tainted : | string.swift:103:3:103:64 | [summary param] this in capitalized(with:) : | +| string.swift:243:13:243:13 | tainted : | string.swift:243:13:243:42 | call to capitalized(with:) | +| string.swift:244:13:244:13 | tainted : | file://:0:0:0:0 | [summary param] this in reversed() : | +| string.swift:244:13:244:13 | tainted : | string.swift:244:13:244:30 | call to reversed() | +| string.swift:246:13:246:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(separator:maxSplits:omittingEmptySubsequences:) : | +| string.swift:246:13:246:13 | tainted : | string.swift:246:13:246:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | +| string.swift:247:13:247:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(maxSplits:omittingEmptySubsequences:whereSeparator:) : | +| string.swift:247:13:247:13 | tainted : | string.swift:247:13:249:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | +| string.swift:250:13:250:13 | tainted : | string.swift:105:3:105:71 | [summary param] this in trimmingCharacters(in:) : | +| string.swift:250:13:250:13 | tainted : | string.swift:250:13:250:68 | call to trimmingCharacters(in:) | +| string.swift:251:13:251:13 | tainted : | string.swift:107:3:107:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | +| string.swift:251:13:251:13 | tainted : | string.swift:251:13:251:70 | call to padding(toLength:withPad:startingAt:) | +| string.swift:252:13:252:13 | tainted : | string.swift:108:3:108:80 | [summary param] this in components(separatedBy:) : | +| string.swift:252:13:252:13 | tainted : | string.swift:252:13:252:69 | call to components(separatedBy:) | +| string.swift:253:13:253:13 | tainted : | string.swift:108:3:108:80 | [summary param] this in components(separatedBy:) : | +| string.swift:253:13:253:13 | tainted : | string.swift:253:13:253:69 | call to components(separatedBy:) : | +| string.swift:253:13:253:69 | call to components(separatedBy:) : | string.swift:253:13:253:72 | ...[...] | +| string.swift:254:13:254:13 | tainted : | string.swift:109:3:109:92 | [summary param] this in folding(options:locale:) : | +| string.swift:254:13:254:13 | tainted : | string.swift:254:13:254:40 | call to folding(options:locale:) | +| string.swift:255:13:255:13 | tainted : | string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | +| string.swift:255:13:255:13 | tainted : | string.swift:255:13:255:55 | call to propertyListFromStringsFileFormat() | +| string.swift:256:13:256:13 | tainted : | string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | +| string.swift:256:13:256:13 | tainted : | string.swift:256:13:256:55 | call to propertyListFromStringsFileFormat() : | +| string.swift:256:13:256:55 | call to propertyListFromStringsFileFormat() : | string.swift:256:13:256:63 | ...! | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:275:13:275:21 | .description | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:277:13:277:21 | .debugDescription | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:279:13:279:21 | .utf8 | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:281:13:281:21 | .utf16 | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:283:13:283:21 | .unicodeScalars | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:285:13:285:21 | .utf8CString | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:287:13:287:21 | .lazy | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:289:13:289:21 | .capitalized | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:291:13:291:21 | .localizedCapitalized | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:293:13:293:21 | .localizedLowercase | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:295:13:295:21 | .localizedUppercase | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:301:13:301:44 | ...! | +| string.swift:263:13:263:13 | tainted : | string.swift:112:8:112:8 | self : | +| string.swift:263:13:263:13 | tainted : | string.swift:263:13:263:13 | [post] tainted : | +| string.swift:309:14:309:22 | call to source2() : | string.swift:310:13:310:13 | str1 | +| string.swift:309:14:309:22 | call to source2() : | string.swift:311:13:311:13 | &... : | +| string.swift:309:14:309:22 | call to source2() : | string.swift:312:13:312:13 | str1 | +| string.swift:311:13:311:13 | &... : | file://:0:0:0:0 | [summary param] this in remove(at:) : | +| string.swift:311:13:311:13 | &... : | string.swift:311:13:311:44 | call to remove(at:) | +| string.swift:314:14:314:22 | call to source2() : | string.swift:315:13:315:13 | str2 | +| string.swift:314:14:314:22 | call to source2() : | string.swift:317:13:317:13 | str2 | +| string.swift:319:14:319:22 | call to source2() : | string.swift:320:13:320:13 | str3 | +| string.swift:319:14:319:22 | call to source2() : | string.swift:322:13:322:13 | str3 | +| string.swift:324:14:324:22 | call to source2() : | string.swift:325:13:325:13 | str4 | +| string.swift:324:14:324:22 | call to source2() : | string.swift:326:13:326:13 | &... : | +| string.swift:324:14:324:22 | call to source2() : | string.swift:327:13:327:13 | str4 | +| string.swift:324:14:324:22 | call to source2() : | string.swift:329:13:329:13 | str4 | +| string.swift:324:14:324:22 | call to source2() : | string.swift:330:13:330:13 | &... : | +| string.swift:324:14:324:22 | call to source2() : | string.swift:331:13:331:13 | str4 | +| string.swift:324:14:324:22 | call to source2() : | string.swift:333:13:333:13 | str4 | +| string.swift:326:13:326:13 | &... : | file://:0:0:0:0 | [summary param] this in removeFirst() : | +| string.swift:326:13:326:13 | &... : | string.swift:326:13:326:30 | call to removeFirst() | +| string.swift:330:13:330:13 | &... : | file://:0:0:0:0 | [summary param] this in removeLast() : | +| string.swift:330:13:330:13 | &... : | string.swift:330:13:330:29 | call to removeLast() | +| string.swift:335:14:335:22 | call to source2() : | string.swift:336:13:336:13 | str5 | +| string.swift:335:14:335:22 | call to source2() : | string.swift:338:13:338:13 | str5 | +| string.swift:340:14:340:22 | call to source2() : | string.swift:341:13:341:13 | str6 | +| string.swift:340:14:340:22 | call to source2() : | string.swift:343:13:343:13 | str6 | +| string.swift:355:23:355:77 | call to String.init(data:encoding:) : | string.swift:358:12:358:25 | ...! | +| string.swift:355:36:355:44 | call to source3() : | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | +| string.swift:355:36:355:44 | call to source3() : | string.swift:355:23:355:77 | call to String.init(data:encoding:) : | +| string.swift:361:30:361:38 | call to source3() : | file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) : | +| string.swift:361:30:361:38 | call to source3() : | string.swift:361:13:361:54 | call to String.init(decoding:as:) | +| string.swift:366:17:366:25 | call to source2() : | string.swift:403:22:403:22 | tainted : | +| string.swift:403:22:403:22 | tainted : | string.swift:111:3:111:74 | [summary param] this in cString(using:) : | +| string.swift:403:22:403:22 | tainted : | string.swift:403:22:403:65 | call to cString(using:) : | +| string.swift:403:22:403:65 | call to cString(using:) : | string.swift:404:13:404:13 | arrayString2 | +| string.swift:450:28:450:36 | call to source4() : | string.swift:470:27:470:27 | taintedUInt8Values : | +| string.swift:450:28:450:36 | call to source4() : | string.swift:473:29:473:29 | taintedUInt8Values : | +| string.swift:470:13:470:77 | call to String.init(bytes:encoding:) : | string.swift:470:13:470:78 | ...! | +| string.swift:470:27:470:27 | taintedUInt8Values : | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | +| string.swift:470:27:470:27 | taintedUInt8Values : | string.swift:470:13:470:77 | call to String.init(bytes:encoding:) : | +| string.swift:473:29:473:29 | taintedUInt8Values : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | +| string.swift:473:29:473:29 | taintedUInt8Values : | string.swift:473:13:473:47 | call to String.init(cString:) | +| string.swift:506:37:506:45 | call to source5() : | string.swift:526:29:526:29 | taintedCCharValues : | +| string.swift:526:29:526:29 | taintedCCharValues : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | +| string.swift:526:29:526:29 | taintedCCharValues : | string.swift:526:13:526:47 | call to String.init(cString:) | +| string.swift:554:17:554:25 | call to source2() : | string.swift:559:13:559:13 | sub1 | +| string.swift:554:17:554:25 | call to source2() : | string.swift:560:20:560:20 | sub1 : | +| string.swift:554:17:554:25 | call to source2() : | string.swift:562:14:562:14 | tainted : | +| string.swift:554:17:554:25 | call to source2() : | string.swift:566:14:566:14 | tainted : | +| string.swift:554:17:554:25 | call to source2() : | string.swift:570:14:570:14 | tainted : | +| string.swift:554:17:554:25 | call to source2() : | string.swift:574:14:574:14 | tainted : | +| string.swift:554:17:554:25 | call to source2() : | string.swift:578:14:578:14 | tainted : | +| string.swift:560:20:560:20 | sub1 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:560:20:560:20 | sub1 : | string.swift:560:13:560:24 | call to String.init(_:) | +| string.swift:562:14:562:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(_:) : | +| string.swift:562:14:562:14 | tainted : | string.swift:562:14:562:31 | call to prefix(_:) : | +| string.swift:562:14:562:31 | call to prefix(_:) : | string.swift:563:13:563:13 | sub2 | +| string.swift:562:14:562:31 | call to prefix(_:) : | string.swift:564:20:564:20 | sub2 : | +| string.swift:564:20:564:20 | sub2 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:564:20:564:20 | sub2 : | string.swift:564:13:564:24 | call to String.init(_:) | +| string.swift:566:14:566:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(through:) : | +| string.swift:566:14:566:14 | tainted : | string.swift:566:14:566:54 | call to prefix(through:) : | +| string.swift:566:14:566:54 | call to prefix(through:) : | string.swift:567:13:567:13 | sub3 | +| string.swift:566:14:566:54 | call to prefix(through:) : | string.swift:568:20:568:20 | sub3 : | +| string.swift:568:20:568:20 | sub3 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:568:20:568:20 | sub3 : | string.swift:568:13:568:24 | call to String.init(_:) | +| string.swift:570:14:570:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(upTo:) : | +| string.swift:570:14:570:14 | tainted : | string.swift:570:14:570:51 | call to prefix(upTo:) : | +| string.swift:570:14:570:51 | call to prefix(upTo:) : | string.swift:571:13:571:13 | sub4 | +| string.swift:570:14:570:51 | call to prefix(upTo:) : | string.swift:572:20:572:20 | sub4 : | +| string.swift:572:20:572:20 | sub4 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:572:20:572:20 | sub4 : | string.swift:572:13:572:24 | call to String.init(_:) | +| string.swift:574:14:574:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(_:) : | +| string.swift:574:14:574:14 | tainted : | string.swift:574:14:574:31 | call to suffix(_:) : | +| string.swift:574:14:574:31 | call to suffix(_:) : | string.swift:575:13:575:13 | sub5 | +| string.swift:574:14:574:31 | call to suffix(_:) : | string.swift:576:20:576:20 | sub5 : | +| string.swift:576:20:576:20 | sub5 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:576:20:576:20 | sub5 : | string.swift:576:13:576:24 | call to String.init(_:) | +| string.swift:578:14:578:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(from:) : | +| string.swift:578:14:578:14 | tainted : | string.swift:578:14:578:53 | call to suffix(from:) : | +| string.swift:578:14:578:53 | call to suffix(from:) : | string.swift:579:13:579:13 | sub6 | +| string.swift:578:14:578:53 | call to suffix(from:) : | string.swift:580:20:580:20 | sub6 : | +| string.swift:580:20:580:20 | sub6 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:580:20:580:20 | sub6 : | string.swift:580:13:580:24 | call to String.init(_:) | +| string.swift:636:20:636:27 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | +| string.swift:636:20:636:27 | call to source() : | string.swift:636:13:636:28 | call to String.init(_:) | +| string.swift:640:32:640:39 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(describing:) : | +| string.swift:640:32:640:39 | call to source() : | string.swift:640:13:640:40 | call to String.init(describing:) | | subscript.swift:13:15:13:22 | call to source() : | subscript.swift:13:15:13:25 | ...[...] | | subscript.swift:14:15:14:23 | call to source2() : | subscript.swift:14:15:14:26 | ...[...] | | try.swift:9:17:9:24 | call to source() : | try.swift:9:13:9:24 | try ... | @@ -1362,202 +1362,202 @@ nodes | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | semmle.label | [summary param] 0 in String.init(format:locale:arguments:) : | | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | semmle.label | [summary param] 0 in localizedStringWithFormat(_:_:) : | | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | semmle.label | [summary param] 0 in String.init(bytes:encoding:) : | -| string.swift:98:3:98:63 | [summary param] this in lowercased(with:) : | semmle.label | [summary param] this in lowercased(with:) : | -| string.swift:99:3:99:63 | [summary param] this in uppercased(with:) : | semmle.label | [summary param] this in uppercased(with:) : | -| string.swift:100:3:100:64 | [summary param] this in capitalized(with:) : | semmle.label | [summary param] this in capitalized(with:) : | -| string.swift:101:3:101:64 | [summary param] this in substring(from:) : | semmle.label | [summary param] this in substring(from:) : | -| string.swift:102:3:102:71 | [summary param] this in trimmingCharacters(in:) : | semmle.label | [summary param] this in trimmingCharacters(in:) : | -| string.swift:103:3:103:82 | [summary param] 0 in appending(_:) : | semmle.label | [summary param] 0 in appending(_:) : | -| string.swift:103:3:103:82 | [summary param] this in appending(_:) : | semmle.label | [summary param] this in appending(_:) : | -| string.swift:104:3:104:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | semmle.label | [summary param] this in padding(toLength:withPad:startingAt:) : | -| string.swift:105:3:105:80 | [summary param] this in components(separatedBy:) : | semmle.label | [summary param] this in components(separatedBy:) : | -| string.swift:106:3:106:92 | [summary param] this in folding(options:locale:) : | semmle.label | [summary param] this in folding(options:locale:) : | -| string.swift:107:3:107:78 | [summary param] this in propertyListFromStringsFileFormat() : | semmle.label | [summary param] this in propertyListFromStringsFileFormat() : | -| string.swift:108:3:108:74 | [summary param] this in cString(using:) : | semmle.label | [summary param] this in cString(using:) : | -| string.swift:109:3:109:79 | self[return] : | semmle.label | self[return] : | -| string.swift:109:8:109:8 | self : | semmle.label | self : | -| string.swift:132:11:132:18 | call to source() : | semmle.label | call to source() : | -| string.swift:134:13:134:13 | "..." | semmle.label | "..." | -| string.swift:136:13:136:13 | "..." | semmle.label | "..." | -| string.swift:138:13:138:13 | "..." | semmle.label | "..." | -| string.swift:144:13:144:13 | "..." | semmle.label | "..." | -| string.swift:146:13:146:13 | "..." | semmle.label | "..." | -| string.swift:156:17:156:25 | call to source2() : | semmle.label | call to source2() : | -| string.swift:159:13:159:13 | tainted | semmle.label | tainted | -| string.swift:162:13:162:21 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| string.swift:163:13:163:23 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| string.swift:164:13:164:23 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| string.swift:167:13:167:29 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| string.swift:170:13:170:36 | call to appending(_:) | semmle.label | call to appending(_:) | -| string.swift:170:29:170:29 | tainted : | semmle.label | tainted : | -| string.swift:171:13:171:13 | tainted : | semmle.label | tainted : | -| string.swift:171:13:171:36 | call to appending(_:) | semmle.label | call to appending(_:) | -| string.swift:172:13:172:13 | tainted : | semmle.label | tainted : | -| string.swift:172:13:172:38 | call to appending(_:) | semmle.label | call to appending(_:) | -| string.swift:172:31:172:31 | tainted : | semmle.label | tainted : | -| string.swift:185:3:185:3 | [post] &... : | semmle.label | [post] &... : | -| string.swift:185:15:185:23 | call to source2() : | semmle.label | call to source2() : | -| string.swift:186:13:186:13 | str2 | semmle.label | str2 | -| string.swift:192:3:192:3 | [post] &... : | semmle.label | [post] &... : | -| string.swift:192:27:192:35 | call to source2() : | semmle.label | call to source2() : | -| string.swift:193:13:193:13 | str3 | semmle.label | str3 | -| string.swift:199:3:199:3 | [post] &... : | semmle.label | [post] &... : | -| string.swift:199:14:199:22 | call to source2() : | semmle.label | call to source2() : | -| string.swift:200:13:200:13 | str4 | semmle.label | str4 | -| string.swift:206:3:206:3 | [post] &... : | semmle.label | [post] &... : | -| string.swift:206:27:206:35 | call to source2() : | semmle.label | call to source2() : | -| string.swift:207:13:207:13 | str5 | semmle.label | str5 | -| string.swift:212:17:212:25 | call to source2() : | semmle.label | call to source2() : | -| string.swift:213:20:213:27 | call to source() : | semmle.label | call to source() : | -| string.swift:216:13:216:27 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:216:20:216:20 | tainted : | semmle.label | tainted : | -| string.swift:217:13:217:30 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:217:20:217:20 | taintedInt : | semmle.label | taintedInt : | -| string.swift:219:13:219:44 | call to String.init(format:_:) | semmle.label | call to String.init(format:_:) | -| string.swift:219:28:219:28 | tainted : | semmle.label | tainted : | -| string.swift:220:13:220:50 | call to String.init(format:arguments:) | semmle.label | call to String.init(format:arguments:) | -| string.swift:220:28:220:28 | tainted : | semmle.label | tainted : | -| string.swift:221:13:221:57 | call to String.init(format:locale:_:) | semmle.label | call to String.init(format:locale:_:) | -| string.swift:221:28:221:28 | tainted : | semmle.label | tainted : | -| string.swift:222:13:222:63 | call to String.init(format:locale:arguments:) | semmle.label | call to String.init(format:locale:arguments:) | -| string.swift:222:28:222:28 | tainted : | semmle.label | tainted : | -| string.swift:223:13:223:62 | call to localizedStringWithFormat(_:_:) | semmle.label | call to localizedStringWithFormat(_:_:) | -| string.swift:223:46:223:46 | tainted : | semmle.label | tainted : | -| string.swift:228:13:228:48 | call to String.init(repeating:count:) | semmle.label | call to String.init(repeating:count:) | -| string.swift:228:31:228:31 | tainted : | semmle.label | tainted : | -| string.swift:230:13:230:13 | tainted : | semmle.label | tainted : | -| string.swift:230:13:230:33 | call to dropFirst(_:) | semmle.label | call to dropFirst(_:) | -| string.swift:231:13:231:13 | tainted : | semmle.label | tainted : | -| string.swift:231:13:231:32 | call to dropLast(_:) | semmle.label | call to dropLast(_:) | -| string.swift:232:13:232:13 | tainted : | semmle.label | tainted : | -| string.swift:232:13:232:55 | call to substring(from:) | semmle.label | call to substring(from:) | -| string.swift:234:13:234:13 | tainted : | semmle.label | tainted : | -| string.swift:234:13:234:32 | call to lowercased() | semmle.label | call to lowercased() | +| string.swift:101:3:101:63 | [summary param] this in lowercased(with:) : | semmle.label | [summary param] this in lowercased(with:) : | +| string.swift:102:3:102:63 | [summary param] this in uppercased(with:) : | semmle.label | [summary param] this in uppercased(with:) : | +| string.swift:103:3:103:64 | [summary param] this in capitalized(with:) : | semmle.label | [summary param] this in capitalized(with:) : | +| string.swift:104:3:104:64 | [summary param] this in substring(from:) : | semmle.label | [summary param] this in substring(from:) : | +| string.swift:105:3:105:71 | [summary param] this in trimmingCharacters(in:) : | semmle.label | [summary param] this in trimmingCharacters(in:) : | +| string.swift:106:3:106:82 | [summary param] 0 in appending(_:) : | semmle.label | [summary param] 0 in appending(_:) : | +| string.swift:106:3:106:82 | [summary param] this in appending(_:) : | semmle.label | [summary param] this in appending(_:) : | +| string.swift:107:3:107:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | semmle.label | [summary param] this in padding(toLength:withPad:startingAt:) : | +| string.swift:108:3:108:80 | [summary param] this in components(separatedBy:) : | semmle.label | [summary param] this in components(separatedBy:) : | +| string.swift:109:3:109:92 | [summary param] this in folding(options:locale:) : | semmle.label | [summary param] this in folding(options:locale:) : | +| string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | semmle.label | [summary param] this in propertyListFromStringsFileFormat() : | +| string.swift:111:3:111:74 | [summary param] this in cString(using:) : | semmle.label | [summary param] this in cString(using:) : | +| string.swift:112:3:112:79 | self[return] : | semmle.label | self[return] : | +| string.swift:112:8:112:8 | self : | semmle.label | self : | +| string.swift:137:11:137:18 | call to source() : | semmle.label | call to source() : | +| string.swift:139:13:139:13 | "..." | semmle.label | "..." | +| string.swift:141:13:141:13 | "..." | semmle.label | "..." | +| string.swift:143:13:143:13 | "..." | semmle.label | "..." | +| string.swift:149:13:149:13 | "..." | semmle.label | "..." | +| string.swift:151:13:151:13 | "..." | semmle.label | "..." | +| string.swift:161:17:161:25 | call to source2() : | semmle.label | call to source2() : | +| string.swift:164:13:164:13 | tainted | semmle.label | tainted | +| string.swift:167:13:167:21 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| string.swift:168:13:168:23 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| string.swift:169:13:169:23 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| string.swift:172:13:172:29 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| string.swift:175:13:175:36 | call to appending(_:) | semmle.label | call to appending(_:) | +| string.swift:175:29:175:29 | tainted : | semmle.label | tainted : | +| string.swift:176:13:176:13 | tainted : | semmle.label | tainted : | +| string.swift:176:13:176:36 | call to appending(_:) | semmle.label | call to appending(_:) | +| string.swift:177:13:177:13 | tainted : | semmle.label | tainted : | +| string.swift:177:13:177:38 | call to appending(_:) | semmle.label | call to appending(_:) | +| string.swift:177:31:177:31 | tainted : | semmle.label | tainted : | +| string.swift:190:3:190:3 | [post] &... : | semmle.label | [post] &... : | +| string.swift:190:15:190:23 | call to source2() : | semmle.label | call to source2() : | +| string.swift:191:13:191:13 | str2 | semmle.label | str2 | +| string.swift:197:3:197:3 | [post] &... : | semmle.label | [post] &... : | +| string.swift:197:27:197:35 | call to source2() : | semmle.label | call to source2() : | +| string.swift:198:13:198:13 | str3 | semmle.label | str3 | +| string.swift:204:3:204:3 | [post] &... : | semmle.label | [post] &... : | +| string.swift:204:14:204:22 | call to source2() : | semmle.label | call to source2() : | +| string.swift:205:13:205:13 | str4 | semmle.label | str4 | +| string.swift:211:3:211:3 | [post] &... : | semmle.label | [post] &... : | +| string.swift:211:27:211:35 | call to source2() : | semmle.label | call to source2() : | +| string.swift:212:13:212:13 | str5 | semmle.label | str5 | +| string.swift:217:17:217:25 | call to source2() : | semmle.label | call to source2() : | +| string.swift:218:20:218:27 | call to source() : | semmle.label | call to source() : | +| string.swift:221:13:221:27 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:221:20:221:20 | tainted : | semmle.label | tainted : | +| string.swift:222:13:222:30 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:222:20:222:20 | taintedInt : | semmle.label | taintedInt : | +| string.swift:224:13:224:44 | call to String.init(format:_:) | semmle.label | call to String.init(format:_:) | +| string.swift:224:28:224:28 | tainted : | semmle.label | tainted : | +| string.swift:225:13:225:50 | call to String.init(format:arguments:) | semmle.label | call to String.init(format:arguments:) | +| string.swift:225:28:225:28 | tainted : | semmle.label | tainted : | +| string.swift:226:13:226:57 | call to String.init(format:locale:_:) | semmle.label | call to String.init(format:locale:_:) | +| string.swift:226:28:226:28 | tainted : | semmle.label | tainted : | +| string.swift:227:13:227:63 | call to String.init(format:locale:arguments:) | semmle.label | call to String.init(format:locale:arguments:) | +| string.swift:227:28:227:28 | tainted : | semmle.label | tainted : | +| string.swift:228:13:228:62 | call to localizedStringWithFormat(_:_:) | semmle.label | call to localizedStringWithFormat(_:_:) | +| string.swift:228:46:228:46 | tainted : | semmle.label | tainted : | +| string.swift:233:13:233:48 | call to String.init(repeating:count:) | semmle.label | call to String.init(repeating:count:) | +| string.swift:233:31:233:31 | tainted : | semmle.label | tainted : | | string.swift:235:13:235:13 | tainted : | semmle.label | tainted : | -| string.swift:235:13:235:32 | call to uppercased() | semmle.label | call to uppercased() | +| string.swift:235:13:235:33 | call to dropFirst(_:) | semmle.label | call to dropFirst(_:) | | string.swift:236:13:236:13 | tainted : | semmle.label | tainted : | -| string.swift:236:13:236:41 | call to lowercased(with:) | semmle.label | call to lowercased(with:) | +| string.swift:236:13:236:32 | call to dropLast(_:) | semmle.label | call to dropLast(_:) | | string.swift:237:13:237:13 | tainted : | semmle.label | tainted : | -| string.swift:237:13:237:41 | call to uppercased(with:) | semmle.label | call to uppercased(with:) | -| string.swift:238:13:238:13 | tainted : | semmle.label | tainted : | -| string.swift:238:13:238:42 | call to capitalized(with:) | semmle.label | call to capitalized(with:) | +| string.swift:237:13:237:55 | call to substring(from:) | semmle.label | call to substring(from:) | | string.swift:239:13:239:13 | tainted : | semmle.label | tainted : | -| string.swift:239:13:239:30 | call to reversed() | semmle.label | call to reversed() | +| string.swift:239:13:239:32 | call to lowercased() | semmle.label | call to lowercased() | +| string.swift:240:13:240:13 | tainted : | semmle.label | tainted : | +| string.swift:240:13:240:32 | call to uppercased() | semmle.label | call to uppercased() | | string.swift:241:13:241:13 | tainted : | semmle.label | tainted : | -| string.swift:241:13:241:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | semmle.label | call to split(separator:maxSplits:omittingEmptySubsequences:) | +| string.swift:241:13:241:41 | call to lowercased(with:) | semmle.label | call to lowercased(with:) | | string.swift:242:13:242:13 | tainted : | semmle.label | tainted : | -| string.swift:242:13:244:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | semmle.label | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | -| string.swift:245:13:245:13 | tainted : | semmle.label | tainted : | -| string.swift:245:13:245:68 | call to trimmingCharacters(in:) | semmle.label | call to trimmingCharacters(in:) | +| string.swift:242:13:242:41 | call to uppercased(with:) | semmle.label | call to uppercased(with:) | +| string.swift:243:13:243:13 | tainted : | semmle.label | tainted : | +| string.swift:243:13:243:42 | call to capitalized(with:) | semmle.label | call to capitalized(with:) | +| string.swift:244:13:244:13 | tainted : | semmle.label | tainted : | +| string.swift:244:13:244:30 | call to reversed() | semmle.label | call to reversed() | | string.swift:246:13:246:13 | tainted : | semmle.label | tainted : | -| string.swift:246:13:246:70 | call to padding(toLength:withPad:startingAt:) | semmle.label | call to padding(toLength:withPad:startingAt:) | +| string.swift:246:13:246:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | semmle.label | call to split(separator:maxSplits:omittingEmptySubsequences:) | | string.swift:247:13:247:13 | tainted : | semmle.label | tainted : | -| string.swift:247:13:247:69 | call to components(separatedBy:) | semmle.label | call to components(separatedBy:) | -| string.swift:248:13:248:13 | tainted : | semmle.label | tainted : | -| string.swift:248:13:248:69 | call to components(separatedBy:) : | semmle.label | call to components(separatedBy:) : | -| string.swift:248:13:248:72 | ...[...] | semmle.label | ...[...] | -| string.swift:249:13:249:13 | tainted : | semmle.label | tainted : | -| string.swift:249:13:249:40 | call to folding(options:locale:) | semmle.label | call to folding(options:locale:) | +| string.swift:247:13:249:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | semmle.label | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | | string.swift:250:13:250:13 | tainted : | semmle.label | tainted : | -| string.swift:250:13:250:55 | call to propertyListFromStringsFileFormat() | semmle.label | call to propertyListFromStringsFileFormat() | +| string.swift:250:13:250:68 | call to trimmingCharacters(in:) | semmle.label | call to trimmingCharacters(in:) | | string.swift:251:13:251:13 | tainted : | semmle.label | tainted : | -| string.swift:251:13:251:55 | call to propertyListFromStringsFileFormat() : | semmle.label | call to propertyListFromStringsFileFormat() : | -| string.swift:251:13:251:63 | ...! | semmle.label | ...! | -| string.swift:258:13:258:13 | [post] tainted : | semmle.label | [post] tainted : | -| string.swift:258:13:258:13 | tainted : | semmle.label | tainted : | -| string.swift:270:13:270:21 | .description | semmle.label | .description | -| string.swift:272:13:272:21 | .debugDescription | semmle.label | .debugDescription | -| string.swift:274:13:274:21 | .utf8 | semmle.label | .utf8 | -| string.swift:276:13:276:21 | .utf16 | semmle.label | .utf16 | -| string.swift:278:13:278:21 | .unicodeScalars | semmle.label | .unicodeScalars | -| string.swift:280:13:280:21 | .utf8CString | semmle.label | .utf8CString | -| string.swift:282:13:282:21 | .lazy | semmle.label | .lazy | -| string.swift:284:13:284:21 | .capitalized | semmle.label | .capitalized | -| string.swift:286:13:286:21 | .localizedCapitalized | semmle.label | .localizedCapitalized | -| string.swift:288:13:288:21 | .localizedLowercase | semmle.label | .localizedLowercase | -| string.swift:290:13:290:21 | .localizedUppercase | semmle.label | .localizedUppercase | -| string.swift:292:13:292:21 | .decomposedStringWithCanonicalMapping | semmle.label | .decomposedStringWithCanonicalMapping | -| string.swift:294:13:294:21 | .precomposedStringWithCompatibilityMapping | semmle.label | .precomposedStringWithCompatibilityMapping | -| string.swift:296:13:296:44 | ...! | semmle.label | ...! | -| string.swift:300:14:300:22 | call to source2() : | semmle.label | call to source2() : | -| string.swift:301:13:301:13 | str1 | semmle.label | str1 | -| string.swift:302:13:302:13 | &... : | semmle.label | &... : | -| string.swift:302:13:302:44 | call to remove(at:) | semmle.label | call to remove(at:) | -| string.swift:303:13:303:13 | str1 | semmle.label | str1 | -| string.swift:305:14:305:22 | call to source2() : | semmle.label | call to source2() : | -| string.swift:306:13:306:13 | str2 | semmle.label | str2 | -| string.swift:308:13:308:13 | str2 | semmle.label | str2 | -| string.swift:310:14:310:22 | call to source2() : | semmle.label | call to source2() : | -| string.swift:311:13:311:13 | str3 | semmle.label | str3 | -| string.swift:313:13:313:13 | str3 | semmle.label | str3 | -| string.swift:315:14:315:22 | call to source2() : | semmle.label | call to source2() : | -| string.swift:316:13:316:13 | str4 | semmle.label | str4 | -| string.swift:317:13:317:13 | &... : | semmle.label | &... : | -| string.swift:317:13:317:30 | call to removeFirst() | semmle.label | call to removeFirst() | -| string.swift:318:13:318:13 | str4 | semmle.label | str4 | -| string.swift:320:13:320:13 | str4 | semmle.label | str4 | -| string.swift:321:13:321:13 | &... : | semmle.label | &... : | -| string.swift:321:13:321:29 | call to removeLast() | semmle.label | call to removeLast() | -| string.swift:322:13:322:13 | str4 | semmle.label | str4 | -| string.swift:324:13:324:13 | str4 | semmle.label | str4 | -| string.swift:326:14:326:22 | call to source2() : | semmle.label | call to source2() : | -| string.swift:327:13:327:13 | str5 | semmle.label | str5 | -| string.swift:329:13:329:13 | str5 | semmle.label | str5 | -| string.swift:331:14:331:22 | call to source2() : | semmle.label | call to source2() : | -| string.swift:332:13:332:13 | str6 | semmle.label | str6 | -| string.swift:334:13:334:13 | str6 | semmle.label | str6 | -| string.swift:341:23:341:77 | call to String.init(data:encoding:) : | semmle.label | call to String.init(data:encoding:) : | -| string.swift:341:36:341:44 | call to source3() : | semmle.label | call to source3() : | -| string.swift:344:12:344:25 | ...! | semmle.label | ...! | -| string.swift:347:13:347:54 | call to String.init(decoding:as:) | semmle.label | call to String.init(decoding:as:) | -| string.swift:347:30:347:38 | call to source3() : | semmle.label | call to source3() : | -| string.swift:352:17:352:25 | call to source2() : | semmle.label | call to source2() : | -| string.swift:389:22:389:22 | tainted : | semmle.label | tainted : | -| string.swift:389:22:389:65 | call to cString(using:) : | semmle.label | call to cString(using:) : | -| string.swift:390:13:390:13 | arrayString2 | semmle.label | arrayString2 | -| string.swift:436:28:436:36 | call to source4() : | semmle.label | call to source4() : | -| string.swift:456:13:456:77 | call to String.init(bytes:encoding:) : | semmle.label | call to String.init(bytes:encoding:) : | -| string.swift:456:13:456:78 | ...! | semmle.label | ...! | -| string.swift:456:27:456:27 | taintedUInt8Values : | semmle.label | taintedUInt8Values : | -| string.swift:459:13:459:47 | call to String.init(cString:) | semmle.label | call to String.init(cString:) | -| string.swift:459:29:459:29 | taintedUInt8Values : | semmle.label | taintedUInt8Values : | -| string.swift:492:37:492:45 | call to source5() : | semmle.label | call to source5() : | -| string.swift:512:13:512:47 | call to String.init(cString:) | semmle.label | call to String.init(cString:) | -| string.swift:512:29:512:29 | taintedCCharValues : | semmle.label | taintedCCharValues : | -| string.swift:540:17:540:25 | call to source2() : | semmle.label | call to source2() : | -| string.swift:542:13:542:21 | call to source7() | semmle.label | call to source7() | -| string.swift:545:13:545:13 | sub1 | semmle.label | sub1 | -| string.swift:546:13:546:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:546:20:546:20 | sub1 : | semmle.label | sub1 : | -| string.swift:548:14:548:14 | tainted : | semmle.label | tainted : | -| string.swift:548:14:548:31 | call to prefix(_:) : | semmle.label | call to prefix(_:) : | -| string.swift:549:13:549:13 | sub2 | semmle.label | sub2 | -| string.swift:550:13:550:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:550:20:550:20 | sub2 : | semmle.label | sub2 : | -| string.swift:552:14:552:14 | tainted : | semmle.label | tainted : | -| string.swift:552:14:552:54 | call to prefix(through:) : | semmle.label | call to prefix(through:) : | -| string.swift:553:13:553:13 | sub3 | semmle.label | sub3 | -| string.swift:554:13:554:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:554:20:554:20 | sub3 : | semmle.label | sub3 : | -| string.swift:556:14:556:14 | tainted : | semmle.label | tainted : | -| string.swift:556:14:556:51 | call to prefix(upTo:) : | semmle.label | call to prefix(upTo:) : | -| string.swift:557:13:557:13 | sub4 | semmle.label | sub4 | -| string.swift:558:13:558:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:558:20:558:20 | sub4 : | semmle.label | sub4 : | -| string.swift:560:14:560:14 | tainted : | semmle.label | tainted : | -| string.swift:560:14:560:31 | call to suffix(_:) : | semmle.label | call to suffix(_:) : | -| string.swift:561:13:561:13 | sub5 | semmle.label | sub5 | -| string.swift:562:13:562:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:562:20:562:20 | sub5 : | semmle.label | sub5 : | -| string.swift:564:14:564:14 | tainted : | semmle.label | tainted : | -| string.swift:564:14:564:53 | call to suffix(from:) : | semmle.label | call to suffix(from:) : | -| string.swift:565:13:565:13 | sub6 | semmle.label | sub6 | -| string.swift:566:13:566:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:566:20:566:20 | sub6 : | semmle.label | sub6 : | -| string.swift:622:13:622:28 | call to String.init(_:) | semmle.label | call to String.init(_:) | -| string.swift:622:20:622:27 | call to source() : | semmle.label | call to source() : | -| string.swift:626:13:626:40 | call to String.init(describing:) | semmle.label | call to String.init(describing:) | -| string.swift:626:32:626:39 | call to source() : | semmle.label | call to source() : | +| string.swift:251:13:251:70 | call to padding(toLength:withPad:startingAt:) | semmle.label | call to padding(toLength:withPad:startingAt:) | +| string.swift:252:13:252:13 | tainted : | semmle.label | tainted : | +| string.swift:252:13:252:69 | call to components(separatedBy:) | semmle.label | call to components(separatedBy:) | +| string.swift:253:13:253:13 | tainted : | semmle.label | tainted : | +| string.swift:253:13:253:69 | call to components(separatedBy:) : | semmle.label | call to components(separatedBy:) : | +| string.swift:253:13:253:72 | ...[...] | semmle.label | ...[...] | +| string.swift:254:13:254:13 | tainted : | semmle.label | tainted : | +| string.swift:254:13:254:40 | call to folding(options:locale:) | semmle.label | call to folding(options:locale:) | +| string.swift:255:13:255:13 | tainted : | semmle.label | tainted : | +| string.swift:255:13:255:55 | call to propertyListFromStringsFileFormat() | semmle.label | call to propertyListFromStringsFileFormat() | +| string.swift:256:13:256:13 | tainted : | semmle.label | tainted : | +| string.swift:256:13:256:55 | call to propertyListFromStringsFileFormat() : | semmle.label | call to propertyListFromStringsFileFormat() : | +| string.swift:256:13:256:63 | ...! | semmle.label | ...! | +| string.swift:263:13:263:13 | [post] tainted : | semmle.label | [post] tainted : | +| string.swift:263:13:263:13 | tainted : | semmle.label | tainted : | +| string.swift:275:13:275:21 | .description | semmle.label | .description | +| string.swift:277:13:277:21 | .debugDescription | semmle.label | .debugDescription | +| string.swift:279:13:279:21 | .utf8 | semmle.label | .utf8 | +| string.swift:281:13:281:21 | .utf16 | semmle.label | .utf16 | +| string.swift:283:13:283:21 | .unicodeScalars | semmle.label | .unicodeScalars | +| string.swift:285:13:285:21 | .utf8CString | semmle.label | .utf8CString | +| string.swift:287:13:287:21 | .lazy | semmle.label | .lazy | +| string.swift:289:13:289:21 | .capitalized | semmle.label | .capitalized | +| string.swift:291:13:291:21 | .localizedCapitalized | semmle.label | .localizedCapitalized | +| string.swift:293:13:293:21 | .localizedLowercase | semmle.label | .localizedLowercase | +| string.swift:295:13:295:21 | .localizedUppercase | semmle.label | .localizedUppercase | +| string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | semmle.label | .decomposedStringWithCanonicalMapping | +| string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | semmle.label | .precomposedStringWithCompatibilityMapping | +| string.swift:301:13:301:44 | ...! | semmle.label | ...! | +| string.swift:309:14:309:22 | call to source2() : | semmle.label | call to source2() : | +| string.swift:310:13:310:13 | str1 | semmle.label | str1 | +| string.swift:311:13:311:13 | &... : | semmle.label | &... : | +| string.swift:311:13:311:44 | call to remove(at:) | semmle.label | call to remove(at:) | +| string.swift:312:13:312:13 | str1 | semmle.label | str1 | +| string.swift:314:14:314:22 | call to source2() : | semmle.label | call to source2() : | +| string.swift:315:13:315:13 | str2 | semmle.label | str2 | +| string.swift:317:13:317:13 | str2 | semmle.label | str2 | +| string.swift:319:14:319:22 | call to source2() : | semmle.label | call to source2() : | +| string.swift:320:13:320:13 | str3 | semmle.label | str3 | +| string.swift:322:13:322:13 | str3 | semmle.label | str3 | +| string.swift:324:14:324:22 | call to source2() : | semmle.label | call to source2() : | +| string.swift:325:13:325:13 | str4 | semmle.label | str4 | +| string.swift:326:13:326:13 | &... : | semmle.label | &... : | +| string.swift:326:13:326:30 | call to removeFirst() | semmle.label | call to removeFirst() | +| string.swift:327:13:327:13 | str4 | semmle.label | str4 | +| string.swift:329:13:329:13 | str4 | semmle.label | str4 | +| string.swift:330:13:330:13 | &... : | semmle.label | &... : | +| string.swift:330:13:330:29 | call to removeLast() | semmle.label | call to removeLast() | +| string.swift:331:13:331:13 | str4 | semmle.label | str4 | +| string.swift:333:13:333:13 | str4 | semmle.label | str4 | +| string.swift:335:14:335:22 | call to source2() : | semmle.label | call to source2() : | +| string.swift:336:13:336:13 | str5 | semmle.label | str5 | +| string.swift:338:13:338:13 | str5 | semmle.label | str5 | +| string.swift:340:14:340:22 | call to source2() : | semmle.label | call to source2() : | +| string.swift:341:13:341:13 | str6 | semmle.label | str6 | +| string.swift:343:13:343:13 | str6 | semmle.label | str6 | +| string.swift:355:23:355:77 | call to String.init(data:encoding:) : | semmle.label | call to String.init(data:encoding:) : | +| string.swift:355:36:355:44 | call to source3() : | semmle.label | call to source3() : | +| string.swift:358:12:358:25 | ...! | semmle.label | ...! | +| string.swift:361:13:361:54 | call to String.init(decoding:as:) | semmle.label | call to String.init(decoding:as:) | +| string.swift:361:30:361:38 | call to source3() : | semmle.label | call to source3() : | +| string.swift:366:17:366:25 | call to source2() : | semmle.label | call to source2() : | +| string.swift:403:22:403:22 | tainted : | semmle.label | tainted : | +| string.swift:403:22:403:65 | call to cString(using:) : | semmle.label | call to cString(using:) : | +| string.swift:404:13:404:13 | arrayString2 | semmle.label | arrayString2 | +| string.swift:450:28:450:36 | call to source4() : | semmle.label | call to source4() : | +| string.swift:470:13:470:77 | call to String.init(bytes:encoding:) : | semmle.label | call to String.init(bytes:encoding:) : | +| string.swift:470:13:470:78 | ...! | semmle.label | ...! | +| string.swift:470:27:470:27 | taintedUInt8Values : | semmle.label | taintedUInt8Values : | +| string.swift:473:13:473:47 | call to String.init(cString:) | semmle.label | call to String.init(cString:) | +| string.swift:473:29:473:29 | taintedUInt8Values : | semmle.label | taintedUInt8Values : | +| string.swift:506:37:506:45 | call to source5() : | semmle.label | call to source5() : | +| string.swift:526:13:526:47 | call to String.init(cString:) | semmle.label | call to String.init(cString:) | +| string.swift:526:29:526:29 | taintedCCharValues : | semmle.label | taintedCCharValues : | +| string.swift:554:17:554:25 | call to source2() : | semmle.label | call to source2() : | +| string.swift:556:13:556:21 | call to source7() | semmle.label | call to source7() | +| string.swift:559:13:559:13 | sub1 | semmle.label | sub1 | +| string.swift:560:13:560:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:560:20:560:20 | sub1 : | semmle.label | sub1 : | +| string.swift:562:14:562:14 | tainted : | semmle.label | tainted : | +| string.swift:562:14:562:31 | call to prefix(_:) : | semmle.label | call to prefix(_:) : | +| string.swift:563:13:563:13 | sub2 | semmle.label | sub2 | +| string.swift:564:13:564:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:564:20:564:20 | sub2 : | semmle.label | sub2 : | +| string.swift:566:14:566:14 | tainted : | semmle.label | tainted : | +| string.swift:566:14:566:54 | call to prefix(through:) : | semmle.label | call to prefix(through:) : | +| string.swift:567:13:567:13 | sub3 | semmle.label | sub3 | +| string.swift:568:13:568:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:568:20:568:20 | sub3 : | semmle.label | sub3 : | +| string.swift:570:14:570:14 | tainted : | semmle.label | tainted : | +| string.swift:570:14:570:51 | call to prefix(upTo:) : | semmle.label | call to prefix(upTo:) : | +| string.swift:571:13:571:13 | sub4 | semmle.label | sub4 | +| string.swift:572:13:572:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:572:20:572:20 | sub4 : | semmle.label | sub4 : | +| string.swift:574:14:574:14 | tainted : | semmle.label | tainted : | +| string.swift:574:14:574:31 | call to suffix(_:) : | semmle.label | call to suffix(_:) : | +| string.swift:575:13:575:13 | sub5 | semmle.label | sub5 | +| string.swift:576:13:576:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:576:20:576:20 | sub5 : | semmle.label | sub5 : | +| string.swift:578:14:578:14 | tainted : | semmle.label | tainted : | +| string.swift:578:14:578:53 | call to suffix(from:) : | semmle.label | call to suffix(from:) : | +| string.swift:579:13:579:13 | sub6 | semmle.label | sub6 | +| string.swift:580:13:580:24 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:580:20:580:20 | sub6 : | semmle.label | sub6 : | +| string.swift:636:13:636:28 | call to String.init(_:) | semmle.label | call to String.init(_:) | +| string.swift:636:20:636:27 | call to source() : | semmle.label | call to source() : | +| string.swift:640:13:640:40 | call to String.init(describing:) | semmle.label | call to String.init(describing:) | +| string.swift:640:32:640:39 | call to source() : | semmle.label | call to source() : | | subscript.swift:13:15:13:22 | call to source() : | semmle.label | call to source() : | | subscript.swift:13:15:13:25 | ...[...] | semmle.label | ...[...] | | subscript.swift:14:15:14:23 | call to source2() : | semmle.label | call to source2() : | @@ -1864,63 +1864,63 @@ subpaths | nsmutabledata.swift:40:66:40:73 | call to source() : | nsmutabledata.swift:17:5:17:121 | [summary param] 1 in replaceBytes(in:withBytes:length:) : | file://:0:0:0:0 | [summary] to write: argument this in replaceBytes(in:withBytes:length:) : | nsmutabledata.swift:40:5:40:5 | [post] nsMutableDataTainted4 : | | nsmutabledata.swift:44:35:44:42 | call to source() : | nsmutabledata.swift:18:5:18:33 | [summary param] 0 in setData(_:) : | file://:0:0:0:0 | [summary] to write: argument this in setData(_:) : | nsmutabledata.swift:44:5:44:5 | [post] nsMutableDataTainted5 : | | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 : | nsmutabledata.swift:13:9:13:9 | self : | file://:0:0:0:0 | .mutableBytes : | nsmutabledata.swift:49:15:49:37 | .mutableBytes | -| string.swift:170:29:170:29 | tainted : | string.swift:103:3:103:82 | [summary param] 0 in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:170:13:170:36 | call to appending(_:) | -| string.swift:171:13:171:13 | tainted : | string.swift:103:3:103:82 | [summary param] this in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:171:13:171:36 | call to appending(_:) | -| string.swift:172:13:172:13 | tainted : | string.swift:103:3:103:82 | [summary param] this in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:172:13:172:38 | call to appending(_:) | -| string.swift:172:31:172:31 | tainted : | string.swift:103:3:103:82 | [summary param] 0 in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:172:13:172:38 | call to appending(_:) | -| string.swift:185:15:185:23 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(_:) : | file://:0:0:0:0 | [summary] to write: argument this in append(_:) : | string.swift:185:3:185:3 | [post] &... : | -| string.swift:192:27:192:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(contentsOf:) : | file://:0:0:0:0 | [summary] to write: argument this in append(contentsOf:) : | string.swift:192:3:192:3 | [post] &... : | -| string.swift:199:14:199:22 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in write(_:) : | file://:0:0:0:0 | [summary] to write: argument this in write(_:) : | string.swift:199:3:199:3 | [post] &... : | -| string.swift:206:27:206:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in insert(contentsOf:at:) : | file://:0:0:0:0 | [summary] to write: argument this in insert(contentsOf:at:) : | string.swift:206:3:206:3 | [post] &... : | -| string.swift:216:20:216:20 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:216:13:216:27 | call to String.init(_:) | -| string.swift:217:20:217:20 | taintedInt : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:217:13:217:30 | call to String.init(_:) | -| string.swift:219:28:219:28 | tainted : | string.swift:64:3:64:63 | [summary param] 0 in String.init(format:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:_:) : | string.swift:219:13:219:44 | call to String.init(format:_:) | -| string.swift:220:28:220:28 | tainted : | string.swift:65:3:65:60 | [summary param] 0 in String.init(format:arguments:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:arguments:) : | string.swift:220:13:220:50 | call to String.init(format:arguments:) | -| string.swift:221:28:221:28 | tainted : | string.swift:66:3:66:75 | [summary param] 0 in String.init(format:locale:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:locale:_:) : | string.swift:221:13:221:57 | call to String.init(format:locale:_:) | -| string.swift:222:28:222:28 | tainted : | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:locale:arguments:) : | string.swift:222:13:222:63 | call to String.init(format:locale:arguments:) | -| string.swift:223:46:223:46 | tainted : | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in localizedStringWithFormat(_:_:) : | string.swift:223:13:223:62 | call to localizedStringWithFormat(_:_:) | -| string.swift:228:31:228:31 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(repeating:count:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(repeating:count:) : | string.swift:228:13:228:48 | call to String.init(repeating:count:) | -| string.swift:230:13:230:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropFirst(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in dropFirst(_:) : | string.swift:230:13:230:33 | call to dropFirst(_:) | -| string.swift:231:13:231:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropLast(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in dropLast(_:) : | string.swift:231:13:231:32 | call to dropLast(_:) | -| string.swift:232:13:232:13 | tainted : | string.swift:101:3:101:64 | [summary param] this in substring(from:) : | file://:0:0:0:0 | [summary] to write: return (return) in substring(from:) : | string.swift:232:13:232:55 | call to substring(from:) | -| string.swift:234:13:234:13 | tainted : | file://:0:0:0:0 | [summary param] this in lowercased() : | file://:0:0:0:0 | [summary] to write: return (return) in lowercased() : | string.swift:234:13:234:32 | call to lowercased() | -| string.swift:235:13:235:13 | tainted : | file://:0:0:0:0 | [summary param] this in uppercased() : | file://:0:0:0:0 | [summary] to write: return (return) in uppercased() : | string.swift:235:13:235:32 | call to uppercased() | -| string.swift:236:13:236:13 | tainted : | string.swift:98:3:98:63 | [summary param] this in lowercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in lowercased(with:) : | string.swift:236:13:236:41 | call to lowercased(with:) | -| string.swift:237:13:237:13 | tainted : | string.swift:99:3:99:63 | [summary param] this in uppercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in uppercased(with:) : | string.swift:237:13:237:41 | call to uppercased(with:) | -| string.swift:238:13:238:13 | tainted : | string.swift:100:3:100:64 | [summary param] this in capitalized(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in capitalized(with:) : | string.swift:238:13:238:42 | call to capitalized(with:) | -| string.swift:239:13:239:13 | tainted : | file://:0:0:0:0 | [summary param] this in reversed() : | file://:0:0:0:0 | [summary] to write: return (return) in reversed() : | string.swift:239:13:239:30 | call to reversed() | -| string.swift:241:13:241:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(separator:maxSplits:omittingEmptySubsequences:) : | file://:0:0:0:0 | [summary] to write: return (return) in split(separator:maxSplits:omittingEmptySubsequences:) : | string.swift:241:13:241:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | -| string.swift:242:13:242:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(maxSplits:omittingEmptySubsequences:whereSeparator:) : | file://:0:0:0:0 | [summary] to write: return (return) in split(maxSplits:omittingEmptySubsequences:whereSeparator:) : | string.swift:242:13:244:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | -| string.swift:245:13:245:13 | tainted : | string.swift:102:3:102:71 | [summary param] this in trimmingCharacters(in:) : | file://:0:0:0:0 | [summary] to write: return (return) in trimmingCharacters(in:) : | string.swift:245:13:245:68 | call to trimmingCharacters(in:) | -| string.swift:246:13:246:13 | tainted : | string.swift:104:3:104:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | file://:0:0:0:0 | [summary] to write: return (return) in padding(toLength:withPad:startingAt:) : | string.swift:246:13:246:70 | call to padding(toLength:withPad:startingAt:) | -| string.swift:247:13:247:13 | tainted : | string.swift:105:3:105:80 | [summary param] this in components(separatedBy:) : | file://:0:0:0:0 | [summary] to write: return (return) in components(separatedBy:) : | string.swift:247:13:247:69 | call to components(separatedBy:) | -| string.swift:248:13:248:13 | tainted : | string.swift:105:3:105:80 | [summary param] this in components(separatedBy:) : | file://:0:0:0:0 | [summary] to write: return (return) in components(separatedBy:) : | string.swift:248:13:248:69 | call to components(separatedBy:) : | -| string.swift:249:13:249:13 | tainted : | string.swift:106:3:106:92 | [summary param] this in folding(options:locale:) : | file://:0:0:0:0 | [summary] to write: return (return) in folding(options:locale:) : | string.swift:249:13:249:40 | call to folding(options:locale:) | -| string.swift:250:13:250:13 | tainted : | string.swift:107:3:107:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | string.swift:250:13:250:55 | call to propertyListFromStringsFileFormat() | -| string.swift:251:13:251:13 | tainted : | string.swift:107:3:107:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | string.swift:251:13:251:55 | call to propertyListFromStringsFileFormat() : | -| string.swift:258:13:258:13 | tainted : | string.swift:109:8:109:8 | self : | string.swift:109:3:109:79 | self[return] : | string.swift:258:13:258:13 | [post] tainted : | -| string.swift:302:13:302:13 | &... : | file://:0:0:0:0 | [summary param] this in remove(at:) : | file://:0:0:0:0 | [summary] to write: return (return) in remove(at:) : | string.swift:302:13:302:44 | call to remove(at:) | -| string.swift:317:13:317:13 | &... : | file://:0:0:0:0 | [summary param] this in removeFirst() : | file://:0:0:0:0 | [summary] to write: return (return) in removeFirst() : | string.swift:317:13:317:30 | call to removeFirst() | -| string.swift:321:13:321:13 | &... : | file://:0:0:0:0 | [summary param] this in removeLast() : | file://:0:0:0:0 | [summary] to write: return (return) in removeLast() : | string.swift:321:13:321:29 | call to removeLast() | -| string.swift:341:36:341:44 | call to source3() : | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(data:encoding:) : | string.swift:341:23:341:77 | call to String.init(data:encoding:) : | -| string.swift:347:30:347:38 | call to source3() : | file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(decoding:as:) : | string.swift:347:13:347:54 | call to String.init(decoding:as:) | -| string.swift:389:22:389:22 | tainted : | string.swift:108:3:108:74 | [summary param] this in cString(using:) : | file://:0:0:0:0 | [summary] to write: return (return) in cString(using:) : | string.swift:389:22:389:65 | call to cString(using:) : | -| string.swift:456:27:456:27 | taintedUInt8Values : | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(bytes:encoding:) : | string.swift:456:13:456:77 | call to String.init(bytes:encoding:) : | -| string.swift:459:29:459:29 | taintedUInt8Values : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(cString:) : | string.swift:459:13:459:47 | call to String.init(cString:) | -| string.swift:512:29:512:29 | taintedCCharValues : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(cString:) : | string.swift:512:13:512:47 | call to String.init(cString:) | -| string.swift:546:20:546:20 | sub1 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:546:13:546:24 | call to String.init(_:) | -| string.swift:548:14:548:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in prefix(_:) : | string.swift:548:14:548:31 | call to prefix(_:) : | -| string.swift:550:20:550:20 | sub2 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:550:13:550:24 | call to String.init(_:) | -| string.swift:552:14:552:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(through:) : | file://:0:0:0:0 | [summary] to write: return (return) in prefix(through:) : | string.swift:552:14:552:54 | call to prefix(through:) : | -| string.swift:554:20:554:20 | sub3 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:554:13:554:24 | call to String.init(_:) | -| string.swift:556:14:556:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(upTo:) : | file://:0:0:0:0 | [summary] to write: return (return) in prefix(upTo:) : | string.swift:556:14:556:51 | call to prefix(upTo:) : | -| string.swift:558:20:558:20 | sub4 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:558:13:558:24 | call to String.init(_:) | -| string.swift:560:14:560:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in suffix(_:) : | string.swift:560:14:560:31 | call to suffix(_:) : | -| string.swift:562:20:562:20 | sub5 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:562:13:562:24 | call to String.init(_:) | -| string.swift:564:14:564:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(from:) : | file://:0:0:0:0 | [summary] to write: return (return) in suffix(from:) : | string.swift:564:14:564:53 | call to suffix(from:) : | -| string.swift:566:20:566:20 | sub6 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:566:13:566:24 | call to String.init(_:) | -| string.swift:622:20:622:27 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:622:13:622:28 | call to String.init(_:) | -| string.swift:626:32:626:39 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(describing:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(describing:) : | string.swift:626:13:626:40 | call to String.init(describing:) | +| string.swift:175:29:175:29 | tainted : | string.swift:106:3:106:82 | [summary param] 0 in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:175:13:175:36 | call to appending(_:) | +| string.swift:176:13:176:13 | tainted : | string.swift:106:3:106:82 | [summary param] this in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:176:13:176:36 | call to appending(_:) | +| string.swift:177:13:177:13 | tainted : | string.swift:106:3:106:82 | [summary param] this in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:177:13:177:38 | call to appending(_:) | +| string.swift:177:31:177:31 | tainted : | string.swift:106:3:106:82 | [summary param] 0 in appending(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in appending(_:) : | string.swift:177:13:177:38 | call to appending(_:) | +| string.swift:190:15:190:23 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(_:) : | file://:0:0:0:0 | [summary] to write: argument this in append(_:) : | string.swift:190:3:190:3 | [post] &... : | +| string.swift:197:27:197:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in append(contentsOf:) : | file://:0:0:0:0 | [summary] to write: argument this in append(contentsOf:) : | string.swift:197:3:197:3 | [post] &... : | +| string.swift:204:14:204:22 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in write(_:) : | file://:0:0:0:0 | [summary] to write: argument this in write(_:) : | string.swift:204:3:204:3 | [post] &... : | +| string.swift:211:27:211:35 | call to source2() : | file://:0:0:0:0 | [summary param] 0 in insert(contentsOf:at:) : | file://:0:0:0:0 | [summary] to write: argument this in insert(contentsOf:at:) : | string.swift:211:3:211:3 | [post] &... : | +| string.swift:221:20:221:20 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:221:13:221:27 | call to String.init(_:) | +| string.swift:222:20:222:20 | taintedInt : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:222:13:222:30 | call to String.init(_:) | +| string.swift:224:28:224:28 | tainted : | string.swift:64:3:64:63 | [summary param] 0 in String.init(format:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:_:) : | string.swift:224:13:224:44 | call to String.init(format:_:) | +| string.swift:225:28:225:28 | tainted : | string.swift:65:3:65:60 | [summary param] 0 in String.init(format:arguments:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:arguments:) : | string.swift:225:13:225:50 | call to String.init(format:arguments:) | +| string.swift:226:28:226:28 | tainted : | string.swift:66:3:66:75 | [summary param] 0 in String.init(format:locale:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:locale:_:) : | string.swift:226:13:226:57 | call to String.init(format:locale:_:) | +| string.swift:227:28:227:28 | tainted : | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:locale:arguments:) : | string.swift:227:13:227:63 | call to String.init(format:locale:arguments:) | +| string.swift:228:46:228:46 | tainted : | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in localizedStringWithFormat(_:_:) : | string.swift:228:13:228:62 | call to localizedStringWithFormat(_:_:) | +| string.swift:233:31:233:31 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(repeating:count:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(repeating:count:) : | string.swift:233:13:233:48 | call to String.init(repeating:count:) | +| string.swift:235:13:235:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropFirst(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in dropFirst(_:) : | string.swift:235:13:235:33 | call to dropFirst(_:) | +| string.swift:236:13:236:13 | tainted : | file://:0:0:0:0 | [summary param] this in dropLast(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in dropLast(_:) : | string.swift:236:13:236:32 | call to dropLast(_:) | +| string.swift:237:13:237:13 | tainted : | string.swift:104:3:104:64 | [summary param] this in substring(from:) : | file://:0:0:0:0 | [summary] to write: return (return) in substring(from:) : | string.swift:237:13:237:55 | call to substring(from:) | +| string.swift:239:13:239:13 | tainted : | file://:0:0:0:0 | [summary param] this in lowercased() : | file://:0:0:0:0 | [summary] to write: return (return) in lowercased() : | string.swift:239:13:239:32 | call to lowercased() | +| string.swift:240:13:240:13 | tainted : | file://:0:0:0:0 | [summary param] this in uppercased() : | file://:0:0:0:0 | [summary] to write: return (return) in uppercased() : | string.swift:240:13:240:32 | call to uppercased() | +| string.swift:241:13:241:13 | tainted : | string.swift:101:3:101:63 | [summary param] this in lowercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in lowercased(with:) : | string.swift:241:13:241:41 | call to lowercased(with:) | +| string.swift:242:13:242:13 | tainted : | string.swift:102:3:102:63 | [summary param] this in uppercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in uppercased(with:) : | string.swift:242:13:242:41 | call to uppercased(with:) | +| string.swift:243:13:243:13 | tainted : | string.swift:103:3:103:64 | [summary param] this in capitalized(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in capitalized(with:) : | string.swift:243:13:243:42 | call to capitalized(with:) | +| string.swift:244:13:244:13 | tainted : | file://:0:0:0:0 | [summary param] this in reversed() : | file://:0:0:0:0 | [summary] to write: return (return) in reversed() : | string.swift:244:13:244:30 | call to reversed() | +| string.swift:246:13:246:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(separator:maxSplits:omittingEmptySubsequences:) : | file://:0:0:0:0 | [summary] to write: return (return) in split(separator:maxSplits:omittingEmptySubsequences:) : | string.swift:246:13:246:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | +| string.swift:247:13:247:13 | tainted : | file://:0:0:0:0 | [summary param] this in split(maxSplits:omittingEmptySubsequences:whereSeparator:) : | file://:0:0:0:0 | [summary] to write: return (return) in split(maxSplits:omittingEmptySubsequences:whereSeparator:) : | string.swift:247:13:249:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | +| string.swift:250:13:250:13 | tainted : | string.swift:105:3:105:71 | [summary param] this in trimmingCharacters(in:) : | file://:0:0:0:0 | [summary] to write: return (return) in trimmingCharacters(in:) : | string.swift:250:13:250:68 | call to trimmingCharacters(in:) | +| string.swift:251:13:251:13 | tainted : | string.swift:107:3:107:138 | [summary param] this in padding(toLength:withPad:startingAt:) : | file://:0:0:0:0 | [summary] to write: return (return) in padding(toLength:withPad:startingAt:) : | string.swift:251:13:251:70 | call to padding(toLength:withPad:startingAt:) | +| string.swift:252:13:252:13 | tainted : | string.swift:108:3:108:80 | [summary param] this in components(separatedBy:) : | file://:0:0:0:0 | [summary] to write: return (return) in components(separatedBy:) : | string.swift:252:13:252:69 | call to components(separatedBy:) | +| string.swift:253:13:253:13 | tainted : | string.swift:108:3:108:80 | [summary param] this in components(separatedBy:) : | file://:0:0:0:0 | [summary] to write: return (return) in components(separatedBy:) : | string.swift:253:13:253:69 | call to components(separatedBy:) : | +| string.swift:254:13:254:13 | tainted : | string.swift:109:3:109:92 | [summary param] this in folding(options:locale:) : | file://:0:0:0:0 | [summary] to write: return (return) in folding(options:locale:) : | string.swift:254:13:254:40 | call to folding(options:locale:) | +| string.swift:255:13:255:13 | tainted : | string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | string.swift:255:13:255:55 | call to propertyListFromStringsFileFormat() | +| string.swift:256:13:256:13 | tainted : | string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | string.swift:256:13:256:55 | call to propertyListFromStringsFileFormat() : | +| string.swift:263:13:263:13 | tainted : | string.swift:112:8:112:8 | self : | string.swift:112:3:112:79 | self[return] : | string.swift:263:13:263:13 | [post] tainted : | +| string.swift:311:13:311:13 | &... : | file://:0:0:0:0 | [summary param] this in remove(at:) : | file://:0:0:0:0 | [summary] to write: return (return) in remove(at:) : | string.swift:311:13:311:44 | call to remove(at:) | +| string.swift:326:13:326:13 | &... : | file://:0:0:0:0 | [summary param] this in removeFirst() : | file://:0:0:0:0 | [summary] to write: return (return) in removeFirst() : | string.swift:326:13:326:30 | call to removeFirst() | +| string.swift:330:13:330:13 | &... : | file://:0:0:0:0 | [summary param] this in removeLast() : | file://:0:0:0:0 | [summary] to write: return (return) in removeLast() : | string.swift:330:13:330:29 | call to removeLast() | +| string.swift:355:36:355:44 | call to source3() : | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(data:encoding:) : | string.swift:355:23:355:77 | call to String.init(data:encoding:) : | +| string.swift:361:30:361:38 | call to source3() : | file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(decoding:as:) : | string.swift:361:13:361:54 | call to String.init(decoding:as:) | +| string.swift:403:22:403:22 | tainted : | string.swift:111:3:111:74 | [summary param] this in cString(using:) : | file://:0:0:0:0 | [summary] to write: return (return) in cString(using:) : | string.swift:403:22:403:65 | call to cString(using:) : | +| string.swift:470:27:470:27 | taintedUInt8Values : | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(bytes:encoding:) : | string.swift:470:13:470:77 | call to String.init(bytes:encoding:) : | +| string.swift:473:29:473:29 | taintedUInt8Values : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(cString:) : | string.swift:473:13:473:47 | call to String.init(cString:) | +| string.swift:526:29:526:29 | taintedCCharValues : | file://:0:0:0:0 | [summary param] 0 in String.init(cString:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(cString:) : | string.swift:526:13:526:47 | call to String.init(cString:) | +| string.swift:560:20:560:20 | sub1 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:560:13:560:24 | call to String.init(_:) | +| string.swift:562:14:562:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in prefix(_:) : | string.swift:562:14:562:31 | call to prefix(_:) : | +| string.swift:564:20:564:20 | sub2 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:564:13:564:24 | call to String.init(_:) | +| string.swift:566:14:566:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(through:) : | file://:0:0:0:0 | [summary] to write: return (return) in prefix(through:) : | string.swift:566:14:566:54 | call to prefix(through:) : | +| string.swift:568:20:568:20 | sub3 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:568:13:568:24 | call to String.init(_:) | +| string.swift:570:14:570:14 | tainted : | file://:0:0:0:0 | [summary param] this in prefix(upTo:) : | file://:0:0:0:0 | [summary] to write: return (return) in prefix(upTo:) : | string.swift:570:14:570:51 | call to prefix(upTo:) : | +| string.swift:572:20:572:20 | sub4 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:572:13:572:24 | call to String.init(_:) | +| string.swift:574:14:574:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in suffix(_:) : | string.swift:574:14:574:31 | call to suffix(_:) : | +| string.swift:576:20:576:20 | sub5 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:576:13:576:24 | call to String.init(_:) | +| string.swift:578:14:578:14 | tainted : | file://:0:0:0:0 | [summary param] this in suffix(from:) : | file://:0:0:0:0 | [summary] to write: return (return) in suffix(from:) : | string.swift:578:14:578:53 | call to suffix(from:) : | +| string.swift:580:20:580:20 | sub6 : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:580:13:580:24 | call to String.init(_:) | +| string.swift:636:20:636:27 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(_:) : | string.swift:636:13:636:28 | call to String.init(_:) | +| string.swift:640:32:640:39 | call to source() : | file://:0:0:0:0 | [summary param] 0 in String.init(describing:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(describing:) : | string.swift:640:13:640:40 | call to String.init(describing:) | | ui.swift:55:10:55:10 | tainted : | ui.swift:16:9:16:9 | self : | file://:0:0:0:0 | .url : | ui.swift:55:10:55:18 | .url | | ui.swift:64:10:64:10 | tainted : | ui.swift:32:13:32:13 | self : | file://:0:0:0:0 | .userActivities : | ui.swift:64:10:64:18 | .userActivities | | ui.swift:68:10:68:10 | tainted : | ui.swift:34:13:34:13 | self : | file://:0:0:0:0 | .urlContexts : | ui.swift:68:10:68:18 | .urlContexts | @@ -2056,102 +2056,102 @@ subpaths | nsmutabledata.swift:41:15:41:15 | nsMutableDataTainted4 | nsmutabledata.swift:40:66:40:73 | call to source() : | nsmutabledata.swift:41:15:41:15 | nsMutableDataTainted4 | result | | nsmutabledata.swift:45:15:45:15 | nsMutableDataTainted5 | nsmutabledata.swift:44:35:44:42 | call to source() : | nsmutabledata.swift:45:15:45:15 | nsMutableDataTainted5 | result | | nsmutabledata.swift:49:15:49:37 | .mutableBytes | nsmutabledata.swift:48:33:48:40 | call to source() : | nsmutabledata.swift:49:15:49:37 | .mutableBytes | result | -| string.swift:134:13:134:13 | "..." | string.swift:132:11:132:18 | call to source() : | string.swift:134:13:134:13 | "..." | result | -| string.swift:136:13:136:13 | "..." | string.swift:132:11:132:18 | call to source() : | string.swift:136:13:136:13 | "..." | result | -| string.swift:138:13:138:13 | "..." | string.swift:132:11:132:18 | call to source() : | string.swift:138:13:138:13 | "..." | result | -| string.swift:144:13:144:13 | "..." | string.swift:132:11:132:18 | call to source() : | string.swift:144:13:144:13 | "..." | result | -| string.swift:146:13:146:13 | "..." | string.swift:132:11:132:18 | call to source() : | string.swift:146:13:146:13 | "..." | result | -| string.swift:159:13:159:13 | tainted | string.swift:156:17:156:25 | call to source2() : | string.swift:159:13:159:13 | tainted | result | -| string.swift:162:13:162:21 | ... .+(_:_:) ... | string.swift:156:17:156:25 | call to source2() : | string.swift:162:13:162:21 | ... .+(_:_:) ... | result | -| string.swift:163:13:163:23 | ... .+(_:_:) ... | string.swift:156:17:156:25 | call to source2() : | string.swift:163:13:163:23 | ... .+(_:_:) ... | result | -| string.swift:164:13:164:23 | ... .+(_:_:) ... | string.swift:156:17:156:25 | call to source2() : | string.swift:164:13:164:23 | ... .+(_:_:) ... | result | -| string.swift:167:13:167:29 | ... .+(_:_:) ... | string.swift:156:17:156:25 | call to source2() : | string.swift:167:13:167:29 | ... .+(_:_:) ... | result | -| string.swift:170:13:170:36 | call to appending(_:) | string.swift:156:17:156:25 | call to source2() : | string.swift:170:13:170:36 | call to appending(_:) | result | -| string.swift:171:13:171:36 | call to appending(_:) | string.swift:156:17:156:25 | call to source2() : | string.swift:171:13:171:36 | call to appending(_:) | result | -| string.swift:172:13:172:38 | call to appending(_:) | string.swift:156:17:156:25 | call to source2() : | string.swift:172:13:172:38 | call to appending(_:) | result | -| string.swift:186:13:186:13 | str2 | string.swift:185:15:185:23 | call to source2() : | string.swift:186:13:186:13 | str2 | result | -| string.swift:193:13:193:13 | str3 | string.swift:192:27:192:35 | call to source2() : | string.swift:193:13:193:13 | str3 | result | -| string.swift:200:13:200:13 | str4 | string.swift:199:14:199:22 | call to source2() : | string.swift:200:13:200:13 | str4 | result | -| string.swift:207:13:207:13 | str5 | string.swift:206:27:206:35 | call to source2() : | string.swift:207:13:207:13 | str5 | result | -| string.swift:216:13:216:27 | call to String.init(_:) | string.swift:212:17:212:25 | call to source2() : | string.swift:216:13:216:27 | call to String.init(_:) | result | -| string.swift:217:13:217:30 | call to String.init(_:) | string.swift:213:20:213:27 | call to source() : | string.swift:217:13:217:30 | call to String.init(_:) | result | -| string.swift:219:13:219:44 | call to String.init(format:_:) | string.swift:212:17:212:25 | call to source2() : | string.swift:219:13:219:44 | call to String.init(format:_:) | result | -| string.swift:220:13:220:50 | call to String.init(format:arguments:) | string.swift:212:17:212:25 | call to source2() : | string.swift:220:13:220:50 | call to String.init(format:arguments:) | result | -| string.swift:221:13:221:57 | call to String.init(format:locale:_:) | string.swift:212:17:212:25 | call to source2() : | string.swift:221:13:221:57 | call to String.init(format:locale:_:) | result | -| string.swift:222:13:222:63 | call to String.init(format:locale:arguments:) | string.swift:212:17:212:25 | call to source2() : | string.swift:222:13:222:63 | call to String.init(format:locale:arguments:) | result | -| string.swift:223:13:223:62 | call to localizedStringWithFormat(_:_:) | string.swift:212:17:212:25 | call to source2() : | string.swift:223:13:223:62 | call to localizedStringWithFormat(_:_:) | result | -| string.swift:228:13:228:48 | call to String.init(repeating:count:) | string.swift:212:17:212:25 | call to source2() : | string.swift:228:13:228:48 | call to String.init(repeating:count:) | result | -| string.swift:230:13:230:33 | call to dropFirst(_:) | string.swift:212:17:212:25 | call to source2() : | string.swift:230:13:230:33 | call to dropFirst(_:) | result | -| string.swift:231:13:231:32 | call to dropLast(_:) | string.swift:212:17:212:25 | call to source2() : | string.swift:231:13:231:32 | call to dropLast(_:) | result | -| string.swift:232:13:232:55 | call to substring(from:) | string.swift:212:17:212:25 | call to source2() : | string.swift:232:13:232:55 | call to substring(from:) | result | -| string.swift:234:13:234:32 | call to lowercased() | string.swift:212:17:212:25 | call to source2() : | string.swift:234:13:234:32 | call to lowercased() | result | -| string.swift:235:13:235:32 | call to uppercased() | string.swift:212:17:212:25 | call to source2() : | string.swift:235:13:235:32 | call to uppercased() | result | -| string.swift:236:13:236:41 | call to lowercased(with:) | string.swift:212:17:212:25 | call to source2() : | string.swift:236:13:236:41 | call to lowercased(with:) | result | -| string.swift:237:13:237:41 | call to uppercased(with:) | string.swift:212:17:212:25 | call to source2() : | string.swift:237:13:237:41 | call to uppercased(with:) | result | -| string.swift:238:13:238:42 | call to capitalized(with:) | string.swift:212:17:212:25 | call to source2() : | string.swift:238:13:238:42 | call to capitalized(with:) | result | -| string.swift:239:13:239:30 | call to reversed() | string.swift:212:17:212:25 | call to source2() : | string.swift:239:13:239:30 | call to reversed() | result | -| string.swift:241:13:241:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | string.swift:212:17:212:25 | call to source2() : | string.swift:241:13:241:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | result | -| string.swift:242:13:244:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | string.swift:212:17:212:25 | call to source2() : | string.swift:242:13:244:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | result | -| string.swift:245:13:245:68 | call to trimmingCharacters(in:) | string.swift:212:17:212:25 | call to source2() : | string.swift:245:13:245:68 | call to trimmingCharacters(in:) | result | -| string.swift:246:13:246:70 | call to padding(toLength:withPad:startingAt:) | string.swift:212:17:212:25 | call to source2() : | string.swift:246:13:246:70 | call to padding(toLength:withPad:startingAt:) | result | -| string.swift:247:13:247:69 | call to components(separatedBy:) | string.swift:212:17:212:25 | call to source2() : | string.swift:247:13:247:69 | call to components(separatedBy:) | result | -| string.swift:248:13:248:72 | ...[...] | string.swift:212:17:212:25 | call to source2() : | string.swift:248:13:248:72 | ...[...] | result | -| string.swift:249:13:249:40 | call to folding(options:locale:) | string.swift:212:17:212:25 | call to source2() : | string.swift:249:13:249:40 | call to folding(options:locale:) | result | -| string.swift:250:13:250:55 | call to propertyListFromStringsFileFormat() | string.swift:212:17:212:25 | call to source2() : | string.swift:250:13:250:55 | call to propertyListFromStringsFileFormat() | result | -| string.swift:251:13:251:63 | ...! | string.swift:212:17:212:25 | call to source2() : | string.swift:251:13:251:63 | ...! | result | -| string.swift:270:13:270:21 | .description | string.swift:212:17:212:25 | call to source2() : | string.swift:270:13:270:21 | .description | result | -| string.swift:272:13:272:21 | .debugDescription | string.swift:212:17:212:25 | call to source2() : | string.swift:272:13:272:21 | .debugDescription | result | -| string.swift:274:13:274:21 | .utf8 | string.swift:212:17:212:25 | call to source2() : | string.swift:274:13:274:21 | .utf8 | result | -| string.swift:276:13:276:21 | .utf16 | string.swift:212:17:212:25 | call to source2() : | string.swift:276:13:276:21 | .utf16 | result | -| string.swift:278:13:278:21 | .unicodeScalars | string.swift:212:17:212:25 | call to source2() : | string.swift:278:13:278:21 | .unicodeScalars | result | -| string.swift:280:13:280:21 | .utf8CString | string.swift:212:17:212:25 | call to source2() : | string.swift:280:13:280:21 | .utf8CString | result | -| string.swift:282:13:282:21 | .lazy | string.swift:212:17:212:25 | call to source2() : | string.swift:282:13:282:21 | .lazy | result | -| string.swift:284:13:284:21 | .capitalized | string.swift:212:17:212:25 | call to source2() : | string.swift:284:13:284:21 | .capitalized | result | -| string.swift:286:13:286:21 | .localizedCapitalized | string.swift:212:17:212:25 | call to source2() : | string.swift:286:13:286:21 | .localizedCapitalized | result | -| string.swift:288:13:288:21 | .localizedLowercase | string.swift:212:17:212:25 | call to source2() : | string.swift:288:13:288:21 | .localizedLowercase | result | -| string.swift:290:13:290:21 | .localizedUppercase | string.swift:212:17:212:25 | call to source2() : | string.swift:290:13:290:21 | .localizedUppercase | result | -| string.swift:292:13:292:21 | .decomposedStringWithCanonicalMapping | string.swift:212:17:212:25 | call to source2() : | string.swift:292:13:292:21 | .decomposedStringWithCanonicalMapping | result | -| string.swift:294:13:294:21 | .precomposedStringWithCompatibilityMapping | string.swift:212:17:212:25 | call to source2() : | string.swift:294:13:294:21 | .precomposedStringWithCompatibilityMapping | result | -| string.swift:296:13:296:44 | ...! | string.swift:212:17:212:25 | call to source2() : | string.swift:296:13:296:44 | ...! | result | -| string.swift:301:13:301:13 | str1 | string.swift:300:14:300:22 | call to source2() : | string.swift:301:13:301:13 | str1 | result | -| string.swift:302:13:302:44 | call to remove(at:) | string.swift:300:14:300:22 | call to source2() : | string.swift:302:13:302:44 | call to remove(at:) | result | -| string.swift:303:13:303:13 | str1 | string.swift:300:14:300:22 | call to source2() : | string.swift:303:13:303:13 | str1 | result | -| string.swift:306:13:306:13 | str2 | string.swift:305:14:305:22 | call to source2() : | string.swift:306:13:306:13 | str2 | result | -| string.swift:308:13:308:13 | str2 | string.swift:305:14:305:22 | call to source2() : | string.swift:308:13:308:13 | str2 | result | -| string.swift:311:13:311:13 | str3 | string.swift:310:14:310:22 | call to source2() : | string.swift:311:13:311:13 | str3 | result | -| string.swift:313:13:313:13 | str3 | string.swift:310:14:310:22 | call to source2() : | string.swift:313:13:313:13 | str3 | result | -| string.swift:316:13:316:13 | str4 | string.swift:315:14:315:22 | call to source2() : | string.swift:316:13:316:13 | str4 | result | -| string.swift:317:13:317:30 | call to removeFirst() | string.swift:315:14:315:22 | call to source2() : | string.swift:317:13:317:30 | call to removeFirst() | result | -| string.swift:318:13:318:13 | str4 | string.swift:315:14:315:22 | call to source2() : | string.swift:318:13:318:13 | str4 | result | -| string.swift:320:13:320:13 | str4 | string.swift:315:14:315:22 | call to source2() : | string.swift:320:13:320:13 | str4 | result | -| string.swift:321:13:321:29 | call to removeLast() | string.swift:315:14:315:22 | call to source2() : | string.swift:321:13:321:29 | call to removeLast() | result | -| string.swift:322:13:322:13 | str4 | string.swift:315:14:315:22 | call to source2() : | string.swift:322:13:322:13 | str4 | result | -| string.swift:324:13:324:13 | str4 | string.swift:315:14:315:22 | call to source2() : | string.swift:324:13:324:13 | str4 | result | -| string.swift:327:13:327:13 | str5 | string.swift:326:14:326:22 | call to source2() : | string.swift:327:13:327:13 | str5 | result | -| string.swift:329:13:329:13 | str5 | string.swift:326:14:326:22 | call to source2() : | string.swift:329:13:329:13 | str5 | result | -| string.swift:332:13:332:13 | str6 | string.swift:331:14:331:22 | call to source2() : | string.swift:332:13:332:13 | str6 | result | -| string.swift:334:13:334:13 | str6 | string.swift:331:14:331:22 | call to source2() : | string.swift:334:13:334:13 | str6 | result | -| string.swift:344:12:344:25 | ...! | string.swift:341:36:341:44 | call to source3() : | string.swift:344:12:344:25 | ...! | result | -| string.swift:347:13:347:54 | call to String.init(decoding:as:) | string.swift:347:30:347:38 | call to source3() : | string.swift:347:13:347:54 | call to String.init(decoding:as:) | result | -| string.swift:390:13:390:13 | arrayString2 | string.swift:352:17:352:25 | call to source2() : | string.swift:390:13:390:13 | arrayString2 | result | -| string.swift:456:13:456:78 | ...! | string.swift:436:28:436:36 | call to source4() : | string.swift:456:13:456:78 | ...! | result | -| string.swift:459:13:459:47 | call to String.init(cString:) | string.swift:436:28:436:36 | call to source4() : | string.swift:459:13:459:47 | call to String.init(cString:) | result | -| string.swift:512:13:512:47 | call to String.init(cString:) | string.swift:492:37:492:45 | call to source5() : | string.swift:512:13:512:47 | call to String.init(cString:) | result | -| string.swift:542:13:542:21 | call to source7() | string.swift:542:13:542:21 | call to source7() | string.swift:542:13:542:21 | call to source7() | result | -| string.swift:545:13:545:13 | sub1 | string.swift:540:17:540:25 | call to source2() : | string.swift:545:13:545:13 | sub1 | result | -| string.swift:546:13:546:24 | call to String.init(_:) | string.swift:540:17:540:25 | call to source2() : | string.swift:546:13:546:24 | call to String.init(_:) | result | -| string.swift:549:13:549:13 | sub2 | string.swift:540:17:540:25 | call to source2() : | string.swift:549:13:549:13 | sub2 | result | -| string.swift:550:13:550:24 | call to String.init(_:) | string.swift:540:17:540:25 | call to source2() : | string.swift:550:13:550:24 | call to String.init(_:) | result | -| string.swift:553:13:553:13 | sub3 | string.swift:540:17:540:25 | call to source2() : | string.swift:553:13:553:13 | sub3 | result | -| string.swift:554:13:554:24 | call to String.init(_:) | string.swift:540:17:540:25 | call to source2() : | string.swift:554:13:554:24 | call to String.init(_:) | result | -| string.swift:557:13:557:13 | sub4 | string.swift:540:17:540:25 | call to source2() : | string.swift:557:13:557:13 | sub4 | result | -| string.swift:558:13:558:24 | call to String.init(_:) | string.swift:540:17:540:25 | call to source2() : | string.swift:558:13:558:24 | call to String.init(_:) | result | -| string.swift:561:13:561:13 | sub5 | string.swift:540:17:540:25 | call to source2() : | string.swift:561:13:561:13 | sub5 | result | -| string.swift:562:13:562:24 | call to String.init(_:) | string.swift:540:17:540:25 | call to source2() : | string.swift:562:13:562:24 | call to String.init(_:) | result | -| string.swift:565:13:565:13 | sub6 | string.swift:540:17:540:25 | call to source2() : | string.swift:565:13:565:13 | sub6 | result | -| string.swift:566:13:566:24 | call to String.init(_:) | string.swift:540:17:540:25 | call to source2() : | string.swift:566:13:566:24 | call to String.init(_:) | result | -| string.swift:622:13:622:28 | call to String.init(_:) | string.swift:622:20:622:27 | call to source() : | string.swift:622:13:622:28 | call to String.init(_:) | result | -| string.swift:626:13:626:40 | call to String.init(describing:) | string.swift:626:32:626:39 | call to source() : | string.swift:626:13:626:40 | call to String.init(describing:) | result | +| string.swift:139:13:139:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:139:13:139:13 | "..." | result | +| string.swift:141:13:141:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:141:13:141:13 | "..." | result | +| string.swift:143:13:143:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:143:13:143:13 | "..." | result | +| string.swift:149:13:149:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:149:13:149:13 | "..." | result | +| string.swift:151:13:151:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:151:13:151:13 | "..." | result | +| string.swift:164:13:164:13 | tainted | string.swift:161:17:161:25 | call to source2() : | string.swift:164:13:164:13 | tainted | result | +| string.swift:167:13:167:21 | ... .+(_:_:) ... | string.swift:161:17:161:25 | call to source2() : | string.swift:167:13:167:21 | ... .+(_:_:) ... | result | +| string.swift:168:13:168:23 | ... .+(_:_:) ... | string.swift:161:17:161:25 | call to source2() : | string.swift:168:13:168:23 | ... .+(_:_:) ... | result | +| string.swift:169:13:169:23 | ... .+(_:_:) ... | string.swift:161:17:161:25 | call to source2() : | string.swift:169:13:169:23 | ... .+(_:_:) ... | result | +| string.swift:172:13:172:29 | ... .+(_:_:) ... | string.swift:161:17:161:25 | call to source2() : | string.swift:172:13:172:29 | ... .+(_:_:) ... | result | +| string.swift:175:13:175:36 | call to appending(_:) | string.swift:161:17:161:25 | call to source2() : | string.swift:175:13:175:36 | call to appending(_:) | result | +| string.swift:176:13:176:36 | call to appending(_:) | string.swift:161:17:161:25 | call to source2() : | string.swift:176:13:176:36 | call to appending(_:) | result | +| string.swift:177:13:177:38 | call to appending(_:) | string.swift:161:17:161:25 | call to source2() : | string.swift:177:13:177:38 | call to appending(_:) | result | +| string.swift:191:13:191:13 | str2 | string.swift:190:15:190:23 | call to source2() : | string.swift:191:13:191:13 | str2 | result | +| string.swift:198:13:198:13 | str3 | string.swift:197:27:197:35 | call to source2() : | string.swift:198:13:198:13 | str3 | result | +| string.swift:205:13:205:13 | str4 | string.swift:204:14:204:22 | call to source2() : | string.swift:205:13:205:13 | str4 | result | +| string.swift:212:13:212:13 | str5 | string.swift:211:27:211:35 | call to source2() : | string.swift:212:13:212:13 | str5 | result | +| string.swift:221:13:221:27 | call to String.init(_:) | string.swift:217:17:217:25 | call to source2() : | string.swift:221:13:221:27 | call to String.init(_:) | result | +| string.swift:222:13:222:30 | call to String.init(_:) | string.swift:218:20:218:27 | call to source() : | string.swift:222:13:222:30 | call to String.init(_:) | result | +| string.swift:224:13:224:44 | call to String.init(format:_:) | string.swift:217:17:217:25 | call to source2() : | string.swift:224:13:224:44 | call to String.init(format:_:) | result | +| string.swift:225:13:225:50 | call to String.init(format:arguments:) | string.swift:217:17:217:25 | call to source2() : | string.swift:225:13:225:50 | call to String.init(format:arguments:) | result | +| string.swift:226:13:226:57 | call to String.init(format:locale:_:) | string.swift:217:17:217:25 | call to source2() : | string.swift:226:13:226:57 | call to String.init(format:locale:_:) | result | +| string.swift:227:13:227:63 | call to String.init(format:locale:arguments:) | string.swift:217:17:217:25 | call to source2() : | string.swift:227:13:227:63 | call to String.init(format:locale:arguments:) | result | +| string.swift:228:13:228:62 | call to localizedStringWithFormat(_:_:) | string.swift:217:17:217:25 | call to source2() : | string.swift:228:13:228:62 | call to localizedStringWithFormat(_:_:) | result | +| string.swift:233:13:233:48 | call to String.init(repeating:count:) | string.swift:217:17:217:25 | call to source2() : | string.swift:233:13:233:48 | call to String.init(repeating:count:) | result | +| string.swift:235:13:235:33 | call to dropFirst(_:) | string.swift:217:17:217:25 | call to source2() : | string.swift:235:13:235:33 | call to dropFirst(_:) | result | +| string.swift:236:13:236:32 | call to dropLast(_:) | string.swift:217:17:217:25 | call to source2() : | string.swift:236:13:236:32 | call to dropLast(_:) | result | +| string.swift:237:13:237:55 | call to substring(from:) | string.swift:217:17:217:25 | call to source2() : | string.swift:237:13:237:55 | call to substring(from:) | result | +| string.swift:239:13:239:32 | call to lowercased() | string.swift:217:17:217:25 | call to source2() : | string.swift:239:13:239:32 | call to lowercased() | result | +| string.swift:240:13:240:32 | call to uppercased() | string.swift:217:17:217:25 | call to source2() : | string.swift:240:13:240:32 | call to uppercased() | result | +| string.swift:241:13:241:41 | call to lowercased(with:) | string.swift:217:17:217:25 | call to source2() : | string.swift:241:13:241:41 | call to lowercased(with:) | result | +| string.swift:242:13:242:41 | call to uppercased(with:) | string.swift:217:17:217:25 | call to source2() : | string.swift:242:13:242:41 | call to uppercased(with:) | result | +| string.swift:243:13:243:42 | call to capitalized(with:) | string.swift:217:17:217:25 | call to source2() : | string.swift:243:13:243:42 | call to capitalized(with:) | result | +| string.swift:244:13:244:30 | call to reversed() | string.swift:217:17:217:25 | call to source2() : | string.swift:244:13:244:30 | call to reversed() | result | +| string.swift:246:13:246:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | string.swift:217:17:217:25 | call to source2() : | string.swift:246:13:246:41 | call to split(separator:maxSplits:omittingEmptySubsequences:) | result | +| string.swift:247:13:249:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | string.swift:217:17:217:25 | call to source2() : | string.swift:247:13:249:4 | call to split(maxSplits:omittingEmptySubsequences:whereSeparator:) | result | +| string.swift:250:13:250:68 | call to trimmingCharacters(in:) | string.swift:217:17:217:25 | call to source2() : | string.swift:250:13:250:68 | call to trimmingCharacters(in:) | result | +| string.swift:251:13:251:70 | call to padding(toLength:withPad:startingAt:) | string.swift:217:17:217:25 | call to source2() : | string.swift:251:13:251:70 | call to padding(toLength:withPad:startingAt:) | result | +| string.swift:252:13:252:69 | call to components(separatedBy:) | string.swift:217:17:217:25 | call to source2() : | string.swift:252:13:252:69 | call to components(separatedBy:) | result | +| string.swift:253:13:253:72 | ...[...] | string.swift:217:17:217:25 | call to source2() : | string.swift:253:13:253:72 | ...[...] | result | +| string.swift:254:13:254:40 | call to folding(options:locale:) | string.swift:217:17:217:25 | call to source2() : | string.swift:254:13:254:40 | call to folding(options:locale:) | result | +| string.swift:255:13:255:55 | call to propertyListFromStringsFileFormat() | string.swift:217:17:217:25 | call to source2() : | string.swift:255:13:255:55 | call to propertyListFromStringsFileFormat() | result | +| string.swift:256:13:256:63 | ...! | string.swift:217:17:217:25 | call to source2() : | string.swift:256:13:256:63 | ...! | result | +| string.swift:275:13:275:21 | .description | string.swift:217:17:217:25 | call to source2() : | string.swift:275:13:275:21 | .description | result | +| string.swift:277:13:277:21 | .debugDescription | string.swift:217:17:217:25 | call to source2() : | string.swift:277:13:277:21 | .debugDescription | result | +| string.swift:279:13:279:21 | .utf8 | string.swift:217:17:217:25 | call to source2() : | string.swift:279:13:279:21 | .utf8 | result | +| string.swift:281:13:281:21 | .utf16 | string.swift:217:17:217:25 | call to source2() : | string.swift:281:13:281:21 | .utf16 | result | +| string.swift:283:13:283:21 | .unicodeScalars | string.swift:217:17:217:25 | call to source2() : | string.swift:283:13:283:21 | .unicodeScalars | result | +| string.swift:285:13:285:21 | .utf8CString | string.swift:217:17:217:25 | call to source2() : | string.swift:285:13:285:21 | .utf8CString | result | +| string.swift:287:13:287:21 | .lazy | string.swift:217:17:217:25 | call to source2() : | string.swift:287:13:287:21 | .lazy | result | +| string.swift:289:13:289:21 | .capitalized | string.swift:217:17:217:25 | call to source2() : | string.swift:289:13:289:21 | .capitalized | result | +| string.swift:291:13:291:21 | .localizedCapitalized | string.swift:217:17:217:25 | call to source2() : | string.swift:291:13:291:21 | .localizedCapitalized | result | +| string.swift:293:13:293:21 | .localizedLowercase | string.swift:217:17:217:25 | call to source2() : | string.swift:293:13:293:21 | .localizedLowercase | result | +| string.swift:295:13:295:21 | .localizedUppercase | string.swift:217:17:217:25 | call to source2() : | string.swift:295:13:295:21 | .localizedUppercase | result | +| string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | string.swift:217:17:217:25 | call to source2() : | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | result | +| string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | string.swift:217:17:217:25 | call to source2() : | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | result | +| string.swift:301:13:301:44 | ...! | string.swift:217:17:217:25 | call to source2() : | string.swift:301:13:301:44 | ...! | result | +| string.swift:310:13:310:13 | str1 | string.swift:309:14:309:22 | call to source2() : | string.swift:310:13:310:13 | str1 | result | +| string.swift:311:13:311:44 | call to remove(at:) | string.swift:309:14:309:22 | call to source2() : | string.swift:311:13:311:44 | call to remove(at:) | result | +| string.swift:312:13:312:13 | str1 | string.swift:309:14:309:22 | call to source2() : | string.swift:312:13:312:13 | str1 | result | +| string.swift:315:13:315:13 | str2 | string.swift:314:14:314:22 | call to source2() : | string.swift:315:13:315:13 | str2 | result | +| string.swift:317:13:317:13 | str2 | string.swift:314:14:314:22 | call to source2() : | string.swift:317:13:317:13 | str2 | result | +| string.swift:320:13:320:13 | str3 | string.swift:319:14:319:22 | call to source2() : | string.swift:320:13:320:13 | str3 | result | +| string.swift:322:13:322:13 | str3 | string.swift:319:14:319:22 | call to source2() : | string.swift:322:13:322:13 | str3 | result | +| string.swift:325:13:325:13 | str4 | string.swift:324:14:324:22 | call to source2() : | string.swift:325:13:325:13 | str4 | result | +| string.swift:326:13:326:30 | call to removeFirst() | string.swift:324:14:324:22 | call to source2() : | string.swift:326:13:326:30 | call to removeFirst() | result | +| string.swift:327:13:327:13 | str4 | string.swift:324:14:324:22 | call to source2() : | string.swift:327:13:327:13 | str4 | result | +| string.swift:329:13:329:13 | str4 | string.swift:324:14:324:22 | call to source2() : | string.swift:329:13:329:13 | str4 | result | +| string.swift:330:13:330:29 | call to removeLast() | string.swift:324:14:324:22 | call to source2() : | string.swift:330:13:330:29 | call to removeLast() | result | +| string.swift:331:13:331:13 | str4 | string.swift:324:14:324:22 | call to source2() : | string.swift:331:13:331:13 | str4 | result | +| string.swift:333:13:333:13 | str4 | string.swift:324:14:324:22 | call to source2() : | string.swift:333:13:333:13 | str4 | result | +| string.swift:336:13:336:13 | str5 | string.swift:335:14:335:22 | call to source2() : | string.swift:336:13:336:13 | str5 | result | +| string.swift:338:13:338:13 | str5 | string.swift:335:14:335:22 | call to source2() : | string.swift:338:13:338:13 | str5 | result | +| string.swift:341:13:341:13 | str6 | string.swift:340:14:340:22 | call to source2() : | string.swift:341:13:341:13 | str6 | result | +| string.swift:343:13:343:13 | str6 | string.swift:340:14:340:22 | call to source2() : | string.swift:343:13:343:13 | str6 | result | +| string.swift:358:12:358:25 | ...! | string.swift:355:36:355:44 | call to source3() : | string.swift:358:12:358:25 | ...! | result | +| string.swift:361:13:361:54 | call to String.init(decoding:as:) | string.swift:361:30:361:38 | call to source3() : | string.swift:361:13:361:54 | call to String.init(decoding:as:) | result | +| string.swift:404:13:404:13 | arrayString2 | string.swift:366:17:366:25 | call to source2() : | string.swift:404:13:404:13 | arrayString2 | result | +| string.swift:470:13:470:78 | ...! | string.swift:450:28:450:36 | call to source4() : | string.swift:470:13:470:78 | ...! | result | +| string.swift:473:13:473:47 | call to String.init(cString:) | string.swift:450:28:450:36 | call to source4() : | string.swift:473:13:473:47 | call to String.init(cString:) | result | +| string.swift:526:13:526:47 | call to String.init(cString:) | string.swift:506:37:506:45 | call to source5() : | string.swift:526:13:526:47 | call to String.init(cString:) | result | +| string.swift:556:13:556:21 | call to source7() | string.swift:556:13:556:21 | call to source7() | string.swift:556:13:556:21 | call to source7() | result | +| string.swift:559:13:559:13 | sub1 | string.swift:554:17:554:25 | call to source2() : | string.swift:559:13:559:13 | sub1 | result | +| string.swift:560:13:560:24 | call to String.init(_:) | string.swift:554:17:554:25 | call to source2() : | string.swift:560:13:560:24 | call to String.init(_:) | result | +| string.swift:563:13:563:13 | sub2 | string.swift:554:17:554:25 | call to source2() : | string.swift:563:13:563:13 | sub2 | result | +| string.swift:564:13:564:24 | call to String.init(_:) | string.swift:554:17:554:25 | call to source2() : | string.swift:564:13:564:24 | call to String.init(_:) | result | +| string.swift:567:13:567:13 | sub3 | string.swift:554:17:554:25 | call to source2() : | string.swift:567:13:567:13 | sub3 | result | +| string.swift:568:13:568:24 | call to String.init(_:) | string.swift:554:17:554:25 | call to source2() : | string.swift:568:13:568:24 | call to String.init(_:) | result | +| string.swift:571:13:571:13 | sub4 | string.swift:554:17:554:25 | call to source2() : | string.swift:571:13:571:13 | sub4 | result | +| string.swift:572:13:572:24 | call to String.init(_:) | string.swift:554:17:554:25 | call to source2() : | string.swift:572:13:572:24 | call to String.init(_:) | result | +| string.swift:575:13:575:13 | sub5 | string.swift:554:17:554:25 | call to source2() : | string.swift:575:13:575:13 | sub5 | result | +| string.swift:576:13:576:24 | call to String.init(_:) | string.swift:554:17:554:25 | call to source2() : | string.swift:576:13:576:24 | call to String.init(_:) | result | +| string.swift:579:13:579:13 | sub6 | string.swift:554:17:554:25 | call to source2() : | string.swift:579:13:579:13 | sub6 | result | +| string.swift:580:13:580:24 | call to String.init(_:) | string.swift:554:17:554:25 | call to source2() : | string.swift:580:13:580:24 | call to String.init(_:) | result | +| string.swift:636:13:636:28 | call to String.init(_:) | string.swift:636:20:636:27 | call to source() : | string.swift:636:13:636:28 | call to String.init(_:) | result | +| string.swift:640:13:640:40 | call to String.init(describing:) | string.swift:640:32:640:39 | call to source() : | string.swift:640:13:640:40 | call to String.init(describing:) | result | | subscript.swift:13:15:13:25 | ...[...] | subscript.swift:13:15:13:22 | call to source() : | subscript.swift:13:15:13:25 | ...[...] | result | | subscript.swift:14:15:14:26 | ...[...] | subscript.swift:14:15:14:23 | call to source2() : | subscript.swift:14:15:14:26 | ...[...] | result | | try.swift:9:13:9:24 | try ... | try.swift:9:17:9:24 | call to source() : | try.swift:9:13:9:24 | try ... | result | diff --git a/swift/ql/test/library-tests/dataflow/taint/string.swift b/swift/ql/test/library-tests/dataflow/taint/string.swift index 45d4bb078a6..0a0245dfb8e 100644 --- a/swift/ql/test/library-tests/dataflow/taint/string.swift +++ b/swift/ql/test/library-tests/dataflow/taint/string.swift @@ -82,6 +82,9 @@ extension String : CVarArg { func withPlatformString(_ body: (UnsafePointer) throws -> Result) rethrows -> Result { return 0 as! Result } init?(validating path: FilePath) { self.init() } + + mutating func replaceSubrange(_ subrange: Range, with newElements: C) + where C : Collection, C.Element == Character {} } extension StringProtocol { @@ -107,6 +110,8 @@ extension StringProtocol { func propertyListFromStringsFileFormat() -> [String : String] { return [:] } func cString(using encoding: String.Encoding) -> [CChar]? { return nil } func enumerateLines(invoking body: @escaping (String, inout Bool) -> Void) {} + func replacingOccurrences(of target: Target, with replacement: Replacement, options: String.CompareOptions = [], range searchRange: Range? = nil) -> String + where Target : StringProtocol, Replacement : StringProtocol { return "" } } class Data @@ -131,19 +136,19 @@ func sink(arg: Any) {} func taintThroughInterpolatedStrings() { var x = source() - sink(arg: "\(x)") // $ tainted=132 + sink(arg: "\(x)") // $ tainted=137 - sink(arg: "\(x) \(x)") // $ tainted=132 + sink(arg: "\(x) \(x)") // $ tainted=137 - sink(arg: "\(x) \(0) \(x)") // $ tainted=132 + sink(arg: "\(x) \(0) \(x)") // $ tainted=137 let y = 42 sink(arg: "\(y)") // clean - sink(arg: "\(x) hello \(y)") // $ tainted=132 + sink(arg: "\(x) hello \(y)") // $ tainted=137 - sink(arg: "\(y) world \(x)") // $ tainted=132 + sink(arg: "\(y) world \(x)") // $ tainted=137 x = 0 sink(arg: "\(x)") // clean @@ -156,55 +161,55 @@ func taintThroughStringConcatenation() { let tainted = source2() sink(arg: clean) - sink(arg: tainted) // $ tainted=156 + sink(arg: tainted) // $ tainted=161 sink(arg: clean + clean) - sink(arg: clean + tainted) // $ tainted=156 - sink(arg: tainted + clean) // $ tainted=156 - sink(arg: tainted + tainted) // $ tainted=156 + sink(arg: clean + tainted) // $ tainted=161 + sink(arg: tainted + clean) // $ tainted=161 + sink(arg: tainted + tainted) // $ tainted=161 sink(arg: ">" + clean + "<") - sink(arg: ">" + tainted + "<") // $ tainted=156 + sink(arg: ">" + tainted + "<") // $ tainted=161 sink(arg: clean.appending(clean)) - sink(arg: clean.appending(tainted)) // $ tainted=156 - sink(arg: tainted.appending(clean)) // $ tainted=156 - sink(arg: tainted.appending(tainted)) // $ tainted=156 + sink(arg: clean.appending(tainted)) // $ tainted=161 + sink(arg: tainted.appending(clean)) // $ tainted=161 + sink(arg: tainted.appending(tainted)) // $ tainted=161 var str = "abc" sink(arg: str) str += "def" sink(arg: str) str += source2() - sink(arg: str) // $ MISSING: tainted=178 + sink(arg: str) // $ MISSING: tainted=183 var str2 = "abc" sink(arg: str2) str2.append("def") sink(arg: str2) str2.append(source2()) - sink(arg: str2) // $ tainted=185 + sink(arg: str2) // $ tainted=190 var str3 = "abc" sink(arg: str3) str3.append(contentsOf: "def") sink(arg: str3) str3.append(contentsOf: source2()) - sink(arg: str3) // $ tainted=192 + sink(arg: str3) // $ tainted=197 var str4 = "abc" sink(arg: str4) str4.write("def") sink(arg: str4) str4.write(source2()) - sink(arg: str4) // $ tainted=199 + sink(arg: str4) // $ tainted=204 var str5 = "abc" sink(arg: str5) str5.insert(contentsOf: "abc", at: str5.startIndex) sink(arg: str5) str5.insert(contentsOf: source2(), at: str5.startIndex) - sink(arg: str5) // $ tainted=206 + sink(arg: str5) // $ tainted=211 } func taintThroughSimpleStringOperations() { @@ -213,42 +218,42 @@ func taintThroughSimpleStringOperations() { let taintedInt = source() sink(arg: String(clean)) - sink(arg: String(tainted)) // $ tainted=212 - sink(arg: String(taintedInt)) // $ tainted=213 + sink(arg: String(tainted)) // $ tainted=217 + sink(arg: String(taintedInt)) // $ tainted=218 - sink(arg: String(format: tainted, 1, 2, 3)) // $ tainted=212 - sink(arg: String(format: tainted, arguments: [])) // $ tainted=212 - sink(arg: String(format: tainted, locale: nil, 1, 2, 3)) // $ tainted=212 - sink(arg: String(format: tainted, locale: nil, arguments: [])) // $ tainted=212 - sink(arg: String.localizedStringWithFormat(tainted, 1, 2, 3)) // $ tainted=212 - sink(arg: String(format: "%s", tainted)) // $ MISSING: tainted=212 - sink(arg: String(format: "%i %i %i", 1, 2, taintedInt)) // $ MISSING: tainted=213 + sink(arg: String(format: tainted, 1, 2, 3)) // $ tainted=217 + sink(arg: String(format: tainted, arguments: [])) // $ tainted=217 + sink(arg: String(format: tainted, locale: nil, 1, 2, 3)) // $ tainted=217 + sink(arg: String(format: tainted, locale: nil, arguments: [])) // $ tainted=217 + sink(arg: String.localizedStringWithFormat(tainted, 1, 2, 3)) // $ tainted=217 + sink(arg: String(format: "%s", tainted)) // $ MISSING: tainted=217 + sink(arg: String(format: "%i %i %i", 1, 2, taintedInt)) // $ MISSING: tainted=218 sink(arg: String(repeating: clean, count: 2)) - sink(arg: String(repeating: tainted, count: 2)) // $ tainted=212 + sink(arg: String(repeating: tainted, count: 2)) // $ tainted=217 - sink(arg: tainted.dropFirst(10)) // $ tainted=212 - sink(arg: tainted.dropLast(10)) // $ tainted=212 - sink(arg: tainted.substring(from: tainted.startIndex)) // $ tainted=212 + sink(arg: tainted.dropFirst(10)) // $ tainted=217 + sink(arg: tainted.dropLast(10)) // $ tainted=217 + sink(arg: tainted.substring(from: tainted.startIndex)) // $ tainted=217 - sink(arg: tainted.lowercased()) // $ tainted=212 - sink(arg: tainted.uppercased()) // $ tainted=212 - sink(arg: tainted.lowercased(with: nil)) // $ tainted=212 - sink(arg: tainted.uppercased(with: nil)) // $ tainted=212 - sink(arg: tainted.capitalized(with: nil)) // $ tainted=212 - sink(arg: tainted.reversed()) // $ tainted=212 + sink(arg: tainted.lowercased()) // $ tainted=217 + sink(arg: tainted.uppercased()) // $ tainted=217 + sink(arg: tainted.lowercased(with: nil)) // $ tainted=217 + sink(arg: tainted.uppercased(with: nil)) // $ tainted=217 + sink(arg: tainted.capitalized(with: nil)) // $ tainted=217 + sink(arg: tainted.reversed()) // $ tainted=217 - sink(arg: tainted.split(separator: ",")) // $ tainted=212 - sink(arg: tainted.split(whereSeparator: { // $ tainted=212 + sink(arg: tainted.split(separator: ",")) // $ tainted=217 + sink(arg: tainted.split(whereSeparator: { // $ tainted=217 c in return (c == ",") })) - sink(arg: tainted.trimmingCharacters(in: CharacterSet.whitespaces)) // $ tainted=212 - sink(arg: tainted.padding(toLength: 20, withPad: " ", startingAt: 0)) // $ tainted=212 - sink(arg: tainted.components(separatedBy: CharacterSet.whitespaces)) // $ tainted=212 - sink(arg: tainted.components(separatedBy: CharacterSet.whitespaces)[0]) // $ tainted=212 - sink(arg: tainted.folding(locale: nil)) // $ tainted=212 - sink(arg: tainted.propertyListFromStringsFileFormat()) // $ tainted=212 - sink(arg: tainted.propertyListFromStringsFileFormat()["key"]!) // $ tainted=212 + sink(arg: tainted.trimmingCharacters(in: CharacterSet.whitespaces)) // $ tainted=217 + sink(arg: tainted.padding(toLength: 20, withPad: " ", startingAt: 0)) // $ tainted=217 + sink(arg: tainted.components(separatedBy: CharacterSet.whitespaces)) // $ tainted=217 + sink(arg: tainted.components(separatedBy: CharacterSet.whitespaces)[0]) // $ tainted=217 + sink(arg: tainted.folding(locale: nil)) // $ tainted=217 + sink(arg: tainted.propertyListFromStringsFileFormat()) // $ tainted=217 + sink(arg: tainted.propertyListFromStringsFileFormat()["key"]!) // $ tainted=217 sink(arg: clean.enumerateLines(invoking: { line, stop in @@ -257,81 +262,90 @@ func taintThroughSimpleStringOperations() { })) sink(arg: tainted.enumerateLines(invoking: { line, stop in - sink(arg: line) // $ MISSING: tainted=212 + sink(arg: line) // $ MISSING: tainted=217 sink(arg: stop) })) sink(arg: [clean, clean].joined()) - sink(arg: [tainted, clean].joined()) // $ MISSING: tainted=212 - sink(arg: [clean, tainted].joined()) // $ MISSING: tainted=212 - sink(arg: [tainted, tainted].joined()) // $ MISSING: tainted=212 + sink(arg: [tainted, clean].joined()) // $ MISSING: tainted=217 + sink(arg: [clean, tainted].joined()) // $ MISSING: tainted=217 + sink(arg: [tainted, tainted].joined()) // $ MISSING: tainted=217 sink(arg: clean.description) - sink(arg: tainted.description) // $ tainted=212 + sink(arg: tainted.description) // $ tainted=217 sink(arg: clean.debugDescription) - sink(arg: tainted.debugDescription) // $ tainted=212 + sink(arg: tainted.debugDescription) // $ tainted=217 sink(arg: clean.utf8) - sink(arg: tainted.utf8) // $ tainted=212 + sink(arg: tainted.utf8) // $ tainted=217 sink(arg: clean.utf16) - sink(arg: tainted.utf16) // $ tainted=212 + sink(arg: tainted.utf16) // $ tainted=217 sink(arg: clean.unicodeScalars) - sink(arg: tainted.unicodeScalars) // $ tainted=212 + sink(arg: tainted.unicodeScalars) // $ tainted=217 sink(arg: clean.utf8CString) - sink(arg: tainted.utf8CString) // $ tainted=212 + sink(arg: tainted.utf8CString) // $ tainted=217 sink(arg: clean.lazy) - sink(arg: tainted.lazy) // $ tainted=212 + sink(arg: tainted.lazy) // $ tainted=217 sink(arg: clean.capitalized) - sink(arg: tainted.capitalized) // $ tainted=212 + sink(arg: tainted.capitalized) // $ tainted=217 sink(arg: clean.localizedCapitalized) - sink(arg: tainted.localizedCapitalized) // $ tainted=212 + sink(arg: tainted.localizedCapitalized) // $ tainted=217 sink(arg: clean.localizedLowercase) - sink(arg: tainted.localizedLowercase) // $ tainted=212 + sink(arg: tainted.localizedLowercase) // $ tainted=217 sink(arg: clean.localizedUppercase) - sink(arg: tainted.localizedUppercase) // $ tainted=212 + sink(arg: tainted.localizedUppercase) // $ tainted=217 sink(arg: clean.decomposedStringWithCanonicalMapping) - sink(arg: tainted.decomposedStringWithCanonicalMapping) // $ tainted=212 + sink(arg: tainted.decomposedStringWithCanonicalMapping) // $ tainted=217 sink(arg: clean.precomposedStringWithCompatibilityMapping) - sink(arg: tainted.precomposedStringWithCompatibilityMapping) // $ tainted=212 + sink(arg: tainted.precomposedStringWithCompatibilityMapping) // $ tainted=217 sink(arg: clean.removingPercentEncoding!) - sink(arg: tainted.removingPercentEncoding!) // $ tainted=212 + sink(arg: tainted.removingPercentEncoding!) // $ tainted=217 + + sink(arg: clean.replacingOccurrences(of: "a", with: "b")) + sink(arg: tainted.replacingOccurrences(of: "a", with: "b")) // $ MISSING: tainted=217 + sink(arg: clean.replacingOccurrences(of: "a", with: source2())) // $ MISSING: tainted=217 } func taintThroughMutatingStringOperations() { var str1 = source2() - sink(arg: str1) // $ tainted=300 - sink(arg: str1.remove(at: str1.startIndex)) // $ tainted=300 - sink(arg: str1) // $ tainted=300 + sink(arg: str1) // $ tainted=309 + sink(arg: str1.remove(at: str1.startIndex)) // $ tainted=309 + sink(arg: str1) // $ tainted=309 var str2 = source2() - sink(arg: str2) // $ tainted=305 + sink(arg: str2) // $ tainted=314 str2.removeAll() - sink(arg: str2) // $ SPURIOUS: tainted=305 + sink(arg: str2) // $ SPURIOUS: tainted=314 var str3 = source2() - sink(arg: str3) // $ tainted=310 + sink(arg: str3) // $ tainted=319 str3.removeAll(where: { _ in true } ) - sink(arg: str3) // $ SPURIOUS: tainted=310 + sink(arg: str3) // $ SPURIOUS: tainted=319 var str4 = source2() - sink(arg: str4) // $ tainted=315 - sink(arg: str4.removeFirst()) // $ tainted=315 - sink(arg: str4) // $ tainted=315 + sink(arg: str4) // $ tainted=324 + sink(arg: str4.removeFirst()) // $ tainted=324 + sink(arg: str4) // $ tainted=324 str4.removeFirst(5) - sink(arg: str4) // $ tainted=315 - sink(arg: str4.removeLast()) // $ tainted=315 - sink(arg: str4) // $ tainted=315 + sink(arg: str4) // $ tainted=324 + sink(arg: str4.removeLast()) // $ tainted=324 + sink(arg: str4) // $ tainted=324 str4.removeLast(5) - sink(arg: str4) // $ tainted=315 + sink(arg: str4) // $ tainted=324 var str5 = source2() - sink(arg: str5) // $ tainted=326 + sink(arg: str5) // $ tainted=335 str5.removeSubrange(str5.startIndex ... str5.index(str5.startIndex, offsetBy: 5)) - sink(arg: str5) // $ tainted=326 + sink(arg: str5) // $ tainted=335 var str6 = source2() - sink(arg: str6) // $ tainted=331 + sink(arg: str6) // $ tainted=340 str6.makeContiguousUTF8() - sink(arg: str6) // $ tainted=331 + sink(arg: str6) // $ tainted=340 + + var str7 = "" + sink(arg: str7) + str7.replaceSubrange((nil as Range?)!, with: source2()) + sink(arg: str7) // $ MISSING: tainted=347 } func source3() -> Data { return Data("") } @@ -341,10 +355,10 @@ func taintThroughData() { let stringTainted = String(data: source3(), encoding: String.Encoding.utf8) sink(arg: stringClean!) - sink(arg: stringTainted!) // $ tainted=341 + sink(arg: stringTainted!) // $ tainted=355 sink(arg: String(decoding: Data(""), as: UTF8.self)) - sink(arg: String(decoding: source3(), as: UTF8.self)) // $ tainted=347 + sink(arg: String(decoding: source3(), as: UTF8.self)) // $ tainted=361 } func taintThroughEncodings() { @@ -358,8 +372,8 @@ func taintThroughEncodings() { }) tainted.withUTF8({ buffer in - sink(arg: buffer) // $ MISSING: tainted=352 - sink(arg: buffer.baseAddress!) // $ MISSING: tainted=352 + sink(arg: buffer) // $ MISSING: tainted=366 + sink(arg: buffer.baseAddress!) // $ MISSING: tainted=366 }) clean.withCString({ @@ -368,7 +382,7 @@ func taintThroughEncodings() { }) tainted.withCString({ ptr in - sink(arg: ptr) // $ MISSING: tainted=352 + sink(arg: ptr) // $ MISSING: tainted=366 }) clean.withCString(encodedAs: UTF8.self, { ptr in @@ -376,7 +390,7 @@ func taintThroughEncodings() { }) tainted.withCString(encodedAs: UTF8.self, { ptr in - sink(arg: ptr) // $ MISSING: tainted=352 + sink(arg: ptr) // $ MISSING: tainted=366 }) let arrayString1 = clean.cString(using: String.Encoding.utf8)! @@ -387,11 +401,11 @@ func taintThroughEncodings() { sink(arg: String(cString: buffer.baseAddress!)) }) let arrayString2 = tainted.cString(using: String.Encoding.utf8)! - sink(arg: arrayString2) // $ tainted=352 + sink(arg: arrayString2) // $ tainted=366 arrayString1.withUnsafeBufferPointer({ buffer in - sink(arg: buffer) // $ MISSING: tainted=352 - sink(arg: String(cString: buffer.baseAddress!)) // $ MISSING: tainted=352 + sink(arg: buffer) // $ MISSING: tainted=366 + sink(arg: String(cString: buffer.baseAddress!)) // $ MISSING: tainted=366 }) clean.withPlatformString({ @@ -407,14 +421,14 @@ func taintThroughEncodings() { }) tainted.withPlatformString({ ptr in - sink(arg: ptr) // $ MISSING: tainted=352 - sink(arg: String(platformString: ptr)) // $ MISSING: tainted=352 + sink(arg: ptr) // $ MISSING: tainted=366 + sink(arg: String(platformString: ptr)) // $ MISSING: tainted=366 let buffer = UnsafeBufferPointer(start: ptr, count: 10) let arrayString = Array(buffer) - sink(arg: buffer) // $ MISSING: tainted=352 - sink(arg: arrayString) // $ MISSING: tainted=352 - sink(arg: String(platformString: arrayString)) // $ MISSING: tainted=352 + sink(arg: buffer) // $ MISSING: tainted=366 + sink(arg: arrayString) // $ MISSING: tainted=366 + sink(arg: String(platformString: arrayString)) // $ MISSING: tainted=366 }) clean.withContiguousStorageIfAvailable({ @@ -425,7 +439,7 @@ func taintThroughEncodings() { tainted.withContiguousStorageIfAvailable({ ptr in sink(arg: ptr) - sink(arg: ptr.baseAddress!) // $ MISSING: tainted=352 + sink(arg: ptr.baseAddress!) // $ MISSING: tainted=366 }) } @@ -443,20 +457,20 @@ func taintFromUInt8Array() { return 3 } )) - sink(arg: String(unsafeUninitializedCapacity: 256, initializingUTF8With: { // $ MISSING: tainted=436 + sink(arg: String(unsafeUninitializedCapacity: 256, initializingUTF8With: { // $ MISSING: tainted=450 (buffer: UnsafeMutableBufferPointer) -> Int in sink(arg: buffer) let _ = buffer.initialize(from: taintedUInt8Values) - sink(arg: buffer) // $ MISSING: tainted=436 + sink(arg: buffer) // $ MISSING: tainted=450 return 256 } )) sink(arg: String(bytes: cleanUInt8Values, encoding: String.Encoding.utf8)!) - sink(arg: String(bytes: taintedUInt8Values, encoding: String.Encoding.utf8)!) // $ tainted=436 + sink(arg: String(bytes: taintedUInt8Values, encoding: String.Encoding.utf8)!) // $ tainted=450 sink(arg: String(cString: cleanUInt8Values)) - sink(arg: String(cString: taintedUInt8Values)) // $ tainted=436 + sink(arg: String(cString: taintedUInt8Values)) // $ tainted=450 try! cleanUInt8Values.withUnsafeBufferPointer({ (buffer: UnsafeBufferPointer) throws in @@ -466,9 +480,9 @@ func taintFromUInt8Array() { }) try! taintedUInt8Values.withUnsafeBufferPointer({ (buffer: UnsafeBufferPointer) throws in - sink(arg: buffer) // $ MISSING: tainted=436 - sink(arg: buffer.baseAddress!) // $ MISSING: tainted=436 - sink(arg: String(cString: buffer.baseAddress!)) // $ MISSING: tainted=436 + sink(arg: buffer) // $ MISSING: tainted=450 + sink(arg: buffer.baseAddress!) // $ MISSING: tainted=450 + sink(arg: String(cString: buffer.baseAddress!)) // $ MISSING: tainted=450 }) try! cleanUInt8Values.withUnsafeMutableBytes({ @@ -479,9 +493,9 @@ func taintFromUInt8Array() { }) try! taintedUInt8Values.withUnsafeMutableBytes({ (buffer: UnsafeMutableRawBufferPointer) throws in - sink(arg: buffer) // $ MISSING: tainted=436 - sink(arg: buffer.baseAddress!) // $ MISSING: tainted=436 - sink(arg: String(bytesNoCopy: buffer.baseAddress!, length: buffer.count, encoding: String.Encoding.utf8, freeWhenDone: false)!) // $ MISSING: tainted=436 + sink(arg: buffer) // $ MISSING: tainted=450 + sink(arg: buffer.baseAddress!) // $ MISSING: tainted=450 + sink(arg: String(bytesNoCopy: buffer.baseAddress!, length: buffer.count, encoding: String.Encoding.utf8, freeWhenDone: false)!) // $ MISSING: tainted=450 }) } @@ -501,15 +515,15 @@ func taintThroughCCharArray() { }) taintedCCharValues.withUnsafeBufferPointer({ ptr in - sink(arg: ptr) // $ MISSING: tainted=492 - sink(arg: ptr.baseAddress!) // $ MISSING: tainted=492 - sink(arg: String(utf8String: ptr.baseAddress!)!) // $ MISSING: tainted=492 - sink(arg: String(validatingUTF8: ptr.baseAddress!)!) // $ MISSING: tainted=492 - sink(arg: String(cString: ptr.baseAddress!)) // $ MISSING: tainted=492 + sink(arg: ptr) // $ MISSING: tainted=506 + sink(arg: ptr.baseAddress!) // $ MISSING: tainted=506 + sink(arg: String(utf8String: ptr.baseAddress!)!) // $ MISSING: tainted=506 + sink(arg: String(validatingUTF8: ptr.baseAddress!)!) // $ MISSING: tainted=506 + sink(arg: String(cString: ptr.baseAddress!)) // $ MISSING: tainted=506 }) sink(arg: String(cString: cleanCCharValues)) - sink(arg: String(cString: taintedCCharValues)) // $ tainted=492 + sink(arg: String(cString: taintedCCharValues)) // $ tainted=506 } func source6() -> [unichar] { return [] } @@ -527,10 +541,10 @@ func taintThroughUnicharArray() { }) taintedUnicharValues.withUnsafeBufferPointer({ ptr in - sink(arg: ptr) // $ MISSING: tainted=519 - sink(arg: ptr.baseAddress!) // $ MISSING: tainted=519 - sink(arg: String(utf16CodeUnits: ptr.baseAddress!, count: ptr.count)) // $ MISSING: tainted=519 - sink(arg: String(utf16CodeUnitsNoCopy: ptr.baseAddress!, count: ptr.count, freeWhenDone: false)) // $ MISSING: tainted=519 + sink(arg: ptr) // $ MISSING: tainted=533 + sink(arg: ptr.baseAddress!) // $ MISSING: tainted=533 + sink(arg: String(utf16CodeUnits: ptr.baseAddress!, count: ptr.count)) // $ MISSING: tainted=533 + sink(arg: String(utf16CodeUnitsNoCopy: ptr.baseAddress!, count: ptr.count, freeWhenDone: false)) // $ MISSING: tainted=533 }) } @@ -539,31 +553,31 @@ func source7() -> Substring { return Substring() } func taintThroughSubstring() { let tainted = source2() - sink(arg: source7()) // $ tainted=542 + sink(arg: source7()) // $ tainted=556 let sub1 = tainted[tainted.startIndex ..< tainted.endIndex] - sink(arg: sub1) // $ tainted=540 - sink(arg: String(sub1)) // $ tainted=540 + sink(arg: sub1) // $ tainted=554 + sink(arg: String(sub1)) // $ tainted=554 let sub2 = tainted.prefix(10) - sink(arg: sub2) // $ tainted=540 - sink(arg: String(sub2)) // $ tainted=540 + sink(arg: sub2) // $ tainted=554 + sink(arg: String(sub2)) // $ tainted=554 let sub3 = tainted.prefix(through: tainted.endIndex) - sink(arg: sub3) // $ tainted=540 - sink(arg: String(sub3)) // $ tainted=540 + sink(arg: sub3) // $ tainted=554 + sink(arg: String(sub3)) // $ tainted=554 let sub4 = tainted.prefix(upTo: tainted.endIndex) - sink(arg: sub4) // $ tainted=540 - sink(arg: String(sub4)) // $ tainted=540 + sink(arg: sub4) // $ tainted=554 + sink(arg: String(sub4)) // $ tainted=554 let sub5 = tainted.suffix(10) - sink(arg: sub5) // $ tainted=540 - sink(arg: String(sub5)) // $ tainted=540 + sink(arg: sub5) // $ tainted=554 + sink(arg: String(sub5)) // $ tainted=554 let sub6 = tainted.suffix(from: tainted.startIndex) - sink(arg: sub6) // $ tainted=540 - sink(arg: String(sub6)) // $ tainted=540 + sink(arg: sub6) // $ tainted=554 + sink(arg: String(sub6)) // $ tainted=554 } func taintedThroughFilePath() { @@ -571,16 +585,16 @@ func taintedThroughFilePath() { let tainted = FilePath(source2()) sink(arg: clean) - sink(arg: tainted) // $ MISSING: tainted=571 + sink(arg: tainted) // $ MISSING: tainted=585 - sink(arg: tainted.extension!) // $ MISSING: tainted=571 - sink(arg: tainted.stem!) // $ MISSING: tainted=571 - sink(arg: tainted.string) // $ MISSING: tainted=571 - sink(arg: tainted.description) // $ MISSING: tainted=571 - sink(arg: tainted.debugDescription) // $ MISSING: tainted=571 + sink(arg: tainted.extension!) // $ MISSING: tainted=585 + sink(arg: tainted.stem!) // $ MISSING: tainted=585 + sink(arg: tainted.string) // $ MISSING: tainted=585 + sink(arg: tainted.description) // $ MISSING: tainted=585 + sink(arg: tainted.debugDescription) // $ MISSING: tainted=585 - sink(arg: String(decoding: tainted)) // $ MISSING: tainted=571 - sink(arg: String(validating: tainted)!) // $ MISSING: tainted=571 + sink(arg: String(decoding: tainted)) // $ MISSING: tainted=585 + sink(arg: String(validating: tainted)!) // $ MISSING: tainted=585 let _ = clean.withCString({ ptr in @@ -588,7 +602,7 @@ func taintedThroughFilePath() { }) let _ = tainted.withCString({ ptr in - sink(arg: ptr) // $ MISSING: tainted=571 + sink(arg: ptr) // $ MISSING: tainted=585 }) let _ = clean.withPlatformString({ @@ -599,34 +613,34 @@ func taintedThroughFilePath() { }) let _ = tainted.withPlatformString({ ptr in - sink(arg: ptr) // $ MISSING: tainted=571 - sink(arg: String(platformString: ptr)) // $ MISSING: tainted=571 - sink(arg: String(validatingPlatformString: ptr)!) // $ MISSING: tainted=571 + sink(arg: ptr) // $ MISSING: tainted=585 + sink(arg: String(platformString: ptr)) // $ MISSING: tainted=585 + sink(arg: String(validatingPlatformString: ptr)!) // $ MISSING: tainted=585 }) var fp1 = FilePath("") sink(arg: fp1) fp1.append(source2()) - sink(arg: fp1) // $ MISSING: tainted=609 + sink(arg: fp1) // $ MISSING: tainted=623 fp1.append("") - sink(arg: fp1) // $ MISSING: tainted=609 + sink(arg: fp1) // $ MISSING: tainted=623 sink(arg: clean.appending("")) - sink(arg: clean.appending(source2())) // $ MISSING: tainted=615 - sink(arg: tainted.appending("")) // $ MISSING: tainted=571 - sink(arg: tainted.appending(source2())) // $ MISSING: tainted=571,617 + sink(arg: clean.appending(source2())) // $ MISSING: tainted=629 + sink(arg: tainted.appending("")) // $ MISSING: tainted=585 + sink(arg: tainted.appending(source2())) // $ MISSING: tainted=585,631 } func taintedThroughConversion() { sink(arg: String(0)) - sink(arg: String(source())) // $ tainted=622 + sink(arg: String(source())) // $ tainted=636 sink(arg: Int(0).description) - sink(arg: source().description) // $ MISSING: tainted=624 + sink(arg: source().description) // $ MISSING: tainted=638 sink(arg: String(describing: 0)) - sink(arg: String(describing: source())) // $ tainted=626 + sink(arg: String(describing: source())) // $ tainted=640 sink(arg: Int("123")!) - sink(arg: Int(source2())!) // $ MISSING: tainted=629 + sink(arg: Int(source2())!) // $ MISSING: tainted=643 } func untaintedFields() { From a894fc6ce8f37457ac8c64bc6e7588d7a843e468 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:53:10 +0000 Subject: [PATCH 291/415] Swift: Fix mistakes in String.qll models. --- .../frameworks/StandardLibrary/String.qll | 8 ++--- .../dataflow/taint/LocalTaint.expected | 9 ++++++ .../dataflow/taint/Taint.expected | 31 +++++++++++++++++++ .../library-tests/dataflow/taint/string.swift | 6 ++-- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll index 3640eca6a97..cf9b73d05ab 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/String.qll @@ -58,8 +58,8 @@ private class StringSummaries extends SummaryModelCsv { ";StringProtocol;true;propertyListFromStringsFileFormat();;;Argument[-1];ReturnValue;taint", ";StringProtocol;true;replacingCharacters(in:with:);;;Argument[-1];ReturnValue;taint", ";StringProtocol;true;replacingCharacters(in:with:);;;Argument[1];ReturnValue;taint", - ";StringProtocol;true;replacingOccurrences(of:with:options:range);;;Argument[-1];ReturnValue;taint", - ";StringProtocol;true;replacingOccurrences(of:with:options:range);;;Argument[1];ReturnValue;taint", + ";StringProtocol;true;replacingOccurrences(of:with:options:range:);;;Argument[-1];ReturnValue;taint", + ";StringProtocol;true;replacingOccurrences(of:with:options:range:);;;Argument[1];ReturnValue;taint", ";StringProtocol;true;replacingPercentEscapes(using:);;;Argument[-1];ReturnValue;taint", ";StringProtocol;true;substring(from:);;;Argument[-1];ReturnValue;taint", ";StringProtocol;true;substring(with:);;;Argument[-1];ReturnValue;taint", @@ -79,7 +79,7 @@ private class StringSummaries extends SummaryModelCsv { ";String;true;init(format:locale:arguments:);;;Argument[0];ReturnValue;taint", ";String;true;init(_:radix:uppercase:);;;Argument[0];ReturnValue;taint", ";String;true;init(bytes:encoding:);;;Argument[0];ReturnValue;taint", - ";String;true;init(bytesNoCopy:length:encoding:freeWhenDone);;;Argument[0];ReturnValue;taint", + ";String;true;init(bytesNoCopy:length:encoding:freeWhenDone:);;;Argument[0];ReturnValue;taint", ";String;true;init(describing:);;;Argument[0];ReturnValue;taint", ";String;true;init(contentsOf:);;;Argument[0];ReturnValue;taint", ";String;true;init(contentsOf:encoding:);;;Argument[0];ReturnValue;taint", @@ -101,7 +101,7 @@ private class StringSummaries extends SummaryModelCsv { ";String;true;write(_:);;;Argument[0];Argument[-1];taint", ";String;true;write(to:);;;Argument[-1];Argument[0];taint", ";String;true;insert(contentsOf:at:);;;Argument[0];Argument[-1];taint", - ";String;true;replaceSubrange(_:with::);;;Argument[1];Argument[-1];taint", + ";String;true;replaceSubrange(_:with:);;;Argument[1];Argument[-1];taint", ";String;true;max();;;Argument[-1];ReturnValue;taint", ";String;true;max(by:);;;Argument[-1];ReturnValue;taint", ";String;true;min();;;Argument[-1];ReturnValue;taint", diff --git a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected index 4738a7d3766..951def0fd91 100644 --- a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected @@ -1369,7 +1369,13 @@ | string.swift:301:13:301:13 | tainted | string.swift:304:13:304:13 | tainted | | string.swift:301:13:301:21 | .removingPercentEncoding | string.swift:301:13:301:44 | ...! | | string.swift:303:13:303:13 | [post] clean | string.swift:305:13:305:13 | clean | +| string.swift:303:13:303:13 | clean | string.swift:303:13:303:58 | call to replacingOccurrences(of:with:options:range:) | | string.swift:303:13:303:13 | clean | string.swift:305:13:305:13 | clean | +| string.swift:303:55:303:55 | b | string.swift:303:13:303:58 | call to replacingOccurrences(of:with:options:range:) | +| string.swift:304:13:304:13 | tainted | string.swift:304:13:304:60 | call to replacingOccurrences(of:with:options:range:) | +| string.swift:304:57:304:57 | b | string.swift:304:13:304:60 | call to replacingOccurrences(of:with:options:range:) | +| string.swift:305:13:305:13 | clean | string.swift:305:13:305:64 | call to replacingOccurrences(of:with:options:range:) | +| string.swift:305:55:305:63 | call to source2() | string.swift:305:13:305:64 | call to replacingOccurrences(of:with:options:range:) | | string.swift:309:7:309:7 | SSA def(str1) | string.swift:310:13:310:13 | str1 | | string.swift:309:14:309:22 | call to source2() | string.swift:309:7:309:7 | SSA def(str1) | | string.swift:310:13:310:13 | [post] str1 | string.swift:311:13:311:13 | str1 | @@ -1446,6 +1452,7 @@ | string.swift:347:3:347:3 | [post] &... | string.swift:348:13:348:13 | str7 | | string.swift:347:3:347:3 | str7 | string.swift:347:3:347:3 | &... | | string.swift:347:25:347:25 | nil | string.swift:347:24:347:53 | ...! | +| string.swift:347:62:347:70 | call to source2() | string.swift:347:3:347:3 | [post] &... | | string.swift:351:38:351:38 | | string.swift:351:33:351:40 | call to Data.init(_:) | | string.swift:354:7:354:7 | SSA def(stringClean) | string.swift:357:12:357:12 | stringClean | | string.swift:354:21:354:74 | call to String.init(data:encoding:) | string.swift:354:7:354:7 | SSA def(stringClean) | @@ -1613,6 +1620,7 @@ | string.swift:492:35:492:35 | [post] buffer | string.swift:492:64:492:64 | buffer | | string.swift:492:35:492:35 | buffer | string.swift:492:64:492:64 | buffer | | string.swift:492:35:492:42 | .baseAddress | string.swift:492:35:492:53 | ...! | +| string.swift:492:35:492:53 | ...! | string.swift:492:15:492:129 | call to String.init(bytesNoCopy:length:encoding:freeWhenDone:) | | string.swift:494:8:494:8 | taintedUInt8Values | string.swift:494:8:494:8 | &... | | string.swift:494:8:499:4 | call to withUnsafeMutableBytes(_:) | string.swift:494:3:499:4 | try! ... | | string.swift:495:6:495:14 | SSA def(buffer) | string.swift:496:15:496:15 | buffer | @@ -1626,6 +1634,7 @@ | string.swift:498:35:498:35 | [post] buffer | string.swift:498:64:498:64 | buffer | | string.swift:498:35:498:35 | buffer | string.swift:498:64:498:64 | buffer | | string.swift:498:35:498:42 | .baseAddress | string.swift:498:35:498:53 | ...! | +| string.swift:498:35:498:53 | ...! | string.swift:498:15:498:129 | call to String.init(bytesNoCopy:length:encoding:freeWhenDone:) | | string.swift:505:7:505:31 | SSA def(cleanCCharValues) | string.swift:508:3:508:3 | cleanCCharValues | | string.swift:505:35:505:55 | [...] | string.swift:505:7:505:31 | SSA def(cleanCCharValues) | | string.swift:506:7:506:33 | SSA def(taintedCCharValues) | string.swift:516:3:516:3 | taintedCCharValues | diff --git a/swift/ql/test/library-tests/dataflow/taint/Taint.expected b/swift/ql/test/library-tests/dataflow/taint/Taint.expected index bd558a8ad63..fef44d98a5a 100644 --- a/swift/ql/test/library-tests/dataflow/taint/Taint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/Taint.expected @@ -338,6 +338,7 @@ edges | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:locale:arguments:) : | | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in localizedStringWithFormat(_:_:) : | | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(bytes:encoding:) : | +| string.swift:86:12:87:51 | [summary param] 1 in replaceSubrange(_:with:) : | file://:0:0:0:0 | [summary] to write: argument this in replaceSubrange(_:with:) : | | string.swift:101:3:101:63 | [summary param] this in lowercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in lowercased(with:) : | | string.swift:102:3:102:63 | [summary param] this in uppercased(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in uppercased(with:) : | | string.swift:103:3:103:64 | [summary param] this in capitalized(with:) : | file://:0:0:0:0 | [summary] to write: return (return) in capitalized(with:) : | @@ -351,6 +352,8 @@ edges | string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | | string.swift:111:3:111:74 | [summary param] this in cString(using:) : | file://:0:0:0:0 | [summary] to write: return (return) in cString(using:) : | | string.swift:112:8:112:8 | self : | string.swift:112:3:112:79 | self[return] : | +| string.swift:113:3:114:77 | [summary param] 1 in replacingOccurrences(of:with:options:range:) : | file://:0:0:0:0 | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | +| string.swift:113:3:114:77 | [summary param] this in replacingOccurrences(of:with:options:range:) : | file://:0:0:0:0 | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | | string.swift:137:11:137:18 | call to source() : | string.swift:139:13:139:13 | "..." | | string.swift:137:11:137:18 | call to source() : | string.swift:141:13:141:13 | "..." | | string.swift:137:11:137:18 | call to source() : | string.swift:143:13:143:13 | "..." | @@ -425,6 +428,7 @@ edges | string.swift:217:17:217:25 | call to source2() : | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | | string.swift:217:17:217:25 | call to source2() : | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | | string.swift:217:17:217:25 | call to source2() : | string.swift:301:13:301:44 | ...! | +| string.swift:217:17:217:25 | call to source2() : | string.swift:304:13:304:13 | tainted : | | string.swift:218:20:218:27 | call to source() : | string.swift:222:20:222:20 | taintedInt : | | string.swift:221:20:221:20 | tainted : | file://:0:0:0:0 | [summary param] 0 in String.init(_:) : | | string.swift:221:20:221:20 | tainted : | string.swift:221:13:221:27 | call to String.init(_:) | @@ -494,8 +498,13 @@ edges | string.swift:263:13:263:13 | [post] tainted : | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | | string.swift:263:13:263:13 | [post] tainted : | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | | string.swift:263:13:263:13 | [post] tainted : | string.swift:301:13:301:44 | ...! | +| string.swift:263:13:263:13 | [post] tainted : | string.swift:304:13:304:13 | tainted : | | string.swift:263:13:263:13 | tainted : | string.swift:112:8:112:8 | self : | | string.swift:263:13:263:13 | tainted : | string.swift:263:13:263:13 | [post] tainted : | +| string.swift:304:13:304:13 | tainted : | string.swift:113:3:114:77 | [summary param] this in replacingOccurrences(of:with:options:range:) : | +| string.swift:304:13:304:13 | tainted : | string.swift:304:13:304:60 | call to replacingOccurrences(of:with:options:range:) | +| string.swift:305:55:305:63 | call to source2() : | string.swift:113:3:114:77 | [summary param] 1 in replacingOccurrences(of:with:options:range:) : | +| string.swift:305:55:305:63 | call to source2() : | string.swift:305:13:305:64 | call to replacingOccurrences(of:with:options:range:) | | string.swift:309:14:309:22 | call to source2() : | string.swift:310:13:310:13 | str1 | | string.swift:309:14:309:22 | call to source2() : | string.swift:311:13:311:13 | &... : | | string.swift:309:14:309:22 | call to source2() : | string.swift:312:13:312:13 | str1 | @@ -520,6 +529,9 @@ edges | string.swift:335:14:335:22 | call to source2() : | string.swift:338:13:338:13 | str5 | | string.swift:340:14:340:22 | call to source2() : | string.swift:341:13:341:13 | str6 | | string.swift:340:14:340:22 | call to source2() : | string.swift:343:13:343:13 | str6 | +| string.swift:347:3:347:3 | [post] &... : | string.swift:348:13:348:13 | str7 | +| string.swift:347:62:347:70 | call to source2() : | string.swift:86:12:87:51 | [summary param] 1 in replaceSubrange(_:with:) : | +| string.swift:347:62:347:70 | call to source2() : | string.swift:347:3:347:3 | [post] &... : | | string.swift:355:23:355:77 | call to String.init(data:encoding:) : | string.swift:358:12:358:25 | ...! | | string.swift:355:36:355:44 | call to source3() : | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | | string.swift:355:36:355:44 | call to source3() : | string.swift:355:23:355:77 | call to String.init(data:encoding:) : | @@ -1097,6 +1109,7 @@ nodes | file://:0:0:0:0 | [summary] to write: argument this in replaceBytes(in:withBytes:length:) : | semmle.label | [summary] to write: argument this in replaceBytes(in:withBytes:length:) : | | file://:0:0:0:0 | [summary] to write: argument this in replaceSubrange(_:with:) : | semmle.label | [summary] to write: argument this in replaceSubrange(_:with:) : | | file://:0:0:0:0 | [summary] to write: argument this in replaceSubrange(_:with:) : | semmle.label | [summary] to write: argument this in replaceSubrange(_:with:) : | +| file://:0:0:0:0 | [summary] to write: argument this in replaceSubrange(_:with:) : | semmle.label | [summary] to write: argument this in replaceSubrange(_:with:) : | | file://:0:0:0:0 | [summary] to write: argument this in replaceSubrange(_:with:count:) : | semmle.label | [summary] to write: argument this in replaceSubrange(_:with:count:) : | | file://:0:0:0:0 | [summary] to write: argument this in replacing(_:with:maxReplacements:) : | semmle.label | [summary] to write: argument this in replacing(_:with:maxReplacements:) : | | file://:0:0:0:0 | [summary] to write: argument this in replacing(_:with:subrange:maxReplacements:) : | semmle.label | [summary] to write: argument this in replacing(_:with:subrange:maxReplacements:) : | @@ -1187,6 +1200,8 @@ nodes | file://:0:0:0:0 | [summary] to write: return (return) in remove(at:) : | semmle.label | [summary] to write: return (return) in remove(at:) : | | file://:0:0:0:0 | [summary] to write: return (return) in removeFirst() : | semmle.label | [summary] to write: return (return) in removeFirst() : | | file://:0:0:0:0 | [summary] to write: return (return) in removeLast() : | semmle.label | [summary] to write: return (return) in removeLast() : | +| file://:0:0:0:0 | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | semmle.label | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | +| file://:0:0:0:0 | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | semmle.label | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | | file://:0:0:0:0 | [summary] to write: return (return) in reversed() : | semmle.label | [summary] to write: return (return) in reversed() : | | file://:0:0:0:0 | [summary] to write: return (return) in reversed() : | semmle.label | [summary] to write: return (return) in reversed() : | | file://:0:0:0:0 | [summary] to write: return (return) in shuffled() : | semmle.label | [summary] to write: return (return) in shuffled() : | @@ -1362,6 +1377,7 @@ nodes | string.swift:67:3:67:77 | [summary param] 0 in String.init(format:locale:arguments:) : | semmle.label | [summary param] 0 in String.init(format:locale:arguments:) : | | string.swift:69:3:69:106 | [summary param] 0 in localizedStringWithFormat(_:_:) : | semmle.label | [summary param] 0 in localizedStringWithFormat(_:_:) : | | string.swift:71:3:71:102 | [summary param] 0 in String.init(bytes:encoding:) : | semmle.label | [summary param] 0 in String.init(bytes:encoding:) : | +| string.swift:86:12:87:51 | [summary param] 1 in replaceSubrange(_:with:) : | semmle.label | [summary param] 1 in replaceSubrange(_:with:) : | | string.swift:101:3:101:63 | [summary param] this in lowercased(with:) : | semmle.label | [summary param] this in lowercased(with:) : | | string.swift:102:3:102:63 | [summary param] this in uppercased(with:) : | semmle.label | [summary param] this in uppercased(with:) : | | string.swift:103:3:103:64 | [summary param] this in capitalized(with:) : | semmle.label | [summary param] this in capitalized(with:) : | @@ -1376,6 +1392,8 @@ nodes | string.swift:111:3:111:74 | [summary param] this in cString(using:) : | semmle.label | [summary param] this in cString(using:) : | | string.swift:112:3:112:79 | self[return] : | semmle.label | self[return] : | | string.swift:112:8:112:8 | self : | semmle.label | self : | +| string.swift:113:3:114:77 | [summary param] 1 in replacingOccurrences(of:with:options:range:) : | semmle.label | [summary param] 1 in replacingOccurrences(of:with:options:range:) : | +| string.swift:113:3:114:77 | [summary param] this in replacingOccurrences(of:with:options:range:) : | semmle.label | [summary param] this in replacingOccurrences(of:with:options:range:) : | | string.swift:137:11:137:18 | call to source() : | semmle.label | call to source() : | | string.swift:139:13:139:13 | "..." | semmle.label | "..." | | string.swift:141:13:141:13 | "..." | semmle.label | "..." | @@ -1479,6 +1497,10 @@ nodes | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | semmle.label | .decomposedStringWithCanonicalMapping | | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | semmle.label | .precomposedStringWithCompatibilityMapping | | string.swift:301:13:301:44 | ...! | semmle.label | ...! | +| string.swift:304:13:304:13 | tainted : | semmle.label | tainted : | +| string.swift:304:13:304:60 | call to replacingOccurrences(of:with:options:range:) | semmle.label | call to replacingOccurrences(of:with:options:range:) | +| string.swift:305:13:305:64 | call to replacingOccurrences(of:with:options:range:) | semmle.label | call to replacingOccurrences(of:with:options:range:) | +| string.swift:305:55:305:63 | call to source2() : | semmle.label | call to source2() : | | string.swift:309:14:309:22 | call to source2() : | semmle.label | call to source2() : | | string.swift:310:13:310:13 | str1 | semmle.label | str1 | | string.swift:311:13:311:13 | &... : | semmle.label | &... : | @@ -1506,6 +1528,9 @@ nodes | string.swift:340:14:340:22 | call to source2() : | semmle.label | call to source2() : | | string.swift:341:13:341:13 | str6 | semmle.label | str6 | | string.swift:343:13:343:13 | str6 | semmle.label | str6 | +| string.swift:347:3:347:3 | [post] &... : | semmle.label | [post] &... : | +| string.swift:347:62:347:70 | call to source2() : | semmle.label | call to source2() : | +| string.swift:348:13:348:13 | str7 | semmle.label | str7 | | string.swift:355:23:355:77 | call to String.init(data:encoding:) : | semmle.label | call to String.init(data:encoding:) : | | string.swift:355:36:355:44 | call to source3() : | semmle.label | call to source3() : | | string.swift:358:12:358:25 | ...! | semmle.label | ...! | @@ -1899,9 +1924,12 @@ subpaths | string.swift:255:13:255:13 | tainted : | string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | string.swift:255:13:255:55 | call to propertyListFromStringsFileFormat() | | string.swift:256:13:256:13 | tainted : | string.swift:110:3:110:78 | [summary param] this in propertyListFromStringsFileFormat() : | file://:0:0:0:0 | [summary] to write: return (return) in propertyListFromStringsFileFormat() : | string.swift:256:13:256:55 | call to propertyListFromStringsFileFormat() : | | string.swift:263:13:263:13 | tainted : | string.swift:112:8:112:8 | self : | string.swift:112:3:112:79 | self[return] : | string.swift:263:13:263:13 | [post] tainted : | +| string.swift:304:13:304:13 | tainted : | string.swift:113:3:114:77 | [summary param] this in replacingOccurrences(of:with:options:range:) : | file://:0:0:0:0 | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | string.swift:304:13:304:60 | call to replacingOccurrences(of:with:options:range:) | +| string.swift:305:55:305:63 | call to source2() : | string.swift:113:3:114:77 | [summary param] 1 in replacingOccurrences(of:with:options:range:) : | file://:0:0:0:0 | [summary] to write: return (return) in replacingOccurrences(of:with:options:range:) : | string.swift:305:13:305:64 | call to replacingOccurrences(of:with:options:range:) | | string.swift:311:13:311:13 | &... : | file://:0:0:0:0 | [summary param] this in remove(at:) : | file://:0:0:0:0 | [summary] to write: return (return) in remove(at:) : | string.swift:311:13:311:44 | call to remove(at:) | | string.swift:326:13:326:13 | &... : | file://:0:0:0:0 | [summary param] this in removeFirst() : | file://:0:0:0:0 | [summary] to write: return (return) in removeFirst() : | string.swift:326:13:326:30 | call to removeFirst() | | string.swift:330:13:330:13 | &... : | file://:0:0:0:0 | [summary param] this in removeLast() : | file://:0:0:0:0 | [summary] to write: return (return) in removeLast() : | string.swift:330:13:330:29 | call to removeLast() | +| string.swift:347:62:347:70 | call to source2() : | string.swift:86:12:87:51 | [summary param] 1 in replaceSubrange(_:with:) : | file://:0:0:0:0 | [summary] to write: argument this in replaceSubrange(_:with:) : | string.swift:347:3:347:3 | [post] &... : | | string.swift:355:36:355:44 | call to source3() : | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(data:encoding:) : | string.swift:355:23:355:77 | call to String.init(data:encoding:) : | | string.swift:361:30:361:38 | call to source3() : | file://:0:0:0:0 | [summary param] 0 in String.init(decoding:as:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(decoding:as:) : | string.swift:361:13:361:54 | call to String.init(decoding:as:) | | string.swift:403:22:403:22 | tainted : | string.swift:111:3:111:74 | [summary param] this in cString(using:) : | file://:0:0:0:0 | [summary] to write: return (return) in cString(using:) : | string.swift:403:22:403:65 | call to cString(using:) : | @@ -2113,6 +2141,8 @@ subpaths | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | string.swift:217:17:217:25 | call to source2() : | string.swift:297:13:297:21 | .decomposedStringWithCanonicalMapping | result | | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | string.swift:217:17:217:25 | call to source2() : | string.swift:299:13:299:21 | .precomposedStringWithCompatibilityMapping | result | | string.swift:301:13:301:44 | ...! | string.swift:217:17:217:25 | call to source2() : | string.swift:301:13:301:44 | ...! | result | +| string.swift:304:13:304:60 | call to replacingOccurrences(of:with:options:range:) | string.swift:217:17:217:25 | call to source2() : | string.swift:304:13:304:60 | call to replacingOccurrences(of:with:options:range:) | result | +| string.swift:305:13:305:64 | call to replacingOccurrences(of:with:options:range:) | string.swift:305:55:305:63 | call to source2() : | string.swift:305:13:305:64 | call to replacingOccurrences(of:with:options:range:) | result | | string.swift:310:13:310:13 | str1 | string.swift:309:14:309:22 | call to source2() : | string.swift:310:13:310:13 | str1 | result | | string.swift:311:13:311:44 | call to remove(at:) | string.swift:309:14:309:22 | call to source2() : | string.swift:311:13:311:44 | call to remove(at:) | result | | string.swift:312:13:312:13 | str1 | string.swift:309:14:309:22 | call to source2() : | string.swift:312:13:312:13 | str1 | result | @@ -2131,6 +2161,7 @@ subpaths | string.swift:338:13:338:13 | str5 | string.swift:335:14:335:22 | call to source2() : | string.swift:338:13:338:13 | str5 | result | | string.swift:341:13:341:13 | str6 | string.swift:340:14:340:22 | call to source2() : | string.swift:341:13:341:13 | str6 | result | | string.swift:343:13:343:13 | str6 | string.swift:340:14:340:22 | call to source2() : | string.swift:343:13:343:13 | str6 | result | +| string.swift:348:13:348:13 | str7 | string.swift:347:62:347:70 | call to source2() : | string.swift:348:13:348:13 | str7 | result | | string.swift:358:12:358:25 | ...! | string.swift:355:36:355:44 | call to source3() : | string.swift:358:12:358:25 | ...! | result | | string.swift:361:13:361:54 | call to String.init(decoding:as:) | string.swift:361:30:361:38 | call to source3() : | string.swift:361:13:361:54 | call to String.init(decoding:as:) | result | | string.swift:404:13:404:13 | arrayString2 | string.swift:366:17:366:25 | call to source2() : | string.swift:404:13:404:13 | arrayString2 | result | diff --git a/swift/ql/test/library-tests/dataflow/taint/string.swift b/swift/ql/test/library-tests/dataflow/taint/string.swift index 0a0245dfb8e..5179d64c0fc 100644 --- a/swift/ql/test/library-tests/dataflow/taint/string.swift +++ b/swift/ql/test/library-tests/dataflow/taint/string.swift @@ -301,8 +301,8 @@ func taintThroughSimpleStringOperations() { sink(arg: tainted.removingPercentEncoding!) // $ tainted=217 sink(arg: clean.replacingOccurrences(of: "a", with: "b")) - sink(arg: tainted.replacingOccurrences(of: "a", with: "b")) // $ MISSING: tainted=217 - sink(arg: clean.replacingOccurrences(of: "a", with: source2())) // $ MISSING: tainted=217 + sink(arg: tainted.replacingOccurrences(of: "a", with: "b")) // $ tainted=217 + sink(arg: clean.replacingOccurrences(of: "a", with: source2())) // $ tainted=305 } func taintThroughMutatingStringOperations() { @@ -345,7 +345,7 @@ func taintThroughMutatingStringOperations() { var str7 = "" sink(arg: str7) str7.replaceSubrange((nil as Range?)!, with: source2()) - sink(arg: str7) // $ MISSING: tainted=347 + sink(arg: str7) // $ tainted=347 } func source3() -> Data { return Data("") } From 2d46dd29360d7ef6e5a16b8919c438136440ac59 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Feb 2023 12:21:08 +0100 Subject: [PATCH 292/415] C#: Add extractor support for the required modifier for fields and properties. --- .../Entities/Modifier.cs | 16 ++++++++++++++-- .../Entities/Modifiers.cs | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs index 7e4a3a95e39..15da81bf5e4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifier.cs @@ -65,6 +65,15 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.has_modifiers(target, Modifier.Create(cx, modifier)); } + private static void ExtractFieldModifiers(Context cx, TextWriter trapFile, IEntity key, IFieldSymbol symbol) + { + if (symbol.IsReadOnly) + HasModifier(cx, trapFile, key, Modifiers.Readonly); + + if (symbol.IsRequired) + HasModifier(cx, trapFile, key, Modifiers.Required); + } + private static void ExtractNamedTypeModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol) { if (symbol.Kind != SymbolKind.NamedType) @@ -106,8 +115,11 @@ namespace Semmle.Extraction.CSharp.Entities if (symbol.IsVirtual) HasModifier(cx, trapFile, key, Modifiers.Virtual); - if (symbol.Kind == SymbolKind.Field && ((IFieldSymbol)symbol).IsReadOnly) - HasModifier(cx, trapFile, key, Modifiers.Readonly); + if (symbol is IFieldSymbol field) + ExtractFieldModifiers(cx, trapFile, key, field); + + if (symbol.Kind == SymbolKind.Property && ((IPropertySymbol)symbol).IsRequired) + HasModifier(cx, trapFile, key, Modifiers.Required); if (symbol.IsOverride) HasModifier(cx, trapFile, key, Modifiers.Override); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifiers.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifiers.cs index f535a9c3058..ef38646bc81 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifiers.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Modifiers.cs @@ -13,6 +13,7 @@ internal static class Modifiers public const string Public = "public"; public const string Readonly = "readonly"; public const string Record = "record"; + public const string Required = "required"; public const string Ref = "ref"; public const string Sealed = "sealed"; public const string Static = "static"; From c0b8e852c5109b2f83b10199c2fb3d9de6a5e8d6 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Feb 2023 12:22:09 +0100 Subject: [PATCH 293/415] C#: Add library support for required members. --- csharp/ql/lib/semmle/code/csharp/Member.qll | 5 +++++ csharp/ql/lib/semmle/code/dotnet/Declaration.qll | 3 +++ 2 files changed, 8 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/Member.qll b/csharp/ql/lib/semmle/code/csharp/Member.qll index 85225ac44cf..0ce8dc44e3c 100644 --- a/csharp/ql/lib/semmle/code/csharp/Member.qll +++ b/csharp/ql/lib/semmle/code/csharp/Member.qll @@ -90,6 +90,9 @@ class Modifiable extends Declaration, @modifiable { /** Holds if this declaration is `const`. */ predicate isConst() { this.hasModifier("const") } + /** Holds if this declaration has the modifier `required`. */ + predicate isRequired() { this.hasModifier("required") } + /** Holds if this declaration is `unsafe`. */ predicate isUnsafe() { this.hasModifier("unsafe") or @@ -178,6 +181,8 @@ class Member extends DotNet::Member, Modifiable, @member { override predicate isAbstract() { Modifiable.super.isAbstract() } override predicate isStatic() { Modifiable.super.isStatic() } + + override predicate isRequired() { Modifiable.super.isRequired() } } private class TOverridable = @virtualizable or @callable_accessor; diff --git a/csharp/ql/lib/semmle/code/dotnet/Declaration.qll b/csharp/ql/lib/semmle/code/dotnet/Declaration.qll index fea5a1aaeca..8e45a06eaca 100644 --- a/csharp/ql/lib/semmle/code/dotnet/Declaration.qll +++ b/csharp/ql/lib/semmle/code/dotnet/Declaration.qll @@ -80,6 +80,9 @@ class Member extends Declaration, @dotnet_member { /** Holds if this member is `static`. */ predicate isStatic() { none() } + /** Holds if this member is declared `required`. */ + predicate isRequired() { none() } + /** * Holds if this member has name `name` and is defined in type `type` * with namespace `namespace`. From 3971dedcf6b330a3c915053a127a061c147e92d4 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Feb 2023 12:25:12 +0100 Subject: [PATCH 294/415] C#: Add testcase for required members. --- .../library-tests/csharp11/PrintAst.expected | 91 +++++++++++++++++++ .../library-tests/csharp11/RequiredMembers.cs | 42 +++++++++ .../csharp11/requiredMembers.expected | 5 + .../library-tests/csharp11/requiredMembers.ql | 8 ++ 4 files changed, 146 insertions(+) create mode 100644 csharp/ql/test/library-tests/csharp11/RequiredMembers.cs create mode 100644 csharp/ql/test/library-tests/csharp11/requiredMembers.expected create mode 100644 csharp/ql/test/library-tests/csharp11/requiredMembers.ql diff --git a/csharp/ql/test/library-tests/csharp11/PrintAst.expected b/csharp/ql/test/library-tests/csharp11/PrintAst.expected index c9ebe7cc05e..3ef77ba3864 100644 --- a/csharp/ql/test/library-tests/csharp11/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp11/PrintAst.expected @@ -657,6 +657,97 @@ RelaxedShift.cs: # 30| 1: [OperatorCall] call to operator >>> # 30| 0: [LocalVariableAccess] access to local variable n31 # 30| 1: [StringLiteralUtf16] "3" +RequiredMembers.cs: +# 4| [Class] ClassRequiredMembers +# 6| 4: [Field] RequiredField +# 6| -1: [TypeMention] object +# 7| 5: [Property] RequiredProperty +# 7| -1: [TypeMention] string +# 7| 3: [Getter] get_RequiredProperty +# 7| 4: [Setter] set_RequiredProperty +#-----| 2: (Parameters) +# 7| 0: [Parameter] value +# 8| 6: [Property] VirtualProperty +# 8| -1: [TypeMention] object +# 8| 3: [Getter] get_VirtualProperty +# 8| 4: [Setter] set_VirtualProperty +#-----| 2: (Parameters) +# 8| 0: [Parameter] value +# 10| 7: [InstanceConstructor] ClassRequiredMembers +# 10| 4: [BlockStmt] {...} +# 13| 8: [InstanceConstructor] ClassRequiredMembers +#-----| 0: (Attributes) +# 12| 1: [DefaultAttribute] [SetsRequiredMembers(...)] +# 12| 0: [TypeMention] SetsRequiredMembersAttribute +#-----| 2: (Parameters) +# 13| 0: [Parameter] requiredField +# 13| -1: [TypeMention] object +# 13| 1: [Parameter] requiredProperty +# 13| -1: [TypeMention] string +# 14| 4: [BlockStmt] {...} +# 15| 0: [ExprStmt] ...; +# 15| 0: [AssignExpr] ... = ... +# 15| 0: [FieldAccess] access to field RequiredField +# 15| 1: [ParameterAccess] access to parameter requiredField +# 16| 1: [ExprStmt] ...; +# 16| 0: [AssignExpr] ... = ... +# 16| 0: [PropertyCall] access to property RequiredProperty +# 16| 1: [ParameterAccess] access to parameter requiredProperty +# 20| [Class] ClassRequiredMembersSub +#-----| 3: (Base types) +# 20| 0: [TypeMention] ClassRequiredMembers +# 22| 4: [Property] VirtualProperty +# 22| -1: [TypeMention] object +# 22| 3: [Getter] get_VirtualProperty +# 22| 4: [Setter] set_VirtualProperty +#-----| 2: (Parameters) +# 22| 0: [Parameter] value +# 24| 5: [InstanceConstructor] ClassRequiredMembersSub +# 24| 3: [ConstructorInitializer] call to constructor ClassRequiredMembers +# 24| 4: [BlockStmt] {...} +# 27| 6: [InstanceConstructor] ClassRequiredMembersSub +#-----| 0: (Attributes) +# 26| 1: [DefaultAttribute] [SetsRequiredMembers(...)] +# 26| 0: [TypeMention] SetsRequiredMembersAttribute +#-----| 2: (Parameters) +# 27| 0: [Parameter] requiredField +# 27| -1: [TypeMention] object +# 27| 1: [Parameter] requiredProperty +# 27| -1: [TypeMention] string +# 27| 2: [Parameter] virtualProperty +# 27| -1: [TypeMention] object +# 27| 3: [ConstructorInitializer] call to constructor ClassRequiredMembers +# 27| 0: [ParameterAccess] access to parameter requiredField +# 27| 1: [ParameterAccess] access to parameter requiredProperty +# 28| 4: [BlockStmt] {...} +# 29| 0: [ExprStmt] ...; +# 29| 0: [AssignExpr] ... = ... +# 29| 0: [PropertyCall] access to property VirtualProperty +# 29| 1: [ParameterAccess] access to parameter virtualProperty +# 33| [RecordClass] RecordRequiredMembers +# 33| 12: [NEOperator] != +#-----| 2: (Parameters) +# 33| 0: [Parameter] left +# 33| 1: [Parameter] right +# 33| 13: [EQOperator] == +#-----| 2: (Parameters) +# 33| 0: [Parameter] left +# 33| 1: [Parameter] right +# 33| 14: [Property] EqualityContract +# 33| 3: [Getter] get_EqualityContract +# 35| 15: [Property] X +# 35| -1: [TypeMention] object +# 35| 3: [Getter] get_X +# 35| 4: [Setter] set_X +#-----| 2: (Parameters) +# 35| 0: [Parameter] value +# 38| [Struct] StructRequiredMembers +# 40| 5: [Property] Y +# 40| -1: [TypeMention] string +# 40| 3: [Getter] get_Y +# 40| 4: [Setter] set_Y +#-----| 2: (Parameters) +# 40| 0: [Parameter] value Scoped.cs: # 1| [Struct] S1 # 2| [Struct] S2 diff --git a/csharp/ql/test/library-tests/csharp11/RequiredMembers.cs b/csharp/ql/test/library-tests/csharp11/RequiredMembers.cs new file mode 100644 index 00000000000..9bccbd24584 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp11/RequiredMembers.cs @@ -0,0 +1,42 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +public class ClassRequiredMembers +{ + public required object? RequiredField; + public required string? RequiredProperty { get; init; } + public virtual object? VirtualProperty { get; init; } + + public ClassRequiredMembers() { } + + [SetsRequiredMembers] + public ClassRequiredMembers(object requiredField, string requiredProperty) + { + RequiredField = requiredField; + RequiredProperty = requiredProperty; + } +} + +public class ClassRequiredMembersSub : ClassRequiredMembers +{ + public override required object? VirtualProperty { get; init; } + + public ClassRequiredMembersSub() : base() { } + + [SetsRequiredMembers] + public ClassRequiredMembersSub(object requiredField, string requiredProperty, object virtualProperty) : base(requiredField, requiredProperty) + { + VirtualProperty = virtualProperty; + } +} + +public record RecordRequiredMembers +{ + public required object? X { get; init; } +} + +public struct StructRequiredMembers +{ + public required string? Y { get; init; } +} + diff --git a/csharp/ql/test/library-tests/csharp11/requiredMembers.expected b/csharp/ql/test/library-tests/csharp11/requiredMembers.expected new file mode 100644 index 00000000000..a54084464de --- /dev/null +++ b/csharp/ql/test/library-tests/csharp11/requiredMembers.expected @@ -0,0 +1,5 @@ +| RequiredMembers.cs:6:29:6:41 | RequiredField | ClassRequiredMembers | Field | +| RequiredMembers.cs:7:29:7:44 | RequiredProperty | ClassRequiredMembers | Property | +| RequiredMembers.cs:22:38:22:52 | VirtualProperty | ClassRequiredMembersSub | Property | +| RequiredMembers.cs:35:29:35:29 | X | RecordRequiredMembers | Property | +| RequiredMembers.cs:40:29:40:29 | Y | StructRequiredMembers | Property | diff --git a/csharp/ql/test/library-tests/csharp11/requiredMembers.ql b/csharp/ql/test/library-tests/csharp11/requiredMembers.ql new file mode 100644 index 00000000000..e0be03dd906 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp11/requiredMembers.ql @@ -0,0 +1,8 @@ +import csharp + +query predicate requiredmembers(Member m, string type, string qlclass) { + m.getFile().getStem() = "RequiredMembers" and + m.isRequired() and + type = m.getDeclaringType().getName() and + qlclass = m.getAPrimaryQlClass() +} From b87de911ba27ad05f13ebbb8c44f5c7ac29b83f1 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Feb 2023 12:26:32 +0100 Subject: [PATCH 295/415] C#: Add change note. --- csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md diff --git a/csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md b/csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md new file mode 100644 index 00000000000..8a318ca52ec --- /dev/null +++ b/csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C# 11: Added extractor support for `required` fields and properties. \ No newline at end of file From 6fc5bdd8710c16cd95c1da6155434acd2f2b07ee Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 17 Feb 2023 08:15:33 +0000 Subject: [PATCH 296/415] Announce JDK20 support --- docs/codeql/reusables/supported-versions-compilers.rst | 4 ++-- java/ql/lib/change-notes/2023-02-17-jdk20.md | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 java/ql/lib/change-notes/2023-02-17-jdk20.md diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index f9f4e091a90..196bb1a44dd 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -17,7 +17,7 @@ .NET 5, .NET 6","``.sln``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" Go (aka Golang), "Go up to 1.20", "Go 1.11 or more recent", ``.go`` - Java,"Java 7 to 19 [4]_","javac (OpenJDK and Oracle JDK), + Java,"Java 7 to 20 [4]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [5]_",``.java`` Kotlin [6]_,"Kotlin 1.5.0 to 1.8.20","kotlinc",``.kt`` @@ -31,7 +31,7 @@ .. [1] C++20 support is currently in beta. Supported for GCC on Linux only. Modules are *not* supported. .. [2] Support for the clang-cl compiler is preliminary. .. [3] Support for the Arm Compiler (armcc) is preliminary. - .. [4] Builds that execute on Java 7 to 19 can be analyzed. The analysis understands Java 19 standard language features. + .. [4] Builds that execute on Java 7 to 20 can be analyzed. The analysis understands Java 20 standard language features. .. [5] ECJ is supported when the build invokes it via the Maven Compiler plugin or the Takari Lifecycle plugin. .. [6] Kotlin support is currently in beta. .. [7] JSX and Flow code, YAML, JSON, HTML, and XML files may also be analyzed with JavaScript files. diff --git a/java/ql/lib/change-notes/2023-02-17-jdk20.md b/java/ql/lib/change-notes/2023-02-17-jdk20.md new file mode 100644 index 00000000000..a2f674cc275 --- /dev/null +++ b/java/ql/lib/change-notes/2023-02-17-jdk20.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The Java extractor now supports builds against JDK 20. \ No newline at end of file From c4c9fd72bb84897d73497f7f38ec0aeb66825a7c Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Fri, 17 Feb 2023 10:03:52 +0100 Subject: [PATCH 297/415] Swift: update to 5.7.3 No changes to the Swift frontend library headers, so no changes to the extractor seem to be required. --- swift/actions/run-integration-tests/action.yml | 2 +- swift/third_party/load.bzl | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/swift/actions/run-integration-tests/action.yml b/swift/actions/run-integration-tests/action.yml index 163f572acde..bf46b22558f 100644 --- a/swift/actions/run-integration-tests/action.yml +++ b/swift/actions/run-integration-tests/action.yml @@ -13,7 +13,7 @@ runs: - uses: actions/setup-python@v4 with: python-version-file: 'swift/.python-version' - - uses: swift-actions/setup-swift@194625b58a582570f61cc707c3b558086c26b723 + - uses: swift-actions/setup-swift@da0e3e04b5e3e15dbc3861bd835ad9f0afe56296 with: swift-version: "${{steps.get_swift_version.outputs.version}}" - uses: ./.github/actions/fetch-codeql diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl index bf6e4ae600e..8bbb0089957 100644 --- a/swift/third_party/load.bzl +++ b/swift/third_party/load.bzl @@ -1,9 +1,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -_swift_prebuilt_version = "swift-5.7.1-RELEASE.44582.104" +_swift_prebuilt_version = "swift-5.7.3-RELEASE.124" _swift_sha_map = { - "Linux-X64": "8d94f2d75f2aa9ee8e5421318d2f07b27e095127c9be0156794a88d8e9a0f19a", - "macOS-X64": "5f0550d2924e7071d006a0c9802acbd9a11f0017073e4a1eb27b7ddc4764f3f2", + "Linux-X64": "9d89a101e09a4581b014b04f266f21192530b56124c91653658606ae2af4f75a", + "macOS-ARM64": "95136fadf91d317526ad61d393e9ac31cb564534105777d04650b048d923c58d", + "macOS-X64": "b91725a401b9d33f235f3ad3435a2fe9a36585a83d368a924d6e274e05499773", } _swift_arch_map = { From d1cd4cd099b20b84110de620795965b07ba783be Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 17 Feb 2023 10:10:22 +0000 Subject: [PATCH 298/415] Add Gradle wrappers for Kotlin tests This avoids tests' behaviour changing due to environmental Gradle version changes --- .../kotlin/compiler_arguments/.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../kotlin/compiler_arguments/gradlew | 244 ++++++++++++++++++ .../kotlin/compiler_arguments/gradlew.bat | 92 +++++++ .../kotlin/compiler_arguments/test.py | 6 +- .../kotlin/gradle_groovy_app/.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../kotlin/gradle_groovy_app/gradlew | 244 ++++++++++++++++++ .../kotlin/gradle_groovy_app/gradlew.bat | 92 +++++++ .../kotlin/gradle_groovy_app/test.py | 7 +- .../.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../gradle_kotlinx_serialization/gradlew | 244 ++++++++++++++++++ .../gradle_kotlinx_serialization/gradlew.bat | 92 +++++++ .../gradle_kotlinx_serialization/test.py | 7 +- .../kotlin/kotlin_kfunction/.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../kotlin/kotlin_kfunction/gradlew | 244 ++++++++++++++++++ .../kotlin/kotlin_kfunction/gradlew.bat | 92 +++++++ .../kotlin/kotlin_kfunction/test.py | 6 +- 24 files changed, 1410 insertions(+), 8 deletions(-) create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew.bat create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew create mode 100644 java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew.bat create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew new file mode 100755 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py index c1ba4d3370b..359771ac6c0 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py @@ -1,5 +1,7 @@ +import platform from create_database_utils import * +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + run_codeql_database_create( - ["gradle build --no-daemon --no-build-cache"], lang="java") -runSuccessfully([get_cmd("gradle"), "clean"]) + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/.gitattributes b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew new file mode 100755 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew.bat b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/test.py b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/test.py index 25737233d4a..359771ac6c0 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/test.py +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_groovy_app/test.py @@ -1,4 +1,7 @@ +import platform from create_database_utils import * -run_codeql_database_create(["gradle build --no-daemon --no-build-cache"], lang="java") -runSuccessfully([get_cmd("gradle"), "clean"]) +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + +run_codeql_database_create( + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/.gitattributes b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew new file mode 100755 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew.bat b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/test.py b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/test.py index 25737233d4a..359771ac6c0 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/test.py +++ b/java/ql/integration-tests/all-platforms/kotlin/gradle_kotlinx_serialization/test.py @@ -1,4 +1,7 @@ +import platform from create_database_utils import * -run_codeql_database_create(["gradle build --no-daemon --no-build-cache"], lang="java") -runSuccessfully([get_cmd("gradle"), "clean"]) +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + +run_codeql_database_create( + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 zcmb5VV{~QRw)Y#`wrv{~+qP{x72B%VwzFc}c2cp;N~)5ZbDrJayPv(!dGEd-##*zr z)#n-$y^sH|_dchh3@8{H5D*j;5D<{i*8l5IFJ|DjL!e)upfGNX(kojugZ3I`oH1PvW`wFW_ske0j@lB9bX zO;2)`y+|!@X(fZ1<2n!Qx*)_^Ai@Cv-dF&(vnudG?0CsddG_&Wtae(n|K59ew)6St z#dj7_(Cfwzh$H$5M!$UDd8=4>IQsD3xV=lXUq($;(h*$0^yd+b{qq63f0r_de#!o_ zXDngc>zy`uor)4A^2M#U*DC~i+dc<)Tb1Tv&~Ev@oM)5iJ4Sn#8iRw16XXuV50BS7 zdBL5Mefch(&^{luE{*5qtCZk$oFr3RH=H!c3wGR=HJ(yKc_re_X9pD` zJ;uxPzUfVpgU>DSq?J;I@a+10l0ONXPcDkiYcihREt5~T5Gb}sT0+6Q;AWHl`S5dV>lv%-p9l#xNNy7ZCr%cyqHY%TZ8Q4 zbp&#ov1*$#grNG#1vgfFOLJCaNG@K|2!W&HSh@3@Y%T?3YI75bJp!VP*$*!< z;(ffNS_;@RJ`=c7yX04!u3JP*<8jeqLHVJu#WV&v6wA!OYJS4h<_}^QI&97-;=ojW zQ-1t)7wnxG*5I%U4)9$wlv5Fr;cIizft@&N+32O%B{R1POm$oap@&f| zh+5J{>U6ftv|vAeKGc|zC=kO(+l7_cLpV}-D#oUltScw})N>~JOZLU_0{Ka2e1evz z{^a*ZrLr+JUj;)K&u2CoCAXLC2=fVScI(m_p~0FmF>>&3DHziouln?;sxW`NB}cSX z8?IsJB)Z=aYRz!X=yJn$kyOWK%rCYf-YarNqKzmWu$ZvkP12b4qH zhS9Q>j<}(*frr?z<%9hl*i^#@*O2q(Z^CN)c2c z>1B~D;@YpG?G!Yk+*yn4vM4sO-_!&m6+`k|3zd;8DJnxsBYtI;W3We+FN@|tQ5EW= z!VU>jtim0Mw#iaT8t_<+qKIEB-WwE04lBd%Letbml9N!?SLrEG$nmn7&W(W`VB@5S zaY=sEw2}i@F_1P4OtEw?xj4@D6>_e=m=797#hg}f*l^`AB|Y0# z9=)o|%TZFCY$SzgSjS|8AI-%J4x}J)!IMxY3_KYze`_I=c1nmrk@E8c9?MVRu)7+Ue79|)rBX7tVB7U|w4*h(;Gi3D9le49B38`wuv zp7{4X^p+K4*$@gU(Tq3K1a#3SmYhvI42)GzG4f|u zwQFT1n_=n|jpi=70-yE9LA+d*T8u z`=VmmXJ_f6WmZveZPct$Cgu^~gFiyL>Lnpj*6ee>*0pz=t$IJ}+rE zsf@>jlcG%Wx;Cp5x)YSVvB1$yyY1l&o zvwX=D7k)Dn;ciX?Z)Pn8$flC8#m`nB&(8?RSdBvr?>T9?E$U3uIX7T?$v4dWCa46 z+&`ot8ZTEgp7G+c52oHJ8nw5}a^dwb_l%MOh(ebVj9>_koQP^$2B~eUfSbw9RY$_< z&DDWf2LW;b0ZDOaZ&2^i^g+5uTd;GwO(-bbo|P^;CNL-%?9mRmxEw~5&z=X^Rvbo^WJW=n_%*7974RY}JhFv46> zd}`2|qkd;89l}R;i~9T)V-Q%K)O=yfVKNM4Gbacc7AOd>#^&W&)Xx!Uy5!BHnp9kh z`a(7MO6+Ren#>R^D0K)1sE{Bv>}s6Rb9MT14u!(NpZOe-?4V=>qZ>}uS)!y~;jEUK z&!U7Fj&{WdgU#L0%bM}SYXRtM5z!6M+kgaMKt%3FkjWYh=#QUpt$XX1!*XkpSq-pl zhMe{muh#knk{9_V3%qdDcWDv}v)m4t9 zQhv{;} zc{}#V^N3H>9mFM8`i`0p+fN@GqX+kl|M94$BK3J-X`Hyj8r!#x6Vt(PXjn?N)qedP z=o1T^#?1^a{;bZ&x`U{f?}TMo8ToN zkHj5v|}r}wDEi7I@)Gj+S1aE-GdnLN+$hw!=DzglMaj#{qjXi_dwpr|HL(gcCXwGLEmi|{4&4#OZ4ChceA zKVd4K!D>_N=_X;{poT~4Q+!Le+ZV>=H7v1*l%w`|`Dx8{)McN@NDlQyln&N3@bFpV z_1w~O4EH3fF@IzJ9kDk@7@QctFq8FbkbaH7K$iX=bV~o#gfh?2JD6lZf(XP>~DACF)fGFt)X%-h1yY~MJU{nA5 ze2zxWMs{YdX3q5XU*9hOH0!_S24DOBA5usB+Ws$6{|AMe*joJ?RxfV}*7AKN9V*~J zK+OMcE@bTD>TG1*yc?*qGqjBN8mgg@h1cJLDv)0!WRPIkC` zZrWXrceVw;fB%3`6kq=a!pq|hFIsQ%ZSlo~)D z|64!aCnw-?>}AG|*iOl44KVf8@|joXi&|)1rB;EQWgm+iHfVbgllP$f!$Wf42%NO5b(j9Bw6L z;0dpUUK$5GX4QbMlTmLM_jJt!ur`_0~$b#BB7FL*%XFf<b__1o)Ao3rlobbN8-(T!1d-bR8D3S0@d zLI!*GMb5s~Q<&sjd}lBb8Nr0>PqE6_!3!2d(KAWFxa{hm`@u|a(%#i(#f8{BP2wbs zt+N_slWF4IF_O|{w`c~)Xvh&R{Au~CFmW#0+}MBd2~X}t9lz6*E7uAD`@EBDe$>7W zzPUkJx<`f$0VA$=>R57^(K^h86>09?>_@M(R4q($!Ck6GG@pnu-x*exAx1jOv|>KH zjNfG5pwm`E-=ydcb+3BJwuU;V&OS=6yM^4Jq{%AVqnTTLwV`AorIDD}T&jWr8pB&j28fVtk_y*JRP^t@l*($UZ z6(B^-PBNZ+z!p?+e8@$&jCv^EWLb$WO=}Scr$6SM*&~B95El~;W_0(Bvoha|uQ1T< zO$%_oLAwf1bW*rKWmlD+@CP&$ObiDy=nh1b2ejz%LO9937N{LDe7gle4i!{}I$;&Y zkexJ9Ybr+lrCmKWg&}p=`2&Gf10orS?4$VrzWidT=*6{KzOGMo?KI0>GL0{iFWc;C z+LPq%VH5g}6V@-tg2m{C!-$fapJ9y}c$U}aUmS{9#0CM*8pC|sfer!)nG7Ji>mfRh z+~6CxNb>6eWKMHBz-w2{mLLwdA7dA-qfTu^A2yG1+9s5k zcF=le_UPYG&q!t5Zd_*E_P3Cf5T6821bO`daa`;DODm8Ih8k89=RN;-asHIigj`n=ux>*f!OC5#;X5i;Q z+V!GUy0|&Y_*8k_QRUA8$lHP;GJ3UUD08P|ALknng|YY13)}!!HW@0z$q+kCH%xet zlWf@BXQ=b=4}QO5eNnN~CzWBbHGUivG=`&eWK}beuV*;?zt=P#pM*eTuy3 zP}c#}AXJ0OIaqXji78l;YrP4sQe#^pOqwZUiiN6^0RCd#D271XCbEKpk`HI0IsN^s zES7YtU#7=8gTn#lkrc~6)R9u&SX6*Jk4GFX7){E)WE?pT8a-%6P+zS6o&A#ml{$WX zABFz#i7`DDlo{34)oo?bOa4Z_lNH>n;f0nbt$JfAl~;4QY@}NH!X|A$KgMmEsd^&Y zt;pi=>AID7ROQfr;MsMtClr5b0)xo|fwhc=qk33wQ|}$@?{}qXcmECh>#kUQ-If0$ zseb{Wf4VFGLNc*Rax#P8ko*=`MwaR-DQ8L8V8r=2N{Gaips2_^cS|oC$+yScRo*uF zUO|5=?Q?{p$inDpx*t#Xyo6=s?bbN}y>NNVxj9NZCdtwRI70jxvm3!5R7yiWjREEd zDUjrsZhS|P&|Ng5r+f^kA6BNN#|Se}_GF>P6sy^e8kBrgMv3#vk%m}9PCwUWJg-AD zFnZ=}lbi*mN-AOm zCs)r=*YQAA!`e#1N>aHF=bb*z*hXH#Wl$z^o}x##ZrUc=kh%OHWhp=7;?8%Xj||@V?1c ziWoaC$^&04;A|T)!Zd9sUzE&$ODyJaBpvqsw19Uiuq{i#VK1!htkdRWBnb z`{rat=nHArT%^R>u#CjjCkw-7%g53|&7z-;X+ewb?OLWiV|#nuc8mp*LuGSi3IP<<*Wyo9GKV7l0Noa4Jr0g3p_$ z*R9{qn=?IXC#WU>48-k5V2Oc_>P;4_)J@bo1|pf=%Rcbgk=5m)CJZ`caHBTm3%!Z9 z_?7LHr_BXbKKr=JD!%?KhwdYSdu8XxPoA{n8^%_lh5cjRHuCY9Zlpz8g+$f@bw@0V z+6DRMT9c|>1^3D|$Vzc(C?M~iZurGH2pXPT%F!JSaAMdO%!5o0uc&iqHx?ImcX6fI zCApkzc~OOnfzAd_+-DcMp&AOQxE_EsMqKM{%dRMI5`5CT&%mQO?-@F6tE*xL?aEGZ z8^wH@wRl`Izx4sDmU>}Ym{ybUm@F83qqZPD6nFm?t?(7>h*?`fw)L3t*l%*iw0Qu#?$5eq!Qc zpQvqgSxrd83NsdO@lL6#{%lsYXWen~d3p4fGBb7&5xqNYJ)yn84!e1PmPo7ChVd%4 zHUsV0Mh?VpzZD=A6%)Qrd~i7 z96*RPbid;BN{Wh?adeD_p8YU``kOrGkNox3D9~!K?w>#kFz!4lzOWR}puS(DmfjJD z`x0z|qB33*^0mZdM&6$|+T>fq>M%yoy(BEjuh9L0>{P&XJ3enGpoQRx`v6$txXt#c z0#N?b5%srj(4xmPvJxrlF3H%OMB!jvfy z;wx8RzU~lb?h_}@V=bh6p8PSb-dG|-T#A?`c&H2`_!u+uenIZe`6f~A7r)`9m8atC zt(b|6Eg#!Q*DfRU=Ix`#B_dK)nnJ_+>Q<1d7W)eynaVn`FNuN~%B;uO2}vXr5^zi2 z!ifIF5@Zlo0^h~8+ixFBGqtweFc`C~JkSq}&*a3C}L?b5Mh-bW=e)({F_g4O3 zb@SFTK3VD9QuFgFnK4Ve_pXc3{S$=+Z;;4+;*{H}Rc;845rP?DLK6G5Y-xdUKkA6E3Dz&5f{F^FjJQ(NSpZ8q-_!L3LL@H* zxbDF{gd^U3uD;)a)sJwAVi}7@%pRM&?5IaUH%+m{E)DlA_$IA1=&jr{KrhD5q&lTC zAa3c)A(K!{#nOvenH6XrR-y>*4M#DpTTOGQEO5Jr6kni9pDW`rvY*fs|ItV;CVITh z=`rxcH2nEJpkQ^(;1c^hfb8vGN;{{oR=qNyKtR1;J>CByul*+=`NydWnSWJR#I2lN zTvgnR|MBx*XFsfdA&;tr^dYaqRZp*2NwkAZE6kV@1f{76e56eUmGrZ>MDId)oqSWw z7d&r3qfazg+W2?bT}F)4jD6sWaw`_fXZGY&wnGm$FRPFL$HzVTH^MYBHWGCOk-89y zA+n+Q6EVSSCpgC~%uHfvyg@ufE^#u?JH?<73A}jj5iILz4Qqk5$+^U(SX(-qv5agK znUkfpke(KDn~dU0>gdKqjTkVk`0`9^0n_wzXO7R!0Thd@S;U`y)VVP&mOd-2 z(hT(|$=>4FY;CBY9#_lB$;|Wd$aOMT5O_3}DYXEHn&Jrc3`2JiB`b6X@EUOD zVl0S{ijm65@n^19T3l%>*;F(?3r3s?zY{thc4%AD30CeL_4{8x6&cN}zN3fE+x<9; zt2j1RRVy5j22-8U8a6$pyT+<`f+x2l$fd_{qEp_bfxfzu>ORJsXaJn4>U6oNJ#|~p z`*ZC&NPXl&=vq2{Ne79AkQncuxvbOG+28*2wU$R=GOmns3W@HE%^r)Fu%Utj=r9t` zd;SVOnA(=MXgnOzI2@3SGKHz8HN~Vpx&!Ea+Df~`*n@8O=0!b4m?7cE^K*~@fqv9q zF*uk#1@6Re_<^9eElgJD!nTA@K9C732tV~;B`hzZ321Ph=^BH?zXddiu{Du5*IPg} zqDM=QxjT!Rp|#Bkp$(mL)aar)f(dOAXUiw81pX0DC|Y4;>Vz>>DMshoips^8Frdv} zlTD=cKa48M>dR<>(YlLPOW%rokJZNF2gp8fwc8b2sN+i6&-pHr?$rj|uFgktK@jg~ zIFS(%=r|QJ=$kvm_~@n=ai1lA{7Z}i+zj&yzY+!t$iGUy|9jH#&oTNJ;JW-3n>DF+ z3aCOzqn|$X-Olu_p7brzn`uk1F*N4@=b=m;S_C?#hy{&NE#3HkATrg?enaVGT^$qIjvgc61y!T$9<1B@?_ibtDZ{G zeXInVr5?OD_nS_O|CK3|RzzMmu+8!#Zb8Ik;rkIAR%6?$pN@d<0dKD2c@k2quB%s( zQL^<_EM6ow8F6^wJN1QcPOm|ehA+dP(!>IX=Euz5qqIq}Y3;ibQtJnkDmZ8c8=Cf3 zu`mJ!Q6wI7EblC5RvP*@)j?}W=WxwCvF3*5Up_`3*a~z$`wHwCy)2risye=1mSp%p zu+tD6NAK3o@)4VBsM!@);qgsjgB$kkCZhaimHg&+k69~drbvRTacWKH;YCK(!rC?8 zP#cK5JPHSw;V;{Yji=55X~S+)%(8fuz}O>*F3)hR;STU`z6T1aM#Wd+FP(M5*@T1P z^06O;I20Sk!bxW<-O;E081KRdHZrtsGJflFRRFS zdi5w9OVDGSL3 zNrC7GVsGN=b;YH9jp8Z2$^!K@h=r-xV(aEH@#JicPy;A0k1>g1g^XeR`YV2HfmqXY zYbRwaxHvf}OlCAwHoVI&QBLr5R|THf?nAevV-=~V8;gCsX>jndvNOcFA+DI+zbh~# zZ7`qNk&w+_+Yp!}j;OYxIfx_{f0-ONc?mHCiCUak=>j>~>YR4#w# zuKz~UhT!L~GfW^CPqG8Lg)&Rc6y^{%3H7iLa%^l}cw_8UuG;8nn9)kbPGXS}p3!L_ zd#9~5CrH8xtUd?{d2y^PJg+z(xIfRU;`}^=OlehGN2=?}9yH$4Rag}*+AWotyxfCJ zHx=r7ZH>j2kV?%7WTtp+-HMa0)_*DBBmC{sd$)np&GEJ__kEd`xB5a2A z*J+yx>4o#ZxwA{;NjhU*1KT~=ZK~GAA;KZHDyBNTaWQ1+;tOFFthnD)DrCn`DjBZ% zk$N5B4^$`n^jNSOr=t(zi8TN4fpaccsb`zOPD~iY=UEK$0Y70bG{idLx@IL)7^(pL z{??Bnu=lDeguDrd%qW1)H)H`9otsOL-f4bSu};o9OXybo6J!Lek`a4ff>*O)BDT_g z<6@SrI|C9klY(>_PfA^qai7A_)VNE4c^ZjFcE$Isp>`e5fLc)rg@8Q_d^Uk24$2bn z9#}6kZ2ZxS9sI(RqT7?El2@B+($>eBQrNi_k#CDJ8D9}8$mmm z4oSKO^F$i+NG)-HE$O6s1--6EzJa?C{x=QgK&c=)b(Q9OVoAXYEEH20G|q$}Hue%~ zO3B^bF=t7t48sN zWh_zA`w~|){-!^g?6Mqf6ieV zFx~aPUOJGR=4{KsW7I?<=J2|lY`NTU=lt=%JE9H1vBpkcn=uq(q~=?iBt_-r(PLBM zP-0dxljJO>4Wq-;stY)CLB4q`-r*T$!K2o}?E-w_i>3_aEbA^MB7P5piwt1dI-6o!qWCy0 ztYy!x9arGTS?kabkkyv*yxvsPQ7Vx)twkS6z2T@kZ|kb8yjm+^$|sEBmvACeqbz)RmxkkDQX-A*K!YFziuhwb|ym>C$}U|J)4y z$(z#)GH%uV6{ec%Zy~AhK|+GtG8u@c884Nq%w`O^wv2#A(&xH@c5M`Vjk*SR_tJnq z0trB#aY)!EKW_}{#L3lph5ow=@|D5LzJYUFD6 z7XnUeo_V0DVSIKMFD_T0AqAO|#VFDc7c?c-Q%#u00F%!_TW1@JVnsfvm@_9HKWflBOUD~)RL``-!P;(bCON_4eVdduMO>?IrQ__*zE@7(OX zUtfH@AX*53&xJW*Pu9zcqxGiM>xol0I~QL5B%Toog3Jlenc^WbVgeBvV8C8AX^Vj& z^I}H})B=VboO%q1;aU5ACMh{yK4J;xlMc`jCnZR^!~LDs_MP&8;dd@4LDWw~*>#OT zeZHwdQWS!tt5MJQI~cw|Ka^b4c|qyd_ly(+Ql2m&AAw^ zQeSXDOOH!!mAgzAp0z)DD>6Xo``b6QwzUV@w%h}Yo>)a|xRi$jGuHQhJVA%>)PUvK zBQ!l0hq<3VZ*RnrDODP)>&iS^wf64C;MGqDvx>|p;35%6(u+IHoNbK z;Gb;TneFo*`zUKS6kwF*&b!U8e5m4YAo03a_e^!5BP42+r)LFhEy?_7U1IR<; z^0v|DhCYMSj<-;MtY%R@Fg;9Kky^pz_t2nJfKWfh5Eu@_l{^ph%1z{jkg5jQrkvD< z#vdK!nku*RrH~TdN~`wDs;d>XY1PH?O<4^U4lmA|wUW{Crrv#r%N>7k#{Gc44Fr|t z@UZP}Y-TrAmnEZ39A*@6;ccsR>)$A)S>$-Cj!=x$rz7IvjHIPM(TB+JFf{ehuIvY$ zsDAwREg*%|=>Hw$`us~RP&3{QJg%}RjJKS^mC_!U;E5u>`X`jW$}P`Mf}?7G7FX#{ zE(9u1SO;3q@ZhDL9O({-RD+SqqPX)`0l5IQu4q)49TUTkxR(czeT}4`WV~pV*KY&i zAl3~X%D2cPVD^B43*~&f%+Op)wl<&|D{;=SZwImydWL6@_RJjxP2g)s=dH)u9Npki zs~z9A+3fj0l?yu4N0^4aC5x)Osnm0qrhz@?nwG_`h(71P znbIewljU%T*cC=~NJy|)#hT+lx#^5MuDDnkaMb*Efw9eThXo|*WOQzJ*#3dmRWm@! zfuSc@#kY{Um^gBc^_Xdxnl!n&y&}R4yAbK&RMc+P^Ti;YIUh|C+K1|=Z^{nZ}}rxH*v{xR!i%qO~o zTr`WDE@k$M9o0r4YUFFeQO7xCu_Zgy)==;fCJ94M_rLAv&~NhfvcLWCoaGg2ao~3e zBG?Ms9B+efMkp}7BhmISGWmJsKI@a8b}4lLI48oWKY|8?zuuNc$lt5Npr+p7a#sWu zh!@2nnLBVJK!$S~>r2-pN||^w|fY`CT{TFnJy`B|e5;=+_v4l8O-fkN&UQbA4NKTyntd zqK{xEKh}U{NHoQUf!M=2(&w+eef77VtYr;xs%^cPfKLObyOV_9q<(%76-J%vR>w9!us-0c-~Y?_EVS%v!* z15s2s3eTs$Osz$JayyH|5nPAIPEX=U;r&p;K14G<1)bvn@?bM5kC{am|C5%hyxv}a z(DeSKI5ZfZ1*%dl8frIX2?);R^^~LuDOpNpk-2R8U1w92HmG1m&|j&J{EK=|p$;f9 z7Rs5|jr4r8k5El&qcuM+YRlKny%t+1CgqEWO>3;BSRZi(LA3U%Jm{@{y+A+w(gzA< z7dBq6a1sEWa4cD0W7=Ld9z0H7RI^Z7vl(bfA;72j?SWCo`#5mVC$l1Q2--%V)-uN* z9ha*s-AdfbDZ8R8*fpwjzx=WvOtmSzGFjC#X)hD%Caeo^OWjS(3h|d9_*U)l%{Ab8 zfv$yoP{OuUl@$(-sEVNt{*=qi5P=lpxWVuz2?I7Dc%BRc+NGNw+323^ z5BXGfS71oP^%apUo(Y#xkxE)y?>BFzEBZ}UBbr~R4$%b7h3iZu3S(|A;&HqBR{nK& z$;GApNnz=kNO^FL&nYcfpB7Qg;hGJPsCW44CbkG1@l9pn0`~oKy5S777uH)l{irK!ru|X+;4&0D;VE*Ii|<3P zUx#xUqvZT5kVQxsF#~MwKnv7;1pR^0;PW@$@T7I?s`_rD1EGUdSA5Q(C<>5SzE!vw z;{L&kKFM-MO>hy#-8z`sdVx})^(Dc-dw;k-h*9O2_YZw}|9^y-|8RQ`BWJUJL(Cer zP5Z@fNc>pTXABbTRY-B5*MphpZv6#i802giwV&SkFCR zGMETyUm(KJbh+&$8X*RB#+{surjr;8^REEt`2&Dubw3$mx>|~B5IKZJ`s_6fw zKAZx9&PwBqW1Oz0r0A4GtnZd7XTKViX2%kPfv+^X3|_}RrQ2e3l=KG_VyY`H?I5&CS+lAX5HbA%TD9u6&s#v!G> zzW9n4J%d5ye7x0y`*{KZvqyXUfMEE^ZIffzI=Hh|3J}^yx7eL=s+TPH(Q2GT-sJ~3 zI463C{(ag7-hS1ETtU;_&+49ABt5!A7CwLwe z=SoA8mYZIQeU;9txI=zcQVbuO%q@E)JI+6Q!3lMc=Gbj(ASg-{V27u>z2e8n;Nc*pf}AqKz1D>p9G#QA+7mqqrEjGfw+85Uyh!=tTFTv3|O z+)-kFe_8FF_EkTw!YzwK^Hi^_dV5x-Ob*UWmD-})qKj9@aE8g240nUh=g|j28^?v7 zHRTBo{0KGaWBbyX2+lx$wgXW{3aUab6Bhm1G1{jTC7ota*JM6t+qy)c5<@ zpc&(jVdTJf(q3xB=JotgF$X>cxh7k*(T`-V~AR+`%e?YOeALQ2Qud( zz35YizXt(aW3qndR}fTw1p()Ol4t!D1pitGNL95{SX4ywzh0SF;=!wf=?Q?_h6!f* zh7<+GFi)q|XBsvXZ^qVCY$LUa{5?!CgwY?EG;*)0ceFe&=A;!~o`ae}Z+6me#^sv- z1F6=WNd6>M(~ z+092z>?Clrcp)lYNQl9jN-JF6n&Y0mp7|I0dpPx+4*RRK+VQI~>en0Dc;Zfl+x z_e_b7s`t1_A`RP3$H}y7F9_na%D7EM+**G_Z0l_nwE+&d_kc35n$Fxkd4r=ltRZhh zr9zER8>j(EdV&Jgh(+i}ltESBK62m0nGH6tCBr90!4)-`HeBmz54p~QP#dsu%nb~W z7sS|(Iydi>C@6ZM(Us!jyIiszMkd)^u<1D+R@~O>HqZIW&kearPWmT>63%_t2B{_G zX{&a(gOYJx!Hq=!T$RZ&<8LDnxsmx9+TBL0gTk$|vz9O5GkK_Yx+55^R=2g!K}NJ3 zW?C;XQCHZl7H`K5^BF!Q5X2^Mj93&0l_O3Ea3!Ave|ixx+~bS@Iv18v2ctpSt4zO{ zp#7pj!AtDmti$T`e9{s^jf(ku&E|83JIJO5Qo9weT6g?@vX!{7)cNwymo1+u(YQ94 zopuz-L@|5=h8A!(g-MXgLJC0MA|CgQF8qlonnu#j z;uCeq9ny9QSD|p)9sp3ebgY3rk#y0DA(SHdh$DUm^?GI<>%e1?&}w(b zdip1;P2Z=1wM+$q=TgLP$}svd!vk+BZ@h<^4R=GS2+sri7Z*2f`9 z5_?i)xj?m#pSVchk-SR!2&uNhzEi+#5t1Z$o0PoLGz*pT64%+|Wa+rd5Z}60(j?X= z{NLjtgRb|W?CUADqOS@(*MA-l|E342NxRaxLTDqsOyfWWe%N(jjBh}G zm7WPel6jXijaTiNita+z(5GCO0NM=Melxud57PP^d_U## zbA;9iVi<@wr0DGB8=T9Ab#2K_#zi=$igyK48@;V|W`fg~7;+!q8)aCOo{HA@vpSy-4`^!ze6-~8|QE||hC{ICKllG9fbg_Y7v z$jn{00!ob3!@~-Z%!rSZ0JO#@>|3k10mLK0JRKP-Cc8UYFu>z93=Ab-r^oL2 zl`-&VBh#=-?{l1TatC;VweM^=M7-DUE>m+xO7Xi6vTEsReyLs8KJ+2GZ&rxw$d4IT zPXy6pu^4#e;;ZTsgmG+ZPx>piodegkx2n0}SM77+Y*j^~ICvp#2wj^BuqRY*&cjmL zcKp78aZt>e{3YBb4!J_2|K~A`lN=u&5j!byw`1itV(+Q_?RvV7&Z5XS1HF)L2v6ji z&kOEPmv+k_lSXb{$)of~(BkO^py&7oOzpjdG>vI1kcm_oPFHy38%D4&A4h_CSo#lX z2#oqMCTEP7UvUR3mwkPxbl8AMW(e{ARi@HCYLPSHE^L<1I}OgZD{I#YH#GKnpRmW3 z2jkz~Sa(D)f?V?$gNi?6)Y;Sm{&?~2p=0&BUl_(@hYeX8YjaRO=IqO7neK0RsSNdYjD zaw$g2sG(>JR=8Iz1SK4`*kqd_3-?;_BIcaaMd^}<@MYbYisWZm2C2|Np_l|8r9yM|JkUngSo@?wci(7&O9a z%|V(4C1c9pps0xxzPbXH=}QTxc2rr7fXk$9`a6TbWKPCz&p=VsB8^W96W=BsB|7bc zf(QR8&Ktj*iz)wK&mW`#V%4XTM&jWNnDF56O+2bo<3|NyUhQ%#OZE8$Uv2a@J>D%t zMVMiHh?es!Ex19q&6eC&L=XDU_BA&uR^^w>fpz2_`U87q_?N2y;!Z!bjoeKrzfC)} z?m^PM=(z{%n9K`p|7Bz$LuC7!>tFOuN74MFELm}OD9?%jpT>38J;=1Y-VWtZAscaI z_8jUZ#GwWz{JqvGEUmL?G#l5E=*m>`cY?m*XOc*yOCNtpuIGD+Z|kn4Xww=BLrNYS zGO=wQh}Gtr|7DGXLF%|`G>J~l{k^*{;S-Zhq|&HO7rC_r;o`gTB7)uMZ|WWIn@e0( zX$MccUMv3ABg^$%_lNrgU{EVi8O^UyGHPNRt%R!1#MQJn41aD|_93NsBQhP80yP<9 zG4(&0u7AtJJXLPcqzjv`S~5;Q|5TVGccN=Uzm}K{v)?f7W!230C<``9(64}D2raRU zAW5bp%}VEo{4Rko`bD%Ehf=0voW?-4Mk#d3_pXTF!-TyIt6U+({6OXWVAa;s-`Ta5 zTqx&8msH3+DLrVmQOTBOAj=uoxKYT3DS1^zBXM?1W+7gI!aQNPYfUl{3;PzS9*F7g zWJN8x?KjBDx^V&6iCY8o_gslO16=kh(|Gp)kz8qlQ`dzxQv;)V&t+B}wwdi~uBs4? zu~G|}y!`3;8#vIMUdyC7YEx6bb^1o}G!Jky4cN?BV9ejBfN<&!4M)L&lRKiuMS#3} z_B}Nkv+zzxhy{dYCW$oGC&J(Ty&7%=5B$sD0bkuPmj7g>|962`(Q{ZZMDv%YMuT^KweiRDvYTEop3IgFv#)(w>1 zSzH>J`q!LK)c(AK>&Ib)A{g`Fdykxqd`Yq@yB}E{gnQV$K!}RsgMGWqC3DKE(=!{}ekB3+(1?g}xF>^icEJbc z5bdxAPkW90atZT+&*7qoLqL#p=>t-(-lsnl2XMpZcYeW|o|a322&)yO_8p(&Sw{|b zn(tY$xn5yS$DD)UYS%sP?c|z>1dp!QUD)l;aW#`%qMtQJjE!s2z`+bTSZmLK7SvCR z=@I4|U^sCwZLQSfd*ACw9B@`1c1|&i^W_OD(570SDLK`MD0wTiR8|$7+%{cF&){$G zU~|$^Ed?TIxyw{1$e|D$050n8AjJvvOWhLtLHbSB|HIfjMp+gu>DraHZJRrdO53(= z+o-f{+qNog+qSLB%KY;5>Av6X(>-qYk3IIEwZ5~6a+P9lMpC^ z8CJ0q>rEpjlsxCvJm=kms@tlN4+sv}He`xkr`S}bGih4t`+#VEIt{1veE z{ZLtb_pSbcfcYPf4=T1+|BtR!x5|X#x2TZEEkUB6kslKAE;x)*0x~ES0kl4Dex4e- zT2P~|lT^vUnMp{7e4OExfxak0EE$Hcw;D$ehTV4a6hqxru0$|Mo``>*a5=1Ym0u>BDJKO|=TEWJ5jZu!W}t$Kv{1!q`4Sn7 zrxRQOt>^6}Iz@%gA3&=5r;Lp=N@WKW;>O!eGIj#J;&>+3va^~GXRHCY2}*g#9ULab zitCJt-OV0*D_Q3Q`p1_+GbPxRtV_T`jyATjax<;zZ?;S+VD}a(aN7j?4<~>BkHK7bO8_Vqfdq1#W&p~2H z&w-gJB4?;Q&pG9%8P(oOGZ#`!m>qAeE)SeL*t8KL|1oe;#+uOK6w&PqSDhw^9-&Fa zuEzbi!!7|YhlWhqmiUm!muO(F8-F7|r#5lU8d0+=;<`{$mS=AnAo4Zb^{%p}*gZL! zeE!#-zg0FWsSnablw!9$<&K(#z!XOW z;*BVx2_+H#`1b@>RtY@=KqD)63brP+`Cm$L1@ArAddNS1oP8UE$p05R=bvZoYz+^6 z<)!v7pRvi!u_-V?!d}XWQR1~0q(H3{d^4JGa=W#^Z<@TvI6J*lk!A zZ*UIKj*hyO#5akL*Bx6iPKvR3_2-^2mw|Rh-3O_SGN3V9GRo52Q;JnW{iTGqb9W99 z7_+F(Op6>~3P-?Q8LTZ-lwB}xh*@J2Ni5HhUI3`ct|*W#pqb>8i*TXOLn~GlYECIj zhLaa_rBH|1jgi(S%~31Xm{NB!30*mcsF_wgOY2N0XjG_`kFB+uQuJbBm3bIM$qhUyE&$_u$gb zpK_r{99svp3N3p4yHHS=#csK@j9ql*>j0X=+cD2dj<^Wiu@i>c_v zK|ovi7}@4sVB#bzq$n3`EgI?~xDmkCW=2&^tD5RuaSNHf@Y!5C(Is$hd6cuyoK|;d zO}w2AqJPS`Zq+(mc*^%6qe>1d&(n&~()6-ZATASNPsJ|XnxelLkz8r1x@c2XS)R*H(_B=IN>JeQUR;T=i3<^~;$<+8W*eRKWGt7c#>N`@;#!`kZ!P!&{9J1>_g8Zj zXEXxmA=^{8A|3=Au+LfxIWra)4p<}1LYd_$1KI0r3o~s1N(x#QYgvL4#2{z8`=mXy zQD#iJ0itk1d@Iy*DtXw)Wz!H@G2St?QZFz zVPkM%H8Cd2EZS?teQN*Ecnu|PrC!a7F_XX}AzfZl3fXfhBtc2-)zaC2eKx*{XdM~QUo4IwcGgVdW69 z1UrSAqqMALf^2|(I}hgo38l|Ur=-SC*^Bo5ej`hb;C$@3%NFxx5{cxXUMnTyaX{>~ zjL~xm;*`d08bG_K3-E+TI>#oqIN2=An(C6aJ*MrKlxj?-;G zICL$hi>`F%{xd%V{$NhisHSL~R>f!F7AWR&7b~TgLu6!3s#~8|VKIX)KtqTH5aZ8j zY?wY)XH~1_a3&>#j7N}0az+HZ;is;Zw(Am{MX}YhDTe(t{ZZ;TG}2qWYO+hdX}vp9 z@uIRR8g#y~-^E`Qyem(31{H0&V?GLdq9LEOb2(ea#e-$_`5Q{T%E?W(6 z(XbX*Ck%TQM;9V2LL}*Tf`yzai{0@pYMwBu%(I@wTY!;kMrzcfq0w?X`+y@0ah510 zQX5SU(I!*Fag4U6a7Lw%LL;L*PQ}2v2WwYF(lHx_Uz2ceI$mnZ7*eZ?RFO8UvKI0H z9Pq-mB`mEqn6n_W9(s~Jt_D~j!Ln9HA)P;owD-l~9FYszs)oEKShF9Zzcmnb8kZ7% zQ`>}ki1kwUO3j~ zEmh140sOkA9v>j@#56ymn_RnSF`p@9cO1XkQy6_Kog?0ivZDb`QWOX@tjMd@^Qr(p z!sFN=A)QZm!sTh(#q%O{Ovl{IxkF!&+A)w2@50=?a-+VuZt6On1;d4YtUDW{YNDN_ zG@_jZi1IlW8cck{uHg^g=H58lPQ^HwnybWy@@8iw%G! zwB9qVGt_?~M*nFAKd|{cGg+8`+w{j_^;nD>IrPf-S%YjBslSEDxgKH{5p)3LNr!lD z4ii)^%d&cCXIU7UK?^ZQwmD(RCd=?OxmY(Ko#+#CsTLT;p#A%{;t5YpHFWgl+@)N1 zZ5VDyB;+TN+g@u~{UrWrv)&#u~k$S&GeW)G{M#&Di)LdYk?{($Cq zZGMKeYW)aMtjmKgvF0Tg>Mmkf9IB#2tYmH-s%D_9y3{tfFmX1BSMtbe<(yqAyWX60 zzkgSgKb3c{QPG2MalYp`7mIrYg|Y<4Jk?XvJK)?|Ecr+)oNf}XLPuTZK%W>;<|r+% zTNViRI|{sf1v7CsWHvFrkQ$F7+FbqPQ#Bj7XX=#M(a~9^80}~l-DueX#;b}Ajn3VE z{BWI}$q{XcQ3g{(p>IOzFcAMDG0xL)H%wA)<(gl3I-oVhK~u_m=hAr&oeo|4lZbf} z+pe)c34Am<=z@5!2;_lwya;l?xV5&kWe}*5uBvckm(d|7R>&(iJNa6Y05SvlZcWBlE{{%2- z`86)Y5?H!**?{QbzGG~|k2O%eA8q=gxx-3}&Csf6<9BsiXC)T;x4YmbBIkNf;0Nd5 z%whM^!K+9zH>on_<&>Ws?^v-EyNE)}4g$Fk?Z#748e+GFp)QrQQETx@u6(1fk2!(W zWiCF~MomG*y4@Zk;h#2H8S@&@xwBIs|82R*^K(i*0MTE%Rz4rgO&$R zo9Neb;}_ulaCcdn3i17MO3NxzyJ=l;LU*N9ztBJ30j=+?6>N4{9YXg$m=^9@Cl9VY zbo^{yS@gU=)EpQ#;UIQBpf&zfCA;00H-ee=1+TRw@(h%W=)7WYSb5a%$UqNS@oI@= zDrq|+Y9e&SmZrH^iA>Of8(9~Cf-G(P^5Xb%dDgMMIl8gk6zdyh`D3OGNVV4P9X|EvIhplXDld8d z^YWtYUz@tpg*38Xys2?zj$F8%ivA47cGSl;hjD23#*62w3+fwxNE7M7zVK?x_`dBSgPK zWY_~wF~OEZi9|~CSH8}Xi>#8G73!QLCAh58W+KMJJC81{60?&~BM_0t-u|VsPBxn* zW7viEKwBBTsn_A{g@1!wnJ8@&h&d>!qAe+j_$$Vk;OJq`hrjzEE8Wjtm)Z>h=*M25 zOgETOM9-8xuuZ&^@rLObtcz>%iWe%!uGV09nUZ*nxJAY%&KAYGY}U1WChFik7HIw% zZP$3Bx|TG_`~19XV7kfi2GaBEhKap&)Q<9`aPs#^!kMjtPb|+-fX66z3^E)iwyXK7 z8)_p<)O{|i&!qxtgBvWXx8*69WO$5zACl++1qa;)0zlXf`eKWl!0zV&I`8?sG)OD2Vy?reNN<{eK+_ za4M;Hh%&IszR%)&gpgRCP}yheQ+l#AS-GnY81M!kzhWxIR?PW`G3G?} z$d%J28uQIuK@QxzGMKU_;r8P0+oIjM+k)&lZ39i#(ntY)*B$fdJnQ3Hw3Lsi8z&V+ zZly2}(Uzpt2aOubRjttzqrvinBFH4jrN)f0hy)tj4__UTwN)#1fj3-&dC_Vh7}ri* zfJ=oqLMJ-_<#rwVyN}_a-rFBe2>U;;1(7UKH!$L??zTbbzP#bvyg7OQBGQklJ~DgP zd<1?RJ<}8lWwSL)`jM53iG+}y2`_yUvC!JkMpbZyb&50V3sR~u+lok zT0uFRS-yx@8q4fPRZ%KIpLp8R#;2%c&Ra4p(GWRT4)qLaPNxa&?8!LRVdOUZ)2vrh zBSx&kB%#Y4!+>~)<&c>D$O}!$o{<1AB$M7-^`h!eW;c(3J~ztoOgy6Ek8Pwu5Y`Xion zFl9fb!k2`3uHPAbd(D^IZmwR5d8D$495nN2`Ue&`W;M-nlb8T-OVKt|fHk zBpjX$a(IR6*-swdNk@#}G?k6F-~c{AE0EWoZ?H|ZpkBxqU<0NUtvubJtwJ1mHV%9v?GdDw; zAyXZiD}f0Zdt-cl9(P1la+vQ$Er0~v}gYJVwQazv zH#+Z%2CIfOf90fNMGos|{zf&N`c0@x0N`tkFv|_9af3~<0z@mnf*e;%r*Fbuwl-IW z{}B3=(mJ#iwLIPiUP`J3SoP~#)6v;aRXJ)A-pD2?_2_CZ#}SAZ<#v7&Vk6{*i(~|5 z9v^nC`T6o`CN*n%&9+bopj^r|E(|pul;|q6m7Tx+U|UMjWK8o-lBSgc3ZF=rP{|l9 zc&R$4+-UG6i}c==!;I#8aDIbAvgLuB66CQLRoTMu~jdw`fPlKy@AKYWS-xyZzPg&JRAa@m-H43*+ne!8B7)HkQY4 zIh}NL4Q79a-`x;I_^>s$Z4J4-Ngq=XNWQ>yAUCoe&SMAYowP>r_O}S=V+3=3&(O=h zNJDYNs*R3Y{WLmBHc?mFEeA4`0Y`_CN%?8qbDvG2m}kMAiqCv`_BK z_6a@n`$#w6Csr@e2YsMx8udNWtNt=kcqDZdWZ-lGA$?1PA*f4?X*)hjn{sSo8!bHz zb&lGdAgBx@iTNPK#T_wy`KvOIZvTWqSHb=gWUCKXAiB5ckQI`1KkPx{{%1R*F2)Oc z(9p@yG{fRSWE*M9cdbrO^)8vQ2U`H6M>V$gK*rz!&f%@3t*d-r3mSW>D;wYxOhUul zk~~&ip5B$mZ~-F1orsq<|1bc3Zpw6)Ws5;4)HilsN;1tx;N6)tuePw& z==OlmaN*ybM&-V`yt|;vDz(_+UZ0m&&9#{9O|?0I|4j1YCMW;fXm}YT$0%EZ5^YEI z4i9WV*JBmEU{qz5O{#bs`R1wU%W$qKx?bC|e-iS&d*Qm7S=l~bMT{~m3iZl+PIXq{ zn-c~|l)*|NWLM%ysfTV-oR0AJ3O>=uB-vpld{V|cWFhI~sx>ciV9sPkC*3i0Gg_9G!=4ar*-W?D9)?EFL1=;O+W8}WGdp8TT!Fgv z{HKD`W>t(`Cds_qliEzuE!r{ihwEv1l5o~iqlgjAyGBi)$%zNvl~fSlg@M=C{TE;V zQkH`zS8b&!ut(m)%4n2E6MB>p*4(oV>+PT51#I{OXs9j1vo>9I<4CL1kv1aurV*AFZ^w_qfVL*G2rG@D2 zrs87oV3#mf8^E5hd_b$IXfH6vHe&lm@7On~Nkcq~YtE!}ad~?5*?X*>y`o;6Q9lkk zmf%TYonZM`{vJg$`lt@MXsg%*&zZZ0uUSse8o=!=bfr&DV)9Y6$c!2$NHyYAQf*Rs zk{^?gl9E z5Im8wlAsvQ6C2?DyG@95gUXZ3?pPijug25g;#(esF_~3uCj3~94}b*L>N2GSk%Qst z=w|Z>UX$m!ZOd(xV*2xvWjN&c5BVEdVZ0wvmk)I+YxnyK%l~caR=7uNQ=+cnNTLZ@&M!I$Mj-r{!P=; z`C2)D=VmvK8@T5S9JZoRtN!S*D_oqOxyy!q6Zk|~4aT|*iRN)fL)c>-yycR>-is0X zKrko-iZw(f(!}dEa?hef5yl%p0-v-8#8CX8!W#n2KNyT--^3hq6r&`)5Y@>}e^4h- zlPiDT^zt}Ynk&x@F8R&=)k8j$=N{w9qUcIc&)Qo9u4Y(Ae@9tA`3oglxjj6c{^pN( zQH+Uds2=9WKjH#KBIwrQI%bbs`mP=7V>rs$KG4|}>dxl_k!}3ZSKeEen4Iswt96GGw`E6^5Ov)VyyY}@itlj&sao|>Sb5 zeY+#1EK(}iaYI~EaHQkh7Uh>DnzcfIKv8ygx1Dv`8N8a6m+AcTa-f;17RiEed>?RT zk=dAksmFYPMV1vIS(Qc6tUO+`1jRZ}tcDP? zt)=7B?yK2RcAd1+Y!$K5*ds=SD;EEqCMG6+OqPoj{&8Y5IqP(&@zq@=A7+X|JBRi4 zMv!czlMPz)gt-St2VZwDD=w_S>gRpc-g zUd*J3>bXeZ?Psjohe;z7k|d<*T21PA1i)AOi8iMRwTBSCd0ses{)Q`9o&p9rsKeLaiY zluBw{1r_IFKR76YCAfl&_S1*(yFW8HM^T()&p#6y%{(j7Qu56^ZJx1LnN`-RTwimdnuo*M8N1ISl+$C-%=HLG-s} zc99>IXRG#FEWqSV9@GFW$V8!{>=lSO%v@X*pz*7()xb>=yz{E$3VE;e)_Ok@A*~El zV$sYm=}uNlUxV~6e<6LtYli1!^X!Ii$L~j4e{sI$tq_A(OkGquC$+>Rw3NFObV2Z)3Rt~Jr{oYGnZaFZ^g5TDZlg;gaeIP} z!7;T{(9h7mv{s@piF{-35L=Ea%kOp;^j|b5ZC#xvD^^n#vPH=)lopYz1n?Kt;vZmJ z!FP>Gs7=W{sva+aO9S}jh0vBs+|(B6Jf7t4F^jO3su;M13I{2rd8PJjQe1JyBUJ5v zcT%>D?8^Kp-70bP8*rulxlm)SySQhG$Pz*bo@mb5bvpLAEp${?r^2!Wl*6d7+0Hs_ zGPaC~w0E!bf1qFLDM@}zso7i~(``)H)zRgcExT_2#!YOPtBVN5Hf5~Ll3f~rWZ(UsJtM?O*cA1_W0)&qz%{bDoA}{$S&-r;0iIkIjbY~ zaAqH45I&ALpP=9Vof4OapFB`+_PLDd-0hMqCQq08>6G+C;9R~}Ug_nm?hhdkK$xpI zgXl24{4jq(!gPr2bGtq+hyd3%Fg%nofK`psHMs}EFh@}sdWCd!5NMs)eZg`ZlS#O0 zru6b8#NClS(25tXqnl{|Ax@RvzEG!+esNW-VRxba(f`}hGoqci$U(g30i}2w9`&z= zb8XjQLGN!REzGx)mg~RSBaU{KCPvQx8)|TNf|Oi8KWgv{7^tu}pZq|BS&S<53fC2K4Fw6>M^s$R$}LD*sUxdy6Pf5YKDbVet;P!bw5Al-8I1Nr(`SAubX5^D9hk6$agWpF}T#Bdf{b9-F#2WVO*5N zp+5uGgADy7m!hAcFz{-sS0kM7O)qq*rC!>W@St~^OW@R1wr{ajyYZq5H!T?P0e+)a zaQ%IL@X_`hzp~vRH0yUblo`#g`LMC%9}P;TGt+I7qNcBSe&tLGL4zqZqB!Bfl%SUa z6-J_XLrnm*WA`34&mF+&e1sPCP9=deazrM=Pc4Bn(nV;X%HG^4%Afv4CI~&l!Sjzb z{rHZ3od0!Al{}oBO>F*mOFAJrz>gX-vs!7>+_G%BB(ljWh$252j1h;9p~xVA=9_`P z5KoFiz96_QsTK%B&>MSXEYh`|U5PjX1(+4b#1PufXRJ*uZ*KWdth1<0 zsAmgjT%bowLyNDv7bTUGy|g~N34I-?lqxOUtFpTLSV6?o?<7-UFy*`-BEUsrdANh} zBWkDt2SAcGHRiqz)x!iVoB~&t?$yn6b#T=SP6Ou8lW=B>=>@ik93LaBL56ub`>Uo!>0@O8?e)$t(sgy$I z6tk3nS@yFFBC#aFf?!d_3;%>wHR;A3f2SP?Na8~$r5C1N(>-ME@HOpv4B|Ty7%jAv zR}GJwsiJZ5@H+D$^Cwj#0XA_(m^COZl8y7Vv(k=iav1=%QgBOVzeAiw zaDzzdrxzj%sE^c9_uM5D;$A_7)Ln}BvBx^=)fO+${ou%B*u$(IzVr-gH3=zL6La;G zu0Kzy5CLyNGoKRtK=G0-w|tnwI)puPDOakRzG(}R9fl7#<|oQEX;E#yCWVg95 z;NzWbyF&wGg_k+_4x4=z1GUcn6JrdX4nOVGaAQ8#^Ga>aFvajQN{!+9rgO-dHP zIp@%&ebVg}IqnRWwZRTNxLds+gz2@~VU(HI=?Epw>?yiEdZ>MjajqlO>2KDxA>)cj z2|k%dhh%d8SijIo1~20*5YT1eZTDkN2rc^zWr!2`5}f<2f%M_$to*3?Ok>e9$X>AV z2jYmfAd)s|(h?|B(XYrIfl=Wa_lBvk9R1KaP{90-z{xKi+&8=dI$W0+qzX|ZovWGOotP+vvYR(o=jo?k1=oG?%;pSqxcU* zWVGVMw?z__XQ9mnP!hziHC`ChGD{k#SqEn*ph6l46PZVkm>JF^Q{p&0=MKy_6apts z`}%_y+Tl_dSP(;Ja&sih$>qBH;bG;4;75)jUoVqw^}ee=ciV;0#t09AOhB^Py7`NC z-m+ybq1>_OO+V*Z>dhk}QFKA8V?9Mc4WSpzj{6IWfFpF7l^au#r7&^BK2Ac7vCkCn{m0uuN93Ee&rXfl1NBY4NnO9lFUp zY++C1I;_{#OH#TeP2Dp?l4KOF8ub?m6zE@XOB5Aiu$E~QNBM@;r+A5mF2W1-c7>ex zHiB=WJ&|`6wDq*+xv8UNLVUy4uW1OT>ey~Xgj@MMpS@wQbHAh>ysYvdl-1YH@&+Q! z075(Qd4C!V`9Q9jI4 zSt{HJRvZec>vaL_brKhQQwbpQd4_Lmmr0@1GdUeU-QcC{{8o=@nwwf>+dIKFVzPriGNX4VjHCa zTbL9w{Y2V87c2ofX%`(48A+4~mYTiFFl!e{3K^C_k%{&QTsgOd0*95KmWN)P}m zTRr{`f7@=v#+z_&fKYkQT!mJn{*crj%ZJz#(+c?>cD&2Lo~FFAWy&UG*Op^pV`BR^I|g?T>4l5;b|5OQ@t*?_Slp`*~Y3`&RfKD^1uLezIW(cE-Dq2z%I zBi8bWsz0857`6e!ahet}1>`9cYyIa{pe53Kl?8|Qg2RGrx@AlvG3HAL-^9c^1GW;)vQt8IK+ zM>!IW*~682A~MDlyCukldMd;8P|JCZ&oNL(;HZgJ>ie1PlaInK7C@Jg{3kMKYui?e!b`(&?t6PTb5UPrW-6DVU%^@^E`*y-Fd(p|`+JH&MzfEq;kikdse ziFOiDWH(D< zyV7Rxt^D0_N{v?O53N$a2gu%1pxbeK;&ua`ZkgSic~$+zvt~|1Yb=UfKJW2F7wC^evlPf(*El+#}ZBy0d4kbVJsK- z05>;>?HZO(YBF&v5tNv_WcI@O@LKFl*VO?L(!BAd!KbkVzo;v@~3v`-816GG?P zY+H3ujC>5=Am3RIZDdT#0G5A6xe`vGCNq88ZC1aVXafJkUlcYmHE^+Z{*S->ol%-O znm9R0TYTr2w*N8Vs#s-5=^w*{Y}qp5GG)Yt1oLNsH7y~N@>Eghms|K*Sdt_u!&I}$ z+GSdFTpbz%KH+?B%Ncy;C`uW6oWI46(tk>r|5|-K6)?O0d_neghUUOa9BXHP*>vi; z={&jIGMn-92HvInCMJcyXwHTJ42FZp&Wxu+9Rx;1x(EcIQwPUQ@YEQQ`bbMy4q3hP zNFoq~Qd0=|xS-R}k1Im3;8s{BnS!iaHIMLx)aITl)+)?Yt#fov|Eh>}dv@o6R{tG>uHsy&jGmWN5+*wAik|78(b?jtysPHC#e+Bzz~V zS3eEXv7!Qn4uWi!FS3B?afdD*{fr9>B~&tc671fi--V}~E4un;Q|PzZRwk-azprM$4AesvUb5`S`(5x#5VJ~4%ET6&%GR$}muHV-5lTsCi_R|6KM(g2PCD@|yOpKluT zakH!1V7nKN)?6JmC-zJoA#ciFux8!)ajiY%K#RtEg$gm1#oKUKX_Ms^%hvKWi|B=~ zLbl-L)-=`bfhl`>m!^sRR{}cP`Oim-{7}oz4p@>Y(FF5FUEOfMwO!ft6YytF`iZRq zfFr{!&0Efqa{1k|bZ4KLox;&V@ZW$997;+Ld8Yle91he{BfjRhjFTFv&^YuBr^&Pe zswA|Bn$vtifycN8Lxr`D7!Kygd7CuQyWqf}Q_PM}cX~S1$-6xUD%-jrSi24sBTFNz(Fy{QL2AmNbaVggWOhP;UY4D>S zqKr!UggZ9Pl9Nh_H;qI`-WoH{ceXj?m8y==MGY`AOJ7l0Uu z)>M%?dtaz2rjn1SW3k+p`1vs&lwb%msw8R!5nLS;upDSxViY98IIbxnh{}mRfEp=9 zbrPl>HEJeN7J=KnB6?dwEA6YMs~chHNG?pJsEj#&iUubdf3JJwu=C(t?JpE6xMyhA3e}SRhunDC zn-~83*9=mADUsk^sCc%&&G1q5T^HR9$P#2DejaG`Ui*z1hI#h7dwpIXg)C{8s< z%^#@uQRAg-$z&fmnYc$Duw63_Zopx|n{Bv*9Xau{a)2%?H<6D>kYY7_)e>OFT<6TT z0A}MQLgXbC2uf`;67`mhlcUhtXd)Kbc$PMm=|V}h;*_%vCw4L6r>3Vi)lE5`8hkSg zNGmW-BAOO)(W((6*e_tW&I>Nt9B$xynx|sj^ux~?q?J@F$L4;rnm_xy8E*JYwO-02u9_@@W0_2@?B@1J{y~Q39N3NX^t7#`=34Wh)X~sU&uZWgS1Z09%_k|EjA4w_QqPdY`oIdv$dJZ;(!k)#U8L+|y~gCzn+6WmFt#d{OUuKHqh1-uX_p*Af8pFYkYvKPKBxyid4KHc}H` z*KcyY;=@wzXYR{`d{6RYPhapShXIV?0cg_?ahZ7do)Ot#mxgXYJYx}<%E1pX;zqHd zf!c(onm{~#!O$2`VIXezECAHVd|`vyP)Uyt^-075X@NZDBaQt<>trA3nY-Dayki4S zZ^j6CCmx1r46`4G9794j-WC0&R9(G7kskS>=y${j-2;(BuIZTLDmAyWTG~`0)Bxqk zd{NkDe9ug|ms@0A>JVmB-IDuse9h?z9nw!U6tr7t-Lri5H`?TjpV~8(gZWFq4Vru4 z!86bDB;3lpV%{rZ`3gtmcRH1hjj!loI9jN>6stN6A*ujt!~s!2Q+U1(EFQEQb(h4E z6VKuRouEH`G6+8Qv2C)K@^;ldIuMVXdDDu}-!7FS8~k^&+}e9EXgx~)4V4~o6P^52 z)a|`J-fOirL^oK}tqD@pqBZi_;7N43%{IQ{v&G9^Y^1?SesL`;Z(dt!nn9Oj5Odde%opv&t zxJ><~b#m+^KV&b?R#)fRi;eyqAJ_0(nL*61yPkJGt;gZxSHY#t>ATnEl-E%q$E16% zZdQfvhm5B((y4E3Hk6cBdwGdDy?i5CqBlCVHZr-rI$B#>Tbi4}Gcvyg_~2=6O9D-8 zY2|tKrNzbVR$h57R?Pe+gUU_il}ZaWu|Az#QO@};=|(L-RVf0AIW zq#pO+RfM7tdV`9lI6g;{qABNId`fG%U9Va^ravVT^)CklDcx)YJKeJdGpM{W1v8jg z@&N+mR?BPB=K1}kNwXk_pj44sd>&^;d!Z~P>O78emE@Qp@&8PyB^^4^2f7e)gekMv z2aZNvP@;%i{+_~>jK7*2wQc6nseT^n6St9KG#1~Y@$~zR_=AcO2hF5lCoH|M&c{vR zSp(GRVVl=T*m~dIA;HvYm8HOdCkW&&4M~UDd^H)`p__!4k+6b)yG0Zcek8OLw$C^K z3-BbLiG_%qX|ZYpXJ$(c@aa7b4-*IQkDF}=gZSV`*ljP|5mWuHSCcf$5qqhZTv&P?I$z^>}qP(q!Aku2yA5vu38d8x*q{6-1`%PrE_r0-9Qo?a#7Zbz#iGI7K<(@k^|i4QJ1H z4jx?{rZbgV!me2VT72@nBjucoT zUM9;Y%TCoDop?Q5fEQ35bCYk7!;gH*;t9t-QHLXGmUF;|vm365#X)6b2Njsyf1h9JW#x$;@x5Nx2$K$Z-O3txa%;OEbOn6xBzd4n4v)Va=sj5 z%rb#j7{_??Tjb8(Hac<^&s^V{yO-BL*uSUk2;X4xt%NC8SjO-3?;Lzld{gM5A=9AV z)DBu-Z8rRvXXwSVDH|dL-3FODWhfe1C_iF``F05e{dl(MmS|W%k-j)!7(ARkV?6r~ zF=o42y+VapxdZn;GnzZfGu<6oG-gQ7j7Zvgo7Am@jYxC2FpS@I;Jb%EyaJDBQC(q% zKlZ}TVu!>;i3t~OAgl@QYy1X|T~D{HOyaS*Bh}A}S#a9MYS{XV{R-|niEB*W%GPW! zP^NU(L<}>Uab<;)#H)rYbnqt|dOK(-DCnY==%d~y(1*{D{Eo1cqIV8*iMfx&J*%yh zx=+WHjt0q2m*pLx8=--UqfM6ZWjkev>W-*}_*$Y(bikH`#-Gn#!6_ zIA&kxn;XYI;eN9yvqztK-a113A%97in5CL5Z&#VsQ4=fyf&3MeKu70)(x^z_uw*RG zo2Pv&+81u*DjMO6>Mrr7vKE2CONqR6C0(*;@4FBM;jPIiuTuhQ-0&C)JIzo_k>TaS zN_hB;_G=JJJvGGpB?uGgSeKaix~AkNtYky4P7GDTW6{rW{}V9K)Cn^vBYKe*OmP!; zohJs=l-0sv5&pL6-bowk~(swtdRBZQHh8)m^r2+qTtZ zt4m$B?OQYNyfBA0E)g28a*{)a=%%f-?{F;++-Xs#5|7kSHTD*E9@$V ztE%7zX4A(L`n)FY8Y4pOnKC|Pf)j$iR#yP;V0+|Hki+D;t4I4BjkfdYliK9Gf6RYw z;3px$Ud5aTd`yq$N7*WOs!{X91hZZ;AJ9iQOH%p;v$R%OQum_h#rq9*{ve(++|24z zh2P;{-Z?u#rOqd0)D^_Ponv(Y9KMB9#?}nJdUX&r_rxF0%3__#8~ZwsyrSPmtWY27 z-54ZquV2t_W!*+%uwC=h-&_q~&nQer0(FL74to%&t^byl^C?wTaZ-IS9OssaQFP)1 zAov0o{?IRAcCf+PjMWSdmP42gysh|c9Ma&Q^?_+>>+-yrC8WR;*XmJ;>r9v*>=W}tgWG;WIt{~L8`gk8DP{dSdG z4SDM7g5ahMHYHHk*|mh9{AKh-qW7X+GEQybJt9A@RV{gaHUAva+=lSroK^NUJYEiL z?X6l9ABpd)9zzA^;FdZ$QQs#uD@hdcaN^;Q=AXlbHv511Meye`p>P4Y2nblEDEeZo}-$@g&L98Aih6tgLz--${eKTxymIipy0xSYgZZ zq^yyS4yNPTtPj-sM?R8@9Q1gtXPqv{$lb5i|C1yymwnGdfYV3nA-;5!Wl zD0fayn!B^grdE?q^}ba{-LIv*Z}+hZm_F9c$$cW!bx2DgJD&6|bBIcL@=}kQA1^Eh zXTEznqk)!!IcTl>ey?V;X8k<+C^DRA{F?T*j0wV`fflrLBQq!l7cbkAUE*6}WabyF zgpb+|tv=aWg0i}9kBL8ZCObYqHEycr5tpc-$|vdvaBsu#lXD@u_e1iL z{h>xMRS0a7KvW?VttrJFpX^5DC4Bv4cp6gNG6#8)7r7IxXfSNSp6)_6tZ4l>(D+0I zPhU)N!sKywaBusHdVE!yo5$20JAU8V_XcW{QmO!p*~ns8{2~bhjydnmA&=r zX9NSM9QYogYMDZ~kS#Qx`mt>AmeR3p@K$`fbJ%LQ1c5lEOz<%BS<}2DL+$>MFcE%e zlxC)heZ7#i80u?32eOJI9oQRz0z;JW@7Th4q}YmQ-`Z?@y3ia^_)7f37QMwDw~<-@ zT)B6fftmK_6YS!?{uaj5lLxyR++u*ZY2Mphm5cd7PA5=%rd)95hJ9+aGSNfjy>Ylc zoI0nGIT3sKmwX8h=6CbvhVO+ehFIR155h8iRuXZx^cW>rq5K4z_dvM#hRER=WR@THs%WELI9uYK9HN44Em2$#@k)hD zicqRPKV#yB;UlcsTL_}zCMK0T;eXHfu`y2(dfwm(v)IBbh|#R>`2cot{m7}8_X&oD zr@94PkMCl%d3FsC4pil=#{3uv^+)pvxfwmPUr)T)T|GcZVD$wVj$mjkjDs`5cm8N! zXVq2CvL;gWGpPI4;9j;2&hS*o+LNp&C5Ac=OXx*W5y6Z^az)^?G0)!_iAfjH5wiSE zD(F}hQZB#tF5iEx@0sS+dP70DbZ*<=5X^)Pxo^8aKzOzuyc2rq=<0-k;Y_ID1>9^v z+)nc36}?>jen*1%OX3R*KRASj${u$gZ$27Hpcj=95kK^aLzxhW6jj_$w6}%#1*$5D zG1H_vYFrCSwrRqYw*9<}OYAOQT)u%9lC`$IjZV<4`9Sc;j{Qv_6+uHrYifK&On4V_7yMil!0Yv55z@dFyD{U@Sy>|vTX=P_( zRm<2xj*Z}B30VAu@0e+}at*y?wXTz|rPalwo?4ZZc>hS0Ky6~mi@kv#?xP2a;yt?5=(-CqvP_3&$KdjB7Ku;# z`GLE*jW1QJB5d&E?IJO?1+!Q8HQMGvv^RuFoi=mM4+^tOqvX%X&viB%Ko2o-v4~~J z267ui;gsW?J=qS=D*@*xJvAy3IOop5bEvfR4MZC>9Y4Z$rGI|EHNNZ7KX;Ix{xSvm z-)Cau-xuTm|7`4kUdXvd_d^E=po(76ELfq5OgxIt3aqDy#zBfIy-5<3gpn{Ce`-ha z<;6y@{Bgqw?c~h*&j{FozQCh=`Lv-5Iw!KdSt;%GDOq%=(V!dJ-}|}|0o5G2kJj6{ z`jCSPs$9Fe8O(+qALZiJ$WtR=<@GvsdM)IJ`7XrBfW0iyYE#Vy^e@zbysg*B5Z_kSL6<)vqoaH zQ{!9!*{e9UZo^h+qZ`T@LfVwAEwc&+9{C8c%oj41q#hyn<&zA9IIur~V|{mmu`n5W z8)-Ou$YgjQ*PMIqHhZ_9E?(uoK0XM5aQkarcp}WT^7b^FC#^i>#8LGZ9puDuXUYas z7caX)V5U6uY-L5Wl%)j$qRkR;7@3T*N64YK_!`Fw=>CAwe~2loI1<>DZW&sb7Q)X;6E08&$h! z2=c1i4UOO{R4TmkTz+o9n`}+%d%blR6P;5{`qjtxlN$~I%tMMDCY`~e{+mRF!rj5( z3ywv)P_PUUqREu)TioPkg&5RKjY6z%pRxQPQ{#GNMTPag^S8(8l{!{WGNs2U1JA-O zq02VeYcArhTAS;v3);k(&6ayCH8SXN@r;1NQeJ*y^NHM+zOd;?t&c!Hq^SR_w6twGV8dl>j zjS+Zc&Yp7cYj&c1y3IxQ%*kWiYypvoh(k8g`HrY<_Bi-r%m-@SLfy-6mobxkWHxyS z>TtM2M4;Uqqy|+8Q++VcEq$PwomV1D4UzNA*Tgkg9#Gpz#~&iPf|Czx!J?qss?e|3 z4gTua75-P{2X7w9eeK3~GE0ip-D;%%gTi)8bR~Ez@)$gpuS~jZs`CrO5SR-Xy7bkA z89fr~mY}u4A$|r1$fe-;T{yJh#9Ime1iRu8eo?uY9@yqAU3P!rx~SsP;LTBL zeoMK(!;(Zt8313 z3)V)q_%eflKW?BnMZa}6E0c7t!$-mC$qt44OME5F(6B$E8w*TUN-h}0dOiXI+TH zYFrr&k1(yO(|J0vP|{22@Z}bxm@7BkjO)f)&^fv|?_JX+s)1*|7X7HH(W?b3QZ3!V|~m?8}uJsF>NvE4@fik zjyyh+U*tt`g6v>k9ub88a;ySvS1QawGn7}aaR**$rJA=a#eUT~ngUbJ%V=qsFIekLbv!YkqjTG{_$F;$w19$(ivIs*1>?2ka%uMOx@B9`LD zhm~)z@u4x*zcM1WhiX)!U{qOjJHt1xs{G1S?rYe)L)ntUu^-(o_dfqZu)}W(X%Uu| zN*qI@&R2fB#Jh|Mi+eMrZDtbNvYD3|v0Kx>E#Ss;Be*T$@DC!2A|mb%d}TTN3J+c= zu@1gTOXFYy972S+=C;#~)Z{Swr0VI5&}WYzH22un_Yg5o%f9fvV(`6!{C<(ZigQ2`wso)cj z9O12k)15^Wuv#rHpe*k5#4vb%c znP+Gjr<-p%01d<+^yrSoG?}F=eI8X;?=Fo2a~HUiJ>L!oE#9tXRp!adg-b9D;(6$E zeW0tH$US04zTX$OxM&X+2ip>KdFM?iG_fgOD-qB|uFng8*#Z5jgqGY=zLU?4!OlO#~YBTB9b9#~H@nqQ#5 z6bV));d?IJTVBC+79>rGuy1JgxPLy$dA7;_^^L)02m}XLjFR*qH`eI~+eJo(7D`LH z(W%lGnGK+Vk_3kyF*zpgO=1MxMg?hxe3}}YI>dVs8l}5eWjYu4=w6MWK09+05 zGdpa#$awd>Q|@aZa*z{5F3xy3n@E4YT9%TmMo0jxW59p0bI?&S}M+ z&^NG%rf7h*m9~p#b19|`wO5OMY-=^XT+=yrfGNpl<&~~FGsx_`IaFn+sEgF$hgOa~oAVAiu^a$jHcqkE=dj`ze z=axsfrzzh6VGD0x#6Ff=t%+VTiq!n6^gv*uIUD<9fOhvR;al5kcY${uunn}-!74<7 zmP^3cl-kyN(QY!!Z-^PY-OUkh=3ZWk6>le$_Q&xk4cgH{?i)C%2RM@pX5Q{jdSlo! zVau5v44cQX5|zQlQDt;dCg)oM0B<=P1CR!W%!^m$!{pKx;bn9DePJjWBX)q!`$;0K zqJIIyD#aK;#-3&Nf=&IhtbV|?ZGYHSphp~6th`p2rkw&((%kBV7<{siEOU7AxJj+FuRdDu$ zcmTW8usU_u!r)#jg|J=Gt{##7;uf4A5cdt6Y02}f(d2)z~ z)CH~gVAOwBLk$ZiIOn}NzDjvfw(w$u|BdCBI#)3xB-Ot?nz?iR38ayCm48M=_#9r7 zw8%pwQ<9mbEs5~_>pN3~#+Er~Q86J+2TDXM6umCbukd-X6pRIr5tF?VauT8jW> zY^#)log>jtJs2s3xoiPB7~8#1ZMv>Zx0}H58k-@H2huNyw~wsl0B8j)H5)H9c7y&i zp8^0;rKbxC1eEZ-#Qxvz)Xv$((8lK9I>BspPajluysw^f#t9P;OUis43mmEzX+lk* zc4T-Ms9_687GR+~QS#0~vxK#DSGN=a-m(@eZTqw2<+lN9>R~gK2)3;sT4%nI%Y|0m zX9SPR!>?~s=j5H4WMqeTW8QaLZ=1bWS5I3xZ&$(ypc=tHrv+hX@s)VG(tc!yvLM7n zshN=C#v={X1r;)xn0Pow_1eMhkn!{;x$BJ#PIz)m585&%cmzk;btQzZAN_^zis;n? z?6I~bN?s;7vg_dtoTc4A5Ow*Rb}No#UYl)sN|RmoYo}k^cKLXd8F`44?RrokkPvN5 ztUrx;U~B;jbE_qGd3n0j2i}A{enJvJ?gSF~NQj~EP5vM-w4@;QQ5n(Npic}XNW6B0 zq9F4T%6kp7qGhd0vpQcz+nMk8GOAmbz8Bt4@GtewGr6_>Xj>ge)SyfY}nu>Y!a@HoIx(StD zx`!>RT&}tpBL%nOF%7XIFW?n1AP*xthCMzhrU6G!U6?m4!CPWTvn#Yaoi_95CT2!L z|B=5zeRW30&ANGN>J9#GtCm&3SF6n4TqDz<-{@ZXkrkRDCpV$DwCtI^e&3i1A{Ar&JZtS^c+lyPa6 z%JJr42S_;eFC#M~bdtQePhOU32WDiZ4@H&af)z#$Y|hnQNb)8(3?1Ad>5uaZ1z zU~!jt3XUI@gpWb8tWTyH7DGvKvzYfqNIy3P{9vpwz_C-QL&`+8Io$F5PS-@YQJoEO z17D9P(+sXajWSH_8&C?fn>rTLX+(?KiwX#JNV)xE0!Q@>Tid$V2#r4y6fkph?YZ>^ z(o^q(0*P->3?I0cELXJn(N|#qTm6 zAPIL~n)m!50;*?5=MOOc4Wk;w(0c$(!e?vpV23S|n|Y7?nyc8)fD8t-KI&nTklH&BzqQ}D(1gH3P+5zGUzIjT~x`;e8JH=86&5&l-DP% z)F+Et(h|GJ?rMy-Zrf>Rv@<3^OrCJ1xv_N*_@-K5=)-jP(}h1Rts44H&ou8!G_C1E zhTfUDASJ2vu!4@j58{NN;78i?6__xR75QEDC4JN{>RmgcNrn-EOpEOcyR<8FS@RB@ zH!R7J=`KK^u06eeI|X@}KvQmdKE3AmAy8 zM4IIvde#e4O(iwag`UL5yQo>6&7^=D4yE-Eo9$9R2hR} zn;Z9i-d=R-xZl4@?s%8|m1M`$J6lW1r0Y)+8q$}Vn4qyR1jqTjGH;@Z!2KiGun2~x zaiEfzVT<|_b6t}~XPeflAm8hvCHP3Bp*tl{^y_e{Jsn@w+KP{7}bH_s=1S2E1sj=18a39*Ag~lbkT^_OQuYQey=b zW^{0xlQ@O$^cSxUZ8l(Mspg8z0cL*?yH4;X2}TdN)uN31A%$3$a=4;{S@h#Y(~i%) zc=K7Ggl=&2hYVic*W65gpSPE70pU;FN@3k?BYdNDKv6wlsBAF^);qiqI zhklsX4TaWiC%VbnZ|yqL+Pcc;(#&E*{+Rx&<&R{uTYCn^OD|mAk4%Q7gbbgMnZwE{ zy7QMK%jIjU@ye?0; z;0--&xVeD}m_hq9A8a}c9WkI2YKj8t!Mkk!o%AQ?|CCBL9}n570}OmZ(w)YI6#QS&p<={tcek*D{CPR%eVA1WBGUXf z%gO2vL7iVDr1$!LAW)1@H>GoIl=&yyZ7=*9;wrOYQ}O}u>h}4FWL?N2ivURlUi11- zl{G0fo`9?$iAEN<4kxa#9e0SZPqa{pw?K=tdN5tRc7HDX-~Ta6_+#s9W&d`6PB7dF*G@|!Mc}i zc=9&T+edI(@la}QU2An#wlkJ&7RmTEMhyC_A8hWM54?s1WldCFuBmT5*I3K9=1aj= z6V@93P-lUou`xmB!ATp0(We$?)p*oQs;(Kku15~q9`-LSl{(Efm&@%(zj?aK2;5}P z{6<@-3^k^5FCDT@Z%XABEcuPoumYkiD&)-8z2Q}HO9OVEU3WM;V^$5r4q>h^m73XF z5!hZ7SCjfxDcXyj(({vg8FU(m2_}36L_yR>fnW)u=`1t@mPa76`2@%8v@2@$N@TE` z)kYhGY1jD;B9V=Dv1>BZhR9IJmB?X9Wj99f@MvJ2Fim*R`rsRilvz_3n!nPFLmj({EP!@CGkY5R*Y_dSO{qto~WerlG}DMw9k+n}pk z*nL~7R2gB{_9=zpqX|*vkU-dx)(j+83uvYGP?K{hr*j2pQsfXn<_As6z%-z+wFLqI zMhTkG>2M}#BLIOZ(ya1y8#W<+uUo@(43=^4@?CX{-hAuaJki(_A(uXD(>`lzuM~M;3XA48ZEN@HRV{1nvt?CV)t;|*dow0Ue2`B*iA&!rI`fZQ=b28= z_dxF}iUQ8}nq0SA4NK@^EQ%=)OY;3fC<$goJ&Kp|APQ@qVbS-MtJQBc)^aO8mYFsbhafeRKdHPW&s^&;%>v zlTz`YE}CuQ@_X&mqm{+{!h2r)fPGeM_Ge4RRYQkrma`&G<>RW<>S(?#LJ}O-t)d$< zf}b0svP^Zu@)MqwEV^Fb_j zPYYs~vmEC~cOIE6Nc^@b@nyL!w5o?nQ!$mGq(Pa|1-MD}K0si<&}eag=}WLSDO zE4+eA~!J(K}605x&4 zT72P7J^)Y)b(3g2MZ@1bv%o1ggwU4Yb!DhQ=uu-;vX+Ix8>#y6wgNKuobvrPNx?$3 zI{BbX<=Y-cBtvY&#MpGTgOLYU4W+csqWZx!=AVMb)Z;8%#1*x_(-)teF>45TCRwi1 z)Nn>hy3_lo44n-4A@=L2gI$yXCK0lPmMuldhLxR8aI;VrHIS{Dk}yp= zwjhB6v@0DN=Hnm~3t>`CtnPzvA*Kumfn5OLg&-m&fObRD};c}Hf?n&mS< z%$wztc%kjWjCf-?+q(bZh9k~(gs?i4`XVfqMXvPVkUWfm4+EBF(nOkg!}4u)6I)JT zU6IXqQk?p1a2(bz^S;6ZH3Wy9!JvbiSr7%c$#G1eK2^=~z1WX+VW)CPD#G~)13~pX zErO(>x$J_4qu-)lNlZkLj2}y$OiKn0ad5Imu5p-2dnt)(YI|b7rJ3TBUQ8FB8=&ym50*ibd2NAbj z;JA&hJ$AJlldM+tO;Yl3rBOFiP8fDdF?t(`gkRpmT9inR@uX{bThYNmxx-LN5K8h0 ztS%w*;V%b`%;-NARbNXn9he&AO4$rvmkB#;aaOx?Wk|yBCmN{oMTK&E)`s&APR<-5 z#;_e75z;LJ)gBG~h<^`SGmw<$Z3p`KG|I@7Pd)sTJnouZ1hRvm3}V+#lPGk4b&A#Y z4VSNi8(R1z7-t=L^%;*;iMTIAjrXl;h106hFrR{n9o8vlz?+*a1P{rEZ2ie{luQs} zr6t746>eoqiO5)^y;4H%2~&FT*Qc*9_oC2$+&syHWsA=rn3B~4#QEW zf4GT3i_@)f(Fj}gAZj`7205M8!B&HhmbgyZB& z+COyAVNxql#DwfP;H48Yc+Y~ChV6b9auLnfXXvpjr<~lQ@>VbCpQvWz=lyVf1??_c zAo3C^otZD@(v?X)UX*@w?TF|F8KF>l7%!Dzu+hksSA^akEkx8QD(V(lK+HBCw6C}2onVExW)f$ zncm*HI(_H;jF@)6eu}Tln!t?ynRkcqBA5MitIM@L^(4_Ke}vy7c%$w{(`&7Rn=u>oDM+Z^RUYcbSOPwT(ONyq76R>$V6_M_UP4vs=__I#io{{((| zy5=k=oVr-Qt$FImP~+&sN8rf2UH*vRMpwohPc@9?id17La4weIfBNa>1Djy+1=ugn z@}Zs;eFY1OC}WBDxDF=i=On_33(jWE-QYV)HbQ^VM!n>Ci9_W0Zofz7!m>do@KH;S z4k}FqEAU2)b%B_B-QcPnM5Zh=dQ+4|DJoJwo?)f2nWBuZE@^>a(gP~ObzMuyNJTgJFUPcH`%9UFA(P23iaKgo0)CI!SZ>35LpFaD7 z)C2sW$ltSEYNW%%j8F;yK{iHI2Q^}coF@LX`=EvxZb*_O;2Z0Z5 z7 zlccxmCfCI;_^awp|G748%Wx%?t9Sh8!V9Y(9$B?9R`G)Nd&snX1j+VpuQ@GGk=y(W zK|<$O`Cad`Y4#W3GKXgs%lZduAd1t1<7LwG4*zaStE*S)XXPFDyKdgiaVXG2)LvDn zf}eQ_S(&2!H0Mq1Yt&WpM1!7b#yt_ie7naOfX129_E=)beKj|p1VW9q>>+e$3@G$K zrB%i_TT1DHjOf7IQ8)Wu4#K%ZSCDGMP7Ab|Kvjq7*~@ewPm~h_-8d4jmNH<&mNZC@CI zKxG5O08|@<4(6IEC@L-lcrrvix&_Dj4tBvl=8A}2UX|)~v#V$L22U}UHk`B-1MF(t zU6aVJWR!>Y0@4m0UA%Sq9B5;4hZvsOu=>L`IU4#3r_t}os|vSDVMA??h>QJ1FD1vR z*@rclvfD!Iqoxh>VP+?b9TVH8g@KjYR@rRWQy44A`f6doIi+8VTP~pa%`(Oa@5?=h z8>YxNvA##a3D0)^P|2|+0~f|UsAJV=q(S>eq-dehQ+T>*Q@qN zU8@kdpU5gGk%ozt?%c8oM6neA?GuSsOfU_b1U)uiEP8eRn~>M$p*R z43nSZs@^ahO78s zulbK@@{3=2=@^yZ)DuIC$ki;`2WNbD_#`LOHN9iMsrgzt-T<8aeh z(oXrqI$Kgt6)Icu=?11NWs>{)_ed1wh>)wv6RYNUA-C&bejw{cBE_5Wzeo!AHdTd+ z)d(_IKN7z^n|As~3XS=cCB_TgM7rK;X586re`{~Foml$aKs zb!4Pe7hEP|370EWwn$HKPM!kL94UPZ1%8B^e5fB+=Iw^6=?5n3tZGYjov83CLB&OQ++p)WCMeshCv_9-~G9C_2x`LxTDjUcW$l6e!6-&a^fM3oP9*g(H zmCk0nGt1UMdU#pfg1G0um5|sc|KO<+qU1E4iBF~RvN*+`7uNHH^gu{?nw2DSCjig% zI@ymKZSK=PhHJa(jW&xeApv&JcfSmNJ4uQ|pY=Lcc>=J|{>5Ug3@x#R_b@55xFgfs za^ANzWdD$ZYtFs$d7+oiw0ZmPk2&l|< zc8()wfiJx@EGpQT zG$8iLkQZ-086doF1R zh<#9cz_vRsJdoXbD=QgOtpm}cFAJX8c}>Jew;PQJSXSb^;wlC zxXLHTS|!GZ-VK_4wV<9bk4RUmlsByzW_^b>)$6R+jQ}^wco1nMA`9Lncs;&QGp!`5Tx#aXXU?}5_RrtUY zx(EMzDhl-a^y^f5yfFLMnOO#u)l69&4M?|ne|2EV>zQ}4JQCBel?~2I4?D|>L$%H(peOOII!U}i z-j)*h1rODe9{0`xmhG;`AKqw1p0_KhEIU8)DoGnEn9wAhXPaxO_(jNSij~J5m$P*$ z9Mt(t;eV}2+i|kjQpBFcNb7_(VbuF<;RQB~R~p>2*Lg>a&7DEEuq*I%Ls4{zHeUDq z+M0&YhEn^C*9-B4Q7HJ$xj)dORCXPK+)ZtLOa0o&)Sl+f(Y{p*68$-#yagW5^HQnQ z0pWpoQpxg8<&gx9im(>=x6v#&RbQ7^AsjxeSDA? zi4MEJUC~ByG!PiBjq7$pK&FA^5 z=Y@dtQnuy%IfsaR`TVP0q^3mixl&J-3!$H!ua#{A>0Z1JdLq#d4UV9nlYm641ZHl zH6mK~iI6lR3OUEVL}Z5{ONZ_6{Nk%Bv03ag<1HVN?R%w2^aR5@E>6(r>}IoMl$wRF zWr-DItN*k7T$NTT8B)+23c?171sADhjInb2Xb>GhFYGC&3{b>huvLlaS4O z^{j5q+b5H?Z)yuy%AByaVl2yj9cnalY1sMQ zXI#e%*CLajxGxP!K6xf9RD2pMHOfAa1d^Lr6kE`IBpxOiGXfNcoQ*FI6wsNtLD!T+ zC4r2q>5qz0f}UY^RY#1^0*FPO*Zp-U1h9U|qWjwqJaDB(pZ`<`U-xo7+JB$zvwV}^ z2>$0&Q5k#l|Er7*PPG1ycj4BGz zg&`d*?nUi1Q!OB>{V@T$A;)8@h;*Rb1{xk_8X<34L`s}xkH-rQZvjM`jI=jaJRGRg zeEcjYChf-78|RLrao%4HyZBfnAx5KaE~@Sx+o-2MLJ>j-6uDb!U`odj*=)0k)K75l zo^)8-iz{_k7-_qy{Ko~N#B`n@o#A22YbKiA>0f3k=p-B~XX=`Ug>jl$e7>I=hph0&AK z?ya;(NaKY_!od=tFUcGU5Kwt!c9EPUQLi;JDCT*{90O@Wc>b| zI;&GIY$JlQW^9?R$-OEUG|3sp+hn+TL(YK?S@ZW<4PQa}=IcUAn_wW3d!r#$B}n08 z*&lf(YN21NDJ74DqwV`l`RX(4zJ<(E4D}N0@QaE-hnfdPDku~@yhb^AeZL73RgovX z6=e>!`&e^l@1WA5h!}}PwwL*Gjg!LbC5g0|qb8H$^S{eGs%cc?4vTyVFW=s6KtfW? z@&Xm+E(uz(qDbwDvRQI9DdB<2sW}FYK9sg*f%-i*>*n{t-_wXvg~N7gM|a91B!x|K zyLbJ~6!!JZpZ`#HpCB8g#Q*~VU47Rp$NyZb3WhEgg3ivSwnjGJgi0BEV?!H}Z@QF| zrO`Kx*52;FR#J-V-;`oR-pr!t>bYf)UYcixN=(FUR6$fhN@~i09^3WeP3*)D*`*mJ z1u%klAbzQ=P4s%|FnVTZv%|@(HDB+ap5S#cFSJUSGkyI*Y>9Lwx|0lTs%uhoCW(f1 zi+|a9;vDPfh3nS<7m~wqTM6+pEm(&z-Ll;lFH!w#(Uk#2>Iv~2Hu}lITn7hnOny`~ z*Vj=r<&Nwpq^@g5m`u&QTBRoK*}plAuHg$L$~NO#wF0!*r0OfcS%)k0A??uY*@B^C zJe9WdU(w){rTIf<;rwJt^_35^d<A@$FqEZW6kwyfAo2x0T$Ye2MZox6Z7<%Qbu$}}u{rtE+h2M+Z}T4I zxF1cwJ(Uvp!T#mogWkhb(?SxD4_#tV(Sc8N4Gu*{Fh#})Pvb^ef%jrlnG*&Ie+J5 zsly5oo?1((um&lLDxn(DkYtk`My>lgKTp3Y4?hTQ4_`YNOFtjF-FUY#d#(EQd(rfz zB8z%Vi;?x)ZM$3c>yc5H8KBvSevnWNdCbAj?QCac)6-K~Xz@EZp}~N9q)5*Ufjz3C z6kkOeI{3H(^VO8hKDrVjy2DXd;5wr4nb`19yJi0DO@607MSx+7F$ zz3F7sl8JV@@sM$6`#JmSilqI%Bs)}Py2eFT;TjcG5?8$zwV60b(_5A>b#uk~7U^bO z>y|6SCrP2IGST(8HFuX|XQUXPLt2gL_hm|uj1Ws`O2VW>SyL^uXkl>Zvkcpi?@!F7 z%svLoT@{R#XrIh^*dE~$YhMwC+b7JE09NAS47kT%Ew zD!XjxA@1+KOAyu`H2z#h+pGm!lG>WI0v745l+Fd><3dh{ATq%h?JSdEt zu%J*zfFUx%Tx&0DS5WSbE)vwZSoAGT=;W#(DoiL($BcK;U*w`xA&kheyMLI673HCb7fGkp{_vdV2uo;vSoAH z9BuLM#Vzwt#rJH>58=KXa#O;*)_N{$>l7`umacQ0g$pI3iW4=L--O;Wiq0zy7OKp`j2r^y3`7X!?sq9rr5B{41BkBr1fEd1#Q3 z-dXc2RSb4U>FvpVhlQCIzQ-hs=8420z=7F2F(^xD;^RXgpjlh8S6*xCP#Gj2+Q0bAg?XARw3dnlQ*Lz3vk}m`HXmCgN=?bIL{T zi}Ds-xn|P)dxhraT@XY$ZQ&^%x8y!o+?n#+>+dZ1c{hYwNTNRke@3enT(a@}V*X{! z81+{Jc2UR;+Zcbc6cUlafh4DFKwp>;M}8SGD+YnW3Q_)*9Z_pny_z+MeYQmz?r%EVaN0d!NE*FVPq&U@vo{ef6wkMIDEWLbDs zz91$($XbGnQ?4WHjB~4xgPgKZts{p|g1B{-4##}#c5aL5C6_RJ_(*5>85B1}U!_<``}q-97Q7~u)(&lsb(WT^(*n7H%33%@_b zO5(?-v??s??33b19xiB7t_YT!q8!qAzN1#RD@3;kYAli%kazt#YN7}MhVu=ljuz27 z1`<+g8oVwy57&$`CiHeaM)tz(OSt4E# zJ@P6E*e504oUw~RD(=9WP8QdW^6wRdFbKII!GAWecJ(?{`EzTR@?j!3g?$@LLCt;U={>!9z7DU!(1Jq zqEwdx5q?W1Ncm7mXP8MFwAr?nw5$H%cb>Q><9j{Tk2RY9ngGvaJgWXx^r!ywk{ph- zs2PFto4@IIwBh{oXe;yMZJYlS?3%a-CJ#js90hoh5W5d^OMwCFmpryHFr|mG+*ZP$ zqyS5BW@s}|3xUO0PR<^{a2M(gkP5BDGxvkWkPudSV*TMRK5Qm4?~VuqVAOerffRt$HGAvp;M++Iq$E6alB z;ykBr-eZ6v_H^1Wip56Czj&=`mb^TsX|FPN#-gnlP03AkiJDM=?y|LzER1M93R4sC z*HT(;EV=*F*>!+Z{r!KG?6ODMGvkt3viG=@kQJHNMYd}bS4KrrHf4`&*(0m0R5Hqz zEk)r=sFeS?MZRvn<@Z0&bDw)XkMnw+_xqgp=W{;ioX`6;G-P9N%wfoYJ$-m$L#MC% z^sH?tSzA|WWP(cN3({~_*X$l{M*;1V{l$;T6b){#l4pswDTid26HaXgKed}13YIP= zJRvA3nmx{}R$Lr&S4!kWU3`~dxM}>VXWu6Xd(VP}z1->h&f%82eXD_TuTs@=c;l0T z|LHmWKJ+?7hkY=YM>t}zvb4|lV;!ARMtWFp!E^J=Asu9w&kVF*i{T#}sY++-qnVh! z5TQ|=>)+vutf{&qB+LO9^jm#rD7E5+tcorr^Fn5Xb0B;)f^$7Ev#}G_`r==ea294V z--v4LwjswWlSq9ba6i?IXr8M_VEGQ$H%hCqJTFQ3+1B9tmxDUhnNU%dy4+zbqYJ|o z3!N{b?A@{;cG2~nb-`|z;gEDL5ffF@oc3`R{fGi)0wtMqEkw4tRX3t;LVS3-zAmg^ zgL7Z{hmdPSz9oA@t>tZ1<|Khn&Lp=_!Q=@a?k+t~H&3jN?dr(}7s;{L+jiKY57?WsFBfW^mu6a03_^VKrdK=9egXw@!nzZ3TbYc*osyQNoCXPYoFS<&Nr97MrQCOK(gO8 z;0@iqRTJy4-RH)PJld5`AJN}n?5r^-enKrHQOR;z>UMfm+e8~4ZL5k>oXMiYq12Bx4eVQv0jFgp_zC#``sjZpywYqISMP}VZ@!~1Mf$!x|opj%mQ98JnSk@`~ zPmmyuPZKtZOnEC!1y!?`TYRsZ!II;d!iln}%e}bk5qIiUADERr*K$3dekgHV9TtBX zi5q!J!6Zgd#cLxRmZN^J`o@Zv{+p+<_#8^nvY)44Hw_2i@?R&5n^q33fpOnDg1nPQ z_r<$hURl~OketX|Tdbvf_7=3x^rSFJtEp@tuDpVB&uq)qW;xUQ7mmkr-@eZwa$l+? zoKk``Vz@TH#>jMce*8>@FZ+@BEUdYa_K0i|{*;j9MW3K%pnM*T;@>|o@lMhgLrpZP5aol(z>g;b4}|e$U~Fn zGL%(}p%Jsl4LxE!VW_Y4T>e}W4e#~F03H_^R!Q)kpJG{lO!@I4{mFo^V#ayHh_5~o zB$O71gcE(G@6xv);#Ky?e(Ed}^O+Ho(t=93T9T3TnEY(OVf_dR-gY@jj+iJSY?q|6prBv(S9A4k=2fNZz!W@S=B@~b?TJRTuBQq448@juN#Y=3q=^VCF>Z}n6wICJ<^^Kn8C;mK zZYiFSN#Z$?NDGV7(#}q2tAZAtE63icK-MY>UQu4MWlGIbJ$AF8Zt-jV;@7P5MPI>% zPWvO!t%1+s>-A%`;0^o8Ezeaa4DMwI8ooQrJ;ax@Qt*6XONWw)dPwOPI9@u*EG&844*1~EoZ2qsAe~M>d`;Bc_CWY zMoDKEmDh-}k9d6*<0g@aQmsnrM1H9IcKYZs)><)d92{|0Hh8?~XbF)7U+UmP@Pw_6geVB?7N$4J4*E0z3EO&5kRS(EE zv92(+e5WxLXMN{h;-|8@!Q#0q247hb^3R%*k3MuMO5*L}$0D#5P*N$aHd54C+=_RToYXTyewugOaDmGsCvb4H1s=@gkfVnzTCWKMa-Mm1v4Wq!t-JIrbV&EWwKDe ze#kJpOq#iRlFz%5#6Fio9IUlKnQ#X&DY8Ux#<-WqxAac-y%U_L+EZZ4Rg5*yNg`f< zSZn&uio@zanUCPqX1l4W&B!;UWs#P7B^|4WwoCxQXl|44n^cBNqu=3Vl*ltAqsUQO z9q_@nD0zq0O8r`coEm>9+|rA3HL#l}X;0##>SJS$cVavOZVCpSGf4mUU1( zWaRCUYc^9QbG9=vpWo%xP}CMFnMb{reA`K7tT(t5DM)d9l}jVPY>qoRzT zE3m-p#=i=$9x*CB`AL>SY}u3agYFl#uULNen#&44H;!L@I{RI=PlWxG8J((f)ma7A z@jLvQ>?Nx`n?3ChRG#HqE3MXP8*o3!Qq`+t8EMt_p)oeKHqPusBxPn!#?R??-=e3e zo73WNs_IZF`WLigre=|`aS2^> zN1zn!7k&Dh28t%VpJ%**&E!eAcB5oLjQFFcJQj*URMia%Ya3@q1UQ18=oWMM6`I}iT_&L1gl?*~6nU4q4Z0`H<5yDp(HeZ+RGf9`mM&= zn-qRp%i!g$R;i1d1aMZ{IewNjE@p2+Z{`x{*xL*x$?WV~{BjJpsP&C&JK0HLoyf z`0z^v&fBQSa!I7FU~9MaQ%e|?RP>sM^2PL!mE^Q1Ig_4M$5BRfi72oMYu6Ke?wmDX z@0a%-V|z}b23K=ye(W+fG#w|jJUnT{=KR5jfuq!RX}<1irTDw(${<&}dWQu4;EuE< z@3u4dBkQaCHHM&;cE0z50_V!(vJ1_V)A8?C#eJuLkt!98Z%|Bgzidc0j|z(&o)TCzYlrgZA zC3@i>L!&Gw_~7`>puB97I2lK)lESZQqVXc_8T^G2O#VHhO?IC$g zOYhXJ7)~C<8l|Xrftka@QuowScM{K&0zskoU$Aw~vIRVRF9TEQ4*3=_5)98B`=t8(N%ZuWqmwlW zllAzq=E5_5!sKDXam@w`ZD(nl%LAPxQuEtDcKPqu9LPJvNIITawU#c^PQ2HmZgs)r zH^+gRwZ?0)8IFQgU)+p@0Iqb^tcEoqcB@zhfz_FaOM&_d<|jnU>q5nSKa<@%9|dje zIupcg1!tRiMP4X=oG<7s4|AW&^-Cw4FL9OuI$t zxjc*y;Uw!G7a|jz>E*2+PlR(CemWebS7m-&*CDwnmxbiRqJvQ&os-sC&4OWt^(2@vG4|jui#Df@-D= zh3D%8Y3R6+jRBStSvH9pt&tCI`NK08J1*pC(?OM0h!bS-JK3I}`pDY-fDIaB_*W6KS+TO0Q*%kkeuN6uWITt=TsCGw6uBE710q; zRluI%j{?@jwhM|l5&TB!-TkQs!A=DXRE>u18t@;zndD0M$U@Igrt?UW2; z7%=dsHIVH_LCkGUU0fW&UMjDnvjcc0Mp(mK&;d~ZJ5EJ)#7@aTZvGDFXzFZg2Lq~s z5PR_LazNN)JD5K_uK*Hy{mXuHTkGGv|9V8KP#iQ$3!G*^>7UiE{|1G1A-qg(xH;Xa>&%f|BZkH zG=J^0pHzSAqv5*5ysQ{Puy^-_|IPrii zKS$mE10Zngf>Sgg@BjpRyJbrHeo zD8Ro0LI*W#+9?^xlOS^c>Z^^n^0I|FH^@^`ZR`{H=$ zjO0_$cnpBM7Zcm?H_RXIu-Lu~qweDSV|tEZBZh!e6hQy->}e;d#osZ1hQj{HhHkC0 zJ|F-HKmeTGgDe979ogBz24;@<|I7;TU!IXb@oWMsMECIETmQy`zPtM`|NP}PjzR_u zKMG1Z{%1kWeMfEf(10U#w!clmQ2)JC8zm(Fv!H4dUHQHCFLikID?hrd{0>kCQt?kP zdqn2ZG0}ytcQJ7t_B3s0ZvH3PYjkjQ`Q%;jV@?MK-+z3etBCGGo4f4`y^|AdCs!DH zThTQ;cL5dM{|tB_1y6K3bVa^hx_<9J(}5`2SDz1^0bT!Vm*JV;9~t&{IC{$DUAVV* z{|E=#yN{wNdTY@$6z{_KNA3&%w|vFu1n9XRcM0Ak>`UW!lQ`ah3D4r%}Z literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew new file mode 100755 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py index 0f2facdec07..359771ac6c0 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py @@ -1,5 +1,7 @@ +import platform from create_database_utils import * +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + run_codeql_database_create( - ["gradle build --no-daemon --no-build-cache --rerun-tasks"], lang="java") -runSuccessfully([get_cmd("gradle"), "clean"]) + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") From 85e4707e0c79f118976bde9bbf659ae28ee78dd4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 16 Feb 2023 14:12:41 +0100 Subject: [PATCH 299/415] Util: Use end line instead of start line for actual results --- shared/util/codeql/util/test/InlineExpectationsTest.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/util/codeql/util/test/InlineExpectationsTest.qll b/shared/util/codeql/util/test/InlineExpectationsTest.qll index 0c4fd403f4f..c297e609a73 100644 --- a/shared/util/codeql/util/test/InlineExpectationsTest.qll +++ b/shared/util/codeql/util/test/InlineExpectationsTest.qll @@ -384,7 +384,7 @@ module Make { la = a.getLocation() and pragma[only_bind_into](lb) = b.getLocation() and pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and - lb.hasLocationInfo(fname, line, _, _, _) + lb.hasLocationInfo(fname, _, _, line, _) ) } From e9bce9f8cd5a9bcfc6f7c59da154ce044a9665ed Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 17 Feb 2023 09:30:25 +0100 Subject: [PATCH 300/415] Ruby: Update test expectations --- .../dataflow/api-graphs/callbacks.rb | 28 +++++++++---------- .../dataflow/api-graphs/test1.rb | 4 +-- .../library-tests/dataflow/api-graphs/use.ql | 2 +- .../dataflow/flow-summaries/semantics.rb | 4 +-- .../improper_memoization.rb | 28 +++++++++---------- ...incomplete_multi_character_sanitization.rb | 8 +++--- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb b/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb index 41383b7a212..34c4d17d212 100644 --- a/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/callbacks.rb @@ -1,30 +1,30 @@ -Something.foo.withCallback do |a, b| #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getReturn() +Something.foo.withCallback do |a, b| #$ use=getMember("Something").getMethod("foo").getReturn() a.something #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getBlock().getParameter(0).getMethod("something").getReturn() b.somethingElse #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getBlock().getParameter(1).getMethod("somethingElse").getReturn() -end +end #$ use=getMember("Something").getMethod("foo").getReturn().getMethod("withCallback").getReturn() -Something.withNamedArg do |a:, b: nil| #$ use=getMember("Something").getMethod("withNamedArg").getReturn() +Something.withNamedArg do |a:, b: nil| #$ use=getMember("Something") a.something #$ use=getMember("Something").getMethod("withNamedArg").getBlock().getKeywordParameter("a").getMethod("something").getReturn() b.somethingElse #$ use=getMember("Something").getMethod("withNamedArg").getBlock().getKeywordParameter("b").getMethod("somethingElse").getReturn() -end +end #$ use=getMember("Something").getMethod("withNamedArg").getReturn() -Something.withLambda ->(a, b) { #$ use=getMember("Something").getMethod("withLambda").getReturn() +Something.withLambda ->(a, b) { #$ use=getMember("Something") a.something #$ use=getMember("Something").getMethod("withLambda").getParameter(0).getParameter(0).getMethod("something").getReturn() b.something #$ use=getMember("Something").getMethod("withLambda").getParameter(0).getParameter(1).getMethod("something").getReturn() -} +} #$ use=getMember("Something").getMethod("withLambda").getReturn() -Something.namedCallback( #$ use=getMember("Something").getMethod("namedCallback").getReturn() +Something.namedCallback( #$ use=getMember("Something") onEvent: ->(a, b) { a.something #$ use=getMember("Something").getMethod("namedCallback").getKeywordParameter("onEvent").getParameter(0).getMethod("something").getReturn() b.something #$ use=getMember("Something").getMethod("namedCallback").getKeywordParameter("onEvent").getParameter(1).getMethod("something").getReturn() } -) +) #$ use=getMember("Something").getMethod("namedCallback").getReturn() -Something.nestedCall1 do |a| #$ use=getMember("Something").getMethod("nestedCall1").getReturn() - a.nestedCall2 do |b:| #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0).getMethod("nestedCall2").getReturn() +Something.nestedCall1 do |a| #$ use=getMember("Something") + a.nestedCall2 do |b:| #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0) b.something #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0).getMethod("nestedCall2").getBlock().getKeywordParameter("b").getMethod("something").getReturn() - end -end + end #$ use=getMember("Something").getMethod("nestedCall1").getBlock().getParameter(0).getMethod("nestedCall2").getReturn() +end #$ use=getMember("Something").getMethod("nestedCall1").getReturn() def getCallback() ->(x) { @@ -33,7 +33,7 @@ def getCallback() end Something.indirectCallback(getCallback()) #$ use=getMember("Something").getMethod("indirectCallback").getReturn() -Something.withMixed do |a, *args, b| #$ use=getMember("Something").getMethod("withMixed").getReturn() +Something.withMixed do |a, *args, b| #$ use=getMember("Something") a.something #$ use=getMember("Something").getMethod("withMixed").getBlock().getParameter(0).getMethod("something").getReturn() # b.something # not currently handled correctly -end +end #$ use=getMember("Something").getMethod("withMixed").getReturn() diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb b/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb index 34e2aa5f9cb..86b8bce9587 100644 --- a/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/test1.rb @@ -13,9 +13,9 @@ Unknown.new.run #$ use=getMember("Unknown").getMethod("new").getReturn().getMeth Foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz") Const = [1, 2, 3] #$ use=getMember("Array").getMethod("[]").getReturn() -Const.each do |c| #$ use=getMember("Const").getMethod("each").getReturn() def=getMember("Const").getMethod("each").getBlock() +Const.each do |c| #$ use=getMember("Const") puts c #$ use=getMember("Const").getMethod("each").getBlock().getParameter(0) use=getMember("Const").getContent(element) -end +end #$ use=getMember("Const").getMethod("each").getReturn() def=getMember("Const").getMethod("each").getBlock() foo = Foo #$ use=getMember("Foo") foo::Bar::Baz #$ use=getMember("Foo").getMember("Bar").getMember("Baz") diff --git a/ruby/ql/test/library-tests/dataflow/api-graphs/use.ql b/ruby/ql/test/library-tests/dataflow/api-graphs/use.ql index 1f2780793ec..9eb450c01ea 100644 --- a/ruby/ql/test/library-tests/dataflow/api-graphs/use.ql +++ b/ruby/ql/test/library-tests/dataflow/api-graphs/use.ql @@ -44,7 +44,7 @@ class ApiUseTest extends InlineExpectationsTest { max(API::Node a2, Location l2, DataFlow::Node n2 | relevantNode(a2, n2, l2, tag) and l2.getFile() = location.getFile() and - l2.getStartLine() = location.getStartLine() + l2.getEndLine() = location.getEndLine() | a2.getPath() order by diff --git a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.rb b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.rb index 090791ddb20..4424893a9b5 100644 --- a/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.rb +++ b/ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.rb @@ -44,9 +44,9 @@ end def m8 sink(s8 { source "a" }) # $ hasValueFlow=a - sink(s8 do # $hasValueFlow=a + sink(s8 do source "a" - end) + end) # $hasValueFlow=a end def m9 diff --git a/ruby/ql/test/query-tests/experimental/improper-memoization/improper_memoization.rb b/ruby/ql/test/query-tests/experimental/improper-memoization/improper_memoization.rb index 9b3bee6e663..e1e60209c79 100644 --- a/ruby/ql/test/query-tests/experimental/improper-memoization/improper_memoization.rb +++ b/ruby/ql/test/query-tests/experimental/improper-memoization/improper_memoization.rb @@ -47,54 +47,54 @@ def m6(arg1, arg2) end # Bad: method has parameter but only one result is memoized. -def m7(arg) # $result=BAD +def m7(arg) @m7 ||= begin arg += 3 end @m7 -end +end # $result=BAD # Bad: method has parameter but only one result is memoized. -def m8(arg) # $result=BAD +def m8(arg) @m8 ||= begin long_running_method(arg) end @m8 -end +end # $result=BAD # Bad: method has parameter but only one result is memoized. -def m9(arg) # $result=BAD +def m9(arg) @m9 ||= long_running_method(arg) -end +end # $result=BAD # Bad: method has parameter but only one result is memoized. -def m10(arg1, arg2) # $result=BAD +def m10(arg1, arg2) @m10 ||= long_running_method(arg1, arg2) -end +end # $result=BAD # Bad: `arg2` not used in key. -def m11(arg1, arg2) # $result=BAD +def m11(arg1, arg2) @m11 ||= {} @m11[arg1] ||= long_running_method(arg1, arg2) -end +end # $result=BAD # Bad: `arg2` not used in key. -def m12(arg1, arg2) # $result=BAD +def m12(arg1, arg2) @m12 ||= Hash.new do |h1, arg1| h1[arg1] = result(arg1, arg2) end @m12[arg1] -end +end # $result=BAD # Bad: arg not used in key. -def m13(id:) # $result=BAD +def m13(id:) @m13 ||= Rails.cache.fetch("product_sku/#{id}", expires_in: 30.minutes) do ActiveRecord::Base.transaction do ProductSku.find_by(id: id) end end @m13 -end +end # $result=BAD # Good (FP): arg is used in key via string interpolation. def m14(arg) diff --git a/ruby/ql/test/query-tests/security/cwe-116/IncompleteMultiCharacterSanitization/incomplete_multi_character_sanitization.rb b/ruby/ql/test/query-tests/security/cwe-116/IncompleteMultiCharacterSanitization/incomplete_multi_character_sanitization.rb index 3301b00e709..a9c61a29c21 100644 --- a/ruby/ql/test/query-tests/security/cwe-116/IncompleteMultiCharacterSanitization/incomplete_multi_character_sanitization.rb +++ b/ruby/ql/test/query-tests/security/cwe-116/IncompleteMultiCharacterSanitization/incomplete_multi_character_sanitization.rb @@ -80,9 +80,9 @@ def m9(x) x = x.gsub(/^(\.\.\/?)+/, "") # OK # NOT OK - x = x.gsub(/)<[^<]*)*<\/script>/) do |match| # $ hasResult=html + x = x.gsub(/)<[^<]*)*<\/script>/) do |match| if unknown then match else "" end - end + end # $ hasResult=html x = x.gsub(/<\/?([a-z][a-z0-9]*)\b[^>]*>/i, "") # NOT OK [INCONSISTENCY] $ hasResult=html @@ -113,10 +113,10 @@ def m9(x) x = x.gsub(//, "") # OK - x = x # $ hasResult=path + x = x .gsub(/^\.\//, "") .gsub(/\/\.\//, "/") - .gsub(/[^\/]*\/\.\.\//, "") + .gsub(/[^\/]*\/\.\.\//, "") # $ hasResult=path x end From 18c6b682329377fba5d9b05352527eae0cc89bd6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 17 Feb 2023 09:33:03 +0100 Subject: [PATCH 301/415] Go: Update test expectations --- go/ql/test/library-tests/semmle/go/Types/variadicFunctions.go | 4 ++-- go/ql/test/library-tests/semmle/go/concepts/HTTP/main.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go/ql/test/library-tests/semmle/go/Types/variadicFunctions.go b/go/ql/test/library-tests/semmle/go/Types/variadicFunctions.go index 427adeb9041..4cedb679b04 100644 --- a/go/ql/test/library-tests/semmle/go/Types/variadicFunctions.go +++ b/go/ql/test/library-tests/semmle/go/Types/variadicFunctions.go @@ -7,7 +7,7 @@ func testing() { nonvariadicDeclaredFunction([]int{}) } -func variadicDeclaredFunction(x ...int) int { // $ isVariadic +func variadicDeclaredFunction(x ...int) int { a := make([]int, 0, 10) y := append(x, a...) print(x[0], x[1]) @@ -15,7 +15,7 @@ func variadicDeclaredFunction(x ...int) int { // $ isVariadic fmt.Fprint(nil, nil, nil) variadicFunctionLiteral := func(z ...int) int { return z[1] } // $ isVariadic return variadicFunctionLiteral(y...) -} +} // $ isVariadic func nonvariadicDeclaredFunction(x []int) int { return 0 diff --git a/go/ql/test/library-tests/semmle/go/concepts/HTTP/main.go b/go/ql/test/library-tests/semmle/go/concepts/HTTP/main.go index 12a3929cec6..5bd6dbf185e 100644 --- a/go/ql/test/library-tests/semmle/go/concepts/HTTP/main.go +++ b/go/ql/test/library-tests/semmle/go/concepts/HTTP/main.go @@ -59,7 +59,7 @@ func main() { http.HandleFunc("/foo", handler) // $ handler="/foo" - http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { // $ handler="/bar" + http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) - }) + }) // $ handler="/bar" } From 37fc8f5039e219dbaa521abf0cea411d6a4dc560 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 17 Feb 2023 09:33:54 +0100 Subject: [PATCH 302/415] Swift: Update test expectations --- swift/ql/test/library-tests/dataflow/taint/string.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/ql/test/library-tests/dataflow/taint/string.swift b/swift/ql/test/library-tests/dataflow/taint/string.swift index 5179d64c0fc..d1843d95ef2 100644 --- a/swift/ql/test/library-tests/dataflow/taint/string.swift +++ b/swift/ql/test/library-tests/dataflow/taint/string.swift @@ -244,9 +244,9 @@ func taintThroughSimpleStringOperations() { sink(arg: tainted.reversed()) // $ tainted=217 sink(arg: tainted.split(separator: ",")) // $ tainted=217 - sink(arg: tainted.split(whereSeparator: { // $ tainted=217 + sink(arg: tainted.split(whereSeparator: { c in return (c == ",") - })) + })) // $ tainted=217 sink(arg: tainted.trimmingCharacters(in: CharacterSet.whitespaces)) // $ tainted=217 sink(arg: tainted.padding(toLength: 20, withPad: " ", startingAt: 0)) // $ tainted=217 sink(arg: tainted.components(separatedBy: CharacterSet.whitespaces)) // $ tainted=217 From 0e0ec89e60653fb83ec06334f6a75b926fc295f8 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Feb 2023 13:20:06 +0000 Subject: [PATCH 303/415] QL: Add tool for extracting blame info I had some trouble getting this to work with version 1.54 of the Rust toolchain, so I had to bump it up to 1.59. --- ql/Cargo.lock | Bin 15321 -> 21930 bytes ql/Cargo.toml | 1 + ql/buramu/Cargo.toml | 12 +++++ ql/buramu/README.md | 22 +++++++++ ql/buramu/src/main.rs | 108 +++++++++++++++++++++++++++++++++++++++++ ql/rust-toolchain.toml | 2 +- 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 ql/buramu/Cargo.toml create mode 100644 ql/buramu/README.md create mode 100644 ql/buramu/src/main.rs diff --git a/ql/Cargo.lock b/ql/Cargo.lock index b0c217453ed40151e64bd34a251109d4d6ae64c4..8bcae25b4aa2f4b96581f96c22f382a1dfc51b9f 100644 GIT binary patch delta 5257 zcmZ`-OKhB171r3TiJhd0TRV2@v~k>|Rh!P}z8|8MjYK67h$cm_t?uL8WT-vk&e%=T z6X%?k7F_@Wweqq+L5NKy)K+3sgjj;arecWz!FT`3!;_>^66gOtbMLw5obPe& z=huGr^UnL8Tbw$yxaX6fwJ(Qq)_cz$7hV>`TgE_klllv!D?rHo3u;;iyAN)}Yq#rj~F z&CwN|ISpOyswZUgwYitKxQQ&t>~SzIgo;8iZLPyQ8>34)$3i@k zi$OVK9obm4rKC`9tvGh!E6cC+!yt6``a9Hpb2y;(JUHICWbQ^rMSt;m^s?zF*PfpUsGGGSd{ zs(9y%wdhWbPuS>ls?|DJJksfOOs&gi!nc{qITYuFv^mM>vMWBw#2G`$nTZ-zkX$Mz zy;4l8EM#KNvZMjlM^>6Ijx97FE-W;EJ$j`1)4XloahEm$6>?mQXuOCqh%7A@Lt{Cs zmD19_ zgd8xby-O}=%VN|SNES*a8+`Uzhnn@~*GGNx(6N`AM`tf>sS=Tw60CPt)ZWh#iz-pL zRgCc*umjeOM%ch}c7|BQk|KDWz3^>6HlH3jw|xEjRHN`7>v`U`Jl2%Tp_Pr%!J@Ba zL`w@Da|Va7Kv7@^!w@y1S0v~hRwNlp%f z=ul~xGYNbPPQ?+NQqpKcIu#2PC9jiFLUC~CkdI2bB?;=-0H!fkAKo> zK7Qo%tmw7a+ycLIVH7JQ0gPB8`rcaTlPN4a1_DR|%mRTV>7!vBNg-Jj02Bz@w@v@{ ziL>j|w0SruRi*Ril zZY2!9OmV9iJ&5M&`)OY9UJd=%_U~o)ds%zwL0@W~Jsq}?7#T=71&uUTL0t_8Z2(v~ zND3Aj2mOKAA_4NO{$RP({w>gij`HC+waGn0k_N9Ig| zLtZrOj*~@Zr*Iz7orf?ws&oxFT38^9&TvoxO(uXtn3WZl$EH$N!>5yIgnCD z+a!;kkx4?3bYLDl4~6pZSJ;hl@D2mhDi2>pL8$B@0h9^))i%{kN;UZhe_Q;~%&ffy zI552PSW=`+x=3(q2r2;)8o&a>R<0^pf#0FdnPLXnLKqbsPSB+^Y~>X6VBw&<{LPuQ zJGNoE7`&%+dkP^m^d4ForDh%>!kreKgr{gCs-)2b-eq4vjz*eXigwv1Q>->V0p1h! zIW}J{N^40#&1+BGd7921>xmwpY^>pgP$!iN69rAALWBg{g02uC03B79sJ}2^Y9W;- zOH5h;)09lgDc{<7q3JHKG~<=kj-FUfus0Yr2M$T1h!q2nF0=Ha2pNQj-XU+`JjY`J znmATNz3|p*n8CX2$*b@%{k?98eR$nUSud=ey`J+NU6>iwkP1I(&t)2!%EPq+E&kfK((!t zAYV)cz&wOW2C1^q3fhXkGHo7ybMeT*cVSakFok5HMF7t!I0Fga&n2pBBr;g-ACRaM$A|Gxu`s>sXaSIt zw@Okr&Sr(DM7el`K_OTP*##L8R~T+m3=CZd>!vCx1N~^-bDh=Z`1#+jPOQUy_GMC} zoD=-629ZOkBtt97Lhx5m^lE4;6?#x3q!T1sK-Fl<2wklf&hRMOM*HOaA7^JctI*gC zn%PK&F#jlspf*yW4B&86qccui)&BpQAh zjff4AMR@wkR_`wyZT@xasg-tWI(&xe7;e!bkC;jWv=HJ1OHlOzo(*#$>?}70^D!C} zj}gk`&^J&IQ&|*sfUBFB^5fh6II*};tA0CE>&P%@NJ!dRiuo&`q&MhL;A*edIZ+t(}YeaG<1t)XLmd3|Fl zl=0OtqFh6~F!lcaN#Rg{u-KS0ZDO#CN#f!MP{AAA1p&T6rvTTD8w`%&6Z1c^WwTo(};q!xxR!!=^ot&pTOJ5RdaLpRP&da_2%)f Ge)NCXYy2Sq delta 1879 zcmYk7ORHT)5QW({qREX$#oU`Kl0>7ykY`u*qq<4RJy8&Kpx1~_M5MdA+XUhxBIwA+ zPe>a7fZ{|a${9KkrxH+SIuI2>bfDl|!F9F>!r{Q#XYcB&Ro`0sqmQTW-uUF%X^rCe zX6wlXH7nYyZxX!Znw{_BxQ3RJW-l@NXo^?Qsj9@DJ5kdX@WXKMp^rahWBfH8S?=BS z!L;Yd$@P1WT)A9yERG&s{(RHh(-^nxA6a%5+= z*j_`9P9vcKHE3ehx@M<1$m=}7-`jh~_qVT)KlW`;G?xv|do`LVbyK;QE}lv7^x-I<2d(4fw zyB;eQ$lQCj(t6Owk?LIV$2-!VS6lVc zn{}O|=Tf*8kHuM2tfFMM*5kT(Z>36e1Q06#*cxvh{C48;_14b9x>SAkiJ)IBE;XuT ztT>@Sk}cP&6#!doEx8pM(L}J#tA}i~VO4JV-QoAvc7@Y^Ts^Y0owE&8UC%8i8;mu< zWy6BgJA|kaCwL642{eRQx(^xMJC40d(tkJp;~neE!}mY7HqJe`F|HlFc)kbYV++o* zQ=w+KC>Qdkxo(R_j-eJvX-#6X@JNOa3bkBJPqmH3*#qmB+G{Uee*IJ~m&fj7=O(+_ z&Vpjblg%1|J5rCf6=Srt?6SgHAz0(P&jQLibcVoP1)o;yJj%*W%ioWEIIRd;gw~~c z!Q%>xa|MYF;8g`OO@wLH6WJ2cxYFBVB<;4DJ~ zL1IfHp%*P&**IaOSRY>dd2S>EF8SBf7<{ z8fvaCxgN;u^5X#OhgK@i)Xc&0rTKFcF7S2$GOfC zBejip=wEC=5Q&8Z>@r*FCU8i8TyuAiU+ovmOa8{LDb4(Fucj73MkJ{T(HH|RfpFh4 z!dapRJkB9F*~9y&QbN~NQQVX(q2|`|hxFOBeCymaji=+zw)Yei@h;I4sW%1KsS!d2 z^}%G7ge{S-TuzV&@FKGV;siO0*AYFiISxK_>o|LUYq{8d_2%XNNABD;Cx_QSB_qiZ z5gu`ynJpPci<|&TKrjmkz%GIVX4PcI`w6mfZ7s_z=8eY=%{gpaUA^EOm@C+y1OyQh ygB6peoV#}}h9+4}iWLO(-U8l!4e9EUZFV-!^~c|tmd7ssHjO<`Z;sv1y#Eg$1tn7e diff --git a/ql/Cargo.toml b/ql/Cargo.toml index 7acbd36afa6..4bc60c3333d 100644 --- a/ql/Cargo.toml +++ b/ql/Cargo.toml @@ -4,4 +4,5 @@ members = [ "extractor", "generator", "node-types", + "buramu", ] diff --git a/ql/buramu/Cargo.toml b/ql/buramu/Cargo.toml new file mode 100644 index 00000000000..8e09c6c1395 --- /dev/null +++ b/ql/buramu/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "buramu" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +lazy_static = "1.4.0" +chrono = "0.4.23" +rayon = "1.5.0" +regex = "1.7.1" diff --git a/ql/buramu/README.md b/ql/buramu/README.md new file mode 100644 index 00000000000..0c2bcb7ed3c --- /dev/null +++ b/ql/buramu/README.md @@ -0,0 +1,22 @@ +Gathers up `git blame` information for all lines with `deprecated` annotations in QL files in the +codebase. + +## Usage + +From within the root of the `codeql` repo (having first run the `create-extractor-pack.sh` script): +``` + ./ql/target/release/buramu > deprecated.blame +``` + +## Output +The contents of the `deprecated.blame` file will look something like this: +``` +today: 2023-02-17 +file: cpp/ql/lib/semmle/code/cpp/security/TaintTrackingImpl.qll + last_modified: 2022-11-25 124 167 173 184 188 329 358 400 415 546 553 584 593 +file: go/ql/lib/semmle/go/security/FlowSources.qll + last_modified: 2022-12-19 33 +file: python/ql/src/experimental/semmle/python/Concepts.qll + last_modified: 2022-08-18 172 202 + last_modified: 2022-03-11 94 110 129 145 177 206 225 241 258 272 289 303 454 485 529 570 +``` diff --git a/ql/buramu/src/main.rs b/ql/buramu/src/main.rs new file mode 100644 index 00000000000..f91ba8352ef --- /dev/null +++ b/ql/buramu/src/main.rs @@ -0,0 +1,108 @@ +use lazy_static::lazy_static; +use rayon::prelude::*; +use regex::Regex; +use std::collections::HashMap; +use std::{io::BufRead, process::Command}; + +// A map from filenames to lists of line numbers (for just the lines with deprecations) +type FileDeprecations = HashMap>; + +fn get_filename_and_lineno(line: &str) -> (String, String) { + let mut parts = line.splitn(3, ':'); + let file = parts.next().unwrap().to_string(); + let lineno = parts.next().unwrap().to_string(); + (file, lineno) +} + +#[test] +fn test_get_filename_and_lineno() { + let line = "path/to/file.ql:61:deprecated class Foo = Bar;"; + let (file, lineno) = get_filename_and_lineno(line); + assert_eq!(file, "path/to/file.ql"); + assert_eq!(lineno, "61"); +} + +fn get_files_with_deprecations() -> FileDeprecations { + let output = Command::new("git") + .args(&[ + "grep", + "-n", + "-E", + "^[^*]*deprecated", // skip lines that have a `*` before `deprecated`, as they are probably comments + "--", + "*.ql", + "*.qll", + ]) + .output() + .expect("failed to execute process"); + let mut file_deprecations: FileDeprecations = HashMap::new(); + for line in output.stdout.lines() { + let (file, lineno) = get_filename_and_lineno(&line.unwrap()); + file_deprecations + .entry(file) + .or_insert_with(Vec::new) + .push(lineno); + } + file_deprecations +} + +struct LastModifiedLine { + date: String, + lineno: String, +} +type LastModifiedMap = HashMap>; + +fn get_blame_dates_for_filedeprecation(file: &str, linenos: &[String]) -> LastModifiedMap { + let mut command = Command::new("git"); + command.arg("blame"); + for lineno in linenos { + command.arg("-L").arg(format!("{},{}", lineno, lineno)); + } + command.arg(file); + let output = command.output().expect("failed to execute process"); + let mut blame_dates = HashMap::new(); + for line in output.stdout.lines() { + let line = line.unwrap(); + let LastModifiedLine { date, lineno } = get_last_modified(&line); + blame_dates + .entry(date) + .or_insert_with(Vec::new) + .push(lineno); + } + blame_dates +} + +lazy_static! { + static ref BLAME_RE: Regex = + Regex::new("(\\d{4}-\\d{2}-\\d{2}).*[+-]\\d{4}\\s+(\\d+)\\)").unwrap(); +} + +fn get_last_modified(line: &str) -> LastModifiedLine { + let caps = BLAME_RE.captures(line).unwrap(); + let date = caps.get(1).unwrap().as_str().into(); + let lineno = caps.get(2).unwrap().as_str().into(); + LastModifiedLine { date, lineno } +} + +#[test] +fn test_get_date_and_lineno() { + let line = "cc7a9ef97a78 (john doe 2022-08-24 12:59:07 +0200 61) deprecated class Foo = Bar;"; + let LastModifiedLine { date, lineno } = get_last_modified(line); + assert_eq!(date, "2022-08-24"); + assert_eq!(lineno, "61"); +} + +fn main() { + let filedeprecations = get_files_with_deprecations(); + let filedeprecations: Vec<(String, Vec)> = filedeprecations.into_iter().collect(); + println!("today: {}", chrono::Local::now().format("%Y-%m-%d")); + let deprecations = filedeprecations + .par_iter() + .map(|(file, linenos)| (file, get_blame_dates_for_filedeprecation(file, linenos))); + deprecations.for_each(|(file, linenos_and_dates)| { + println!("file: {}", file); + for (date, linenos) in linenos_and_dates.iter() { + println!(" last_modified: {} {}", date, linenos.join(" ")); + } + }); +} diff --git a/ql/rust-toolchain.toml b/ql/rust-toolchain.toml index c0ca7a2593a..38ca5da4f14 100644 --- a/ql/rust-toolchain.toml +++ b/ql/rust-toolchain.toml @@ -2,6 +2,6 @@ # extractor. It is set to the lowest version of Rust we want to support. [toolchain] -channel = "1.54" +channel = "1.59" profile = "minimal" components = [ "rustfmt" ] From 59c1cfb43aafacd4a28996cd4c85a8e1cc9216ea Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Feb 2023 13:21:44 +0000 Subject: [PATCH 304/415] QL: Add grammar for parsing blame files --- ql/buramu/tree-sitter-blame/Cargo.toml | 26 + ql/buramu/tree-sitter-blame/binding.gyp | 19 + .../bindings/node/binding.cc | 28 + .../tree-sitter-blame/bindings/node/index.js | 19 + .../tree-sitter-blame/bindings/rust/build.rs | 40 + .../tree-sitter-blame/bindings/rust/lib.rs | 52 + ql/buramu/tree-sitter-blame/dep.out | 20160 ++++++++++++++++ ql/buramu/tree-sitter-blame/grammar.js | 30 + ql/buramu/tree-sitter-blame/package.json | 19 + ql/buramu/tree-sitter-blame/src/grammar.json | 126 + .../tree-sitter-blame/src/node-types.json | 108 + ql/buramu/tree-sitter-blame/src/parser.c | 691 + .../src/tree_sitter/parser.h | 224 + ql/buramu/tree-sitter-blame/test.blame | 24 + 14 files changed, 21566 insertions(+) create mode 100644 ql/buramu/tree-sitter-blame/Cargo.toml create mode 100644 ql/buramu/tree-sitter-blame/binding.gyp create mode 100644 ql/buramu/tree-sitter-blame/bindings/node/binding.cc create mode 100644 ql/buramu/tree-sitter-blame/bindings/node/index.js create mode 100644 ql/buramu/tree-sitter-blame/bindings/rust/build.rs create mode 100644 ql/buramu/tree-sitter-blame/bindings/rust/lib.rs create mode 100644 ql/buramu/tree-sitter-blame/dep.out create mode 100644 ql/buramu/tree-sitter-blame/grammar.js create mode 100644 ql/buramu/tree-sitter-blame/package.json create mode 100644 ql/buramu/tree-sitter-blame/src/grammar.json create mode 100644 ql/buramu/tree-sitter-blame/src/node-types.json create mode 100644 ql/buramu/tree-sitter-blame/src/parser.c create mode 100644 ql/buramu/tree-sitter-blame/src/tree_sitter/parser.h create mode 100644 ql/buramu/tree-sitter-blame/test.blame diff --git a/ql/buramu/tree-sitter-blame/Cargo.toml b/ql/buramu/tree-sitter-blame/Cargo.toml new file mode 100644 index 00000000000..95dc42c3e74 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tree-sitter-blame" +description = "blame grammar for the tree-sitter parsing library" +version = "0.0.1" +keywords = ["incremental", "parsing", "blame"] +categories = ["parsing", "text-editors"] +repository = "https://github.com/tree-sitter/tree-sitter-blame" +edition = "2018" +license = "MIT" + +build = "bindings/rust/build.rs" +include = [ + "bindings/rust/*", + "grammar.js", + "queries/*", + "src/*", +] + +[lib] +path = "bindings/rust/lib.rs" + +[dependencies] +tree-sitter = "~0.20.3" + +[build-dependencies] +cc = "1.0" diff --git a/ql/buramu/tree-sitter-blame/binding.gyp b/ql/buramu/tree-sitter-blame/binding.gyp new file mode 100644 index 00000000000..d6cc395af07 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/binding.gyp @@ -0,0 +1,19 @@ +{ + "targets": [ + { + "target_name": "tree_sitter_blame_binding", + "include_dirs": [ + " +#include "nan.h" + +using namespace v8; + +extern "C" TSLanguage * tree_sitter_blame(); + +namespace { + +NAN_METHOD(New) {} + +void Init(Local exports, Local module) { + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("Language").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); + Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); + Nan::SetInternalFieldPointer(instance, 0, tree_sitter_blame()); + + Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("blame").ToLocalChecked()); + Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); +} + +NODE_MODULE(tree_sitter_blame_binding, Init) + +} // namespace diff --git a/ql/buramu/tree-sitter-blame/bindings/node/index.js b/ql/buramu/tree-sitter-blame/bindings/node/index.js new file mode 100644 index 00000000000..23af3bb321c --- /dev/null +++ b/ql/buramu/tree-sitter-blame/bindings/node/index.js @@ -0,0 +1,19 @@ +try { + module.exports = require("../../build/Release/tree_sitter_blame_binding"); +} catch (error1) { + if (error1.code !== 'MODULE_NOT_FOUND') { + throw error1; + } + try { + module.exports = require("../../build/Debug/tree_sitter_blame_binding"); + } catch (error2) { + if (error2.code !== 'MODULE_NOT_FOUND') { + throw error2; + } + throw error1 + } +} + +try { + module.exports.nodeTypeInfo = require("../../src/node-types.json"); +} catch (_) {} diff --git a/ql/buramu/tree-sitter-blame/bindings/rust/build.rs b/ql/buramu/tree-sitter-blame/bindings/rust/build.rs new file mode 100644 index 00000000000..c6061f09953 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/bindings/rust/build.rs @@ -0,0 +1,40 @@ +fn main() { + let src_dir = std::path::Path::new("src"); + + let mut c_config = cc::Build::new(); + c_config.include(&src_dir); + c_config + .flag_if_supported("-Wno-unused-parameter") + .flag_if_supported("-Wno-unused-but-set-variable") + .flag_if_supported("-Wno-trigraphs"); + let parser_path = src_dir.join("parser.c"); + c_config.file(&parser_path); + + // If your language uses an external scanner written in C, + // then include this block of code: + + /* + let scanner_path = src_dir.join("scanner.c"); + c_config.file(&scanner_path); + println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); + */ + + c_config.compile("parser"); + println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); + + // If your language uses an external scanner written in C++, + // then include this block of code: + + /* + let mut cpp_config = cc::Build::new(); + cpp_config.cpp(true); + cpp_config.include(&src_dir); + cpp_config + .flag_if_supported("-Wno-unused-parameter") + .flag_if_supported("-Wno-unused-but-set-variable"); + let scanner_path = src_dir.join("scanner.cc"); + cpp_config.file(&scanner_path); + cpp_config.compile("scanner"); + println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); + */ +} diff --git a/ql/buramu/tree-sitter-blame/bindings/rust/lib.rs b/ql/buramu/tree-sitter-blame/bindings/rust/lib.rs new file mode 100644 index 00000000000..268243b164f --- /dev/null +++ b/ql/buramu/tree-sitter-blame/bindings/rust/lib.rs @@ -0,0 +1,52 @@ +//! This crate provides blame language support for the [tree-sitter][] parsing library. +//! +//! Typically, you will use the [language][language func] function to add this language to a +//! tree-sitter [Parser][], and then use the parser to parse some code: +//! +//! ``` +//! let code = ""; +//! let mut parser = tree_sitter::Parser::new(); +//! parser.set_language(tree_sitter_blame::language()).expect("Error loading blame grammar"); +//! let tree = parser.parse(code, None).unwrap(); +//! ``` +//! +//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html +//! [language func]: fn.language.html +//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html +//! [tree-sitter]: https://tree-sitter.github.io/ + +use tree_sitter::Language; + +extern "C" { + fn tree_sitter_blame() -> Language; +} + +/// Get the tree-sitter [Language][] for this grammar. +/// +/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html +pub fn language() -> Language { + unsafe { tree_sitter_blame() } +} + +/// The content of the [`node-types.json`][] file for this grammar. +/// +/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types +pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); + +// Uncomment these to include any queries that this grammar contains + +// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm"); +// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm"); +// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm"); +// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm"); + +#[cfg(test)] +mod tests { + #[test] + fn test_can_load_grammar() { + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(super::language()) + .expect("Error loading blame language"); + } +} diff --git a/ql/buramu/tree-sitter-blame/dep.out b/ql/buramu/tree-sitter-blame/dep.out new file mode 100644 index 00000000000..4e87db56088 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/dep.out @@ -0,0 +1,20160 @@ +(blame_info [0, 0] - [2442, 0] + today: (date [0, 7] - [0, 17]) + (file_entry [1, 0] - [19, 25] + file_name: (filename [1, 6] - [1, 76]) + (blame_entry [2, 4] - [2, 25] + line: (number [2, 11] - [2, 14]) + date: (date [2, 15] - [2, 25])) + (blame_entry [3, 4] - [3, 25] + line: (number [3, 11] - [3, 14]) + date: (date [3, 15] - [3, 25])) + (blame_entry [4, 4] - [4, 25] + line: (number [4, 11] - [4, 14]) + date: (date [4, 15] - [4, 25])) + (blame_entry [5, 4] - [5, 25] + line: (number [5, 11] - [5, 14]) + date: (date [5, 15] - [5, 25])) + (blame_entry [6, 4] - [6, 25] + line: (number [6, 11] - [6, 14]) + date: (date [6, 15] - [6, 25])) + (blame_entry [7, 4] - [7, 25] + line: (number [7, 11] - [7, 14]) + date: (date [7, 15] - [7, 25])) + (blame_entry [8, 4] - [8, 25] + line: (number [8, 11] - [8, 14]) + date: (date [8, 15] - [8, 25])) + (blame_entry [9, 4] - [9, 25] + line: (number [9, 11] - [9, 14]) + date: (date [9, 15] - [9, 25])) + (blame_entry [10, 4] - [10, 25] + line: (number [10, 11] - [10, 14]) + date: (date [10, 15] - [10, 25])) + (blame_entry [11, 4] - [11, 25] + line: (number [11, 11] - [11, 14]) + date: (date [11, 15] - [11, 25])) + (blame_entry [12, 4] - [12, 25] + line: (number [12, 11] - [12, 14]) + date: (date [12, 15] - [12, 25])) + (blame_entry [13, 4] - [13, 25] + line: (number [13, 11] - [13, 14]) + date: (date [13, 15] - [13, 25])) + (blame_entry [14, 4] - [14, 25] + line: (number [14, 11] - [14, 14]) + date: (date [14, 15] - [14, 25])) + (blame_entry [15, 4] - [15, 25] + line: (number [15, 11] - [15, 14]) + date: (date [15, 15] - [15, 25])) + (blame_entry [16, 4] - [16, 25] + line: (number [16, 11] - [16, 14]) + date: (date [16, 15] - [16, 25])) + (blame_entry [17, 4] - [17, 25] + line: (number [17, 11] - [17, 14]) + date: (date [17, 15] - [17, 25])) + (blame_entry [18, 4] - [18, 25] + line: (number [18, 11] - [18, 14]) + date: (date [18, 15] - [18, 25])) + (blame_entry [19, 4] - [19, 25] + line: (number [19, 11] - [19, 14]) + date: (date [19, 15] - [19, 25]))) + (file_entry [20, 0] - [21, 24] + file_name: (filename [20, 6] - [20, 58]) + (blame_entry [21, 4] - [21, 24] + line: (number [21, 11] - [21, 13]) + date: (date [21, 14] - [21, 24]))) + (file_entry [22, 0] - [25, 24] + file_name: (filename [22, 6] - [22, 43]) + (blame_entry [23, 4] - [23, 24] + line: (number [23, 11] - [23, 13]) + date: (date [23, 14] - [23, 24])) + (blame_entry [24, 4] - [24, 24] + line: (number [24, 11] - [24, 13]) + date: (date [24, 14] - [24, 24])) + (blame_entry [25, 4] - [25, 24] + line: (number [25, 11] - [25, 13]) + date: (date [25, 14] - [25, 24]))) + (file_entry [26, 0] - [27, 24] + file_name: (filename [26, 6] - [26, 64]) + (blame_entry [27, 4] - [27, 24] + line: (number [27, 11] - [27, 13]) + date: (date [27, 14] - [27, 24]))) + (file_entry [28, 0] - [29, 24] + file_name: (filename [28, 6] - [28, 57]) + (blame_entry [29, 4] - [29, 24] + line: (number [29, 11] - [29, 13]) + date: (date [29, 14] - [29, 24]))) + (file_entry [30, 0] - [35, 25] + file_name: (filename [30, 6] - [30, 42]) + (blame_entry [31, 4] - [31, 24] + line: (number [31, 11] - [31, 13]) + date: (date [31, 14] - [31, 24])) + (blame_entry [32, 4] - [32, 24] + line: (number [32, 11] - [32, 13]) + date: (date [32, 14] - [32, 24])) + (blame_entry [33, 4] - [33, 25] + line: (number [33, 11] - [33, 14]) + date: (date [33, 15] - [33, 25])) + (blame_entry [34, 4] - [34, 25] + line: (number [34, 11] - [34, 14]) + date: (date [34, 15] - [34, 25])) + (blame_entry [35, 4] - [35, 25] + line: (number [35, 11] - [35, 14]) + date: (date [35, 15] - [35, 25]))) + (file_entry [36, 0] - [38, 24] + file_name: (filename [36, 6] - [36, 67]) + (blame_entry [37, 4] - [37, 24] + line: (number [37, 11] - [37, 13]) + date: (date [37, 14] - [37, 24])) + (blame_entry [38, 4] - [38, 24] + line: (number [38, 11] - [38, 13]) + date: (date [38, 14] - [38, 24]))) + (file_entry [39, 0] - [41, 25] + file_name: (filename [39, 6] - [39, 57]) + (blame_entry [40, 4] - [40, 25] + line: (number [40, 11] - [40, 14]) + date: (date [40, 15] - [40, 25])) + (blame_entry [41, 4] - [41, 25] + line: (number [41, 11] - [41, 14]) + date: (date [41, 15] - [41, 25]))) + (file_entry [42, 0] - [43, 23] + file_name: (filename [42, 6] - [42, 68]) + (blame_entry [43, 4] - [43, 23] + line: (number [43, 11] - [43, 12]) + date: (date [43, 13] - [43, 23]))) + (file_entry [44, 0] - [45, 24] + file_name: (filename [44, 6] - [44, 73]) + (blame_entry [45, 4] - [45, 24] + line: (number [45, 11] - [45, 13]) + date: (date [45, 14] - [45, 24]))) + (file_entry [46, 0] - [47, 24] + file_name: (filename [46, 6] - [46, 59]) + (blame_entry [47, 4] - [47, 24] + line: (number [47, 11] - [47, 13]) + date: (date [47, 14] - [47, 24]))) + (file_entry [48, 0] - [49, 24] + file_name: (filename [48, 6] - [48, 81]) + (blame_entry [49, 4] - [49, 24] + line: (number [49, 11] - [49, 13]) + date: (date [49, 14] - [49, 24]))) + (file_entry [50, 0] - [52, 25] + file_name: (filename [50, 6] - [50, 78]) + (blame_entry [51, 4] - [51, 25] + line: (number [51, 11] - [51, 14]) + date: (date [51, 15] - [51, 25])) + (blame_entry [52, 4] - [52, 25] + line: (number [52, 11] - [52, 14]) + date: (date [52, 15] - [52, 25]))) + (file_entry [53, 0] - [56, 25] + file_name: (filename [53, 6] - [53, 79]) + (blame_entry [54, 4] - [54, 24] + line: (number [54, 11] - [54, 13]) + date: (date [54, 14] - [54, 24])) + (blame_entry [55, 4] - [55, 24] + line: (number [55, 11] - [55, 13]) + date: (date [55, 14] - [55, 24])) + (blame_entry [56, 4] - [56, 25] + line: (number [56, 11] - [56, 14]) + date: (date [56, 15] - [56, 25]))) + (file_entry [57, 0] - [59, 25] + file_name: (filename [57, 6] - [57, 76]) + (blame_entry [58, 4] - [58, 24] + line: (number [58, 11] - [58, 13]) + date: (date [58, 14] - [58, 24])) + (blame_entry [59, 4] - [59, 25] + line: (number [59, 11] - [59, 14]) + date: (date [59, 15] - [59, 25]))) + (file_entry [60, 0] - [65, 25] + file_name: (filename [60, 6] - [60, 82]) + (blame_entry [61, 4] - [61, 25] + line: (number [61, 11] - [61, 14]) + date: (date [61, 15] - [61, 25])) + (blame_entry [62, 4] - [62, 25] + line: (number [62, 11] - [62, 14]) + date: (date [62, 15] - [62, 25])) + (blame_entry [63, 4] - [63, 25] + line: (number [63, 11] - [63, 14]) + date: (date [63, 15] - [63, 25])) + (blame_entry [64, 4] - [64, 25] + line: (number [64, 11] - [64, 14]) + date: (date [64, 15] - [64, 25])) + (blame_entry [65, 4] - [65, 25] + line: (number [65, 11] - [65, 14]) + date: (date [65, 15] - [65, 25]))) + (file_entry [66, 0] - [68, 25] + file_name: (filename [66, 6] - [66, 120]) + (blame_entry [67, 4] - [67, 24] + line: (number [67, 11] - [67, 13]) + date: (date [67, 14] - [67, 24])) + (blame_entry [68, 4] - [68, 25] + line: (number [68, 11] - [68, 14]) + date: (date [68, 15] - [68, 25]))) + (file_entry [69, 0] - [94, 25] + file_name: (filename [69, 6] - [69, 45]) + (blame_entry [70, 4] - [70, 23] + line: (number [70, 11] - [70, 12]) + date: (date [70, 13] - [70, 23])) + (blame_entry [71, 4] - [71, 24] + line: (number [71, 11] - [71, 13]) + date: (date [71, 14] - [71, 24])) + (blame_entry [72, 4] - [72, 24] + line: (number [72, 11] - [72, 13]) + date: (date [72, 14] - [72, 24])) + (blame_entry [73, 4] - [73, 24] + line: (number [73, 11] - [73, 13]) + date: (date [73, 14] - [73, 24])) + (blame_entry [74, 4] - [74, 24] + line: (number [74, 11] - [74, 13]) + date: (date [74, 14] - [74, 24])) + (blame_entry [75, 4] - [75, 24] + line: (number [75, 11] - [75, 13]) + date: (date [75, 14] - [75, 24])) + (blame_entry [76, 4] - [76, 25] + line: (number [76, 11] - [76, 14]) + date: (date [76, 15] - [76, 25])) + (blame_entry [77, 4] - [77, 25] + line: (number [77, 11] - [77, 14]) + date: (date [77, 15] - [77, 25])) + (blame_entry [78, 4] - [78, 25] + line: (number [78, 11] - [78, 14]) + date: (date [78, 15] - [78, 25])) + (blame_entry [79, 4] - [79, 25] + line: (number [79, 11] - [79, 14]) + date: (date [79, 15] - [79, 25])) + (blame_entry [80, 4] - [80, 25] + line: (number [80, 11] - [80, 14]) + date: (date [80, 15] - [80, 25])) + (blame_entry [81, 4] - [81, 25] + line: (number [81, 11] - [81, 14]) + date: (date [81, 15] - [81, 25])) + (blame_entry [82, 4] - [82, 25] + line: (number [82, 11] - [82, 14]) + date: (date [82, 15] - [82, 25])) + (blame_entry [83, 4] - [83, 25] + line: (number [83, 11] - [83, 14]) + date: (date [83, 15] - [83, 25])) + (blame_entry [84, 4] - [84, 25] + line: (number [84, 11] - [84, 14]) + date: (date [84, 15] - [84, 25])) + (blame_entry [85, 4] - [85, 25] + line: (number [85, 11] - [85, 14]) + date: (date [85, 15] - [85, 25])) + (blame_entry [86, 4] - [86, 25] + line: (number [86, 11] - [86, 14]) + date: (date [86, 15] - [86, 25])) + (blame_entry [87, 4] - [87, 25] + line: (number [87, 11] - [87, 14]) + date: (date [87, 15] - [87, 25])) + (blame_entry [88, 4] - [88, 25] + line: (number [88, 11] - [88, 14]) + date: (date [88, 15] - [88, 25])) + (blame_entry [89, 4] - [89, 25] + line: (number [89, 11] - [89, 14]) + date: (date [89, 15] - [89, 25])) + (blame_entry [90, 4] - [90, 25] + line: (number [90, 11] - [90, 14]) + date: (date [90, 15] - [90, 25])) + (blame_entry [91, 4] - [91, 25] + line: (number [91, 11] - [91, 14]) + date: (date [91, 15] - [91, 25])) + (blame_entry [92, 4] - [92, 25] + line: (number [92, 11] - [92, 14]) + date: (date [92, 15] - [92, 25])) + (blame_entry [93, 4] - [93, 25] + line: (number [93, 11] - [93, 14]) + date: (date [93, 15] - [93, 25])) + (blame_entry [94, 4] - [94, 25] + line: (number [94, 11] - [94, 14]) + date: (date [94, 15] - [94, 25]))) + (file_entry [95, 0] - [98, 25] + file_name: (filename [95, 6] - [95, 41]) + (blame_entry [96, 4] - [96, 24] + line: (number [96, 11] - [96, 13]) + date: (date [96, 14] - [96, 24])) + (blame_entry [97, 4] - [97, 25] + line: (number [97, 11] - [97, 14]) + date: (date [97, 15] - [97, 25])) + (blame_entry [98, 4] - [98, 25] + line: (number [98, 11] - [98, 14]) + date: (date [98, 15] - [98, 25]))) + (file_entry [99, 0] - [102, 26] + file_name: (filename [99, 6] - [99, 61]) + (blame_entry [100, 4] - [100, 26] + line: (number [100, 11] - [100, 15]) + date: (date [100, 16] - [100, 26])) + (blame_entry [101, 4] - [101, 26] + line: (number [101, 11] - [101, 15]) + date: (date [101, 16] - [101, 26])) + (blame_entry [102, 4] - [102, 26] + line: (number [102, 11] - [102, 15]) + date: (date [102, 16] - [102, 26]))) + (file_entry [103, 0] - [104, 25] + file_name: (filename [103, 6] - [103, 57]) + (blame_entry [104, 4] - [104, 25] + line: (number [104, 11] - [104, 14]) + date: (date [104, 15] - [104, 25]))) + (file_entry [105, 0] - [108, 24] + file_name: (filename [105, 6] - [105, 80]) + (blame_entry [106, 4] - [106, 24] + line: (number [106, 11] - [106, 13]) + date: (date [106, 14] - [106, 24])) + (blame_entry [107, 4] - [107, 24] + line: (number [107, 11] - [107, 13]) + date: (date [107, 14] - [107, 24])) + (blame_entry [108, 4] - [108, 24] + line: (number [108, 11] - [108, 13]) + date: (date [108, 14] - [108, 24]))) + (file_entry [109, 0] - [114, 25] + file_name: (filename [109, 6] - [109, 49]) + (blame_entry [110, 4] - [110, 25] + line: (number [110, 11] - [110, 14]) + date: (date [110, 15] - [110, 25])) + (blame_entry [111, 4] - [111, 25] + line: (number [111, 11] - [111, 14]) + date: (date [111, 15] - [111, 25])) + (blame_entry [112, 4] - [112, 25] + line: (number [112, 11] - [112, 14]) + date: (date [112, 15] - [112, 25])) + (blame_entry [113, 4] - [113, 25] + line: (number [113, 11] - [113, 14]) + date: (date [113, 15] - [113, 25])) + (blame_entry [114, 4] - [114, 25] + line: (number [114, 11] - [114, 14]) + date: (date [114, 15] - [114, 25]))) + (file_entry [115, 0] - [120, 26] + file_name: (filename [115, 6] - [115, 93]) + (blame_entry [116, 4] - [116, 25] + line: (number [116, 11] - [116, 14]) + date: (date [116, 15] - [116, 25])) + (blame_entry [117, 4] - [117, 25] + line: (number [117, 11] - [117, 14]) + date: (date [117, 15] - [117, 25])) + (blame_entry [118, 4] - [118, 26] + line: (number [118, 11] - [118, 15]) + date: (date [118, 16] - [118, 26])) + (blame_entry [119, 4] - [119, 26] + line: (number [119, 11] - [119, 15]) + date: (date [119, 16] - [119, 26])) + (blame_entry [120, 4] - [120, 26] + line: (number [120, 11] - [120, 15]) + date: (date [120, 16] - [120, 26]))) + (file_entry [121, 0] - [125, 25] + file_name: (filename [121, 6] - [121, 73]) + (blame_entry [122, 4] - [122, 24] + line: (number [122, 11] - [122, 13]) + date: (date [122, 14] - [122, 24])) + (blame_entry [123, 4] - [123, 25] + line: (number [123, 11] - [123, 14]) + date: (date [123, 15] - [123, 25])) + (blame_entry [124, 4] - [124, 25] + line: (number [124, 11] - [124, 14]) + date: (date [124, 15] - [124, 25])) + (blame_entry [125, 4] - [125, 25] + line: (number [125, 11] - [125, 14]) + date: (date [125, 15] - [125, 25]))) + (file_entry [126, 0] - [127, 24] + file_name: (filename [126, 6] - [126, 50]) + (blame_entry [127, 4] - [127, 24] + line: (number [127, 11] - [127, 13]) + date: (date [127, 14] - [127, 24]))) + (file_entry [128, 0] - [136, 24] + file_name: (filename [128, 6] - [128, 57]) + (blame_entry [129, 4] - [129, 24] + line: (number [129, 11] - [129, 13]) + date: (date [129, 14] - [129, 24])) + (blame_entry [130, 4] - [130, 24] + line: (number [130, 11] - [130, 13]) + date: (date [130, 14] - [130, 24])) + (blame_entry [131, 4] - [131, 24] + line: (number [131, 11] - [131, 13]) + date: (date [131, 14] - [131, 24])) + (blame_entry [132, 4] - [132, 24] + line: (number [132, 11] - [132, 13]) + date: (date [132, 14] - [132, 24])) + (blame_entry [133, 4] - [133, 24] + line: (number [133, 11] - [133, 13]) + date: (date [133, 14] - [133, 24])) + (blame_entry [134, 4] - [134, 24] + line: (number [134, 11] - [134, 13]) + date: (date [134, 14] - [134, 24])) + (blame_entry [135, 4] - [135, 24] + line: (number [135, 11] - [135, 13]) + date: (date [135, 14] - [135, 24])) + (blame_entry [136, 4] - [136, 24] + line: (number [136, 11] - [136, 13]) + date: (date [136, 14] - [136, 24]))) + (file_entry [137, 0] - [138, 25] + file_name: (filename [137, 6] - [137, 71]) + (blame_entry [138, 4] - [138, 25] + line: (number [138, 11] - [138, 14]) + date: (date [138, 15] - [138, 25]))) + (file_entry [139, 0] - [149, 25] + file_name: (filename [139, 6] - [139, 48]) + (blame_entry [140, 4] - [140, 24] + line: (number [140, 11] - [140, 13]) + date: (date [140, 14] - [140, 24])) + (blame_entry [141, 4] - [141, 24] + line: (number [141, 11] - [141, 13]) + date: (date [141, 14] - [141, 24])) + (blame_entry [142, 4] - [142, 24] + line: (number [142, 11] - [142, 13]) + date: (date [142, 14] - [142, 24])) + (blame_entry [143, 4] - [143, 24] + line: (number [143, 11] - [143, 13]) + date: (date [143, 14] - [143, 24])) + (blame_entry [144, 4] - [144, 24] + line: (number [144, 11] - [144, 13]) + date: (date [144, 14] - [144, 24])) + (blame_entry [145, 4] - [145, 24] + line: (number [145, 11] - [145, 13]) + date: (date [145, 14] - [145, 24])) + (blame_entry [146, 4] - [146, 24] + line: (number [146, 11] - [146, 13]) + date: (date [146, 14] - [146, 24])) + (blame_entry [147, 4] - [147, 24] + line: (number [147, 11] - [147, 13]) + date: (date [147, 14] - [147, 24])) + (blame_entry [148, 4] - [148, 24] + line: (number [148, 11] - [148, 13]) + date: (date [148, 14] - [148, 24])) + (blame_entry [149, 4] - [149, 25] + line: (number [149, 11] - [149, 14]) + date: (date [149, 15] - [149, 25]))) + (file_entry [150, 0] - [166, 25] + file_name: (filename [150, 6] - [150, 67]) + (blame_entry [151, 4] - [151, 24] + line: (number [151, 11] - [151, 13]) + date: (date [151, 14] - [151, 24])) + (blame_entry [152, 4] - [152, 24] + line: (number [152, 11] - [152, 13]) + date: (date [152, 14] - [152, 24])) + (blame_entry [153, 4] - [153, 24] + line: (number [153, 11] - [153, 13]) + date: (date [153, 14] - [153, 24])) + (blame_entry [154, 4] - [154, 24] + line: (number [154, 11] - [154, 13]) + date: (date [154, 14] - [154, 24])) + (blame_entry [155, 4] - [155, 24] + line: (number [155, 11] - [155, 13]) + date: (date [155, 14] - [155, 24])) + (blame_entry [156, 4] - [156, 24] + line: (number [156, 11] - [156, 13]) + date: (date [156, 14] - [156, 24])) + (blame_entry [157, 4] - [157, 24] + line: (number [157, 11] - [157, 13]) + date: (date [157, 14] - [157, 24])) + (blame_entry [158, 4] - [158, 24] + line: (number [158, 11] - [158, 13]) + date: (date [158, 14] - [158, 24])) + (blame_entry [159, 4] - [159, 24] + line: (number [159, 11] - [159, 13]) + date: (date [159, 14] - [159, 24])) + (blame_entry [160, 4] - [160, 24] + line: (number [160, 11] - [160, 13]) + date: (date [160, 14] - [160, 24])) + (blame_entry [161, 4] - [161, 24] + line: (number [161, 11] - [161, 13]) + date: (date [161, 14] - [161, 24])) + (blame_entry [162, 4] - [162, 25] + line: (number [162, 11] - [162, 14]) + date: (date [162, 15] - [162, 25])) + (blame_entry [163, 4] - [163, 25] + line: (number [163, 11] - [163, 14]) + date: (date [163, 15] - [163, 25])) + (blame_entry [164, 4] - [164, 25] + line: (number [164, 11] - [164, 14]) + date: (date [164, 15] - [164, 25])) + (blame_entry [165, 4] - [165, 25] + line: (number [165, 11] - [165, 14]) + date: (date [165, 15] - [165, 25])) + (blame_entry [166, 4] - [166, 25] + line: (number [166, 11] - [166, 14]) + date: (date [166, 15] - [166, 25]))) + (file_entry [167, 0] - [169, 26] + file_name: (filename [167, 6] - [167, 46]) + (blame_entry [168, 4] - [168, 25] + line: (number [168, 11] - [168, 14]) + date: (date [168, 15] - [168, 25])) + (blame_entry [169, 4] - [169, 26] + line: (number [169, 11] - [169, 15]) + date: (date [169, 16] - [169, 26]))) + (file_entry [170, 0] - [174, 25] + file_name: (filename [170, 6] - [170, 70]) + (blame_entry [171, 4] - [171, 24] + line: (number [171, 11] - [171, 13]) + date: (date [171, 14] - [171, 24])) + (blame_entry [172, 4] - [172, 25] + line: (number [172, 11] - [172, 14]) + date: (date [172, 15] - [172, 25])) + (blame_entry [173, 4] - [173, 25] + line: (number [173, 11] - [173, 14]) + date: (date [173, 15] - [173, 25])) + (blame_entry [174, 4] - [174, 25] + line: (number [174, 11] - [174, 14]) + date: (date [174, 15] - [174, 25]))) + (file_entry [175, 0] - [176, 23] + file_name: (filename [175, 6] - [175, 52]) + (blame_entry [176, 4] - [176, 23] + line: (number [176, 11] - [176, 12]) + date: (date [176, 13] - [176, 23]))) + (file_entry [177, 0] - [179, 24] + file_name: (filename [177, 6] - [177, 61]) + (blame_entry [178, 4] - [178, 24] + line: (number [178, 11] - [178, 13]) + date: (date [178, 14] - [178, 24])) + (blame_entry [179, 4] - [179, 24] + line: (number [179, 11] - [179, 13]) + date: (date [179, 14] - [179, 24]))) + (file_entry [180, 0] - [182, 25] + file_name: (filename [180, 6] - [180, 59]) + (blame_entry [181, 4] - [181, 24] + line: (number [181, 11] - [181, 13]) + date: (date [181, 14] - [181, 24])) + (blame_entry [182, 4] - [182, 25] + line: (number [182, 11] - [182, 14]) + date: (date [182, 15] - [182, 25]))) + (file_entry [183, 0] - [184, 23] + file_name: (filename [183, 6] - [183, 64]) + (blame_entry [184, 4] - [184, 23] + line: (number [184, 11] - [184, 12]) + date: (date [184, 13] - [184, 23]))) + (file_entry [185, 0] - [198, 25] + file_name: (filename [185, 6] - [185, 46]) + (blame_entry [186, 4] - [186, 24] + line: (number [186, 11] - [186, 13]) + date: (date [186, 14] - [186, 24])) + (blame_entry [187, 4] - [187, 24] + line: (number [187, 11] - [187, 13]) + date: (date [187, 14] - [187, 24])) + (blame_entry [188, 4] - [188, 25] + line: (number [188, 11] - [188, 14]) + date: (date [188, 15] - [188, 25])) + (blame_entry [189, 4] - [189, 25] + line: (number [189, 11] - [189, 14]) + date: (date [189, 15] - [189, 25])) + (blame_entry [190, 4] - [190, 25] + line: (number [190, 11] - [190, 14]) + date: (date [190, 15] - [190, 25])) + (blame_entry [191, 4] - [191, 25] + line: (number [191, 11] - [191, 14]) + date: (date [191, 15] - [191, 25])) + (blame_entry [192, 4] - [192, 25] + line: (number [192, 11] - [192, 14]) + date: (date [192, 15] - [192, 25])) + (blame_entry [193, 4] - [193, 25] + line: (number [193, 11] - [193, 14]) + date: (date [193, 15] - [193, 25])) + (blame_entry [194, 4] - [194, 25] + line: (number [194, 11] - [194, 14]) + date: (date [194, 15] - [194, 25])) + (blame_entry [195, 4] - [195, 25] + line: (number [195, 11] - [195, 14]) + date: (date [195, 15] - [195, 25])) + (blame_entry [196, 4] - [196, 25] + line: (number [196, 11] - [196, 14]) + date: (date [196, 15] - [196, 25])) + (blame_entry [197, 4] - [197, 25] + line: (number [197, 11] - [197, 14]) + date: (date [197, 15] - [197, 25])) + (blame_entry [198, 4] - [198, 25] + line: (number [198, 11] - [198, 14]) + date: (date [198, 15] - [198, 25]))) + (file_entry [199, 0] - [201, 25] + file_name: (filename [199, 6] - [199, 59]) + (blame_entry [200, 4] - [200, 25] + line: (number [200, 11] - [200, 14]) + date: (date [200, 15] - [200, 25])) + (blame_entry [201, 4] - [201, 25] + line: (number [201, 11] - [201, 14]) + date: (date [201, 15] - [201, 25]))) + (file_entry [202, 0] - [205, 24] + file_name: (filename [202, 6] - [202, 56]) + (blame_entry [203, 4] - [203, 24] + line: (number [203, 11] - [203, 13]) + date: (date [203, 14] - [203, 24])) + (blame_entry [204, 4] - [204, 24] + line: (number [204, 11] - [204, 13]) + date: (date [204, 14] - [204, 24])) + (blame_entry [205, 4] - [205, 24] + line: (number [205, 11] - [205, 13]) + date: (date [205, 14] - [205, 24]))) + (file_entry [206, 0] - [210, 25] + file_name: (filename [206, 6] - [206, 80]) + (blame_entry [207, 4] - [207, 25] + line: (number [207, 11] - [207, 14]) + date: (date [207, 15] - [207, 25])) + (blame_entry [208, 4] - [208, 25] + line: (number [208, 11] - [208, 14]) + date: (date [208, 15] - [208, 25])) + (blame_entry [209, 4] - [209, 25] + line: (number [209, 11] - [209, 14]) + date: (date [209, 15] - [209, 25])) + (blame_entry [210, 4] - [210, 25] + line: (number [210, 11] - [210, 14]) + date: (date [210, 15] - [210, 25]))) + (file_entry [211, 0] - [212, 24] + file_name: (filename [211, 6] - [211, 82]) + (blame_entry [212, 4] - [212, 24] + line: (number [212, 11] - [212, 13]) + date: (date [212, 14] - [212, 24]))) + (file_entry [213, 0] - [214, 23] + file_name: (filename [213, 6] - [213, 76]) + (blame_entry [214, 4] - [214, 23] + line: (number [214, 11] - [214, 12]) + date: (date [214, 13] - [214, 23]))) + (file_entry [215, 0] - [216, 25] + file_name: (filename [215, 6] - [215, 64]) + (blame_entry [216, 4] - [216, 25] + line: (number [216, 11] - [216, 14]) + date: (date [216, 15] - [216, 25]))) + (file_entry [217, 0] - [221, 25] + file_name: (filename [217, 6] - [217, 50]) + (blame_entry [218, 4] - [218, 25] + line: (number [218, 11] - [218, 14]) + date: (date [218, 15] - [218, 25])) + (blame_entry [219, 4] - [219, 25] + line: (number [219, 11] - [219, 14]) + date: (date [219, 15] - [219, 25])) + (blame_entry [220, 4] - [220, 25] + line: (number [220, 11] - [220, 14]) + date: (date [220, 15] - [220, 25])) + (blame_entry [221, 4] - [221, 25] + line: (number [221, 11] - [221, 14]) + date: (date [221, 15] - [221, 25]))) + (file_entry [222, 0] - [223, 24] + file_name: (filename [222, 6] - [222, 85]) + (blame_entry [223, 4] - [223, 24] + line: (number [223, 11] - [223, 13]) + date: (date [223, 14] - [223, 24]))) + (file_entry [224, 0] - [228, 25] + file_name: (filename [224, 6] - [224, 83]) + (blame_entry [225, 4] - [225, 24] + line: (number [225, 11] - [225, 13]) + date: (date [225, 14] - [225, 24])) + (blame_entry [226, 4] - [226, 25] + line: (number [226, 11] - [226, 14]) + date: (date [226, 15] - [226, 25])) + (blame_entry [227, 4] - [227, 25] + line: (number [227, 11] - [227, 14]) + date: (date [227, 15] - [227, 25])) + (blame_entry [228, 4] - [228, 25] + line: (number [228, 11] - [228, 14]) + date: (date [228, 15] - [228, 25]))) + (file_entry [229, 0] - [230, 24] + file_name: (filename [229, 6] - [229, 67]) + (blame_entry [230, 4] - [230, 24] + line: (number [230, 11] - [230, 13]) + date: (date [230, 14] - [230, 24]))) + (file_entry [231, 0] - [246, 25] + file_name: (filename [231, 6] - [231, 64]) + (blame_entry [232, 4] - [232, 25] + line: (number [232, 11] - [232, 14]) + date: (date [232, 15] - [232, 25])) + (blame_entry [233, 4] - [233, 25] + line: (number [233, 11] - [233, 14]) + date: (date [233, 15] - [233, 25])) + (blame_entry [234, 4] - [234, 25] + line: (number [234, 11] - [234, 14]) + date: (date [234, 15] - [234, 25])) + (blame_entry [235, 4] - [235, 25] + line: (number [235, 11] - [235, 14]) + date: (date [235, 15] - [235, 25])) + (blame_entry [236, 4] - [236, 25] + line: (number [236, 11] - [236, 14]) + date: (date [236, 15] - [236, 25])) + (blame_entry [237, 4] - [237, 25] + line: (number [237, 11] - [237, 14]) + date: (date [237, 15] - [237, 25])) + (blame_entry [238, 4] - [238, 25] + line: (number [238, 11] - [238, 14]) + date: (date [238, 15] - [238, 25])) + (blame_entry [239, 4] - [239, 25] + line: (number [239, 11] - [239, 14]) + date: (date [239, 15] - [239, 25])) + (blame_entry [240, 4] - [240, 25] + line: (number [240, 11] - [240, 14]) + date: (date [240, 15] - [240, 25])) + (blame_entry [241, 4] - [241, 25] + line: (number [241, 11] - [241, 14]) + date: (date [241, 15] - [241, 25])) + (blame_entry [242, 4] - [242, 25] + line: (number [242, 11] - [242, 14]) + date: (date [242, 15] - [242, 25])) + (blame_entry [243, 4] - [243, 25] + line: (number [243, 11] - [243, 14]) + date: (date [243, 15] - [243, 25])) + (blame_entry [244, 4] - [244, 25] + line: (number [244, 11] - [244, 14]) + date: (date [244, 15] - [244, 25])) + (blame_entry [245, 4] - [245, 25] + line: (number [245, 11] - [245, 14]) + date: (date [245, 15] - [245, 25])) + (blame_entry [246, 4] - [246, 25] + line: (number [246, 11] - [246, 14]) + date: (date [246, 15] - [246, 25]))) + (file_entry [247, 0] - [249, 25] + file_name: (filename [247, 6] - [247, 65]) + (blame_entry [248, 4] - [248, 25] + line: (number [248, 11] - [248, 14]) + date: (date [248, 15] - [248, 25])) + (blame_entry [249, 4] - [249, 25] + line: (number [249, 11] - [249, 14]) + date: (date [249, 15] - [249, 25]))) + (file_entry [250, 0] - [251, 24] + file_name: (filename [250, 6] - [250, 75]) + (blame_entry [251, 4] - [251, 24] + line: (number [251, 11] - [251, 13]) + date: (date [251, 14] - [251, 24]))) + (file_entry [252, 0] - [253, 24] + file_name: (filename [252, 6] - [252, 63]) + (blame_entry [253, 4] - [253, 24] + line: (number [253, 11] - [253, 13]) + date: (date [253, 14] - [253, 24]))) + (file_entry [254, 0] - [255, 24] + file_name: (filename [254, 6] - [254, 84]) + (blame_entry [255, 4] - [255, 24] + line: (number [255, 11] - [255, 13]) + date: (date [255, 14] - [255, 24]))) + (file_entry [256, 0] - [257, 24] + file_name: (filename [256, 6] - [256, 61]) + (blame_entry [257, 4] - [257, 24] + line: (number [257, 11] - [257, 13]) + date: (date [257, 14] - [257, 24]))) + (file_entry [258, 0] - [260, 25] + file_name: (filename [258, 6] - [258, 75]) + (blame_entry [259, 4] - [259, 25] + line: (number [259, 11] - [259, 14]) + date: (date [259, 15] - [259, 25])) + (blame_entry [260, 4] - [260, 25] + line: (number [260, 11] - [260, 14]) + date: (date [260, 15] - [260, 25]))) + (file_entry [261, 0] - [270, 25] + file_name: (filename [261, 6] - [261, 60]) + (blame_entry [262, 4] - [262, 23] + line: (number [262, 11] - [262, 12]) + date: (date [262, 13] - [262, 23])) + (blame_entry [263, 4] - [263, 24] + line: (number [263, 11] - [263, 13]) + date: (date [263, 14] - [263, 24])) + (blame_entry [264, 4] - [264, 24] + line: (number [264, 11] - [264, 13]) + date: (date [264, 14] - [264, 24])) + (blame_entry [265, 4] - [265, 24] + line: (number [265, 11] - [265, 13]) + date: (date [265, 14] - [265, 24])) + (blame_entry [266, 4] - [266, 24] + line: (number [266, 11] - [266, 13]) + date: (date [266, 14] - [266, 24])) + (blame_entry [267, 4] - [267, 24] + line: (number [267, 11] - [267, 13]) + date: (date [267, 14] - [267, 24])) + (blame_entry [268, 4] - [268, 25] + line: (number [268, 11] - [268, 14]) + date: (date [268, 15] - [268, 25])) + (blame_entry [269, 4] - [269, 25] + line: (number [269, 11] - [269, 14]) + date: (date [269, 15] - [269, 25])) + (blame_entry [270, 4] - [270, 25] + line: (number [270, 11] - [270, 14]) + date: (date [270, 15] - [270, 25]))) + (file_entry [271, 0] - [272, 24] + file_name: (filename [271, 6] - [271, 61]) + (blame_entry [272, 4] - [272, 24] + line: (number [272, 11] - [272, 13]) + date: (date [272, 14] - [272, 24]))) + (file_entry [273, 0] - [277, 24] + file_name: (filename [273, 6] - [273, 60]) + (blame_entry [274, 4] - [274, 24] + line: (number [274, 11] - [274, 13]) + date: (date [274, 14] - [274, 24])) + (blame_entry [275, 4] - [275, 24] + line: (number [275, 11] - [275, 13]) + date: (date [275, 14] - [275, 24])) + (blame_entry [276, 4] - [276, 24] + line: (number [276, 11] - [276, 13]) + date: (date [276, 14] - [276, 24])) + (blame_entry [277, 4] - [277, 24] + line: (number [277, 11] - [277, 13]) + date: (date [277, 14] - [277, 24]))) + (file_entry [278, 0] - [279, 24] + file_name: (filename [278, 6] - [278, 79]) + (blame_entry [279, 4] - [279, 24] + line: (number [279, 11] - [279, 13]) + date: (date [279, 14] - [279, 24]))) + (file_entry [280, 0] - [282, 25] + file_name: (filename [280, 6] - [280, 80]) + (blame_entry [281, 4] - [281, 25] + line: (number [281, 11] - [281, 14]) + date: (date [281, 15] - [281, 25])) + (blame_entry [282, 4] - [282, 25] + line: (number [282, 11] - [282, 14]) + date: (date [282, 15] - [282, 25]))) + (file_entry [283, 0] - [284, 23] + file_name: (filename [283, 6] - [283, 68]) + (blame_entry [284, 4] - [284, 23] + line: (number [284, 11] - [284, 12]) + date: (date [284, 13] - [284, 23]))) + (file_entry [285, 0] - [287, 24] + file_name: (filename [285, 6] - [285, 68]) + (blame_entry [286, 4] - [286, 23] + line: (number [286, 11] - [286, 12]) + date: (date [286, 13] - [286, 23])) + (blame_entry [287, 4] - [287, 24] + line: (number [287, 11] - [287, 13]) + date: (date [287, 14] - [287, 24]))) + (file_entry [288, 0] - [290, 24] + file_name: (filename [288, 6] - [288, 74]) + (blame_entry [289, 4] - [289, 23] + line: (number [289, 11] - [289, 12]) + date: (date [289, 13] - [289, 23])) + (blame_entry [290, 4] - [290, 24] + line: (number [290, 11] - [290, 13]) + date: (date [290, 14] - [290, 24]))) + (file_entry [291, 0] - [295, 25] + file_name: (filename [291, 6] - [291, 42]) + (blame_entry [292, 4] - [292, 25] + line: (number [292, 11] - [292, 14]) + date: (date [292, 15] - [292, 25])) + (blame_entry [293, 4] - [293, 25] + line: (number [293, 11] - [293, 14]) + date: (date [293, 15] - [293, 25])) + (blame_entry [294, 4] - [294, 25] + line: (number [294, 11] - [294, 14]) + date: (date [294, 15] - [294, 25])) + (blame_entry [295, 4] - [295, 25] + line: (number [295, 11] - [295, 14]) + date: (date [295, 15] - [295, 25]))) + (file_entry [296, 0] - [297, 24] + file_name: (filename [296, 6] - [296, 53]) + (blame_entry [297, 4] - [297, 24] + line: (number [297, 11] - [297, 13]) + date: (date [297, 14] - [297, 24]))) + (file_entry [298, 0] - [303, 25] + file_name: (filename [298, 6] - [298, 49]) + (blame_entry [299, 4] - [299, 24] + line: (number [299, 11] - [299, 13]) + date: (date [299, 14] - [299, 24])) + (blame_entry [300, 4] - [300, 24] + line: (number [300, 11] - [300, 13]) + date: (date [300, 14] - [300, 24])) + (blame_entry [301, 4] - [301, 24] + line: (number [301, 11] - [301, 13]) + date: (date [301, 14] - [301, 24])) + (blame_entry [302, 4] - [302, 25] + line: (number [302, 11] - [302, 14]) + date: (date [302, 15] - [302, 25])) + (blame_entry [303, 4] - [303, 25] + line: (number [303, 11] - [303, 14]) + date: (date [303, 15] - [303, 25]))) + (file_entry [304, 0] - [307, 25] + file_name: (filename [304, 6] - [304, 60]) + (blame_entry [305, 4] - [305, 24] + line: (number [305, 11] - [305, 13]) + date: (date [305, 14] - [305, 24])) + (blame_entry [306, 4] - [306, 24] + line: (number [306, 11] - [306, 13]) + date: (date [306, 14] - [306, 24])) + (blame_entry [307, 4] - [307, 25] + line: (number [307, 11] - [307, 14]) + date: (date [307, 15] - [307, 25]))) + (file_entry [308, 0] - [309, 25] + file_name: (filename [308, 6] - [308, 58]) + (blame_entry [309, 4] - [309, 25] + line: (number [309, 11] - [309, 14]) + date: (date [309, 15] - [309, 25]))) + (file_entry [310, 0] - [313, 24] + file_name: (filename [310, 6] - [310, 63]) + (blame_entry [311, 4] - [311, 23] + line: (number [311, 11] - [311, 12]) + date: (date [311, 13] - [311, 23])) + (blame_entry [312, 4] - [312, 23] + line: (number [312, 11] - [312, 12]) + date: (date [312, 13] - [312, 23])) + (blame_entry [313, 4] - [313, 24] + line: (number [313, 11] - [313, 13]) + date: (date [313, 14] - [313, 24]))) + (file_entry [314, 0] - [318, 25] + file_name: (filename [314, 6] - [314, 45]) + (blame_entry [315, 4] - [315, 24] + line: (number [315, 11] - [315, 13]) + date: (date [315, 14] - [315, 24])) + (blame_entry [316, 4] - [316, 24] + line: (number [316, 11] - [316, 13]) + date: (date [316, 14] - [316, 24])) + (blame_entry [317, 4] - [317, 24] + line: (number [317, 11] - [317, 13]) + date: (date [317, 14] - [317, 24])) + (blame_entry [318, 4] - [318, 25] + line: (number [318, 11] - [318, 14]) + date: (date [318, 15] - [318, 25]))) + (file_entry [319, 0] - [320, 23] + file_name: (filename [319, 6] - [319, 64]) + (blame_entry [320, 4] - [320, 23] + line: (number [320, 11] - [320, 12]) + date: (date [320, 13] - [320, 23]))) + (file_entry [321, 0] - [322, 24] + file_name: (filename [321, 6] - [321, 67]) + (blame_entry [322, 4] - [322, 24] + line: (number [322, 11] - [322, 13]) + date: (date [322, 14] - [322, 24]))) + (file_entry [323, 0] - [324, 24] + file_name: (filename [323, 6] - [323, 73]) + (blame_entry [324, 4] - [324, 24] + line: (number [324, 11] - [324, 13]) + date: (date [324, 14] - [324, 24]))) + (file_entry [325, 0] - [328, 25] + file_name: (filename [325, 6] - [325, 94]) + (blame_entry [326, 4] - [326, 24] + line: (number [326, 11] - [326, 13]) + date: (date [326, 14] - [326, 24])) + (blame_entry [327, 4] - [327, 25] + line: (number [327, 11] - [327, 14]) + date: (date [327, 15] - [327, 25])) + (blame_entry [328, 4] - [328, 25] + line: (number [328, 11] - [328, 14]) + date: (date [328, 15] - [328, 25]))) + (file_entry [329, 0] - [331, 26] + file_name: (filename [329, 6] - [329, 63]) + (blame_entry [330, 4] - [330, 25] + line: (number [330, 11] - [330, 14]) + date: (date [330, 15] - [330, 25])) + (blame_entry [331, 4] - [331, 26] + line: (number [331, 11] - [331, 15]) + date: (date [331, 16] - [331, 26]))) + (file_entry [332, 0] - [336, 24] + file_name: (filename [332, 6] - [332, 43]) + (blame_entry [333, 4] - [333, 24] + line: (number [333, 11] - [333, 13]) + date: (date [333, 14] - [333, 24])) + (blame_entry [334, 4] - [334, 24] + line: (number [334, 11] - [334, 13]) + date: (date [334, 14] - [334, 24])) + (blame_entry [335, 4] - [335, 24] + line: (number [335, 11] - [335, 13]) + date: (date [335, 14] - [335, 24])) + (blame_entry [336, 4] - [336, 24] + line: (number [336, 11] - [336, 13]) + date: (date [336, 14] - [336, 24]))) + (file_entry [337, 0] - [339, 24] + file_name: (filename [337, 6] - [337, 54]) + (blame_entry [338, 4] - [338, 24] + line: (number [338, 11] - [338, 13]) + date: (date [338, 14] - [338, 24])) + (blame_entry [339, 4] - [339, 24] + line: (number [339, 11] - [339, 13]) + date: (date [339, 14] - [339, 24]))) + (file_entry [340, 0] - [343, 25] + file_name: (filename [340, 6] - [340, 110]) + (blame_entry [341, 4] - [341, 24] + line: (number [341, 11] - [341, 13]) + date: (date [341, 14] - [341, 24])) + (blame_entry [342, 4] - [342, 24] + line: (number [342, 11] - [342, 13]) + date: (date [342, 14] - [342, 24])) + (blame_entry [343, 4] - [343, 25] + line: (number [343, 11] - [343, 14]) + date: (date [343, 15] - [343, 25]))) + (file_entry [344, 0] - [346, 25] + file_name: (filename [344, 6] - [344, 80]) + (blame_entry [345, 4] - [345, 25] + line: (number [345, 11] - [345, 14]) + date: (date [345, 15] - [345, 25])) + (blame_entry [346, 4] - [346, 25] + line: (number [346, 11] - [346, 14]) + date: (date [346, 15] - [346, 25]))) + (file_entry [347, 0] - [348, 24] + file_name: (filename [347, 6] - [347, 51]) + (blame_entry [348, 4] - [348, 24] + line: (number [348, 11] - [348, 13]) + date: (date [348, 14] - [348, 24]))) + (file_entry [349, 0] - [350, 24] + file_name: (filename [349, 6] - [349, 48]) + (blame_entry [350, 4] - [350, 24] + line: (number [350, 11] - [350, 13]) + date: (date [350, 14] - [350, 24]))) + (file_entry [351, 0] - [357, 25] + file_name: (filename [351, 6] - [351, 78]) + (blame_entry [352, 4] - [352, 24] + line: (number [352, 11] - [352, 13]) + date: (date [352, 14] - [352, 24])) + (blame_entry [353, 4] - [353, 24] + line: (number [353, 11] - [353, 13]) + date: (date [353, 14] - [353, 24])) + (blame_entry [354, 4] - [354, 24] + line: (number [354, 11] - [354, 13]) + date: (date [354, 14] - [354, 24])) + (blame_entry [355, 4] - [355, 25] + line: (number [355, 11] - [355, 14]) + date: (date [355, 15] - [355, 25])) + (blame_entry [356, 4] - [356, 25] + line: (number [356, 11] - [356, 14]) + date: (date [356, 15] - [356, 25])) + (blame_entry [357, 4] - [357, 25] + line: (number [357, 11] - [357, 14]) + date: (date [357, 15] - [357, 25]))) + (file_entry [358, 0] - [359, 24] + file_name: (filename [358, 6] - [358, 81]) + (blame_entry [359, 4] - [359, 24] + line: (number [359, 11] - [359, 13]) + date: (date [359, 14] - [359, 24]))) + (file_entry [360, 0] - [361, 23] + file_name: (filename [360, 6] - [360, 71]) + (blame_entry [361, 4] - [361, 23] + line: (number [361, 11] - [361, 12]) + date: (date [361, 13] - [361, 23]))) + (file_entry [362, 0] - [363, 24] + file_name: (filename [362, 6] - [362, 81]) + (blame_entry [363, 4] - [363, 24] + line: (number [363, 11] - [363, 13]) + date: (date [363, 14] - [363, 24]))) + (file_entry [364, 0] - [367, 25] + file_name: (filename [364, 6] - [364, 67]) + (blame_entry [365, 4] - [365, 24] + line: (number [365, 11] - [365, 13]) + date: (date [365, 14] - [365, 24])) + (blame_entry [366, 4] - [366, 25] + line: (number [366, 11] - [366, 14]) + date: (date [366, 15] - [366, 25])) + (blame_entry [367, 4] - [367, 25] + line: (number [367, 11] - [367, 14]) + date: (date [367, 15] - [367, 25]))) + (file_entry [368, 0] - [369, 24] + file_name: (filename [368, 6] - [368, 43]) + (blame_entry [369, 4] - [369, 24] + line: (number [369, 11] - [369, 13]) + date: (date [369, 14] - [369, 24]))) + (file_entry [370, 0] - [371, 23] + file_name: (filename [370, 6] - [370, 68]) + (blame_entry [371, 4] - [371, 23] + line: (number [371, 11] - [371, 12]) + date: (date [371, 13] - [371, 23]))) + (file_entry [372, 0] - [378, 24] + file_name: (filename [372, 6] - [372, 47]) + (blame_entry [373, 4] - [373, 23] + line: (number [373, 11] - [373, 12]) + date: (date [373, 13] - [373, 23])) + (blame_entry [374, 4] - [374, 23] + line: (number [374, 11] - [374, 12]) + date: (date [374, 13] - [374, 23])) + (blame_entry [375, 4] - [375, 24] + line: (number [375, 11] - [375, 13]) + date: (date [375, 14] - [375, 24])) + (blame_entry [376, 4] - [376, 24] + line: (number [376, 11] - [376, 13]) + date: (date [376, 14] - [376, 24])) + (blame_entry [377, 4] - [377, 24] + line: (number [377, 11] - [377, 13]) + date: (date [377, 14] - [377, 24])) + (blame_entry [378, 4] - [378, 24] + line: (number [378, 11] - [378, 13]) + date: (date [378, 14] - [378, 24]))) + (file_entry [379, 0] - [386, 25] + file_name: (filename [379, 6] - [379, 55]) + (blame_entry [380, 4] - [380, 25] + line: (number [380, 11] - [380, 14]) + date: (date [380, 15] - [380, 25])) + (blame_entry [381, 4] - [381, 25] + line: (number [381, 11] - [381, 14]) + date: (date [381, 15] - [381, 25])) + (blame_entry [382, 4] - [382, 25] + line: (number [382, 11] - [382, 14]) + date: (date [382, 15] - [382, 25])) + (blame_entry [383, 4] - [383, 25] + line: (number [383, 11] - [383, 14]) + date: (date [383, 15] - [383, 25])) + (blame_entry [384, 4] - [384, 25] + line: (number [384, 11] - [384, 14]) + date: (date [384, 15] - [384, 25])) + (blame_entry [385, 4] - [385, 25] + line: (number [385, 11] - [385, 14]) + date: (date [385, 15] - [385, 25])) + (blame_entry [386, 4] - [386, 25] + line: (number [386, 11] - [386, 14]) + date: (date [386, 15] - [386, 25]))) + (file_entry [387, 0] - [389, 24] + file_name: (filename [387, 6] - [387, 54]) + (blame_entry [388, 4] - [388, 24] + line: (number [388, 11] - [388, 13]) + date: (date [388, 14] - [388, 24])) + (blame_entry [389, 4] - [389, 24] + line: (number [389, 11] - [389, 13]) + date: (date [389, 14] - [389, 24]))) + (file_entry [390, 0] - [391, 25] + file_name: (filename [390, 6] - [390, 51]) + (blame_entry [391, 4] - [391, 25] + line: (number [391, 11] - [391, 14]) + date: (date [391, 15] - [391, 25]))) + (file_entry [392, 0] - [395, 25] + file_name: (filename [392, 6] - [392, 65]) + (blame_entry [393, 4] - [393, 25] + line: (number [393, 11] - [393, 14]) + date: (date [393, 15] - [393, 25])) + (blame_entry [394, 4] - [394, 25] + line: (number [394, 11] - [394, 14]) + date: (date [394, 15] - [394, 25])) + (blame_entry [395, 4] - [395, 25] + line: (number [395, 11] - [395, 14]) + date: (date [395, 15] - [395, 25]))) + (file_entry [396, 0] - [398, 25] + file_name: (filename [396, 6] - [396, 51]) + (blame_entry [397, 4] - [397, 25] + line: (number [397, 11] - [397, 14]) + date: (date [397, 15] - [397, 25])) + (blame_entry [398, 4] - [398, 25] + line: (number [398, 11] - [398, 14]) + date: (date [398, 15] - [398, 25]))) + (file_entry [399, 0] - [404, 25] + file_name: (filename [399, 6] - [399, 60]) + (blame_entry [400, 4] - [400, 24] + line: (number [400, 11] - [400, 13]) + date: (date [400, 14] - [400, 24])) + (blame_entry [401, 4] - [401, 24] + line: (number [401, 11] - [401, 13]) + date: (date [401, 14] - [401, 24])) + (blame_entry [402, 4] - [402, 25] + line: (number [402, 11] - [402, 14]) + date: (date [402, 15] - [402, 25])) + (blame_entry [403, 4] - [403, 25] + line: (number [403, 11] - [403, 14]) + date: (date [403, 15] - [403, 25])) + (blame_entry [404, 4] - [404, 25] + line: (number [404, 11] - [404, 14]) + date: (date [404, 15] - [404, 25]))) + (file_entry [405, 0] - [407, 24] + file_name: (filename [405, 6] - [405, 67]) + (blame_entry [406, 4] - [406, 23] + line: (number [406, 11] - [406, 12]) + date: (date [406, 13] - [406, 23])) + (blame_entry [407, 4] - [407, 24] + line: (number [407, 11] - [407, 13]) + date: (date [407, 14] - [407, 24]))) + (file_entry [408, 0] - [409, 23] + file_name: (filename [408, 6] - [408, 72]) + (blame_entry [409, 4] - [409, 23] + line: (number [409, 11] - [409, 12]) + date: (date [409, 13] - [409, 23]))) + (file_entry [410, 0] - [413, 24] + file_name: (filename [410, 6] - [410, 57]) + (blame_entry [411, 4] - [411, 23] + line: (number [411, 11] - [411, 12]) + date: (date [411, 13] - [411, 23])) + (blame_entry [412, 4] - [412, 24] + line: (number [412, 11] - [412, 13]) + date: (date [412, 14] - [412, 24])) + (blame_entry [413, 4] - [413, 24] + line: (number [413, 11] - [413, 13]) + date: (date [413, 14] - [413, 24]))) + (file_entry [414, 0] - [418, 25] + file_name: (filename [414, 6] - [414, 87]) + (blame_entry [415, 4] - [415, 25] + line: (number [415, 11] - [415, 14]) + date: (date [415, 15] - [415, 25])) + (blame_entry [416, 4] - [416, 25] + line: (number [416, 11] - [416, 14]) + date: (date [416, 15] - [416, 25])) + (blame_entry [417, 4] - [417, 25] + line: (number [417, 11] - [417, 14]) + date: (date [417, 15] - [417, 25])) + (blame_entry [418, 4] - [418, 25] + line: (number [418, 11] - [418, 14]) + date: (date [418, 15] - [418, 25]))) + (file_entry [419, 0] - [423, 25] + file_name: (filename [419, 6] - [419, 68]) + (blame_entry [420, 4] - [420, 24] + line: (number [420, 11] - [420, 13]) + date: (date [420, 14] - [420, 24])) + (blame_entry [421, 4] - [421, 25] + line: (number [421, 11] - [421, 14]) + date: (date [421, 15] - [421, 25])) + (blame_entry [422, 4] - [422, 25] + line: (number [422, 11] - [422, 14]) + date: (date [422, 15] - [422, 25])) + (blame_entry [423, 4] - [423, 25] + line: (number [423, 11] - [423, 14]) + date: (date [423, 15] - [423, 25]))) + (file_entry [424, 0] - [426, 24] + file_name: (filename [424, 6] - [424, 65]) + (blame_entry [425, 4] - [425, 24] + line: (number [425, 11] - [425, 13]) + date: (date [425, 14] - [425, 24])) + (blame_entry [426, 4] - [426, 24] + line: (number [426, 11] - [426, 13]) + date: (date [426, 14] - [426, 24]))) + (file_entry [427, 0] - [428, 24] + file_name: (filename [427, 6] - [427, 89]) + (blame_entry [428, 4] - [428, 24] + line: (number [428, 11] - [428, 13]) + date: (date [428, 14] - [428, 24]))) + (file_entry [429, 0] - [430, 23] + file_name: (filename [429, 6] - [429, 71]) + (blame_entry [430, 4] - [430, 23] + line: (number [430, 11] - [430, 12]) + date: (date [430, 13] - [430, 23]))) + (file_entry [431, 0] - [435, 25] + file_name: (filename [431, 6] - [431, 70]) + (blame_entry [432, 4] - [432, 24] + line: (number [432, 11] - [432, 13]) + date: (date [432, 14] - [432, 24])) + (blame_entry [433, 4] - [433, 25] + line: (number [433, 11] - [433, 14]) + date: (date [433, 15] - [433, 25])) + (blame_entry [434, 4] - [434, 25] + line: (number [434, 11] - [434, 14]) + date: (date [434, 15] - [434, 25])) + (blame_entry [435, 4] - [435, 25] + line: (number [435, 11] - [435, 14]) + date: (date [435, 15] - [435, 25]))) + (file_entry [436, 0] - [437, 23] + file_name: (filename [436, 6] - [436, 84]) + (blame_entry [437, 4] - [437, 23] + line: (number [437, 11] - [437, 12]) + date: (date [437, 13] - [437, 23]))) + (file_entry [438, 0] - [439, 24] + file_name: (filename [438, 6] - [438, 87]) + (blame_entry [439, 4] - [439, 24] + line: (number [439, 11] - [439, 13]) + date: (date [439, 14] - [439, 24]))) + (file_entry [440, 0] - [448, 25] + file_name: (filename [440, 6] - [440, 66]) + (blame_entry [441, 4] - [441, 23] + line: (number [441, 11] - [441, 12]) + date: (date [441, 13] - [441, 23])) + (blame_entry [442, 4] - [442, 24] + line: (number [442, 11] - [442, 13]) + date: (date [442, 14] - [442, 24])) + (blame_entry [443, 4] - [443, 24] + line: (number [443, 11] - [443, 13]) + date: (date [443, 14] - [443, 24])) + (blame_entry [444, 4] - [444, 24] + line: (number [444, 11] - [444, 13]) + date: (date [444, 14] - [444, 24])) + (blame_entry [445, 4] - [445, 25] + line: (number [445, 11] - [445, 14]) + date: (date [445, 15] - [445, 25])) + (blame_entry [446, 4] - [446, 25] + line: (number [446, 11] - [446, 14]) + date: (date [446, 15] - [446, 25])) + (blame_entry [447, 4] - [447, 25] + line: (number [447, 11] - [447, 14]) + date: (date [447, 15] - [447, 25])) + (blame_entry [448, 4] - [448, 25] + line: (number [448, 11] - [448, 14]) + date: (date [448, 15] - [448, 25]))) + (file_entry [449, 0] - [453, 25] + file_name: (filename [449, 6] - [449, 70]) + (blame_entry [450, 4] - [450, 24] + line: (number [450, 11] - [450, 13]) + date: (date [450, 14] - [450, 24])) + (blame_entry [451, 4] - [451, 25] + line: (number [451, 11] - [451, 14]) + date: (date [451, 15] - [451, 25])) + (blame_entry [452, 4] - [452, 25] + line: (number [452, 11] - [452, 14]) + date: (date [452, 15] - [452, 25])) + (blame_entry [453, 4] - [453, 25] + line: (number [453, 11] - [453, 14]) + date: (date [453, 15] - [453, 25]))) + (file_entry [454, 0] - [458, 25] + file_name: (filename [454, 6] - [454, 68]) + (blame_entry [455, 4] - [455, 24] + line: (number [455, 11] - [455, 13]) + date: (date [455, 14] - [455, 24])) + (blame_entry [456, 4] - [456, 25] + line: (number [456, 11] - [456, 14]) + date: (date [456, 15] - [456, 25])) + (blame_entry [457, 4] - [457, 25] + line: (number [457, 11] - [457, 14]) + date: (date [457, 15] - [457, 25])) + (blame_entry [458, 4] - [458, 25] + line: (number [458, 11] - [458, 14]) + date: (date [458, 15] - [458, 25]))) + (file_entry [459, 0] - [461, 24] + file_name: (filename [459, 6] - [459, 42]) + (blame_entry [460, 4] - [460, 24] + line: (number [460, 11] - [460, 13]) + date: (date [460, 14] - [460, 24])) + (blame_entry [461, 4] - [461, 24] + line: (number [461, 11] - [461, 13]) + date: (date [461, 14] - [461, 24]))) + (file_entry [462, 0] - [463, 24] + file_name: (filename [462, 6] - [462, 34]) + (blame_entry [463, 4] - [463, 24] + line: (number [463, 11] - [463, 13]) + date: (date [463, 14] - [463, 24]))) + (file_entry [464, 0] - [470, 25] + file_name: (filename [464, 6] - [464, 59]) + (blame_entry [465, 4] - [465, 24] + line: (number [465, 11] - [465, 13]) + date: (date [465, 14] - [465, 24])) + (blame_entry [466, 4] - [466, 24] + line: (number [466, 11] - [466, 13]) + date: (date [466, 14] - [466, 24])) + (blame_entry [467, 4] - [467, 24] + line: (number [467, 11] - [467, 13]) + date: (date [467, 14] - [467, 24])) + (blame_entry [468, 4] - [468, 25] + line: (number [468, 11] - [468, 14]) + date: (date [468, 15] - [468, 25])) + (blame_entry [469, 4] - [469, 25] + line: (number [469, 11] - [469, 14]) + date: (date [469, 15] - [469, 25])) + (blame_entry [470, 4] - [470, 25] + line: (number [470, 11] - [470, 14]) + date: (date [470, 15] - [470, 25]))) + (file_entry [471, 0] - [473, 24] + file_name: (filename [471, 6] - [471, 90]) + (blame_entry [472, 4] - [472, 24] + line: (number [472, 11] - [472, 13]) + date: (date [472, 14] - [472, 24])) + (blame_entry [473, 4] - [473, 24] + line: (number [473, 11] - [473, 13]) + date: (date [473, 14] - [473, 24]))) + (file_entry [474, 0] - [475, 24] + file_name: (filename [474, 6] - [474, 72]) + (blame_entry [475, 4] - [475, 24] + line: (number [475, 11] - [475, 13]) + date: (date [475, 14] - [475, 24]))) + (file_entry [476, 0] - [477, 23] + file_name: (filename [476, 6] - [476, 80]) + (blame_entry [477, 4] - [477, 23] + line: (number [477, 11] - [477, 12]) + date: (date [477, 13] - [477, 23]))) + (file_entry [478, 0] - [479, 24] + file_name: (filename [478, 6] - [478, 75]) + (blame_entry [479, 4] - [479, 24] + line: (number [479, 11] - [479, 13]) + date: (date [479, 14] - [479, 24]))) + (file_entry [480, 0] - [481, 24] + file_name: (filename [480, 6] - [480, 67]) + (blame_entry [481, 4] - [481, 24] + line: (number [481, 11] - [481, 13]) + date: (date [481, 14] - [481, 24]))) + (file_entry [482, 0] - [483, 24] + file_name: (filename [482, 6] - [482, 77]) + (blame_entry [483, 4] - [483, 24] + line: (number [483, 11] - [483, 13]) + date: (date [483, 14] - [483, 24]))) + (file_entry [484, 0] - [485, 25] + file_name: (filename [484, 6] - [484, 62]) + (blame_entry [485, 4] - [485, 25] + line: (number [485, 11] - [485, 14]) + date: (date [485, 15] - [485, 25]))) + (file_entry [486, 0] - [488, 25] + file_name: (filename [486, 6] - [486, 49]) + (blame_entry [487, 4] - [487, 24] + line: (number [487, 11] - [487, 13]) + date: (date [487, 14] - [487, 24])) + (blame_entry [488, 4] - [488, 25] + line: (number [488, 11] - [488, 14]) + date: (date [488, 15] - [488, 25]))) + (file_entry [489, 0] - [491, 24] + file_name: (filename [489, 6] - [489, 101]) + (blame_entry [490, 4] - [490, 23] + line: (number [490, 11] - [490, 12]) + date: (date [490, 13] - [490, 23])) + (blame_entry [491, 4] - [491, 24] + line: (number [491, 11] - [491, 13]) + date: (date [491, 14] - [491, 24]))) + (file_entry [492, 0] - [493, 24] + file_name: (filename [492, 6] - [492, 70]) + (blame_entry [493, 4] - [493, 24] + line: (number [493, 11] - [493, 13]) + date: (date [493, 14] - [493, 24]))) + (file_entry [494, 0] - [498, 25] + file_name: (filename [494, 6] - [494, 92]) + (blame_entry [495, 4] - [495, 25] + line: (number [495, 11] - [495, 14]) + date: (date [495, 15] - [495, 25])) + (blame_entry [496, 4] - [496, 25] + line: (number [496, 11] - [496, 14]) + date: (date [496, 15] - [496, 25])) + (blame_entry [497, 4] - [497, 25] + line: (number [497, 11] - [497, 14]) + date: (date [497, 15] - [497, 25])) + (blame_entry [498, 4] - [498, 25] + line: (number [498, 11] - [498, 14]) + date: (date [498, 15] - [498, 25]))) + (file_entry [499, 0] - [507, 24] + file_name: (filename [499, 6] - [499, 58]) + (blame_entry [500, 4] - [500, 24] + line: (number [500, 11] - [500, 13]) + date: (date [500, 14] - [500, 24])) + (blame_entry [501, 4] - [501, 24] + line: (number [501, 11] - [501, 13]) + date: (date [501, 14] - [501, 24])) + (blame_entry [502, 4] - [502, 24] + line: (number [502, 11] - [502, 13]) + date: (date [502, 14] - [502, 24])) + (blame_entry [503, 4] - [503, 24] + line: (number [503, 11] - [503, 13]) + date: (date [503, 14] - [503, 24])) + (blame_entry [504, 4] - [504, 24] + line: (number [504, 11] - [504, 13]) + date: (date [504, 14] - [504, 24])) + (blame_entry [505, 4] - [505, 24] + line: (number [505, 11] - [505, 13]) + date: (date [505, 14] - [505, 24])) + (blame_entry [506, 4] - [506, 24] + line: (number [506, 11] - [506, 13]) + date: (date [506, 14] - [506, 24])) + (blame_entry [507, 4] - [507, 24] + line: (number [507, 11] - [507, 13]) + date: (date [507, 14] - [507, 24]))) + (file_entry [508, 0] - [512, 25] + file_name: (filename [508, 6] - [508, 92]) + (blame_entry [509, 4] - [509, 25] + line: (number [509, 11] - [509, 14]) + date: (date [509, 15] - [509, 25])) + (blame_entry [510, 4] - [510, 25] + line: (number [510, 11] - [510, 14]) + date: (date [510, 15] - [510, 25])) + (blame_entry [511, 4] - [511, 25] + line: (number [511, 11] - [511, 14]) + date: (date [511, 15] - [511, 25])) + (blame_entry [512, 4] - [512, 25] + line: (number [512, 11] - [512, 14]) + date: (date [512, 15] - [512, 25]))) + (file_entry [513, 0] - [515, 24] + file_name: (filename [513, 6] - [513, 77]) + (blame_entry [514, 4] - [514, 23] + line: (number [514, 11] - [514, 12]) + date: (date [514, 13] - [514, 23])) + (blame_entry [515, 4] - [515, 24] + line: (number [515, 11] - [515, 13]) + date: (date [515, 14] - [515, 24]))) + (file_entry [516, 0] - [520, 25] + file_name: (filename [516, 6] - [516, 70]) + (blame_entry [517, 4] - [517, 24] + line: (number [517, 11] - [517, 13]) + date: (date [517, 14] - [517, 24])) + (blame_entry [518, 4] - [518, 25] + line: (number [518, 11] - [518, 14]) + date: (date [518, 15] - [518, 25])) + (blame_entry [519, 4] - [519, 25] + line: (number [519, 11] - [519, 14]) + date: (date [519, 15] - [519, 25])) + (blame_entry [520, 4] - [520, 25] + line: (number [520, 11] - [520, 14]) + date: (date [520, 15] - [520, 25]))) + (file_entry [521, 0] - [524, 25] + file_name: (filename [521, 6] - [521, 46]) + (blame_entry [522, 4] - [522, 25] + line: (number [522, 11] - [522, 14]) + date: (date [522, 15] - [522, 25])) + (blame_entry [523, 4] - [523, 25] + line: (number [523, 11] - [523, 14]) + date: (date [523, 15] - [523, 25])) + (blame_entry [524, 4] - [524, 25] + line: (number [524, 11] - [524, 14]) + date: (date [524, 15] - [524, 25]))) + (file_entry [525, 0] - [526, 24] + file_name: (filename [525, 6] - [525, 52]) + (blame_entry [526, 4] - [526, 24] + line: (number [526, 11] - [526, 13]) + date: (date [526, 14] - [526, 24]))) + (file_entry [527, 0] - [532, 25] + file_name: (filename [527, 6] - [527, 66]) + (blame_entry [528, 4] - [528, 24] + line: (number [528, 11] - [528, 13]) + date: (date [528, 14] - [528, 24])) + (blame_entry [529, 4] - [529, 24] + line: (number [529, 11] - [529, 13]) + date: (date [529, 14] - [529, 24])) + (blame_entry [530, 4] - [530, 25] + line: (number [530, 11] - [530, 14]) + date: (date [530, 15] - [530, 25])) + (blame_entry [531, 4] - [531, 25] + line: (number [531, 11] - [531, 14]) + date: (date [531, 15] - [531, 25])) + (blame_entry [532, 4] - [532, 25] + line: (number [532, 11] - [532, 14]) + date: (date [532, 15] - [532, 25]))) + (file_entry [533, 0] - [540, 25] + file_name: (filename [533, 6] - [533, 77]) + (blame_entry [534, 4] - [534, 25] + line: (number [534, 11] - [534, 14]) + date: (date [534, 15] - [534, 25])) + (blame_entry [535, 4] - [535, 25] + line: (number [535, 11] - [535, 14]) + date: (date [535, 15] - [535, 25])) + (blame_entry [536, 4] - [536, 25] + line: (number [536, 11] - [536, 14]) + date: (date [536, 15] - [536, 25])) + (blame_entry [537, 4] - [537, 25] + line: (number [537, 11] - [537, 14]) + date: (date [537, 15] - [537, 25])) + (blame_entry [538, 4] - [538, 25] + line: (number [538, 11] - [538, 14]) + date: (date [538, 15] - [538, 25])) + (blame_entry [539, 4] - [539, 25] + line: (number [539, 11] - [539, 14]) + date: (date [539, 15] - [539, 25])) + (blame_entry [540, 4] - [540, 25] + line: (number [540, 11] - [540, 14]) + date: (date [540, 15] - [540, 25]))) + (file_entry [541, 0] - [546, 25] + file_name: (filename [541, 6] - [541, 45]) + (blame_entry [542, 4] - [542, 24] + line: (number [542, 11] - [542, 13]) + date: (date [542, 14] - [542, 24])) + (blame_entry [543, 4] - [543, 25] + line: (number [543, 11] - [543, 14]) + date: (date [543, 15] - [543, 25])) + (blame_entry [544, 4] - [544, 25] + line: (number [544, 11] - [544, 14]) + date: (date [544, 15] - [544, 25])) + (blame_entry [545, 4] - [545, 25] + line: (number [545, 11] - [545, 14]) + date: (date [545, 15] - [545, 25])) + (blame_entry [546, 4] - [546, 25] + line: (number [546, 11] - [546, 14]) + date: (date [546, 15] - [546, 25]))) + (file_entry [547, 0] - [549, 24] + file_name: (filename [547, 6] - [547, 68]) + (blame_entry [548, 4] - [548, 23] + line: (number [548, 11] - [548, 12]) + date: (date [548, 13] - [548, 23])) + (blame_entry [549, 4] - [549, 24] + line: (number [549, 11] - [549, 13]) + date: (date [549, 14] - [549, 24]))) + (file_entry [550, 0] - [551, 25] + file_name: (filename [550, 6] - [550, 82]) + (blame_entry [551, 4] - [551, 25] + line: (number [551, 11] - [551, 14]) + date: (date [551, 15] - [551, 25]))) + (file_entry [552, 0] - [559, 25] + file_name: (filename [552, 6] - [552, 51]) + (blame_entry [553, 4] - [553, 24] + line: (number [553, 11] - [553, 13]) + date: (date [553, 14] - [553, 24])) + (blame_entry [554, 4] - [554, 25] + line: (number [554, 11] - [554, 14]) + date: (date [554, 15] - [554, 25])) + (blame_entry [555, 4] - [555, 25] + line: (number [555, 11] - [555, 14]) + date: (date [555, 15] - [555, 25])) + (blame_entry [556, 4] - [556, 25] + line: (number [556, 11] - [556, 14]) + date: (date [556, 15] - [556, 25])) + (blame_entry [557, 4] - [557, 25] + line: (number [557, 11] - [557, 14]) + date: (date [557, 15] - [557, 25])) + (blame_entry [558, 4] - [558, 25] + line: (number [558, 11] - [558, 14]) + date: (date [558, 15] - [558, 25])) + (blame_entry [559, 4] - [559, 25] + line: (number [559, 11] - [559, 14]) + date: (date [559, 15] - [559, 25]))) + (file_entry [560, 0] - [561, 24] + file_name: (filename [560, 6] - [560, 53]) + (blame_entry [561, 4] - [561, 24] + line: (number [561, 11] - [561, 13]) + date: (date [561, 14] - [561, 24]))) + (file_entry [562, 0] - [566, 25] + file_name: (filename [562, 6] - [562, 91]) + (blame_entry [563, 4] - [563, 24] + line: (number [563, 11] - [563, 13]) + date: (date [563, 14] - [563, 24])) + (blame_entry [564, 4] - [564, 25] + line: (number [564, 11] - [564, 14]) + date: (date [564, 15] - [564, 25])) + (blame_entry [565, 4] - [565, 25] + line: (number [565, 11] - [565, 14]) + date: (date [565, 15] - [565, 25])) + (blame_entry [566, 4] - [566, 25] + line: (number [566, 11] - [566, 14]) + date: (date [566, 15] - [566, 25]))) + (file_entry [567, 0] - [570, 23] + file_name: (filename [567, 6] - [567, 54]) + (blame_entry [568, 4] - [568, 23] + line: (number [568, 11] - [568, 12]) + date: (date [568, 13] - [568, 23])) + (blame_entry [569, 4] - [569, 23] + line: (number [569, 11] - [569, 12]) + date: (date [569, 13] - [569, 23])) + (blame_entry [570, 4] - [570, 23] + line: (number [570, 11] - [570, 12]) + date: (date [570, 13] - [570, 23]))) + (file_entry [571, 0] - [575, 25] + file_name: (filename [571, 6] - [571, 92]) + (blame_entry [572, 4] - [572, 25] + line: (number [572, 11] - [572, 14]) + date: (date [572, 15] - [572, 25])) + (blame_entry [573, 4] - [573, 25] + line: (number [573, 11] - [573, 14]) + date: (date [573, 15] - [573, 25])) + (blame_entry [574, 4] - [574, 25] + line: (number [574, 11] - [574, 14]) + date: (date [574, 15] - [574, 25])) + (blame_entry [575, 4] - [575, 25] + line: (number [575, 11] - [575, 14]) + date: (date [575, 15] - [575, 25]))) + (file_entry [576, 0] - [589, 25] + file_name: (filename [576, 6] - [576, 40]) + (blame_entry [577, 4] - [577, 24] + line: (number [577, 11] - [577, 13]) + date: (date [577, 14] - [577, 24])) + (blame_entry [578, 4] - [578, 24] + line: (number [578, 11] - [578, 13]) + date: (date [578, 14] - [578, 24])) + (blame_entry [579, 4] - [579, 25] + line: (number [579, 11] - [579, 14]) + date: (date [579, 15] - [579, 25])) + (blame_entry [580, 4] - [580, 25] + line: (number [580, 11] - [580, 14]) + date: (date [580, 15] - [580, 25])) + (blame_entry [581, 4] - [581, 25] + line: (number [581, 11] - [581, 14]) + date: (date [581, 15] - [581, 25])) + (blame_entry [582, 4] - [582, 25] + line: (number [582, 11] - [582, 14]) + date: (date [582, 15] - [582, 25])) + (blame_entry [583, 4] - [583, 25] + line: (number [583, 11] - [583, 14]) + date: (date [583, 15] - [583, 25])) + (blame_entry [584, 4] - [584, 25] + line: (number [584, 11] - [584, 14]) + date: (date [584, 15] - [584, 25])) + (blame_entry [585, 4] - [585, 25] + line: (number [585, 11] - [585, 14]) + date: (date [585, 15] - [585, 25])) + (blame_entry [586, 4] - [586, 25] + line: (number [586, 11] - [586, 14]) + date: (date [586, 15] - [586, 25])) + (blame_entry [587, 4] - [587, 25] + line: (number [587, 11] - [587, 14]) + date: (date [587, 15] - [587, 25])) + (blame_entry [588, 4] - [588, 25] + line: (number [588, 11] - [588, 14]) + date: (date [588, 15] - [588, 25])) + (blame_entry [589, 4] - [589, 25] + line: (number [589, 11] - [589, 14]) + date: (date [589, 15] - [589, 25]))) + (file_entry [590, 0] - [593, 24] + file_name: (filename [590, 6] - [590, 80]) + (blame_entry [591, 4] - [591, 24] + line: (number [591, 11] - [591, 13]) + date: (date [591, 14] - [591, 24])) + (blame_entry [592, 4] - [592, 24] + line: (number [592, 11] - [592, 13]) + date: (date [592, 14] - [592, 24])) + (blame_entry [593, 4] - [593, 24] + line: (number [593, 11] - [593, 13]) + date: (date [593, 14] - [593, 24]))) + (file_entry [594, 0] - [596, 24] + file_name: (filename [594, 6] - [594, 56]) + (blame_entry [595, 4] - [595, 23] + line: (number [595, 11] - [595, 12]) + date: (date [595, 13] - [595, 23])) + (blame_entry [596, 4] - [596, 24] + line: (number [596, 11] - [596, 13]) + date: (date [596, 14] - [596, 24]))) + (file_entry [597, 0] - [598, 24] + file_name: (filename [597, 6] - [597, 50]) + (blame_entry [598, 4] - [598, 24] + line: (number [598, 11] - [598, 13]) + date: (date [598, 14] - [598, 24]))) + (file_entry [599, 0] - [600, 24] + file_name: (filename [599, 6] - [599, 82]) + (blame_entry [600, 4] - [600, 24] + line: (number [600, 11] - [600, 13]) + date: (date [600, 14] - [600, 24]))) + (file_entry [601, 0] - [602, 24] + file_name: (filename [601, 6] - [601, 73]) + (blame_entry [602, 4] - [602, 24] + line: (number [602, 11] - [602, 13]) + date: (date [602, 14] - [602, 24]))) + (file_entry [603, 0] - [621, 25] + file_name: (filename [603, 6] - [603, 59]) + (blame_entry [604, 4] - [604, 24] + line: (number [604, 11] - [604, 13]) + date: (date [604, 14] - [604, 24])) + (blame_entry [605, 4] - [605, 25] + line: (number [605, 11] - [605, 14]) + date: (date [605, 15] - [605, 25])) + (blame_entry [606, 4] - [606, 25] + line: (number [606, 11] - [606, 14]) + date: (date [606, 15] - [606, 25])) + (blame_entry [607, 4] - [607, 25] + line: (number [607, 11] - [607, 14]) + date: (date [607, 15] - [607, 25])) + (blame_entry [608, 4] - [608, 25] + line: (number [608, 11] - [608, 14]) + date: (date [608, 15] - [608, 25])) + (blame_entry [609, 4] - [609, 25] + line: (number [609, 11] - [609, 14]) + date: (date [609, 15] - [609, 25])) + (blame_entry [610, 4] - [610, 25] + line: (number [610, 11] - [610, 14]) + date: (date [610, 15] - [610, 25])) + (blame_entry [611, 4] - [611, 25] + line: (number [611, 11] - [611, 14]) + date: (date [611, 15] - [611, 25])) + (blame_entry [612, 4] - [612, 25] + line: (number [612, 11] - [612, 14]) + date: (date [612, 15] - [612, 25])) + (blame_entry [613, 4] - [613, 25] + line: (number [613, 11] - [613, 14]) + date: (date [613, 15] - [613, 25])) + (blame_entry [614, 4] - [614, 25] + line: (number [614, 11] - [614, 14]) + date: (date [614, 15] - [614, 25])) + (blame_entry [615, 4] - [615, 25] + line: (number [615, 11] - [615, 14]) + date: (date [615, 15] - [615, 25])) + (blame_entry [616, 4] - [616, 25] + line: (number [616, 11] - [616, 14]) + date: (date [616, 15] - [616, 25])) + (blame_entry [617, 4] - [617, 25] + line: (number [617, 11] - [617, 14]) + date: (date [617, 15] - [617, 25])) + (blame_entry [618, 4] - [618, 25] + line: (number [618, 11] - [618, 14]) + date: (date [618, 15] - [618, 25])) + (blame_entry [619, 4] - [619, 25] + line: (number [619, 11] - [619, 14]) + date: (date [619, 15] - [619, 25])) + (blame_entry [620, 4] - [620, 25] + line: (number [620, 11] - [620, 14]) + date: (date [620, 15] - [620, 25])) + (blame_entry [621, 4] - [621, 25] + line: (number [621, 11] - [621, 14]) + date: (date [621, 15] - [621, 25]))) + (file_entry [622, 0] - [623, 24] + file_name: (filename [622, 6] - [622, 50]) + (blame_entry [623, 4] - [623, 24] + line: (number [623, 11] - [623, 13]) + date: (date [623, 14] - [623, 24]))) + (file_entry [624, 0] - [625, 25] + file_name: (filename [624, 6] - [624, 59]) + (blame_entry [625, 4] - [625, 25] + line: (number [625, 11] - [625, 14]) + date: (date [625, 15] - [625, 25]))) + (file_entry [626, 0] - [628, 25] + file_name: (filename [626, 6] - [626, 76]) + (blame_entry [627, 4] - [627, 24] + line: (number [627, 11] - [627, 13]) + date: (date [627, 14] - [627, 24])) + (blame_entry [628, 4] - [628, 25] + line: (number [628, 11] - [628, 14]) + date: (date [628, 15] - [628, 25]))) + (file_entry [629, 0] - [631, 24] + file_name: (filename [629, 6] - [629, 68]) + (blame_entry [630, 4] - [630, 23] + line: (number [630, 11] - [630, 12]) + date: (date [630, 13] - [630, 23])) + (blame_entry [631, 4] - [631, 24] + line: (number [631, 11] - [631, 13]) + date: (date [631, 14] - [631, 24]))) + (file_entry [632, 0] - [633, 24] + file_name: (filename [632, 6] - [632, 69]) + (blame_entry [633, 4] - [633, 24] + line: (number [633, 11] - [633, 13]) + date: (date [633, 14] - [633, 24]))) + (file_entry [634, 0] - [635, 24] + file_name: (filename [634, 6] - [634, 82]) + (blame_entry [635, 4] - [635, 24] + line: (number [635, 11] - [635, 13]) + date: (date [635, 14] - [635, 24]))) + (file_entry [636, 0] - [639, 25] + file_name: (filename [636, 6] - [636, 62]) + (blame_entry [637, 4] - [637, 25] + line: (number [637, 11] - [637, 14]) + date: (date [637, 15] - [637, 25])) + (blame_entry [638, 4] - [638, 25] + line: (number [638, 11] - [638, 14]) + date: (date [638, 15] - [638, 25])) + (blame_entry [639, 4] - [639, 25] + line: (number [639, 11] - [639, 14]) + date: (date [639, 15] - [639, 25]))) + (file_entry [640, 0] - [641, 24] + file_name: (filename [640, 6] - [640, 82]) + (blame_entry [641, 4] - [641, 24] + line: (number [641, 11] - [641, 13]) + date: (date [641, 14] - [641, 24]))) + (file_entry [642, 0] - [644, 24] + file_name: (filename [642, 6] - [642, 62]) + (blame_entry [643, 4] - [643, 24] + line: (number [643, 11] - [643, 13]) + date: (date [643, 14] - [643, 24])) + (blame_entry [644, 4] - [644, 24] + line: (number [644, 11] - [644, 13]) + date: (date [644, 14] - [644, 24]))) + (file_entry [645, 0] - [650, 24] + file_name: (filename [645, 6] - [645, 54]) + (blame_entry [646, 4] - [646, 23] + line: (number [646, 11] - [646, 12]) + date: (date [646, 13] - [646, 23])) + (blame_entry [647, 4] - [647, 24] + line: (number [647, 11] - [647, 13]) + date: (date [647, 14] - [647, 24])) + (blame_entry [648, 4] - [648, 24] + line: (number [648, 11] - [648, 13]) + date: (date [648, 14] - [648, 24])) + (blame_entry [649, 4] - [649, 24] + line: (number [649, 11] - [649, 13]) + date: (date [649, 14] - [649, 24])) + (blame_entry [650, 4] - [650, 24] + line: (number [650, 11] - [650, 13]) + date: (date [650, 14] - [650, 24]))) + (file_entry [651, 0] - [656, 26] + file_name: (filename [651, 6] - [651, 91]) + (blame_entry [652, 4] - [652, 25] + line: (number [652, 11] - [652, 14]) + date: (date [652, 15] - [652, 25])) + (blame_entry [653, 4] - [653, 25] + line: (number [653, 11] - [653, 14]) + date: (date [653, 15] - [653, 25])) + (blame_entry [654, 4] - [654, 26] + line: (number [654, 11] - [654, 15]) + date: (date [654, 16] - [654, 26])) + (blame_entry [655, 4] - [655, 26] + line: (number [655, 11] - [655, 15]) + date: (date [655, 16] - [655, 26])) + (blame_entry [656, 4] - [656, 26] + line: (number [656, 11] - [656, 15]) + date: (date [656, 16] - [656, 26]))) + (file_entry [657, 0] - [661, 25] + file_name: (filename [657, 6] - [657, 93]) + (blame_entry [658, 4] - [658, 25] + line: (number [658, 11] - [658, 14]) + date: (date [658, 15] - [658, 25])) + (blame_entry [659, 4] - [659, 25] + line: (number [659, 11] - [659, 14]) + date: (date [659, 15] - [659, 25])) + (blame_entry [660, 4] - [660, 25] + line: (number [660, 11] - [660, 14]) + date: (date [660, 15] - [660, 25])) + (blame_entry [661, 4] - [661, 25] + line: (number [661, 11] - [661, 14]) + date: (date [661, 15] - [661, 25]))) + (file_entry [662, 0] - [664, 25] + file_name: (filename [662, 6] - [662, 70]) + (blame_entry [663, 4] - [663, 25] + line: (number [663, 11] - [663, 14]) + date: (date [663, 15] - [663, 25])) + (blame_entry [664, 4] - [664, 25] + line: (number [664, 11] - [664, 14]) + date: (date [664, 15] - [664, 25]))) + (file_entry [665, 0] - [669, 25] + file_name: (filename [665, 6] - [665, 61]) + (blame_entry [666, 4] - [666, 24] + line: (number [666, 11] - [666, 13]) + date: (date [666, 14] - [666, 24])) + (blame_entry [667, 4] - [667, 25] + line: (number [667, 11] - [667, 14]) + date: (date [667, 15] - [667, 25])) + (blame_entry [668, 4] - [668, 25] + line: (number [668, 11] - [668, 14]) + date: (date [668, 15] - [668, 25])) + (blame_entry [669, 4] - [669, 25] + line: (number [669, 11] - [669, 14]) + date: (date [669, 15] - [669, 25]))) + (file_entry [670, 0] - [673, 24] + file_name: (filename [670, 6] - [670, 87]) + (blame_entry [671, 4] - [671, 24] + line: (number [671, 11] - [671, 13]) + date: (date [671, 14] - [671, 24])) + (blame_entry [672, 4] - [672, 24] + line: (number [672, 11] - [672, 13]) + date: (date [672, 14] - [672, 24])) + (blame_entry [673, 4] - [673, 24] + line: (number [673, 11] - [673, 13]) + date: (date [673, 14] - [673, 24]))) + (file_entry [674, 0] - [676, 24] + file_name: (filename [674, 6] - [674, 57]) + (blame_entry [675, 4] - [675, 24] + line: (number [675, 11] - [675, 13]) + date: (date [675, 14] - [675, 24])) + (blame_entry [676, 4] - [676, 24] + line: (number [676, 11] - [676, 13]) + date: (date [676, 14] - [676, 24]))) + (file_entry [677, 0] - [678, 24] + file_name: (filename [677, 6] - [677, 65]) + (blame_entry [678, 4] - [678, 24] + line: (number [678, 11] - [678, 13]) + date: (date [678, 14] - [678, 24]))) + (file_entry [679, 0] - [683, 25] + file_name: (filename [679, 6] - [679, 93]) + (blame_entry [680, 4] - [680, 25] + line: (number [680, 11] - [680, 14]) + date: (date [680, 15] - [680, 25])) + (blame_entry [681, 4] - [681, 25] + line: (number [681, 11] - [681, 14]) + date: (date [681, 15] - [681, 25])) + (blame_entry [682, 4] - [682, 25] + line: (number [682, 11] - [682, 14]) + date: (date [682, 15] - [682, 25])) + (blame_entry [683, 4] - [683, 25] + line: (number [683, 11] - [683, 14]) + date: (date [683, 15] - [683, 25]))) + (file_entry [684, 0] - [685, 24] + file_name: (filename [684, 6] - [684, 65]) + (blame_entry [685, 4] - [685, 24] + line: (number [685, 11] - [685, 13]) + date: (date [685, 14] - [685, 24]))) + (file_entry [686, 0] - [688, 25] + file_name: (filename [686, 6] - [686, 70]) + (blame_entry [687, 4] - [687, 25] + line: (number [687, 11] - [687, 14]) + date: (date [687, 15] - [687, 25])) + (blame_entry [688, 4] - [688, 25] + line: (number [688, 11] - [688, 14]) + date: (date [688, 15] - [688, 25]))) + (file_entry [689, 0] - [691, 24] + file_name: (filename [689, 6] - [689, 60]) + (blame_entry [690, 4] - [690, 24] + line: (number [690, 11] - [690, 13]) + date: (date [690, 14] - [690, 24])) + (blame_entry [691, 4] - [691, 24] + line: (number [691, 11] - [691, 13]) + date: (date [691, 14] - [691, 24]))) + (file_entry [692, 0] - [696, 25] + file_name: (filename [692, 6] - [692, 75]) + (blame_entry [693, 4] - [693, 24] + line: (number [693, 11] - [693, 13]) + date: (date [693, 14] - [693, 24])) + (blame_entry [694, 4] - [694, 25] + line: (number [694, 11] - [694, 14]) + date: (date [694, 15] - [694, 25])) + (blame_entry [695, 4] - [695, 25] + line: (number [695, 11] - [695, 14]) + date: (date [695, 15] - [695, 25])) + (blame_entry [696, 4] - [696, 25] + line: (number [696, 11] - [696, 14]) + date: (date [696, 15] - [696, 25]))) + (file_entry [697, 0] - [698, 24] + file_name: (filename [697, 6] - [697, 86]) + (blame_entry [698, 4] - [698, 24] + line: (number [698, 11] - [698, 13]) + date: (date [698, 14] - [698, 24]))) + (file_entry [699, 0] - [700, 24] + file_name: (filename [699, 6] - [699, 82]) + (blame_entry [700, 4] - [700, 24] + line: (number [700, 11] - [700, 13]) + date: (date [700, 14] - [700, 24]))) + (file_entry [701, 0] - [702, 25] + file_name: (filename [701, 6] - [701, 61]) + (blame_entry [702, 4] - [702, 25] + line: (number [702, 11] - [702, 14]) + date: (date [702, 15] - [702, 25]))) + (file_entry [703, 0] - [705, 24] + file_name: (filename [703, 6] - [703, 75]) + (blame_entry [704, 4] - [704, 23] + line: (number [704, 11] - [704, 12]) + date: (date [704, 13] - [704, 23])) + (blame_entry [705, 4] - [705, 24] + line: (number [705, 11] - [705, 13]) + date: (date [705, 14] - [705, 24]))) + (file_entry [706, 0] - [718, 25] + file_name: (filename [706, 6] - [706, 61]) + (blame_entry [707, 4] - [707, 24] + line: (number [707, 11] - [707, 13]) + date: (date [707, 14] - [707, 24])) + (blame_entry [708, 4] - [708, 24] + line: (number [708, 11] - [708, 13]) + date: (date [708, 14] - [708, 24])) + (blame_entry [709, 4] - [709, 25] + line: (number [709, 11] - [709, 14]) + date: (date [709, 15] - [709, 25])) + (blame_entry [710, 4] - [710, 25] + line: (number [710, 11] - [710, 14]) + date: (date [710, 15] - [710, 25])) + (blame_entry [711, 4] - [711, 25] + line: (number [711, 11] - [711, 14]) + date: (date [711, 15] - [711, 25])) + (blame_entry [712, 4] - [712, 25] + line: (number [712, 11] - [712, 14]) + date: (date [712, 15] - [712, 25])) + (blame_entry [713, 4] - [713, 25] + line: (number [713, 11] - [713, 14]) + date: (date [713, 15] - [713, 25])) + (blame_entry [714, 4] - [714, 25] + line: (number [714, 11] - [714, 14]) + date: (date [714, 15] - [714, 25])) + (blame_entry [715, 4] - [715, 25] + line: (number [715, 11] - [715, 14]) + date: (date [715, 15] - [715, 25])) + (blame_entry [716, 4] - [716, 25] + line: (number [716, 11] - [716, 14]) + date: (date [716, 15] - [716, 25])) + (blame_entry [717, 4] - [717, 25] + line: (number [717, 11] - [717, 14]) + date: (date [717, 15] - [717, 25])) + (blame_entry [718, 4] - [718, 25] + line: (number [718, 11] - [718, 14]) + date: (date [718, 15] - [718, 25]))) + (file_entry [719, 0] - [723, 25] + file_name: (filename [719, 6] - [719, 103]) + (blame_entry [720, 4] - [720, 25] + line: (number [720, 11] - [720, 14]) + date: (date [720, 15] - [720, 25])) + (blame_entry [721, 4] - [721, 25] + line: (number [721, 11] - [721, 14]) + date: (date [721, 15] - [721, 25])) + (blame_entry [722, 4] - [722, 25] + line: (number [722, 11] - [722, 14]) + date: (date [722, 15] - [722, 25])) + (blame_entry [723, 4] - [723, 25] + line: (number [723, 11] - [723, 14]) + date: (date [723, 15] - [723, 25]))) + (file_entry [724, 0] - [726, 25] + file_name: (filename [724, 6] - [724, 76]) + (blame_entry [725, 4] - [725, 24] + line: (number [725, 11] - [725, 13]) + date: (date [725, 14] - [725, 24])) + (blame_entry [726, 4] - [726, 25] + line: (number [726, 11] - [726, 14]) + date: (date [726, 15] - [726, 25]))) + (file_entry [727, 0] - [728, 24] + file_name: (filename [727, 6] - [727, 78]) + (blame_entry [728, 4] - [728, 24] + line: (number [728, 11] - [728, 13]) + date: (date [728, 14] - [728, 24]))) + (file_entry [729, 0] - [730, 25] + file_name: (filename [729, 6] - [729, 47]) + (blame_entry [730, 4] - [730, 25] + line: (number [730, 11] - [730, 14]) + date: (date [730, 15] - [730, 25]))) + (file_entry [731, 0] - [735, 25] + file_name: (filename [731, 6] - [731, 93]) + (blame_entry [732, 4] - [732, 25] + line: (number [732, 11] - [732, 14]) + date: (date [732, 15] - [732, 25])) + (blame_entry [733, 4] - [733, 25] + line: (number [733, 11] - [733, 14]) + date: (date [733, 15] - [733, 25])) + (blame_entry [734, 4] - [734, 25] + line: (number [734, 11] - [734, 14]) + date: (date [734, 15] - [734, 25])) + (blame_entry [735, 4] - [735, 25] + line: (number [735, 11] - [735, 14]) + date: (date [735, 15] - [735, 25]))) + (file_entry [736, 0] - [740, 24] + file_name: (filename [736, 6] - [736, 55]) + (blame_entry [737, 4] - [737, 24] + line: (number [737, 11] - [737, 13]) + date: (date [737, 14] - [737, 24])) + (blame_entry [738, 4] - [738, 24] + line: (number [738, 11] - [738, 13]) + date: (date [738, 14] - [738, 24])) + (blame_entry [739, 4] - [739, 24] + line: (number [739, 11] - [739, 13]) + date: (date [739, 14] - [739, 24])) + (blame_entry [740, 4] - [740, 24] + line: (number [740, 11] - [740, 13]) + date: (date [740, 14] - [740, 24]))) + (file_entry [741, 0] - [744, 24] + file_name: (filename [741, 6] - [741, 61]) + (blame_entry [742, 4] - [742, 24] + line: (number [742, 11] - [742, 13]) + date: (date [742, 14] - [742, 24])) + (blame_entry [743, 4] - [743, 24] + line: (number [743, 11] - [743, 13]) + date: (date [743, 14] - [743, 24])) + (blame_entry [744, 4] - [744, 24] + line: (number [744, 11] - [744, 13]) + date: (date [744, 14] - [744, 24]))) + (file_entry [745, 0] - [746, 25] + file_name: (filename [745, 6] - [745, 64]) + (blame_entry [746, 4] - [746, 25] + line: (number [746, 11] - [746, 14]) + date: (date [746, 15] - [746, 25]))) + (file_entry [747, 0] - [762, 25] + file_name: (filename [747, 6] - [747, 64]) + (blame_entry [748, 4] - [748, 24] + line: (number [748, 11] - [748, 13]) + date: (date [748, 14] - [748, 24])) + (blame_entry [749, 4] - [749, 24] + line: (number [749, 11] - [749, 13]) + date: (date [749, 14] - [749, 24])) + (blame_entry [750, 4] - [750, 25] + line: (number [750, 11] - [750, 14]) + date: (date [750, 15] - [750, 25])) + (blame_entry [751, 4] - [751, 25] + line: (number [751, 11] - [751, 14]) + date: (date [751, 15] - [751, 25])) + (blame_entry [752, 4] - [752, 25] + line: (number [752, 11] - [752, 14]) + date: (date [752, 15] - [752, 25])) + (blame_entry [753, 4] - [753, 25] + line: (number [753, 11] - [753, 14]) + date: (date [753, 15] - [753, 25])) + (blame_entry [754, 4] - [754, 25] + line: (number [754, 11] - [754, 14]) + date: (date [754, 15] - [754, 25])) + (blame_entry [755, 4] - [755, 25] + line: (number [755, 11] - [755, 14]) + date: (date [755, 15] - [755, 25])) + (blame_entry [756, 4] - [756, 25] + line: (number [756, 11] - [756, 14]) + date: (date [756, 15] - [756, 25])) + (blame_entry [757, 4] - [757, 25] + line: (number [757, 11] - [757, 14]) + date: (date [757, 15] - [757, 25])) + (blame_entry [758, 4] - [758, 25] + line: (number [758, 11] - [758, 14]) + date: (date [758, 15] - [758, 25])) + (blame_entry [759, 4] - [759, 25] + line: (number [759, 11] - [759, 14]) + date: (date [759, 15] - [759, 25])) + (blame_entry [760, 4] - [760, 25] + line: (number [760, 11] - [760, 14]) + date: (date [760, 15] - [760, 25])) + (blame_entry [761, 4] - [761, 25] + line: (number [761, 11] - [761, 14]) + date: (date [761, 15] - [761, 25])) + (blame_entry [762, 4] - [762, 25] + line: (number [762, 11] - [762, 14]) + date: (date [762, 15] - [762, 25]))) + (file_entry [763, 0] - [766, 24] + file_name: (filename [763, 6] - [763, 53]) + (blame_entry [764, 4] - [764, 24] + line: (number [764, 11] - [764, 13]) + date: (date [764, 14] - [764, 24])) + (blame_entry [765, 4] - [765, 24] + line: (number [765, 11] - [765, 13]) + date: (date [765, 14] - [765, 24])) + (blame_entry [766, 4] - [766, 24] + line: (number [766, 11] - [766, 13]) + date: (date [766, 14] - [766, 24]))) + (file_entry [767, 0] - [769, 24] + file_name: (filename [767, 6] - [767, 99]) + (blame_entry [768, 4] - [768, 23] + line: (number [768, 11] - [768, 12]) + date: (date [768, 13] - [768, 23])) + (blame_entry [769, 4] - [769, 24] + line: (number [769, 11] - [769, 13]) + date: (date [769, 14] - [769, 24]))) + (file_entry [770, 0] - [776, 25] + file_name: (filename [770, 6] - [770, 56]) + (blame_entry [771, 4] - [771, 24] + line: (number [771, 11] - [771, 13]) + date: (date [771, 14] - [771, 24])) + (blame_entry [772, 4] - [772, 24] + line: (number [772, 11] - [772, 13]) + date: (date [772, 14] - [772, 24])) + (blame_entry [773, 4] - [773, 24] + line: (number [773, 11] - [773, 13]) + date: (date [773, 14] - [773, 24])) + (blame_entry [774, 4] - [774, 24] + line: (number [774, 11] - [774, 13]) + date: (date [774, 14] - [774, 24])) + (blame_entry [775, 4] - [775, 24] + line: (number [775, 11] - [775, 13]) + date: (date [775, 14] - [775, 24])) + (blame_entry [776, 4] - [776, 25] + line: (number [776, 11] - [776, 14]) + date: (date [776, 15] - [776, 25]))) + (file_entry [777, 0] - [808, 26] + file_name: (filename [777, 6] - [777, 58]) + (blame_entry [778, 4] - [778, 25] + line: (number [778, 11] - [778, 14]) + date: (date [778, 15] - [778, 25])) + (blame_entry [779, 4] - [779, 25] + line: (number [779, 11] - [779, 14]) + date: (date [779, 15] - [779, 25])) + (blame_entry [780, 4] - [780, 25] + line: (number [780, 11] - [780, 14]) + date: (date [780, 15] - [780, 25])) + (blame_entry [781, 4] - [781, 25] + line: (number [781, 11] - [781, 14]) + date: (date [781, 15] - [781, 25])) + (blame_entry [782, 4] - [782, 25] + line: (number [782, 11] - [782, 14]) + date: (date [782, 15] - [782, 25])) + (blame_entry [783, 4] - [783, 25] + line: (number [783, 11] - [783, 14]) + date: (date [783, 15] - [783, 25])) + (blame_entry [784, 4] - [784, 25] + line: (number [784, 11] - [784, 14]) + date: (date [784, 15] - [784, 25])) + (blame_entry [785, 4] - [785, 25] + line: (number [785, 11] - [785, 14]) + date: (date [785, 15] - [785, 25])) + (blame_entry [786, 4] - [786, 25] + line: (number [786, 11] - [786, 14]) + date: (date [786, 15] - [786, 25])) + (blame_entry [787, 4] - [787, 25] + line: (number [787, 11] - [787, 14]) + date: (date [787, 15] - [787, 25])) + (blame_entry [788, 4] - [788, 25] + line: (number [788, 11] - [788, 14]) + date: (date [788, 15] - [788, 25])) + (blame_entry [789, 4] - [789, 25] + line: (number [789, 11] - [789, 14]) + date: (date [789, 15] - [789, 25])) + (blame_entry [790, 4] - [790, 25] + line: (number [790, 11] - [790, 14]) + date: (date [790, 15] - [790, 25])) + (blame_entry [791, 4] - [791, 25] + line: (number [791, 11] - [791, 14]) + date: (date [791, 15] - [791, 25])) + (blame_entry [792, 4] - [792, 25] + line: (number [792, 11] - [792, 14]) + date: (date [792, 15] - [792, 25])) + (blame_entry [793, 4] - [793, 25] + line: (number [793, 11] - [793, 14]) + date: (date [793, 15] - [793, 25])) + (blame_entry [794, 4] - [794, 25] + line: (number [794, 11] - [794, 14]) + date: (date [794, 15] - [794, 25])) + (blame_entry [795, 4] - [795, 25] + line: (number [795, 11] - [795, 14]) + date: (date [795, 15] - [795, 25])) + (blame_entry [796, 4] - [796, 25] + line: (number [796, 11] - [796, 14]) + date: (date [796, 15] - [796, 25])) + (blame_entry [797, 4] - [797, 25] + line: (number [797, 11] - [797, 14]) + date: (date [797, 15] - [797, 25])) + (blame_entry [798, 4] - [798, 25] + line: (number [798, 11] - [798, 14]) + date: (date [798, 15] - [798, 25])) + (blame_entry [799, 4] - [799, 25] + line: (number [799, 11] - [799, 14]) + date: (date [799, 15] - [799, 25])) + (blame_entry [800, 4] - [800, 25] + line: (number [800, 11] - [800, 14]) + date: (date [800, 15] - [800, 25])) + (blame_entry [801, 4] - [801, 25] + line: (number [801, 11] - [801, 14]) + date: (date [801, 15] - [801, 25])) + (blame_entry [802, 4] - [802, 25] + line: (number [802, 11] - [802, 14]) + date: (date [802, 15] - [802, 25])) + (blame_entry [803, 4] - [803, 25] + line: (number [803, 11] - [803, 14]) + date: (date [803, 15] - [803, 25])) + (blame_entry [804, 4] - [804, 26] + line: (number [804, 11] - [804, 15]) + date: (date [804, 16] - [804, 26])) + (blame_entry [805, 4] - [805, 26] + line: (number [805, 11] - [805, 15]) + date: (date [805, 16] - [805, 26])) + (blame_entry [806, 4] - [806, 26] + line: (number [806, 11] - [806, 15]) + date: (date [806, 16] - [806, 26])) + (blame_entry [807, 4] - [807, 26] + line: (number [807, 11] - [807, 15]) + date: (date [807, 16] - [807, 26])) + (blame_entry [808, 4] - [808, 26] + line: (number [808, 11] - [808, 15]) + date: (date [808, 16] - [808, 26]))) + (file_entry [809, 0] - [810, 24] + file_name: (filename [809, 6] - [809, 74]) + (blame_entry [810, 4] - [810, 24] + line: (number [810, 11] - [810, 13]) + date: (date [810, 14] - [810, 24]))) + (file_entry [811, 0] - [812, 24] + file_name: (filename [811, 6] - [811, 68]) + (blame_entry [812, 4] - [812, 24] + line: (number [812, 11] - [812, 13]) + date: (date [812, 14] - [812, 24]))) + (file_entry [813, 0] - [814, 25] + file_name: (filename [813, 6] - [813, 63]) + (blame_entry [814, 4] - [814, 25] + line: (number [814, 11] - [814, 14]) + date: (date [814, 15] - [814, 25]))) + (file_entry [815, 0] - [816, 24] + file_name: (filename [815, 6] - [815, 56]) + (blame_entry [816, 4] - [816, 24] + line: (number [816, 11] - [816, 13]) + date: (date [816, 14] - [816, 24]))) + (file_entry [817, 0] - [821, 25] + file_name: (filename [817, 6] - [817, 92]) + (blame_entry [818, 4] - [818, 25] + line: (number [818, 11] - [818, 14]) + date: (date [818, 15] - [818, 25])) + (blame_entry [819, 4] - [819, 25] + line: (number [819, 11] - [819, 14]) + date: (date [819, 15] - [819, 25])) + (blame_entry [820, 4] - [820, 25] + line: (number [820, 11] - [820, 14]) + date: (date [820, 15] - [820, 25])) + (blame_entry [821, 4] - [821, 25] + line: (number [821, 11] - [821, 14]) + date: (date [821, 15] - [821, 25]))) + (file_entry [822, 0] - [824, 24] + file_name: (filename [822, 6] - [822, 83]) + (blame_entry [823, 4] - [823, 24] + line: (number [823, 11] - [823, 13]) + date: (date [823, 14] - [823, 24])) + (blame_entry [824, 4] - [824, 24] + line: (number [824, 11] - [824, 13]) + date: (date [824, 14] - [824, 24]))) + (file_entry [825, 0] - [829, 25] + file_name: (filename [825, 6] - [825, 103]) + (blame_entry [826, 4] - [826, 25] + line: (number [826, 11] - [826, 14]) + date: (date [826, 15] - [826, 25])) + (blame_entry [827, 4] - [827, 25] + line: (number [827, 11] - [827, 14]) + date: (date [827, 15] - [827, 25])) + (blame_entry [828, 4] - [828, 25] + line: (number [828, 11] - [828, 14]) + date: (date [828, 15] - [828, 25])) + (blame_entry [829, 4] - [829, 25] + line: (number [829, 11] - [829, 14]) + date: (date [829, 15] - [829, 25]))) + (file_entry [830, 0] - [834, 25] + file_name: (filename [830, 6] - [830, 80]) + (blame_entry [831, 4] - [831, 25] + line: (number [831, 11] - [831, 14]) + date: (date [831, 15] - [831, 25])) + (blame_entry [832, 4] - [832, 25] + line: (number [832, 11] - [832, 14]) + date: (date [832, 15] - [832, 25])) + (blame_entry [833, 4] - [833, 25] + line: (number [833, 11] - [833, 14]) + date: (date [833, 15] - [833, 25])) + (blame_entry [834, 4] - [834, 25] + line: (number [834, 11] - [834, 14]) + date: (date [834, 15] - [834, 25]))) + (file_entry [835, 0] - [836, 23] + file_name: (filename [835, 6] - [835, 65]) + (blame_entry [836, 4] - [836, 23] + line: (number [836, 11] - [836, 12]) + date: (date [836, 13] - [836, 23]))) + (file_entry [837, 0] - [842, 26] + file_name: (filename [837, 6] - [837, 93]) + (blame_entry [838, 4] - [838, 25] + line: (number [838, 11] - [838, 14]) + date: (date [838, 15] - [838, 25])) + (blame_entry [839, 4] - [839, 25] + line: (number [839, 11] - [839, 14]) + date: (date [839, 15] - [839, 25])) + (blame_entry [840, 4] - [840, 26] + line: (number [840, 11] - [840, 15]) + date: (date [840, 16] - [840, 26])) + (blame_entry [841, 4] - [841, 26] + line: (number [841, 11] - [841, 15]) + date: (date [841, 16] - [841, 26])) + (blame_entry [842, 4] - [842, 26] + line: (number [842, 11] - [842, 15]) + date: (date [842, 16] - [842, 26]))) + (file_entry [843, 0] - [844, 24] + file_name: (filename [843, 6] - [843, 70]) + (blame_entry [844, 4] - [844, 24] + line: (number [844, 11] - [844, 13]) + date: (date [844, 14] - [844, 24]))) + (file_entry [845, 0] - [850, 24] + file_name: (filename [845, 6] - [845, 47]) + (blame_entry [846, 4] - [846, 24] + line: (number [846, 11] - [846, 13]) + date: (date [846, 14] - [846, 24])) + (blame_entry [847, 4] - [847, 24] + line: (number [847, 11] - [847, 13]) + date: (date [847, 14] - [847, 24])) + (blame_entry [848, 4] - [848, 24] + line: (number [848, 11] - [848, 13]) + date: (date [848, 14] - [848, 24])) + (blame_entry [849, 4] - [849, 24] + line: (number [849, 11] - [849, 13]) + date: (date [849, 14] - [849, 24])) + (blame_entry [850, 4] - [850, 24] + line: (number [850, 11] - [850, 13]) + date: (date [850, 14] - [850, 24]))) + (file_entry [851, 0] - [853, 25] + file_name: (filename [851, 6] - [851, 71]) + (blame_entry [852, 4] - [852, 25] + line: (number [852, 11] - [852, 14]) + date: (date [852, 15] - [852, 25])) + (blame_entry [853, 4] - [853, 25] + line: (number [853, 11] - [853, 14]) + date: (date [853, 15] - [853, 25]))) + (file_entry [854, 0] - [867, 25] + file_name: (filename [854, 6] - [854, 45]) + (blame_entry [855, 4] - [855, 24] + line: (number [855, 11] - [855, 13]) + date: (date [855, 14] - [855, 24])) + (blame_entry [856, 4] - [856, 24] + line: (number [856, 11] - [856, 13]) + date: (date [856, 14] - [856, 24])) + (blame_entry [857, 4] - [857, 25] + line: (number [857, 11] - [857, 14]) + date: (date [857, 15] - [857, 25])) + (blame_entry [858, 4] - [858, 25] + line: (number [858, 11] - [858, 14]) + date: (date [858, 15] - [858, 25])) + (blame_entry [859, 4] - [859, 25] + line: (number [859, 11] - [859, 14]) + date: (date [859, 15] - [859, 25])) + (blame_entry [860, 4] - [860, 25] + line: (number [860, 11] - [860, 14]) + date: (date [860, 15] - [860, 25])) + (blame_entry [861, 4] - [861, 25] + line: (number [861, 11] - [861, 14]) + date: (date [861, 15] - [861, 25])) + (blame_entry [862, 4] - [862, 25] + line: (number [862, 11] - [862, 14]) + date: (date [862, 15] - [862, 25])) + (blame_entry [863, 4] - [863, 25] + line: (number [863, 11] - [863, 14]) + date: (date [863, 15] - [863, 25])) + (blame_entry [864, 4] - [864, 25] + line: (number [864, 11] - [864, 14]) + date: (date [864, 15] - [864, 25])) + (blame_entry [865, 4] - [865, 25] + line: (number [865, 11] - [865, 14]) + date: (date [865, 15] - [865, 25])) + (blame_entry [866, 4] - [866, 25] + line: (number [866, 11] - [866, 14]) + date: (date [866, 15] - [866, 25])) + (blame_entry [867, 4] - [867, 25] + line: (number [867, 11] - [867, 14]) + date: (date [867, 15] - [867, 25]))) + (file_entry [868, 0] - [870, 24] + file_name: (filename [868, 6] - [868, 47]) + (blame_entry [869, 4] - [869, 24] + line: (number [869, 11] - [869, 13]) + date: (date [869, 14] - [869, 24])) + (blame_entry [870, 4] - [870, 24] + line: (number [870, 11] - [870, 13]) + date: (date [870, 14] - [870, 24]))) + (file_entry [871, 0] - [872, 24] + file_name: (filename [871, 6] - [871, 62]) + (blame_entry [872, 4] - [872, 24] + line: (number [872, 11] - [872, 13]) + date: (date [872, 14] - [872, 24]))) + (file_entry [873, 0] - [874, 24] + file_name: (filename [873, 6] - [873, 71]) + (blame_entry [874, 4] - [874, 24] + line: (number [874, 11] - [874, 13]) + date: (date [874, 14] - [874, 24]))) + (file_entry [875, 0] - [880, 25] + file_name: (filename [875, 6] - [875, 59]) + (blame_entry [876, 4] - [876, 25] + line: (number [876, 11] - [876, 14]) + date: (date [876, 15] - [876, 25])) + (blame_entry [877, 4] - [877, 25] + line: (number [877, 11] - [877, 14]) + date: (date [877, 15] - [877, 25])) + (blame_entry [878, 4] - [878, 25] + line: (number [878, 11] - [878, 14]) + date: (date [878, 15] - [878, 25])) + (blame_entry [879, 4] - [879, 25] + line: (number [879, 11] - [879, 14]) + date: (date [879, 15] - [879, 25])) + (blame_entry [880, 4] - [880, 25] + line: (number [880, 11] - [880, 14]) + date: (date [880, 15] - [880, 25]))) + (file_entry [881, 0] - [883, 24] + file_name: (filename [881, 6] - [881, 74]) + (blame_entry [882, 4] - [882, 23] + line: (number [882, 11] - [882, 12]) + date: (date [882, 13] - [882, 23])) + (blame_entry [883, 4] - [883, 24] + line: (number [883, 11] - [883, 13]) + date: (date [883, 14] - [883, 24]))) + (file_entry [884, 0] - [890, 24] + file_name: (filename [884, 6] - [884, 57]) + (blame_entry [885, 4] - [885, 23] + line: (number [885, 11] - [885, 12]) + date: (date [885, 13] - [885, 23])) + (blame_entry [886, 4] - [886, 23] + line: (number [886, 11] - [886, 12]) + date: (date [886, 13] - [886, 23])) + (blame_entry [887, 4] - [887, 24] + line: (number [887, 11] - [887, 13]) + date: (date [887, 14] - [887, 24])) + (blame_entry [888, 4] - [888, 24] + line: (number [888, 11] - [888, 13]) + date: (date [888, 14] - [888, 24])) + (blame_entry [889, 4] - [889, 24] + line: (number [889, 11] - [889, 13]) + date: (date [889, 14] - [889, 24])) + (blame_entry [890, 4] - [890, 24] + line: (number [890, 11] - [890, 13]) + date: (date [890, 14] - [890, 24]))) + (file_entry [891, 0] - [897, 25] + file_name: (filename [891, 6] - [891, 43]) + (blame_entry [892, 4] - [892, 25] + line: (number [892, 11] - [892, 14]) + date: (date [892, 15] - [892, 25])) + (blame_entry [893, 4] - [893, 25] + line: (number [893, 11] - [893, 14]) + date: (date [893, 15] - [893, 25])) + (blame_entry [894, 4] - [894, 25] + line: (number [894, 11] - [894, 14]) + date: (date [894, 15] - [894, 25])) + (blame_entry [895, 4] - [895, 25] + line: (number [895, 11] - [895, 14]) + date: (date [895, 15] - [895, 25])) + (blame_entry [896, 4] - [896, 25] + line: (number [896, 11] - [896, 14]) + date: (date [896, 15] - [896, 25])) + (blame_entry [897, 4] - [897, 25] + line: (number [897, 11] - [897, 14]) + date: (date [897, 15] - [897, 25]))) + (file_entry [898, 0] - [915, 25] + file_name: (filename [898, 6] - [898, 54]) + (blame_entry [899, 4] - [899, 25] + line: (number [899, 11] - [899, 14]) + date: (date [899, 15] - [899, 25])) + (blame_entry [900, 4] - [900, 25] + line: (number [900, 11] - [900, 14]) + date: (date [900, 15] - [900, 25])) + (blame_entry [901, 4] - [901, 25] + line: (number [901, 11] - [901, 14]) + date: (date [901, 15] - [901, 25])) + (blame_entry [902, 4] - [902, 25] + line: (number [902, 11] - [902, 14]) + date: (date [902, 15] - [902, 25])) + (blame_entry [903, 4] - [903, 25] + line: (number [903, 11] - [903, 14]) + date: (date [903, 15] - [903, 25])) + (blame_entry [904, 4] - [904, 25] + line: (number [904, 11] - [904, 14]) + date: (date [904, 15] - [904, 25])) + (blame_entry [905, 4] - [905, 25] + line: (number [905, 11] - [905, 14]) + date: (date [905, 15] - [905, 25])) + (blame_entry [906, 4] - [906, 25] + line: (number [906, 11] - [906, 14]) + date: (date [906, 15] - [906, 25])) + (blame_entry [907, 4] - [907, 25] + line: (number [907, 11] - [907, 14]) + date: (date [907, 15] - [907, 25])) + (blame_entry [908, 4] - [908, 25] + line: (number [908, 11] - [908, 14]) + date: (date [908, 15] - [908, 25])) + (blame_entry [909, 4] - [909, 25] + line: (number [909, 11] - [909, 14]) + date: (date [909, 15] - [909, 25])) + (blame_entry [910, 4] - [910, 25] + line: (number [910, 11] - [910, 14]) + date: (date [910, 15] - [910, 25])) + (blame_entry [911, 4] - [911, 25] + line: (number [911, 11] - [911, 14]) + date: (date [911, 15] - [911, 25])) + (blame_entry [912, 4] - [912, 25] + line: (number [912, 11] - [912, 14]) + date: (date [912, 15] - [912, 25])) + (blame_entry [913, 4] - [913, 25] + line: (number [913, 11] - [913, 14]) + date: (date [913, 15] - [913, 25])) + (blame_entry [914, 4] - [914, 25] + line: (number [914, 11] - [914, 14]) + date: (date [914, 15] - [914, 25])) + (blame_entry [915, 4] - [915, 25] + line: (number [915, 11] - [915, 14]) + date: (date [915, 15] - [915, 25]))) + (file_entry [916, 0] - [919, 24] + file_name: (filename [916, 6] - [916, 68]) + (blame_entry [917, 4] - [917, 23] + line: (number [917, 11] - [917, 12]) + date: (date [917, 13] - [917, 23])) + (blame_entry [918, 4] - [918, 24] + line: (number [918, 11] - [918, 13]) + date: (date [918, 14] - [918, 24])) + (blame_entry [919, 4] - [919, 24] + line: (number [919, 11] - [919, 13]) + date: (date [919, 14] - [919, 24]))) + (file_entry [920, 0] - [921, 23] + file_name: (filename [920, 6] - [920, 84]) + (blame_entry [921, 4] - [921, 23] + line: (number [921, 11] - [921, 12]) + date: (date [921, 13] - [921, 23]))) + (file_entry [922, 0] - [923, 24] + file_name: (filename [922, 6] - [922, 60]) + (blame_entry [923, 4] - [923, 24] + line: (number [923, 11] - [923, 13]) + date: (date [923, 14] - [923, 24]))) + (file_entry [924, 0] - [925, 24] + file_name: (filename [924, 6] - [924, 74]) + (blame_entry [925, 4] - [925, 24] + line: (number [925, 11] - [925, 13]) + date: (date [925, 14] - [925, 24]))) + (file_entry [926, 0] - [931, 24] + file_name: (filename [926, 6] - [926, 51]) + (blame_entry [927, 4] - [927, 23] + line: (number [927, 11] - [927, 12]) + date: (date [927, 13] - [927, 23])) + (blame_entry [928, 4] - [928, 24] + line: (number [928, 11] - [928, 13]) + date: (date [928, 14] - [928, 24])) + (blame_entry [929, 4] - [929, 24] + line: (number [929, 11] - [929, 13]) + date: (date [929, 14] - [929, 24])) + (blame_entry [930, 4] - [930, 24] + line: (number [930, 11] - [930, 13]) + date: (date [930, 14] - [930, 24])) + (blame_entry [931, 4] - [931, 24] + line: (number [931, 11] - [931, 13]) + date: (date [931, 14] - [931, 24]))) + (file_entry [932, 0] - [933, 23] + file_name: (filename [932, 6] - [932, 59]) + (blame_entry [933, 4] - [933, 23] + line: (number [933, 11] - [933, 12]) + date: (date [933, 13] - [933, 23]))) + (file_entry [934, 0] - [935, 25] + file_name: (filename [934, 6] - [934, 51]) + (blame_entry [935, 4] - [935, 25] + line: (number [935, 11] - [935, 14]) + date: (date [935, 15] - [935, 25]))) + (file_entry [936, 0] - [940, 25] + file_name: (filename [936, 6] - [936, 69]) + (blame_entry [937, 4] - [937, 24] + line: (number [937, 11] - [937, 13]) + date: (date [937, 14] - [937, 24])) + (blame_entry [938, 4] - [938, 25] + line: (number [938, 11] - [938, 14]) + date: (date [938, 15] - [938, 25])) + (blame_entry [939, 4] - [939, 25] + line: (number [939, 11] - [939, 14]) + date: (date [939, 15] - [939, 25])) + (blame_entry [940, 4] - [940, 25] + line: (number [940, 11] - [940, 14]) + date: (date [940, 15] - [940, 25]))) + (file_entry [941, 0] - [942, 23] + file_name: (filename [941, 6] - [941, 84]) + (blame_entry [942, 4] - [942, 23] + line: (number [942, 11] - [942, 12]) + date: (date [942, 13] - [942, 23]))) + (file_entry [943, 0] - [944, 26] + file_name: (filename [943, 6] - [943, 58]) + (blame_entry [944, 4] - [944, 26] + line: (number [944, 11] - [944, 15]) + date: (date [944, 16] - [944, 26]))) + (file_entry [945, 0] - [947, 25] + file_name: (filename [945, 6] - [945, 56]) + (blame_entry [946, 4] - [946, 24] + line: (number [946, 11] - [946, 13]) + date: (date [946, 14] - [946, 24])) + (blame_entry [947, 4] - [947, 25] + line: (number [947, 11] - [947, 14]) + date: (date [947, 15] - [947, 25]))) + (file_entry [948, 0] - [953, 25] + file_name: (filename [948, 6] - [948, 98]) + (blame_entry [949, 4] - [949, 24] + line: (number [949, 11] - [949, 13]) + date: (date [949, 14] - [949, 24])) + (blame_entry [950, 4] - [950, 24] + line: (number [950, 11] - [950, 13]) + date: (date [950, 14] - [950, 24])) + (blame_entry [951, 4] - [951, 25] + line: (number [951, 11] - [951, 14]) + date: (date [951, 15] - [951, 25])) + (blame_entry [952, 4] - [952, 25] + line: (number [952, 11] - [952, 14]) + date: (date [952, 15] - [952, 25])) + (blame_entry [953, 4] - [953, 25] + line: (number [953, 11] - [953, 14]) + date: (date [953, 15] - [953, 25]))) + (file_entry [954, 0] - [955, 25] + file_name: (filename [954, 6] - [954, 68]) + (blame_entry [955, 4] - [955, 25] + line: (number [955, 11] - [955, 14]) + date: (date [955, 15] - [955, 25]))) + (file_entry [956, 0] - [957, 24] + file_name: (filename [956, 6] - [956, 94]) + (blame_entry [957, 4] - [957, 24] + line: (number [957, 11] - [957, 13]) + date: (date [957, 14] - [957, 24]))) + (file_entry [958, 0] - [959, 23] + file_name: (filename [958, 6] - [958, 67]) + (blame_entry [959, 4] - [959, 23] + line: (number [959, 11] - [959, 12]) + date: (date [959, 13] - [959, 23]))) + (file_entry [960, 0] - [966, 26] + file_name: (filename [960, 6] - [960, 55]) + (blame_entry [961, 4] - [961, 26] + line: (number [961, 11] - [961, 15]) + date: (date [961, 16] - [961, 26])) + (blame_entry [962, 4] - [962, 26] + line: (number [962, 11] - [962, 15]) + date: (date [962, 16] - [962, 26])) + (blame_entry [963, 4] - [963, 26] + line: (number [963, 11] - [963, 15]) + date: (date [963, 16] - [963, 26])) + (blame_entry [964, 4] - [964, 26] + line: (number [964, 11] - [964, 15]) + date: (date [964, 16] - [964, 26])) + (blame_entry [965, 4] - [965, 26] + line: (number [965, 11] - [965, 15]) + date: (date [965, 16] - [965, 26])) + (blame_entry [966, 4] - [966, 26] + line: (number [966, 11] - [966, 15]) + date: (date [966, 16] - [966, 26]))) + (file_entry [967, 0] - [973, 24] + file_name: (filename [967, 6] - [967, 60]) + (blame_entry [968, 4] - [968, 24] + line: (number [968, 11] - [968, 13]) + date: (date [968, 14] - [968, 24])) + (blame_entry [969, 4] - [969, 24] + line: (number [969, 11] - [969, 13]) + date: (date [969, 14] - [969, 24])) + (blame_entry [970, 4] - [970, 24] + line: (number [970, 11] - [970, 13]) + date: (date [970, 14] - [970, 24])) + (blame_entry [971, 4] - [971, 24] + line: (number [971, 11] - [971, 13]) + date: (date [971, 14] - [971, 24])) + (blame_entry [972, 4] - [972, 24] + line: (number [972, 11] - [972, 13]) + date: (date [972, 14] - [972, 24])) + (blame_entry [973, 4] - [973, 24] + line: (number [973, 11] - [973, 13]) + date: (date [973, 14] - [973, 24]))) + (file_entry [974, 0] - [976, 24] + file_name: (filename [974, 6] - [974, 70]) + (blame_entry [975, 4] - [975, 24] + line: (number [975, 11] - [975, 13]) + date: (date [975, 14] - [975, 24])) + (blame_entry [976, 4] - [976, 24] + line: (number [976, 11] - [976, 13]) + date: (date [976, 14] - [976, 24]))) + (file_entry [977, 0] - [978, 23] + file_name: (filename [977, 6] - [977, 68]) + (blame_entry [978, 4] - [978, 23] + line: (number [978, 11] - [978, 12]) + date: (date [978, 13] - [978, 23]))) + (file_entry [979, 0] - [980, 25] + file_name: (filename [979, 6] - [979, 50]) + (blame_entry [980, 4] - [980, 25] + line: (number [980, 11] - [980, 14]) + date: (date [980, 15] - [980, 25]))) + (file_entry [981, 0] - [984, 25] + file_name: (filename [981, 6] - [981, 74]) + (blame_entry [982, 4] - [982, 24] + line: (number [982, 11] - [982, 13]) + date: (date [982, 14] - [982, 24])) + (blame_entry [983, 4] - [983, 24] + line: (number [983, 11] - [983, 13]) + date: (date [983, 14] - [983, 24])) + (blame_entry [984, 4] - [984, 25] + line: (number [984, 11] - [984, 14]) + date: (date [984, 15] - [984, 25]))) + (file_entry [985, 0] - [993, 25] + file_name: (filename [985, 6] - [985, 69]) + (blame_entry [986, 4] - [986, 23] + line: (number [986, 11] - [986, 12]) + date: (date [986, 13] - [986, 23])) + (blame_entry [987, 4] - [987, 24] + line: (number [987, 11] - [987, 13]) + date: (date [987, 14] - [987, 24])) + (blame_entry [988, 4] - [988, 24] + line: (number [988, 11] - [988, 13]) + date: (date [988, 14] - [988, 24])) + (blame_entry [989, 4] - [989, 24] + line: (number [989, 11] - [989, 13]) + date: (date [989, 14] - [989, 24])) + (blame_entry [990, 4] - [990, 24] + line: (number [990, 11] - [990, 13]) + date: (date [990, 14] - [990, 24])) + (blame_entry [991, 4] - [991, 24] + line: (number [991, 11] - [991, 13]) + date: (date [991, 14] - [991, 24])) + (blame_entry [992, 4] - [992, 25] + line: (number [992, 11] - [992, 14]) + date: (date [992, 15] - [992, 25])) + (blame_entry [993, 4] - [993, 25] + line: (number [993, 11] - [993, 14]) + date: (date [993, 15] - [993, 25]))) + (file_entry [994, 0] - [998, 25] + file_name: (filename [994, 6] - [994, 81]) + (blame_entry [995, 4] - [995, 24] + line: (number [995, 11] - [995, 13]) + date: (date [995, 14] - [995, 24])) + (blame_entry [996, 4] - [996, 25] + line: (number [996, 11] - [996, 14]) + date: (date [996, 15] - [996, 25])) + (blame_entry [997, 4] - [997, 25] + line: (number [997, 11] - [997, 14]) + date: (date [997, 15] - [997, 25])) + (blame_entry [998, 4] - [998, 25] + line: (number [998, 11] - [998, 14]) + date: (date [998, 15] - [998, 25]))) + (file_entry [999, 0] - [1003, 25] + file_name: (filename [999, 6] - [999, 72]) + (blame_entry [1000, 4] - [1000, 24] + line: (number [1000, 11] - [1000, 13]) + date: (date [1000, 14] - [1000, 24])) + (blame_entry [1001, 4] - [1001, 25] + line: (number [1001, 11] - [1001, 14]) + date: (date [1001, 15] - [1001, 25])) + (blame_entry [1002, 4] - [1002, 25] + line: (number [1002, 11] - [1002, 14]) + date: (date [1002, 15] - [1002, 25])) + (blame_entry [1003, 4] - [1003, 25] + line: (number [1003, 11] - [1003, 14]) + date: (date [1003, 15] - [1003, 25]))) + (file_entry [1004, 0] - [1005, 25] + file_name: (filename [1004, 6] - [1004, 67]) + (blame_entry [1005, 4] - [1005, 25] + line: (number [1005, 11] - [1005, 14]) + date: (date [1005, 15] - [1005, 25]))) + (file_entry [1006, 0] - [1007, 25] + file_name: (filename [1006, 6] - [1006, 109]) + (blame_entry [1007, 4] - [1007, 25] + line: (number [1007, 11] - [1007, 14]) + date: (date [1007, 15] - [1007, 25]))) + (file_entry [1008, 0] - [1010, 25] + file_name: (filename [1008, 6] - [1008, 73]) + (blame_entry [1009, 4] - [1009, 24] + line: (number [1009, 11] - [1009, 13]) + date: (date [1009, 14] - [1009, 24])) + (blame_entry [1010, 4] - [1010, 25] + line: (number [1010, 11] - [1010, 14]) + date: (date [1010, 15] - [1010, 25]))) + (file_entry [1011, 0] - [1015, 25] + file_name: (filename [1011, 6] - [1011, 74]) + (blame_entry [1012, 4] - [1012, 24] + line: (number [1012, 11] - [1012, 13]) + date: (date [1012, 14] - [1012, 24])) + (blame_entry [1013, 4] - [1013, 25] + line: (number [1013, 11] - [1013, 14]) + date: (date [1013, 15] - [1013, 25])) + (blame_entry [1014, 4] - [1014, 25] + line: (number [1014, 11] - [1014, 14]) + date: (date [1014, 15] - [1014, 25])) + (blame_entry [1015, 4] - [1015, 25] + line: (number [1015, 11] - [1015, 14]) + date: (date [1015, 15] - [1015, 25]))) + (file_entry [1016, 0] - [1017, 24] + file_name: (filename [1016, 6] - [1016, 51]) + (blame_entry [1017, 4] - [1017, 24] + line: (number [1017, 11] - [1017, 13]) + date: (date [1017, 14] - [1017, 24]))) + (file_entry [1018, 0] - [1019, 23] + file_name: (filename [1018, 6] - [1018, 60]) + (blame_entry [1019, 4] - [1019, 23] + line: (number [1019, 11] - [1019, 12]) + date: (date [1019, 13] - [1019, 23]))) + (file_entry [1020, 0] - [1021, 25] + file_name: (filename [1020, 6] - [1020, 54]) + (blame_entry [1021, 4] - [1021, 25] + line: (number [1021, 11] - [1021, 14]) + date: (date [1021, 15] - [1021, 25]))) + (file_entry [1022, 0] - [1027, 24] + file_name: (filename [1022, 6] - [1022, 56]) + (blame_entry [1023, 4] - [1023, 23] + line: (number [1023, 11] - [1023, 12]) + date: (date [1023, 13] - [1023, 23])) + (blame_entry [1024, 4] - [1024, 24] + line: (number [1024, 11] - [1024, 13]) + date: (date [1024, 14] - [1024, 24])) + (blame_entry [1025, 4] - [1025, 24] + line: (number [1025, 11] - [1025, 13]) + date: (date [1025, 14] - [1025, 24])) + (blame_entry [1026, 4] - [1026, 24] + line: (number [1026, 11] - [1026, 13]) + date: (date [1026, 14] - [1026, 24])) + (blame_entry [1027, 4] - [1027, 24] + line: (number [1027, 11] - [1027, 13]) + date: (date [1027, 14] - [1027, 24]))) + (file_entry [1028, 0] - [1032, 25] + file_name: (filename [1028, 6] - [1028, 70]) + (blame_entry [1029, 4] - [1029, 24] + line: (number [1029, 11] - [1029, 13]) + date: (date [1029, 14] - [1029, 24])) + (blame_entry [1030, 4] - [1030, 25] + line: (number [1030, 11] - [1030, 14]) + date: (date [1030, 15] - [1030, 25])) + (blame_entry [1031, 4] - [1031, 25] + line: (number [1031, 11] - [1031, 14]) + date: (date [1031, 15] - [1031, 25])) + (blame_entry [1032, 4] - [1032, 25] + line: (number [1032, 11] - [1032, 14]) + date: (date [1032, 15] - [1032, 25]))) + (file_entry [1033, 0] - [1047, 25] + file_name: (filename [1033, 6] - [1033, 64]) + (blame_entry [1034, 4] - [1034, 24] + line: (number [1034, 11] - [1034, 13]) + date: (date [1034, 14] - [1034, 24])) + (blame_entry [1035, 4] - [1035, 24] + line: (number [1035, 11] - [1035, 13]) + date: (date [1035, 14] - [1035, 24])) + (blame_entry [1036, 4] - [1036, 24] + line: (number [1036, 11] - [1036, 13]) + date: (date [1036, 14] - [1036, 24])) + (blame_entry [1037, 4] - [1037, 24] + line: (number [1037, 11] - [1037, 13]) + date: (date [1037, 14] - [1037, 24])) + (blame_entry [1038, 4] - [1038, 24] + line: (number [1038, 11] - [1038, 13]) + date: (date [1038, 14] - [1038, 24])) + (blame_entry [1039, 4] - [1039, 24] + line: (number [1039, 11] - [1039, 13]) + date: (date [1039, 14] - [1039, 24])) + (blame_entry [1040, 4] - [1040, 24] + line: (number [1040, 11] - [1040, 13]) + date: (date [1040, 14] - [1040, 24])) + (blame_entry [1041, 4] - [1041, 25] + line: (number [1041, 11] - [1041, 14]) + date: (date [1041, 15] - [1041, 25])) + (blame_entry [1042, 4] - [1042, 25] + line: (number [1042, 11] - [1042, 14]) + date: (date [1042, 15] - [1042, 25])) + (blame_entry [1043, 4] - [1043, 25] + line: (number [1043, 11] - [1043, 14]) + date: (date [1043, 15] - [1043, 25])) + (blame_entry [1044, 4] - [1044, 25] + line: (number [1044, 11] - [1044, 14]) + date: (date [1044, 15] - [1044, 25])) + (blame_entry [1045, 4] - [1045, 25] + line: (number [1045, 11] - [1045, 14]) + date: (date [1045, 15] - [1045, 25])) + (blame_entry [1046, 4] - [1046, 25] + line: (number [1046, 11] - [1046, 14]) + date: (date [1046, 15] - [1046, 25])) + (blame_entry [1047, 4] - [1047, 25] + line: (number [1047, 11] - [1047, 14]) + date: (date [1047, 15] - [1047, 25]))) + (file_entry [1048, 0] - [1052, 25] + file_name: (filename [1048, 6] - [1048, 90]) + (blame_entry [1049, 4] - [1049, 25] + line: (number [1049, 11] - [1049, 14]) + date: (date [1049, 15] - [1049, 25])) + (blame_entry [1050, 4] - [1050, 25] + line: (number [1050, 11] - [1050, 14]) + date: (date [1050, 15] - [1050, 25])) + (blame_entry [1051, 4] - [1051, 25] + line: (number [1051, 11] - [1051, 14]) + date: (date [1051, 15] - [1051, 25])) + (blame_entry [1052, 4] - [1052, 25] + line: (number [1052, 11] - [1052, 14]) + date: (date [1052, 15] - [1052, 25]))) + (file_entry [1053, 0] - [1057, 25] + file_name: (filename [1053, 6] - [1053, 70]) + (blame_entry [1054, 4] - [1054, 24] + line: (number [1054, 11] - [1054, 13]) + date: (date [1054, 14] - [1054, 24])) + (blame_entry [1055, 4] - [1055, 25] + line: (number [1055, 11] - [1055, 14]) + date: (date [1055, 15] - [1055, 25])) + (blame_entry [1056, 4] - [1056, 25] + line: (number [1056, 11] - [1056, 14]) + date: (date [1056, 15] - [1056, 25])) + (blame_entry [1057, 4] - [1057, 25] + line: (number [1057, 11] - [1057, 14]) + date: (date [1057, 15] - [1057, 25]))) + (file_entry [1058, 0] - [1060, 25] + file_name: (filename [1058, 6] - [1058, 85]) + (blame_entry [1059, 4] - [1059, 25] + line: (number [1059, 11] - [1059, 14]) + date: (date [1059, 15] - [1059, 25])) + (blame_entry [1060, 4] - [1060, 25] + line: (number [1060, 11] - [1060, 14]) + date: (date [1060, 15] - [1060, 25]))) + (file_entry [1061, 0] - [1064, 25] + file_name: (filename [1061, 6] - [1061, 77]) + (blame_entry [1062, 4] - [1062, 24] + line: (number [1062, 11] - [1062, 13]) + date: (date [1062, 14] - [1062, 24])) + (blame_entry [1063, 4] - [1063, 24] + line: (number [1063, 11] - [1063, 13]) + date: (date [1063, 14] - [1063, 24])) + (blame_entry [1064, 4] - [1064, 25] + line: (number [1064, 11] - [1064, 14]) + date: (date [1064, 15] - [1064, 25]))) + (file_entry [1065, 0] - [1069, 25] + file_name: (filename [1065, 6] - [1065, 81]) + (blame_entry [1066, 4] - [1066, 24] + line: (number [1066, 11] - [1066, 13]) + date: (date [1066, 14] - [1066, 24])) + (blame_entry [1067, 4] - [1067, 25] + line: (number [1067, 11] - [1067, 14]) + date: (date [1067, 15] - [1067, 25])) + (blame_entry [1068, 4] - [1068, 25] + line: (number [1068, 11] - [1068, 14]) + date: (date [1068, 15] - [1068, 25])) + (blame_entry [1069, 4] - [1069, 25] + line: (number [1069, 11] - [1069, 14]) + date: (date [1069, 15] - [1069, 25]))) + (file_entry [1070, 0] - [1071, 24] + file_name: (filename [1070, 6] - [1070, 73]) + (blame_entry [1071, 4] - [1071, 24] + line: (number [1071, 11] - [1071, 13]) + date: (date [1071, 14] - [1071, 24]))) + (file_entry [1072, 0] - [1073, 24] + file_name: (filename [1072, 6] - [1072, 49]) + (blame_entry [1073, 4] - [1073, 24] + line: (number [1073, 11] - [1073, 13]) + date: (date [1073, 14] - [1073, 24]))) + (file_entry [1074, 0] - [1076, 25] + file_name: (filename [1074, 6] - [1074, 52]) + (blame_entry [1075, 4] - [1075, 25] + line: (number [1075, 11] - [1075, 14]) + date: (date [1075, 15] - [1075, 25])) + (blame_entry [1076, 4] - [1076, 25] + line: (number [1076, 11] - [1076, 14]) + date: (date [1076, 15] - [1076, 25]))) + (file_entry [1077, 0] - [1079, 24] + file_name: (filename [1077, 6] - [1077, 57]) + (blame_entry [1078, 4] - [1078, 24] + line: (number [1078, 11] - [1078, 13]) + date: (date [1078, 14] - [1078, 24])) + (blame_entry [1079, 4] - [1079, 24] + line: (number [1079, 11] - [1079, 13]) + date: (date [1079, 14] - [1079, 24]))) + (file_entry [1080, 0] - [1081, 24] + file_name: (filename [1080, 6] - [1080, 68]) + (blame_entry [1081, 4] - [1081, 24] + line: (number [1081, 11] - [1081, 13]) + date: (date [1081, 14] - [1081, 24]))) + (file_entry [1082, 0] - [1086, 25] + file_name: (filename [1082, 6] - [1082, 74]) + (blame_entry [1083, 4] - [1083, 24] + line: (number [1083, 11] - [1083, 13]) + date: (date [1083, 14] - [1083, 24])) + (blame_entry [1084, 4] - [1084, 25] + line: (number [1084, 11] - [1084, 14]) + date: (date [1084, 15] - [1084, 25])) + (blame_entry [1085, 4] - [1085, 25] + line: (number [1085, 11] - [1085, 14]) + date: (date [1085, 15] - [1085, 25])) + (blame_entry [1086, 4] - [1086, 25] + line: (number [1086, 11] - [1086, 14]) + date: (date [1086, 15] - [1086, 25]))) + (file_entry [1087, 0] - [1091, 25] + file_name: (filename [1087, 6] - [1087, 73]) + (blame_entry [1088, 4] - [1088, 24] + line: (number [1088, 11] - [1088, 13]) + date: (date [1088, 14] - [1088, 24])) + (blame_entry [1089, 4] - [1089, 25] + line: (number [1089, 11] - [1089, 14]) + date: (date [1089, 15] - [1089, 25])) + (blame_entry [1090, 4] - [1090, 25] + line: (number [1090, 11] - [1090, 14]) + date: (date [1090, 15] - [1090, 25])) + (blame_entry [1091, 4] - [1091, 25] + line: (number [1091, 11] - [1091, 14]) + date: (date [1091, 15] - [1091, 25]))) + (file_entry [1092, 0] - [1100, 25] + file_name: (filename [1092, 6] - [1092, 69]) + (blame_entry [1093, 4] - [1093, 23] + line: (number [1093, 11] - [1093, 12]) + date: (date [1093, 13] - [1093, 23])) + (blame_entry [1094, 4] - [1094, 24] + line: (number [1094, 11] - [1094, 13]) + date: (date [1094, 14] - [1094, 24])) + (blame_entry [1095, 4] - [1095, 25] + line: (number [1095, 11] - [1095, 14]) + date: (date [1095, 15] - [1095, 25])) + (blame_entry [1096, 4] - [1096, 25] + line: (number [1096, 11] - [1096, 14]) + date: (date [1096, 15] - [1096, 25])) + (blame_entry [1097, 4] - [1097, 25] + line: (number [1097, 11] - [1097, 14]) + date: (date [1097, 15] - [1097, 25])) + (blame_entry [1098, 4] - [1098, 25] + line: (number [1098, 11] - [1098, 14]) + date: (date [1098, 15] - [1098, 25])) + (blame_entry [1099, 4] - [1099, 25] + line: (number [1099, 11] - [1099, 14]) + date: (date [1099, 15] - [1099, 25])) + (blame_entry [1100, 4] - [1100, 25] + line: (number [1100, 11] - [1100, 14]) + date: (date [1100, 15] - [1100, 25]))) + (file_entry [1101, 0] - [1102, 24] + file_name: (filename [1101, 6] - [1101, 72]) + (blame_entry [1102, 4] - [1102, 24] + line: (number [1102, 11] - [1102, 13]) + date: (date [1102, 14] - [1102, 24]))) + (file_entry [1103, 0] - [1106, 25] + file_name: (filename [1103, 6] - [1103, 45]) + (blame_entry [1104, 4] - [1104, 25] + line: (number [1104, 11] - [1104, 14]) + date: (date [1104, 15] - [1104, 25])) + (blame_entry [1105, 4] - [1105, 25] + line: (number [1105, 11] - [1105, 14]) + date: (date [1105, 15] - [1105, 25])) + (blame_entry [1106, 4] - [1106, 25] + line: (number [1106, 11] - [1106, 14]) + date: (date [1106, 15] - [1106, 25]))) + (file_entry [1107, 0] - [1111, 24] + file_name: (filename [1107, 6] - [1107, 57]) + (blame_entry [1108, 4] - [1108, 23] + line: (number [1108, 11] - [1108, 12]) + date: (date [1108, 13] - [1108, 23])) + (blame_entry [1109, 4] - [1109, 24] + line: (number [1109, 11] - [1109, 13]) + date: (date [1109, 14] - [1109, 24])) + (blame_entry [1110, 4] - [1110, 24] + line: (number [1110, 11] - [1110, 13]) + date: (date [1110, 14] - [1110, 24])) + (blame_entry [1111, 4] - [1111, 24] + line: (number [1111, 11] - [1111, 13]) + date: (date [1111, 14] - [1111, 24]))) + (file_entry [1112, 0] - [1113, 24] + file_name: (filename [1112, 6] - [1112, 72]) + (blame_entry [1113, 4] - [1113, 24] + line: (number [1113, 11] - [1113, 13]) + date: (date [1113, 14] - [1113, 24]))) + (file_entry [1114, 0] - [1115, 24] + file_name: (filename [1114, 6] - [1114, 72]) + (blame_entry [1115, 4] - [1115, 24] + line: (number [1115, 11] - [1115, 13]) + date: (date [1115, 14] - [1115, 24]))) + (file_entry [1116, 0] - [1118, 24] + file_name: (filename [1116, 6] - [1116, 96]) + (blame_entry [1117, 4] - [1117, 23] + line: (number [1117, 11] - [1117, 12]) + date: (date [1117, 13] - [1117, 23])) + (blame_entry [1118, 4] - [1118, 24] + line: (number [1118, 11] - [1118, 13]) + date: (date [1118, 14] - [1118, 24]))) + (file_entry [1119, 0] - [1120, 23] + file_name: (filename [1119, 6] - [1119, 75]) + (blame_entry [1120, 4] - [1120, 23] + line: (number [1120, 11] - [1120, 12]) + date: (date [1120, 13] - [1120, 23]))) + (file_entry [1121, 0] - [1122, 23] + file_name: (filename [1121, 6] - [1121, 54]) + (blame_entry [1122, 4] - [1122, 23] + line: (number [1122, 11] - [1122, 12]) + date: (date [1122, 13] - [1122, 23]))) + (file_entry [1123, 0] - [1124, 24] + file_name: (filename [1123, 6] - [1123, 70]) + (blame_entry [1124, 4] - [1124, 24] + line: (number [1124, 11] - [1124, 13]) + date: (date [1124, 14] - [1124, 24]))) + (file_entry [1125, 0] - [1126, 25] + file_name: (filename [1125, 6] - [1125, 71]) + (blame_entry [1126, 4] - [1126, 25] + line: (number [1126, 11] - [1126, 14]) + date: (date [1126, 15] - [1126, 25]))) + (file_entry [1127, 0] - [1131, 25] + file_name: (filename [1127, 6] - [1127, 47]) + (blame_entry [1128, 4] - [1128, 25] + line: (number [1128, 11] - [1128, 14]) + date: (date [1128, 15] - [1128, 25])) + (blame_entry [1129, 4] - [1129, 25] + line: (number [1129, 11] - [1129, 14]) + date: (date [1129, 15] - [1129, 25])) + (blame_entry [1130, 4] - [1130, 25] + line: (number [1130, 11] - [1130, 14]) + date: (date [1130, 15] - [1130, 25])) + (blame_entry [1131, 4] - [1131, 25] + line: (number [1131, 11] - [1131, 14]) + date: (date [1131, 15] - [1131, 25]))) + (file_entry [1132, 0] - [1134, 24] + file_name: (filename [1132, 6] - [1132, 58]) + (blame_entry [1133, 4] - [1133, 24] + line: (number [1133, 11] - [1133, 13]) + date: (date [1133, 14] - [1133, 24])) + (blame_entry [1134, 4] - [1134, 24] + line: (number [1134, 11] - [1134, 13]) + date: (date [1134, 14] - [1134, 24]))) + (file_entry [1135, 0] - [1136, 25] + file_name: (filename [1135, 6] - [1135, 46]) + (blame_entry [1136, 4] - [1136, 25] + line: (number [1136, 11] - [1136, 14]) + date: (date [1136, 15] - [1136, 25]))) + (file_entry [1137, 0] - [1138, 25] + file_name: (filename [1137, 6] - [1137, 89]) + (blame_entry [1138, 4] - [1138, 25] + line: (number [1138, 11] - [1138, 14]) + date: (date [1138, 15] - [1138, 25]))) + (file_entry [1139, 0] - [1141, 24] + file_name: (filename [1139, 6] - [1139, 73]) + (blame_entry [1140, 4] - [1140, 24] + line: (number [1140, 11] - [1140, 13]) + date: (date [1140, 14] - [1140, 24])) + (blame_entry [1141, 4] - [1141, 24] + line: (number [1141, 11] - [1141, 13]) + date: (date [1141, 14] - [1141, 24]))) + (file_entry [1142, 0] - [1144, 24] + file_name: (filename [1142, 6] - [1142, 57]) + (blame_entry [1143, 4] - [1143, 24] + line: (number [1143, 11] - [1143, 13]) + date: (date [1143, 14] - [1143, 24])) + (blame_entry [1144, 4] - [1144, 24] + line: (number [1144, 11] - [1144, 13]) + date: (date [1144, 14] - [1144, 24]))) + (file_entry [1145, 0] - [1154, 25] + file_name: (filename [1145, 6] - [1145, 50]) + (blame_entry [1146, 4] - [1146, 24] + line: (number [1146, 11] - [1146, 13]) + date: (date [1146, 14] - [1146, 24])) + (blame_entry [1147, 4] - [1147, 24] + line: (number [1147, 11] - [1147, 13]) + date: (date [1147, 14] - [1147, 24])) + (blame_entry [1148, 4] - [1148, 25] + line: (number [1148, 11] - [1148, 14]) + date: (date [1148, 15] - [1148, 25])) + (blame_entry [1149, 4] - [1149, 25] + line: (number [1149, 11] - [1149, 14]) + date: (date [1149, 15] - [1149, 25])) + (blame_entry [1150, 4] - [1150, 25] + line: (number [1150, 11] - [1150, 14]) + date: (date [1150, 15] - [1150, 25])) + (blame_entry [1151, 4] - [1151, 25] + line: (number [1151, 11] - [1151, 14]) + date: (date [1151, 15] - [1151, 25])) + (blame_entry [1152, 4] - [1152, 25] + line: (number [1152, 11] - [1152, 14]) + date: (date [1152, 15] - [1152, 25])) + (blame_entry [1153, 4] - [1153, 25] + line: (number [1153, 11] - [1153, 14]) + date: (date [1153, 15] - [1153, 25])) + (blame_entry [1154, 4] - [1154, 25] + line: (number [1154, 11] - [1154, 14]) + date: (date [1154, 15] - [1154, 25]))) + (file_entry [1155, 0] - [1158, 25] + file_name: (filename [1155, 6] - [1155, 101]) + (blame_entry [1156, 4] - [1156, 24] + line: (number [1156, 11] - [1156, 13]) + date: (date [1156, 14] - [1156, 24])) + (blame_entry [1157, 4] - [1157, 24] + line: (number [1157, 11] - [1157, 13]) + date: (date [1157, 14] - [1157, 24])) + (blame_entry [1158, 4] - [1158, 25] + line: (number [1158, 11] - [1158, 14]) + date: (date [1158, 15] - [1158, 25]))) + (file_entry [1159, 0] - [1162, 24] + file_name: (filename [1159, 6] - [1159, 58]) + (blame_entry [1160, 4] - [1160, 23] + line: (number [1160, 11] - [1160, 12]) + date: (date [1160, 13] - [1160, 23])) + (blame_entry [1161, 4] - [1161, 23] + line: (number [1161, 11] - [1161, 12]) + date: (date [1161, 13] - [1161, 23])) + (blame_entry [1162, 4] - [1162, 24] + line: (number [1162, 11] - [1162, 13]) + date: (date [1162, 14] - [1162, 24]))) + (file_entry [1163, 0] - [1164, 24] + file_name: (filename [1163, 6] - [1163, 91]) + (blame_entry [1164, 4] - [1164, 24] + line: (number [1164, 11] - [1164, 13]) + date: (date [1164, 14] - [1164, 24]))) + (file_entry [1165, 0] - [1167, 24] + file_name: (filename [1165, 6] - [1165, 80]) + (blame_entry [1166, 4] - [1166, 24] + line: (number [1166, 11] - [1166, 13]) + date: (date [1166, 14] - [1166, 24])) + (blame_entry [1167, 4] - [1167, 24] + line: (number [1167, 11] - [1167, 13]) + date: (date [1167, 14] - [1167, 24]))) + (file_entry [1168, 0] - [1169, 25] + file_name: (filename [1168, 6] - [1168, 68]) + (blame_entry [1169, 4] - [1169, 25] + line: (number [1169, 11] - [1169, 14]) + date: (date [1169, 15] - [1169, 25]))) + (file_entry [1170, 0] - [1172, 24] + file_name: (filename [1170, 6] - [1170, 57]) + (blame_entry [1171, 4] - [1171, 24] + line: (number [1171, 11] - [1171, 13]) + date: (date [1171, 14] - [1171, 24])) + (blame_entry [1172, 4] - [1172, 24] + line: (number [1172, 11] - [1172, 13]) + date: (date [1172, 14] - [1172, 24]))) + (file_entry [1173, 0] - [1174, 24] + file_name: (filename [1173, 6] - [1173, 69]) + (blame_entry [1174, 4] - [1174, 24] + line: (number [1174, 11] - [1174, 13]) + date: (date [1174, 14] - [1174, 24]))) + (file_entry [1175, 0] - [1184, 26] + file_name: (filename [1175, 6] - [1175, 43]) + (blame_entry [1176, 4] - [1176, 25] + line: (number [1176, 11] - [1176, 14]) + date: (date [1176, 15] - [1176, 25])) + (blame_entry [1177, 4] - [1177, 25] + line: (number [1177, 11] - [1177, 14]) + date: (date [1177, 15] - [1177, 25])) + (blame_entry [1178, 4] - [1178, 25] + line: (number [1178, 11] - [1178, 14]) + date: (date [1178, 15] - [1178, 25])) + (blame_entry [1179, 4] - [1179, 25] + line: (number [1179, 11] - [1179, 14]) + date: (date [1179, 15] - [1179, 25])) + (blame_entry [1180, 4] - [1180, 25] + line: (number [1180, 11] - [1180, 14]) + date: (date [1180, 15] - [1180, 25])) + (blame_entry [1181, 4] - [1181, 25] + line: (number [1181, 11] - [1181, 14]) + date: (date [1181, 15] - [1181, 25])) + (blame_entry [1182, 4] - [1182, 25] + line: (number [1182, 11] - [1182, 14]) + date: (date [1182, 15] - [1182, 25])) + (blame_entry [1183, 4] - [1183, 25] + line: (number [1183, 11] - [1183, 14]) + date: (date [1183, 15] - [1183, 25])) + (blame_entry [1184, 4] - [1184, 26] + line: (number [1184, 11] - [1184, 15]) + date: (date [1184, 16] - [1184, 26]))) + (file_entry [1185, 0] - [1188, 24] + file_name: (filename [1185, 6] - [1185, 70]) + (blame_entry [1186, 4] - [1186, 24] + line: (number [1186, 11] - [1186, 13]) + date: (date [1186, 14] - [1186, 24])) + (blame_entry [1187, 4] - [1187, 24] + line: (number [1187, 11] - [1187, 13]) + date: (date [1187, 14] - [1187, 24])) + (blame_entry [1188, 4] - [1188, 24] + line: (number [1188, 11] - [1188, 13]) + date: (date [1188, 14] - [1188, 24]))) + (file_entry [1189, 0] - [1190, 23] + file_name: (filename [1189, 6] - [1189, 61]) + (blame_entry [1190, 4] - [1190, 23] + line: (number [1190, 11] - [1190, 12]) + date: (date [1190, 13] - [1190, 23]))) + (file_entry [1191, 0] - [1192, 24] + file_name: (filename [1191, 6] - [1191, 51]) + (blame_entry [1192, 4] - [1192, 24] + line: (number [1192, 11] - [1192, 13]) + date: (date [1192, 14] - [1192, 24]))) + (file_entry [1193, 0] - [1195, 24] + file_name: (filename [1193, 6] - [1193, 40]) + (blame_entry [1194, 4] - [1194, 24] + line: (number [1194, 11] - [1194, 13]) + date: (date [1194, 14] - [1194, 24])) + (blame_entry [1195, 4] - [1195, 24] + line: (number [1195, 11] - [1195, 13]) + date: (date [1195, 14] - [1195, 24]))) + (file_entry [1196, 0] - [1198, 25] + file_name: (filename [1196, 6] - [1196, 62]) + (blame_entry [1197, 4] - [1197, 25] + line: (number [1197, 11] - [1197, 14]) + date: (date [1197, 15] - [1197, 25])) + (blame_entry [1198, 4] - [1198, 25] + line: (number [1198, 11] - [1198, 14]) + date: (date [1198, 15] - [1198, 25]))) + (file_entry [1199, 0] - [1200, 24] + file_name: (filename [1199, 6] - [1199, 85]) + (blame_entry [1200, 4] - [1200, 24] + line: (number [1200, 11] - [1200, 13]) + date: (date [1200, 14] - [1200, 24]))) + (file_entry [1201, 0] - [1202, 24] + file_name: (filename [1201, 6] - [1201, 76]) + (blame_entry [1202, 4] - [1202, 24] + line: (number [1202, 11] - [1202, 13]) + date: (date [1202, 14] - [1202, 24]))) + (file_entry [1203, 0] - [1204, 24] + file_name: (filename [1203, 6] - [1203, 82]) + (blame_entry [1204, 4] - [1204, 24] + line: (number [1204, 11] - [1204, 13]) + date: (date [1204, 14] - [1204, 24]))) + (file_entry [1205, 0] - [1207, 24] + file_name: (filename [1205, 6] - [1205, 65]) + (blame_entry [1206, 4] - [1206, 23] + line: (number [1206, 11] - [1206, 12]) + date: (date [1206, 13] - [1206, 23])) + (blame_entry [1207, 4] - [1207, 24] + line: (number [1207, 11] - [1207, 13]) + date: (date [1207, 14] - [1207, 24]))) + (file_entry [1208, 0] - [1209, 25] + file_name: (filename [1208, 6] - [1208, 71]) + (blame_entry [1209, 4] - [1209, 25] + line: (number [1209, 11] - [1209, 14]) + date: (date [1209, 15] - [1209, 25]))) + (file_entry [1210, 0] - [1228, 24] + file_name: (filename [1210, 6] - [1210, 60]) + (blame_entry [1211, 4] - [1211, 24] + line: (number [1211, 11] - [1211, 13]) + date: (date [1211, 14] - [1211, 24])) + (blame_entry [1212, 4] - [1212, 24] + line: (number [1212, 11] - [1212, 13]) + date: (date [1212, 14] - [1212, 24])) + (blame_entry [1213, 4] - [1213, 24] + line: (number [1213, 11] - [1213, 13]) + date: (date [1213, 14] - [1213, 24])) + (blame_entry [1214, 4] - [1214, 24] + line: (number [1214, 11] - [1214, 13]) + date: (date [1214, 14] - [1214, 24])) + (blame_entry [1215, 4] - [1215, 24] + line: (number [1215, 11] - [1215, 13]) + date: (date [1215, 14] - [1215, 24])) + (blame_entry [1216, 4] - [1216, 24] + line: (number [1216, 11] - [1216, 13]) + date: (date [1216, 14] - [1216, 24])) + (blame_entry [1217, 4] - [1217, 24] + line: (number [1217, 11] - [1217, 13]) + date: (date [1217, 14] - [1217, 24])) + (blame_entry [1218, 4] - [1218, 24] + line: (number [1218, 11] - [1218, 13]) + date: (date [1218, 14] - [1218, 24])) + (blame_entry [1219, 4] - [1219, 24] + line: (number [1219, 11] - [1219, 13]) + date: (date [1219, 14] - [1219, 24])) + (blame_entry [1220, 4] - [1220, 24] + line: (number [1220, 11] - [1220, 13]) + date: (date [1220, 14] - [1220, 24])) + (blame_entry [1221, 4] - [1221, 24] + line: (number [1221, 11] - [1221, 13]) + date: (date [1221, 14] - [1221, 24])) + (blame_entry [1222, 4] - [1222, 24] + line: (number [1222, 11] - [1222, 13]) + date: (date [1222, 14] - [1222, 24])) + (blame_entry [1223, 4] - [1223, 24] + line: (number [1223, 11] - [1223, 13]) + date: (date [1223, 14] - [1223, 24])) + (blame_entry [1224, 4] - [1224, 24] + line: (number [1224, 11] - [1224, 13]) + date: (date [1224, 14] - [1224, 24])) + (blame_entry [1225, 4] - [1225, 24] + line: (number [1225, 11] - [1225, 13]) + date: (date [1225, 14] - [1225, 24])) + (blame_entry [1226, 4] - [1226, 24] + line: (number [1226, 11] - [1226, 13]) + date: (date [1226, 14] - [1226, 24])) + (blame_entry [1227, 4] - [1227, 24] + line: (number [1227, 11] - [1227, 13]) + date: (date [1227, 14] - [1227, 24])) + (blame_entry [1228, 4] - [1228, 24] + line: (number [1228, 11] - [1228, 13]) + date: (date [1228, 14] - [1228, 24]))) + (file_entry [1229, 0] - [1230, 24] + file_name: (filename [1229, 6] - [1229, 45]) + (blame_entry [1230, 4] - [1230, 24] + line: (number [1230, 11] - [1230, 13]) + date: (date [1230, 14] - [1230, 24]))) + (file_entry [1231, 0] - [1232, 24] + file_name: (filename [1231, 6] - [1231, 64]) + (blame_entry [1232, 4] - [1232, 24] + line: (number [1232, 11] - [1232, 13]) + date: (date [1232, 14] - [1232, 24]))) + (file_entry [1233, 0] - [1234, 25] + file_name: (filename [1233, 6] - [1233, 50]) + (blame_entry [1234, 4] - [1234, 25] + line: (number [1234, 11] - [1234, 14]) + date: (date [1234, 15] - [1234, 25]))) + (file_entry [1235, 0] - [1237, 24] + file_name: (filename [1235, 6] - [1235, 68]) + (blame_entry [1236, 4] - [1236, 24] + line: (number [1236, 11] - [1236, 13]) + date: (date [1236, 14] - [1236, 24])) + (blame_entry [1237, 4] - [1237, 24] + line: (number [1237, 11] - [1237, 13]) + date: (date [1237, 14] - [1237, 24]))) + (file_entry [1238, 0] - [1243, 25] + file_name: (filename [1238, 6] - [1238, 66]) + (blame_entry [1239, 4] - [1239, 24] + line: (number [1239, 11] - [1239, 13]) + date: (date [1239, 14] - [1239, 24])) + (blame_entry [1240, 4] - [1240, 25] + line: (number [1240, 11] - [1240, 14]) + date: (date [1240, 15] - [1240, 25])) + (blame_entry [1241, 4] - [1241, 25] + line: (number [1241, 11] - [1241, 14]) + date: (date [1241, 15] - [1241, 25])) + (blame_entry [1242, 4] - [1242, 25] + line: (number [1242, 11] - [1242, 14]) + date: (date [1242, 15] - [1242, 25])) + (blame_entry [1243, 4] - [1243, 25] + line: (number [1243, 11] - [1243, 14]) + date: (date [1243, 15] - [1243, 25]))) + (file_entry [1244, 0] - [1245, 24] + file_name: (filename [1244, 6] - [1244, 72]) + (blame_entry [1245, 4] - [1245, 24] + line: (number [1245, 11] - [1245, 13]) + date: (date [1245, 14] - [1245, 24]))) + (file_entry [1246, 0] - [1248, 25] + file_name: (filename [1246, 6] - [1246, 46]) + (blame_entry [1247, 4] - [1247, 25] + line: (number [1247, 11] - [1247, 14]) + date: (date [1247, 15] - [1247, 25])) + (blame_entry [1248, 4] - [1248, 25] + line: (number [1248, 11] - [1248, 14]) + date: (date [1248, 15] - [1248, 25]))) + (file_entry [1249, 0] - [1250, 25] + file_name: (filename [1249, 6] - [1249, 49]) + (blame_entry [1250, 4] - [1250, 25] + line: (number [1250, 11] - [1250, 14]) + date: (date [1250, 15] - [1250, 25]))) + (file_entry [1251, 0] - [1252, 24] + file_name: (filename [1251, 6] - [1251, 48]) + (blame_entry [1252, 4] - [1252, 24] + line: (number [1252, 11] - [1252, 13]) + date: (date [1252, 14] - [1252, 24]))) + (file_entry [1253, 0] - [1254, 24] + file_name: (filename [1253, 6] - [1253, 79]) + (blame_entry [1254, 4] - [1254, 24] + line: (number [1254, 11] - [1254, 13]) + date: (date [1254, 14] - [1254, 24]))) + (file_entry [1255, 0] - [1256, 24] + file_name: (filename [1255, 6] - [1255, 70]) + (blame_entry [1256, 4] - [1256, 24] + line: (number [1256, 11] - [1256, 13]) + date: (date [1256, 14] - [1256, 24]))) + (file_entry [1257, 0] - [1258, 24] + file_name: (filename [1257, 6] - [1257, 64]) + (blame_entry [1258, 4] - [1258, 24] + line: (number [1258, 11] - [1258, 13]) + date: (date [1258, 14] - [1258, 24]))) + (file_entry [1259, 0] - [1261, 24] + file_name: (filename [1259, 6] - [1259, 71]) + (blame_entry [1260, 4] - [1260, 24] + line: (number [1260, 11] - [1260, 13]) + date: (date [1260, 14] - [1260, 24])) + (blame_entry [1261, 4] - [1261, 24] + line: (number [1261, 11] - [1261, 13]) + date: (date [1261, 14] - [1261, 24]))) + (file_entry [1262, 0] - [1263, 24] + file_name: (filename [1262, 6] - [1262, 84]) + (blame_entry [1263, 4] - [1263, 24] + line: (number [1263, 11] - [1263, 13]) + date: (date [1263, 14] - [1263, 24]))) + (file_entry [1264, 0] - [1265, 25] + file_name: (filename [1264, 6] - [1264, 66]) + (blame_entry [1265, 4] - [1265, 25] + line: (number [1265, 11] - [1265, 14]) + date: (date [1265, 15] - [1265, 25]))) + (file_entry [1266, 0] - [1267, 23] + file_name: (filename [1266, 6] - [1266, 84]) + (blame_entry [1267, 4] - [1267, 23] + line: (number [1267, 11] - [1267, 12]) + date: (date [1267, 13] - [1267, 23]))) + (file_entry [1268, 0] - [1273, 25] + file_name: (filename [1268, 6] - [1268, 68]) + (blame_entry [1269, 4] - [1269, 24] + line: (number [1269, 11] - [1269, 13]) + date: (date [1269, 14] - [1269, 24])) + (blame_entry [1270, 4] - [1270, 24] + line: (number [1270, 11] - [1270, 13]) + date: (date [1270, 14] - [1270, 24])) + (blame_entry [1271, 4] - [1271, 24] + line: (number [1271, 11] - [1271, 13]) + date: (date [1271, 14] - [1271, 24])) + (blame_entry [1272, 4] - [1272, 25] + line: (number [1272, 11] - [1272, 14]) + date: (date [1272, 15] - [1272, 25])) + (blame_entry [1273, 4] - [1273, 25] + line: (number [1273, 11] - [1273, 14]) + date: (date [1273, 15] - [1273, 25]))) + (file_entry [1274, 0] - [1278, 24] + file_name: (filename [1274, 6] - [1274, 67]) + (blame_entry [1275, 4] - [1275, 23] + line: (number [1275, 11] - [1275, 12]) + date: (date [1275, 13] - [1275, 23])) + (blame_entry [1276, 4] - [1276, 24] + line: (number [1276, 11] - [1276, 13]) + date: (date [1276, 14] - [1276, 24])) + (blame_entry [1277, 4] - [1277, 24] + line: (number [1277, 11] - [1277, 13]) + date: (date [1277, 14] - [1277, 24])) + (blame_entry [1278, 4] - [1278, 24] + line: (number [1278, 11] - [1278, 13]) + date: (date [1278, 14] - [1278, 24]))) + (file_entry [1279, 0] - [1283, 24] + file_name: (filename [1279, 6] - [1279, 58]) + (blame_entry [1280, 4] - [1280, 23] + line: (number [1280, 11] - [1280, 12]) + date: (date [1280, 13] - [1280, 23])) + (blame_entry [1281, 4] - [1281, 24] + line: (number [1281, 11] - [1281, 13]) + date: (date [1281, 14] - [1281, 24])) + (blame_entry [1282, 4] - [1282, 24] + line: (number [1282, 11] - [1282, 13]) + date: (date [1282, 14] - [1282, 24])) + (blame_entry [1283, 4] - [1283, 24] + line: (number [1283, 11] - [1283, 13]) + date: (date [1283, 14] - [1283, 24]))) + (file_entry [1284, 0] - [1286, 24] + file_name: (filename [1284, 6] - [1284, 72]) + (blame_entry [1285, 4] - [1285, 23] + line: (number [1285, 11] - [1285, 12]) + date: (date [1285, 13] - [1285, 23])) + (blame_entry [1286, 4] - [1286, 24] + line: (number [1286, 11] - [1286, 13]) + date: (date [1286, 14] - [1286, 24]))) + (file_entry [1287, 0] - [1291, 25] + file_name: (filename [1287, 6] - [1287, 84]) + (blame_entry [1288, 4] - [1288, 24] + line: (number [1288, 11] - [1288, 13]) + date: (date [1288, 14] - [1288, 24])) + (blame_entry [1289, 4] - [1289, 25] + line: (number [1289, 11] - [1289, 14]) + date: (date [1289, 15] - [1289, 25])) + (blame_entry [1290, 4] - [1290, 25] + line: (number [1290, 11] - [1290, 14]) + date: (date [1290, 15] - [1290, 25])) + (blame_entry [1291, 4] - [1291, 25] + line: (number [1291, 11] - [1291, 14]) + date: (date [1291, 15] - [1291, 25]))) + (file_entry [1292, 0] - [1294, 24] + file_name: (filename [1292, 6] - [1292, 64]) + (blame_entry [1293, 4] - [1293, 24] + line: (number [1293, 11] - [1293, 13]) + date: (date [1293, 14] - [1293, 24])) + (blame_entry [1294, 4] - [1294, 24] + line: (number [1294, 11] - [1294, 13]) + date: (date [1294, 14] - [1294, 24]))) + (file_entry [1295, 0] - [1296, 23] + file_name: (filename [1295, 6] - [1295, 82]) + (blame_entry [1296, 4] - [1296, 23] + line: (number [1296, 11] - [1296, 12]) + date: (date [1296, 13] - [1296, 23]))) + (file_entry [1297, 0] - [1298, 24] + file_name: (filename [1297, 6] - [1297, 68]) + (blame_entry [1298, 4] - [1298, 24] + line: (number [1298, 11] - [1298, 13]) + date: (date [1298, 14] - [1298, 24]))) + (file_entry [1299, 0] - [1301, 26] + file_name: (filename [1299, 6] - [1299, 68]) + (blame_entry [1300, 4] - [1300, 25] + line: (number [1300, 11] - [1300, 14]) + date: (date [1300, 15] - [1300, 25])) + (blame_entry [1301, 4] - [1301, 26] + line: (number [1301, 11] - [1301, 15]) + date: (date [1301, 16] - [1301, 26]))) + (file_entry [1302, 0] - [1306, 24] + file_name: (filename [1302, 6] - [1302, 66]) + (blame_entry [1303, 4] - [1303, 23] + line: (number [1303, 11] - [1303, 12]) + date: (date [1303, 13] - [1303, 23])) + (blame_entry [1304, 4] - [1304, 24] + line: (number [1304, 11] - [1304, 13]) + date: (date [1304, 14] - [1304, 24])) + (blame_entry [1305, 4] - [1305, 24] + line: (number [1305, 11] - [1305, 13]) + date: (date [1305, 14] - [1305, 24])) + (blame_entry [1306, 4] - [1306, 24] + line: (number [1306, 11] - [1306, 13]) + date: (date [1306, 14] - [1306, 24]))) + (file_entry [1307, 0] - [1309, 24] + file_name: (filename [1307, 6] - [1307, 60]) + (blame_entry [1308, 4] - [1308, 24] + line: (number [1308, 11] - [1308, 13]) + date: (date [1308, 14] - [1308, 24])) + (blame_entry [1309, 4] - [1309, 24] + line: (number [1309, 11] - [1309, 13]) + date: (date [1309, 14] - [1309, 24]))) + (file_entry [1310, 0] - [1311, 25] + file_name: (filename [1310, 6] - [1310, 43]) + (blame_entry [1311, 4] - [1311, 25] + line: (number [1311, 11] - [1311, 14]) + date: (date [1311, 15] - [1311, 25]))) + (file_entry [1312, 0] - [1313, 23] + file_name: (filename [1312, 6] - [1312, 96]) + (blame_entry [1313, 4] - [1313, 23] + line: (number [1313, 11] - [1313, 12]) + date: (date [1313, 13] - [1313, 23]))) + (file_entry [1314, 0] - [1316, 24] + file_name: (filename [1314, 6] - [1314, 42]) + (blame_entry [1315, 4] - [1315, 24] + line: (number [1315, 11] - [1315, 13]) + date: (date [1315, 14] - [1315, 24])) + (blame_entry [1316, 4] - [1316, 24] + line: (number [1316, 11] - [1316, 13]) + date: (date [1316, 14] - [1316, 24]))) + (file_entry [1317, 0] - [1318, 24] + file_name: (filename [1317, 6] - [1317, 64]) + (blame_entry [1318, 4] - [1318, 24] + line: (number [1318, 11] - [1318, 13]) + date: (date [1318, 14] - [1318, 24]))) + (file_entry [1319, 0] - [1323, 25] + file_name: (filename [1319, 6] - [1319, 103]) + (blame_entry [1320, 4] - [1320, 25] + line: (number [1320, 11] - [1320, 14]) + date: (date [1320, 15] - [1320, 25])) + (blame_entry [1321, 4] - [1321, 25] + line: (number [1321, 11] - [1321, 14]) + date: (date [1321, 15] - [1321, 25])) + (blame_entry [1322, 4] - [1322, 25] + line: (number [1322, 11] - [1322, 14]) + date: (date [1322, 15] - [1322, 25])) + (blame_entry [1323, 4] - [1323, 25] + line: (number [1323, 11] - [1323, 14]) + date: (date [1323, 15] - [1323, 25]))) + (file_entry [1324, 0] - [1325, 24] + file_name: (filename [1324, 6] - [1324, 79]) + (blame_entry [1325, 4] - [1325, 24] + line: (number [1325, 11] - [1325, 13]) + date: (date [1325, 14] - [1325, 24]))) + (file_entry [1326, 0] - [1328, 25] + file_name: (filename [1326, 6] - [1326, 83]) + (blame_entry [1327, 4] - [1327, 24] + line: (number [1327, 11] - [1327, 13]) + date: (date [1327, 14] - [1327, 24])) + (blame_entry [1328, 4] - [1328, 25] + line: (number [1328, 11] - [1328, 14]) + date: (date [1328, 15] - [1328, 25]))) + (file_entry [1329, 0] - [1330, 24] + file_name: (filename [1329, 6] - [1329, 70]) + (blame_entry [1330, 4] - [1330, 24] + line: (number [1330, 11] - [1330, 13]) + date: (date [1330, 14] - [1330, 24]))) + (file_entry [1331, 0] - [1334, 24] + file_name: (filename [1331, 6] - [1331, 71]) + (blame_entry [1332, 4] - [1332, 24] + line: (number [1332, 11] - [1332, 13]) + date: (date [1332, 14] - [1332, 24])) + (blame_entry [1333, 4] - [1333, 24] + line: (number [1333, 11] - [1333, 13]) + date: (date [1333, 14] - [1333, 24])) + (blame_entry [1334, 4] - [1334, 24] + line: (number [1334, 11] - [1334, 13]) + date: (date [1334, 14] - [1334, 24]))) + (file_entry [1335, 0] - [1337, 24] + file_name: (filename [1335, 6] - [1335, 61]) + (blame_entry [1336, 4] - [1336, 24] + line: (number [1336, 11] - [1336, 13]) + date: (date [1336, 14] - [1336, 24])) + (blame_entry [1337, 4] - [1337, 24] + line: (number [1337, 11] - [1337, 13]) + date: (date [1337, 14] - [1337, 24]))) + (file_entry [1338, 0] - [1339, 24] + file_name: (filename [1338, 6] - [1338, 54]) + (blame_entry [1339, 4] - [1339, 24] + line: (number [1339, 11] - [1339, 13]) + date: (date [1339, 14] - [1339, 24]))) + (file_entry [1340, 0] - [1341, 24] + file_name: (filename [1340, 6] - [1340, 59]) + (blame_entry [1341, 4] - [1341, 24] + line: (number [1341, 11] - [1341, 13]) + date: (date [1341, 14] - [1341, 24]))) + (file_entry [1342, 0] - [1349, 24] + file_name: (filename [1342, 6] - [1342, 61]) + (blame_entry [1343, 4] - [1343, 23] + line: (number [1343, 11] - [1343, 12]) + date: (date [1343, 13] - [1343, 23])) + (blame_entry [1344, 4] - [1344, 24] + line: (number [1344, 11] - [1344, 13]) + date: (date [1344, 14] - [1344, 24])) + (blame_entry [1345, 4] - [1345, 24] + line: (number [1345, 11] - [1345, 13]) + date: (date [1345, 14] - [1345, 24])) + (blame_entry [1346, 4] - [1346, 24] + line: (number [1346, 11] - [1346, 13]) + date: (date [1346, 14] - [1346, 24])) + (blame_entry [1347, 4] - [1347, 24] + line: (number [1347, 11] - [1347, 13]) + date: (date [1347, 14] - [1347, 24])) + (blame_entry [1348, 4] - [1348, 24] + line: (number [1348, 11] - [1348, 13]) + date: (date [1348, 14] - [1348, 24])) + (blame_entry [1349, 4] - [1349, 24] + line: (number [1349, 11] - [1349, 13]) + date: (date [1349, 14] - [1349, 24]))) + (file_entry [1350, 0] - [1353, 25] + file_name: (filename [1350, 6] - [1350, 45]) + (blame_entry [1351, 4] - [1351, 25] + line: (number [1351, 11] - [1351, 14]) + date: (date [1351, 15] - [1351, 25])) + (blame_entry [1352, 4] - [1352, 25] + line: (number [1352, 11] - [1352, 14]) + date: (date [1352, 15] - [1352, 25])) + (blame_entry [1353, 4] - [1353, 25] + line: (number [1353, 11] - [1353, 14]) + date: (date [1353, 15] - [1353, 25]))) + (file_entry [1354, 0] - [1355, 24] + file_name: (filename [1354, 6] - [1354, 72]) + (blame_entry [1355, 4] - [1355, 24] + line: (number [1355, 11] - [1355, 13]) + date: (date [1355, 14] - [1355, 24]))) + (file_entry [1356, 0] - [1357, 24] + file_name: (filename [1356, 6] - [1356, 65]) + (blame_entry [1357, 4] - [1357, 24] + line: (number [1357, 11] - [1357, 13]) + date: (date [1357, 14] - [1357, 24]))) + (file_entry [1358, 0] - [1359, 24] + file_name: (filename [1358, 6] - [1358, 54]) + (blame_entry [1359, 4] - [1359, 24] + line: (number [1359, 11] - [1359, 13]) + date: (date [1359, 14] - [1359, 24]))) + (file_entry [1360, 0] - [1363, 25] + file_name: (filename [1360, 6] - [1360, 69]) + (blame_entry [1361, 4] - [1361, 24] + line: (number [1361, 11] - [1361, 13]) + date: (date [1361, 14] - [1361, 24])) + (blame_entry [1362, 4] - [1362, 24] + line: (number [1362, 11] - [1362, 13]) + date: (date [1362, 14] - [1362, 24])) + (blame_entry [1363, 4] - [1363, 25] + line: (number [1363, 11] - [1363, 14]) + date: (date [1363, 15] - [1363, 25]))) + (file_entry [1364, 0] - [1365, 23] + file_name: (filename [1364, 6] - [1364, 76]) + (blame_entry [1365, 4] - [1365, 23] + line: (number [1365, 11] - [1365, 12]) + date: (date [1365, 13] - [1365, 23]))) + (file_entry [1366, 0] - [1368, 25] + file_name: (filename [1366, 6] - [1366, 66]) + (blame_entry [1367, 4] - [1367, 24] + line: (number [1367, 11] - [1367, 13]) + date: (date [1367, 14] - [1367, 24])) + (blame_entry [1368, 4] - [1368, 25] + line: (number [1368, 11] - [1368, 14]) + date: (date [1368, 15] - [1368, 25]))) + (file_entry [1369, 0] - [1371, 23] + file_name: (filename [1369, 6] - [1369, 55]) + (blame_entry [1370, 4] - [1370, 23] + line: (number [1370, 11] - [1370, 12]) + date: (date [1370, 13] - [1370, 23])) + (blame_entry [1371, 4] - [1371, 23] + line: (number [1371, 11] - [1371, 12]) + date: (date [1371, 13] - [1371, 23]))) + (file_entry [1372, 0] - [1378, 24] + file_name: (filename [1372, 6] - [1372, 57]) + (blame_entry [1373, 4] - [1373, 23] + line: (number [1373, 11] - [1373, 12]) + date: (date [1373, 13] - [1373, 23])) + (blame_entry [1374, 4] - [1374, 24] + line: (number [1374, 11] - [1374, 13]) + date: (date [1374, 14] - [1374, 24])) + (blame_entry [1375, 4] - [1375, 24] + line: (number [1375, 11] - [1375, 13]) + date: (date [1375, 14] - [1375, 24])) + (blame_entry [1376, 4] - [1376, 24] + line: (number [1376, 11] - [1376, 13]) + date: (date [1376, 14] - [1376, 24])) + (blame_entry [1377, 4] - [1377, 24] + line: (number [1377, 11] - [1377, 13]) + date: (date [1377, 14] - [1377, 24])) + (blame_entry [1378, 4] - [1378, 24] + line: (number [1378, 11] - [1378, 13]) + date: (date [1378, 14] - [1378, 24]))) + (file_entry [1379, 0] - [1381, 24] + file_name: (filename [1379, 6] - [1379, 52]) + (blame_entry [1380, 4] - [1380, 24] + line: (number [1380, 11] - [1380, 13]) + date: (date [1380, 14] - [1380, 24])) + (blame_entry [1381, 4] - [1381, 24] + line: (number [1381, 11] - [1381, 13]) + date: (date [1381, 14] - [1381, 24]))) + (file_entry [1382, 0] - [1392, 24] + file_name: (filename [1382, 6] - [1382, 46]) + (blame_entry [1383, 4] - [1383, 23] + line: (number [1383, 11] - [1383, 12]) + date: (date [1383, 13] - [1383, 23])) + (blame_entry [1384, 4] - [1384, 24] + line: (number [1384, 11] - [1384, 13]) + date: (date [1384, 14] - [1384, 24])) + (blame_entry [1385, 4] - [1385, 24] + line: (number [1385, 11] - [1385, 13]) + date: (date [1385, 14] - [1385, 24])) + (blame_entry [1386, 4] - [1386, 24] + line: (number [1386, 11] - [1386, 13]) + date: (date [1386, 14] - [1386, 24])) + (blame_entry [1387, 4] - [1387, 24] + line: (number [1387, 11] - [1387, 13]) + date: (date [1387, 14] - [1387, 24])) + (blame_entry [1388, 4] - [1388, 24] + line: (number [1388, 11] - [1388, 13]) + date: (date [1388, 14] - [1388, 24])) + (blame_entry [1389, 4] - [1389, 24] + line: (number [1389, 11] - [1389, 13]) + date: (date [1389, 14] - [1389, 24])) + (blame_entry [1390, 4] - [1390, 24] + line: (number [1390, 11] - [1390, 13]) + date: (date [1390, 14] - [1390, 24])) + (blame_entry [1391, 4] - [1391, 24] + line: (number [1391, 11] - [1391, 13]) + date: (date [1391, 14] - [1391, 24])) + (blame_entry [1392, 4] - [1392, 24] + line: (number [1392, 11] - [1392, 13]) + date: (date [1392, 14] - [1392, 24]))) + (file_entry [1393, 0] - [1395, 25] + file_name: (filename [1393, 6] - [1393, 56]) + (blame_entry [1394, 4] - [1394, 24] + line: (number [1394, 11] - [1394, 13]) + date: (date [1394, 14] - [1394, 24])) + (blame_entry [1395, 4] - [1395, 25] + line: (number [1395, 11] - [1395, 14]) + date: (date [1395, 15] - [1395, 25]))) + (file_entry [1396, 0] - [1397, 23] + file_name: (filename [1396, 6] - [1396, 82]) + (blame_entry [1397, 4] - [1397, 23] + line: (number [1397, 11] - [1397, 12]) + date: (date [1397, 13] - [1397, 23]))) + (file_entry [1398, 0] - [1400, 24] + file_name: (filename [1398, 6] - [1398, 65]) + (blame_entry [1399, 4] - [1399, 24] + line: (number [1399, 11] - [1399, 13]) + date: (date [1399, 14] - [1399, 24])) + (blame_entry [1400, 4] - [1400, 24] + line: (number [1400, 11] - [1400, 13]) + date: (date [1400, 14] - [1400, 24]))) + (file_entry [1401, 0] - [1403, 25] + file_name: (filename [1401, 6] - [1401, 74]) + (blame_entry [1402, 4] - [1402, 24] + line: (number [1402, 11] - [1402, 13]) + date: (date [1402, 14] - [1402, 24])) + (blame_entry [1403, 4] - [1403, 25] + line: (number [1403, 11] - [1403, 14]) + date: (date [1403, 15] - [1403, 25]))) + (file_entry [1404, 0] - [1406, 25] + file_name: (filename [1404, 6] - [1404, 53]) + (blame_entry [1405, 4] - [1405, 25] + line: (number [1405, 11] - [1405, 14]) + date: (date [1405, 15] - [1405, 25])) + (blame_entry [1406, 4] - [1406, 25] + line: (number [1406, 11] - [1406, 14]) + date: (date [1406, 15] - [1406, 25]))) + (file_entry [1407, 0] - [1408, 25] + file_name: (filename [1407, 6] - [1407, 47]) + (blame_entry [1408, 4] - [1408, 25] + line: (number [1408, 11] - [1408, 14]) + date: (date [1408, 15] - [1408, 25]))) + (file_entry [1409, 0] - [1410, 24] + file_name: (filename [1409, 6] - [1409, 87]) + (blame_entry [1410, 4] - [1410, 24] + line: (number [1410, 11] - [1410, 13]) + date: (date [1410, 14] - [1410, 24]))) + (file_entry [1411, 0] - [1413, 25] + file_name: (filename [1411, 6] - [1411, 50]) + (blame_entry [1412, 4] - [1412, 25] + line: (number [1412, 11] - [1412, 14]) + date: (date [1412, 15] - [1412, 25])) + (blame_entry [1413, 4] - [1413, 25] + line: (number [1413, 11] - [1413, 14]) + date: (date [1413, 15] - [1413, 25]))) + (file_entry [1414, 0] - [1416, 25] + file_name: (filename [1414, 6] - [1414, 60]) + (blame_entry [1415, 4] - [1415, 25] + line: (number [1415, 11] - [1415, 14]) + date: (date [1415, 15] - [1415, 25])) + (blame_entry [1416, 4] - [1416, 25] + line: (number [1416, 11] - [1416, 14]) + date: (date [1416, 15] - [1416, 25]))) + (file_entry [1417, 0] - [1418, 24] + file_name: (filename [1417, 6] - [1417, 85]) + (blame_entry [1418, 4] - [1418, 24] + line: (number [1418, 11] - [1418, 13]) + date: (date [1418, 14] - [1418, 24]))) + (file_entry [1419, 0] - [1420, 23] + file_name: (filename [1419, 6] - [1419, 66]) + (blame_entry [1420, 4] - [1420, 23] + line: (number [1420, 11] - [1420, 12]) + date: (date [1420, 13] - [1420, 23]))) + (file_entry [1421, 0] - [1423, 24] + file_name: (filename [1421, 6] - [1421, 56]) + (blame_entry [1422, 4] - [1422, 24] + line: (number [1422, 11] - [1422, 13]) + date: (date [1422, 14] - [1422, 24])) + (blame_entry [1423, 4] - [1423, 24] + line: (number [1423, 11] - [1423, 13]) + date: (date [1423, 14] - [1423, 24]))) + (file_entry [1424, 0] - [1426, 24] + file_name: (filename [1424, 6] - [1424, 58]) + (blame_entry [1425, 4] - [1425, 23] + line: (number [1425, 11] - [1425, 12]) + date: (date [1425, 13] - [1425, 23])) + (blame_entry [1426, 4] - [1426, 24] + line: (number [1426, 11] - [1426, 13]) + date: (date [1426, 14] - [1426, 24]))) + (file_entry [1427, 0] - [1428, 24] + file_name: (filename [1427, 6] - [1427, 64]) + (blame_entry [1428, 4] - [1428, 24] + line: (number [1428, 11] - [1428, 13]) + date: (date [1428, 14] - [1428, 24]))) + (file_entry [1429, 0] - [1432, 25] + file_name: (filename [1429, 6] - [1429, 69]) + (blame_entry [1430, 4] - [1430, 24] + line: (number [1430, 11] - [1430, 13]) + date: (date [1430, 14] - [1430, 24])) + (blame_entry [1431, 4] - [1431, 24] + line: (number [1431, 11] - [1431, 13]) + date: (date [1431, 14] - [1431, 24])) + (blame_entry [1432, 4] - [1432, 25] + line: (number [1432, 11] - [1432, 14]) + date: (date [1432, 15] - [1432, 25]))) + (file_entry [1433, 0] - [1437, 25] + file_name: (filename [1433, 6] - [1433, 72]) + (blame_entry [1434, 4] - [1434, 24] + line: (number [1434, 11] - [1434, 13]) + date: (date [1434, 14] - [1434, 24])) + (blame_entry [1435, 4] - [1435, 25] + line: (number [1435, 11] - [1435, 14]) + date: (date [1435, 15] - [1435, 25])) + (blame_entry [1436, 4] - [1436, 25] + line: (number [1436, 11] - [1436, 14]) + date: (date [1436, 15] - [1436, 25])) + (blame_entry [1437, 4] - [1437, 25] + line: (number [1437, 11] - [1437, 14]) + date: (date [1437, 15] - [1437, 25]))) + (file_entry [1438, 0] - [1439, 25] + file_name: (filename [1438, 6] - [1438, 85]) + (blame_entry [1439, 4] - [1439, 25] + line: (number [1439, 11] - [1439, 14]) + date: (date [1439, 15] - [1439, 25]))) + (file_entry [1440, 0] - [1444, 25] + file_name: (filename [1440, 6] - [1440, 90]) + (blame_entry [1441, 4] - [1441, 25] + line: (number [1441, 11] - [1441, 14]) + date: (date [1441, 15] - [1441, 25])) + (blame_entry [1442, 4] - [1442, 25] + line: (number [1442, 11] - [1442, 14]) + date: (date [1442, 15] - [1442, 25])) + (blame_entry [1443, 4] - [1443, 25] + line: (number [1443, 11] - [1443, 14]) + date: (date [1443, 15] - [1443, 25])) + (blame_entry [1444, 4] - [1444, 25] + line: (number [1444, 11] - [1444, 14]) + date: (date [1444, 15] - [1444, 25]))) + (file_entry [1445, 0] - [1447, 24] + file_name: (filename [1445, 6] - [1445, 75]) + (blame_entry [1446, 4] - [1446, 24] + line: (number [1446, 11] - [1446, 13]) + date: (date [1446, 14] - [1446, 24])) + (blame_entry [1447, 4] - [1447, 24] + line: (number [1447, 11] - [1447, 13]) + date: (date [1447, 14] - [1447, 24]))) + (file_entry [1448, 0] - [1455, 25] + file_name: (filename [1448, 6] - [1448, 71]) + (blame_entry [1449, 4] - [1449, 24] + line: (number [1449, 11] - [1449, 13]) + date: (date [1449, 14] - [1449, 24])) + (blame_entry [1450, 4] - [1450, 24] + line: (number [1450, 11] - [1450, 13]) + date: (date [1450, 14] - [1450, 24])) + (blame_entry [1451, 4] - [1451, 24] + line: (number [1451, 11] - [1451, 13]) + date: (date [1451, 14] - [1451, 24])) + (blame_entry [1452, 4] - [1452, 25] + line: (number [1452, 11] - [1452, 14]) + date: (date [1452, 15] - [1452, 25])) + (blame_entry [1453, 4] - [1453, 25] + line: (number [1453, 11] - [1453, 14]) + date: (date [1453, 15] - [1453, 25])) + (blame_entry [1454, 4] - [1454, 25] + line: (number [1454, 11] - [1454, 14]) + date: (date [1454, 15] - [1454, 25])) + (blame_entry [1455, 4] - [1455, 25] + line: (number [1455, 11] - [1455, 14]) + date: (date [1455, 15] - [1455, 25]))) + (file_entry [1456, 0] - [1457, 24] + file_name: (filename [1456, 6] - [1456, 67]) + (blame_entry [1457, 4] - [1457, 24] + line: (number [1457, 11] - [1457, 13]) + date: (date [1457, 14] - [1457, 24]))) + (file_entry [1458, 0] - [1462, 25] + file_name: (filename [1458, 6] - [1458, 84]) + (blame_entry [1459, 4] - [1459, 25] + line: (number [1459, 11] - [1459, 14]) + date: (date [1459, 15] - [1459, 25])) + (blame_entry [1460, 4] - [1460, 25] + line: (number [1460, 11] - [1460, 14]) + date: (date [1460, 15] - [1460, 25])) + (blame_entry [1461, 4] - [1461, 25] + line: (number [1461, 11] - [1461, 14]) + date: (date [1461, 15] - [1461, 25])) + (blame_entry [1462, 4] - [1462, 25] + line: (number [1462, 11] - [1462, 14]) + date: (date [1462, 15] - [1462, 25]))) + (file_entry [1463, 0] - [1476, 25] + file_name: (filename [1463, 6] - [1463, 63]) + (blame_entry [1464, 4] - [1464, 25] + line: (number [1464, 11] - [1464, 14]) + date: (date [1464, 15] - [1464, 25])) + (blame_entry [1465, 4] - [1465, 25] + line: (number [1465, 11] - [1465, 14]) + date: (date [1465, 15] - [1465, 25])) + (blame_entry [1466, 4] - [1466, 25] + line: (number [1466, 11] - [1466, 14]) + date: (date [1466, 15] - [1466, 25])) + (blame_entry [1467, 4] - [1467, 25] + line: (number [1467, 11] - [1467, 14]) + date: (date [1467, 15] - [1467, 25])) + (blame_entry [1468, 4] - [1468, 25] + line: (number [1468, 11] - [1468, 14]) + date: (date [1468, 15] - [1468, 25])) + (blame_entry [1469, 4] - [1469, 25] + line: (number [1469, 11] - [1469, 14]) + date: (date [1469, 15] - [1469, 25])) + (blame_entry [1470, 4] - [1470, 25] + line: (number [1470, 11] - [1470, 14]) + date: (date [1470, 15] - [1470, 25])) + (blame_entry [1471, 4] - [1471, 25] + line: (number [1471, 11] - [1471, 14]) + date: (date [1471, 15] - [1471, 25])) + (blame_entry [1472, 4] - [1472, 25] + line: (number [1472, 11] - [1472, 14]) + date: (date [1472, 15] - [1472, 25])) + (blame_entry [1473, 4] - [1473, 25] + line: (number [1473, 11] - [1473, 14]) + date: (date [1473, 15] - [1473, 25])) + (blame_entry [1474, 4] - [1474, 25] + line: (number [1474, 11] - [1474, 14]) + date: (date [1474, 15] - [1474, 25])) + (blame_entry [1475, 4] - [1475, 25] + line: (number [1475, 11] - [1475, 14]) + date: (date [1475, 15] - [1475, 25])) + (blame_entry [1476, 4] - [1476, 25] + line: (number [1476, 11] - [1476, 14]) + date: (date [1476, 15] - [1476, 25]))) + (file_entry [1477, 0] - [1481, 25] + file_name: (filename [1477, 6] - [1477, 60]) + (blame_entry [1478, 4] - [1478, 24] + line: (number [1478, 11] - [1478, 13]) + date: (date [1478, 14] - [1478, 24])) + (blame_entry [1479, 4] - [1479, 25] + line: (number [1479, 11] - [1479, 14]) + date: (date [1479, 15] - [1479, 25])) + (blame_entry [1480, 4] - [1480, 25] + line: (number [1480, 11] - [1480, 14]) + date: (date [1480, 15] - [1480, 25])) + (blame_entry [1481, 4] - [1481, 25] + line: (number [1481, 11] - [1481, 14]) + date: (date [1481, 15] - [1481, 25]))) + (file_entry [1482, 0] - [1483, 23] + file_name: (filename [1482, 6] - [1482, 64]) + (blame_entry [1483, 4] - [1483, 23] + line: (number [1483, 11] - [1483, 12]) + date: (date [1483, 13] - [1483, 23]))) + (file_entry [1484, 0] - [1488, 25] + file_name: (filename [1484, 6] - [1484, 89]) + (blame_entry [1485, 4] - [1485, 25] + line: (number [1485, 11] - [1485, 14]) + date: (date [1485, 15] - [1485, 25])) + (blame_entry [1486, 4] - [1486, 25] + line: (number [1486, 11] - [1486, 14]) + date: (date [1486, 15] - [1486, 25])) + (blame_entry [1487, 4] - [1487, 25] + line: (number [1487, 11] - [1487, 14]) + date: (date [1487, 15] - [1487, 25])) + (blame_entry [1488, 4] - [1488, 25] + line: (number [1488, 11] - [1488, 14]) + date: (date [1488, 15] - [1488, 25]))) + (file_entry [1489, 0] - [1490, 24] + file_name: (filename [1489, 6] - [1489, 88]) + (blame_entry [1490, 4] - [1490, 24] + line: (number [1490, 11] - [1490, 13]) + date: (date [1490, 14] - [1490, 24]))) + (file_entry [1491, 0] - [1492, 24] + file_name: (filename [1491, 6] - [1491, 57]) + (blame_entry [1492, 4] - [1492, 24] + line: (number [1492, 11] - [1492, 13]) + date: (date [1492, 14] - [1492, 24]))) + (file_entry [1493, 0] - [1494, 24] + file_name: (filename [1493, 6] - [1493, 66]) + (blame_entry [1494, 4] - [1494, 24] + line: (number [1494, 11] - [1494, 13]) + date: (date [1494, 14] - [1494, 24]))) + (file_entry [1495, 0] - [1496, 23] + file_name: (filename [1495, 6] - [1495, 83]) + (blame_entry [1496, 4] - [1496, 23] + line: (number [1496, 11] - [1496, 12]) + date: (date [1496, 13] - [1496, 23]))) + (file_entry [1497, 0] - [1498, 25] + file_name: (filename [1497, 6] - [1497, 82]) + (blame_entry [1498, 4] - [1498, 25] + line: (number [1498, 11] - [1498, 14]) + date: (date [1498, 15] - [1498, 25]))) + (file_entry [1499, 0] - [1501, 24] + file_name: (filename [1499, 6] - [1499, 55]) + (blame_entry [1500, 4] - [1500, 23] + line: (number [1500, 11] - [1500, 12]) + date: (date [1500, 13] - [1500, 23])) + (blame_entry [1501, 4] - [1501, 24] + line: (number [1501, 11] - [1501, 13]) + date: (date [1501, 14] - [1501, 24]))) + (file_entry [1502, 0] - [1503, 23] + file_name: (filename [1502, 6] - [1502, 69]) + (blame_entry [1503, 4] - [1503, 23] + line: (number [1503, 11] - [1503, 12]) + date: (date [1503, 13] - [1503, 23]))) + (file_entry [1504, 0] - [1505, 24] + file_name: (filename [1504, 6] - [1504, 68]) + (blame_entry [1505, 4] - [1505, 24] + line: (number [1505, 11] - [1505, 13]) + date: (date [1505, 14] - [1505, 24]))) + (file_entry [1506, 0] - [1508, 25] + file_name: (filename [1506, 6] - [1506, 86]) + (blame_entry [1507, 4] - [1507, 24] + line: (number [1507, 11] - [1507, 13]) + date: (date [1507, 14] - [1507, 24])) + (blame_entry [1508, 4] - [1508, 25] + line: (number [1508, 11] - [1508, 14]) + date: (date [1508, 15] - [1508, 25]))) + (file_entry [1509, 0] - [1520, 25] + file_name: (filename [1509, 6] - [1509, 49]) + (blame_entry [1510, 4] - [1510, 24] + line: (number [1510, 11] - [1510, 13]) + date: (date [1510, 14] - [1510, 24])) + (blame_entry [1511, 4] - [1511, 24] + line: (number [1511, 11] - [1511, 13]) + date: (date [1511, 14] - [1511, 24])) + (blame_entry [1512, 4] - [1512, 24] + line: (number [1512, 11] - [1512, 13]) + date: (date [1512, 14] - [1512, 24])) + (blame_entry [1513, 4] - [1513, 25] + line: (number [1513, 11] - [1513, 14]) + date: (date [1513, 15] - [1513, 25])) + (blame_entry [1514, 4] - [1514, 25] + line: (number [1514, 11] - [1514, 14]) + date: (date [1514, 15] - [1514, 25])) + (blame_entry [1515, 4] - [1515, 25] + line: (number [1515, 11] - [1515, 14]) + date: (date [1515, 15] - [1515, 25])) + (blame_entry [1516, 4] - [1516, 25] + line: (number [1516, 11] - [1516, 14]) + date: (date [1516, 15] - [1516, 25])) + (blame_entry [1517, 4] - [1517, 25] + line: (number [1517, 11] - [1517, 14]) + date: (date [1517, 15] - [1517, 25])) + (blame_entry [1518, 4] - [1518, 25] + line: (number [1518, 11] - [1518, 14]) + date: (date [1518, 15] - [1518, 25])) + (blame_entry [1519, 4] - [1519, 25] + line: (number [1519, 11] - [1519, 14]) + date: (date [1519, 15] - [1519, 25])) + (blame_entry [1520, 4] - [1520, 25] + line: (number [1520, 11] - [1520, 14]) + date: (date [1520, 15] - [1520, 25]))) + (file_entry [1521, 0] - [1522, 24] + file_name: (filename [1521, 6] - [1521, 119]) + (blame_entry [1522, 4] - [1522, 24] + line: (number [1522, 11] - [1522, 13]) + date: (date [1522, 14] - [1522, 24]))) + (file_entry [1523, 0] - [1524, 23] + file_name: (filename [1523, 6] - [1523, 69]) + (blame_entry [1524, 4] - [1524, 23] + line: (number [1524, 11] - [1524, 12]) + date: (date [1524, 13] - [1524, 23]))) + (file_entry [1525, 0] - [1527, 24] + file_name: (filename [1525, 6] - [1525, 63]) + (blame_entry [1526, 4] - [1526, 24] + line: (number [1526, 11] - [1526, 13]) + date: (date [1526, 14] - [1526, 24])) + (blame_entry [1527, 4] - [1527, 24] + line: (number [1527, 11] - [1527, 13]) + date: (date [1527, 14] - [1527, 24]))) + (file_entry [1528, 0] - [1529, 23] + file_name: (filename [1528, 6] - [1528, 91]) + (blame_entry [1529, 4] - [1529, 23] + line: (number [1529, 11] - [1529, 12]) + date: (date [1529, 13] - [1529, 23]))) + (file_entry [1530, 0] - [1531, 23] + file_name: (filename [1530, 6] - [1530, 82]) + (blame_entry [1531, 4] - [1531, 23] + line: (number [1531, 11] - [1531, 12]) + date: (date [1531, 13] - [1531, 23]))) + (file_entry [1532, 0] - [1533, 24] + file_name: (filename [1532, 6] - [1532, 78]) + (blame_entry [1533, 4] - [1533, 24] + line: (number [1533, 11] - [1533, 13]) + date: (date [1533, 14] - [1533, 24]))) + (file_entry [1534, 0] - [1536, 25] + file_name: (filename [1534, 6] - [1534, 57]) + (blame_entry [1535, 4] - [1535, 25] + line: (number [1535, 11] - [1535, 14]) + date: (date [1535, 15] - [1535, 25])) + (blame_entry [1536, 4] - [1536, 25] + line: (number [1536, 11] - [1536, 14]) + date: (date [1536, 15] - [1536, 25]))) + (file_entry [1537, 0] - [1539, 24] + file_name: (filename [1537, 6] - [1537, 56]) + (blame_entry [1538, 4] - [1538, 23] + line: (number [1538, 11] - [1538, 12]) + date: (date [1538, 13] - [1538, 23])) + (blame_entry [1539, 4] - [1539, 24] + line: (number [1539, 11] - [1539, 13]) + date: (date [1539, 14] - [1539, 24]))) + (file_entry [1540, 0] - [1544, 25] + file_name: (filename [1540, 6] - [1540, 89]) + (blame_entry [1541, 4] - [1541, 25] + line: (number [1541, 11] - [1541, 14]) + date: (date [1541, 15] - [1541, 25])) + (blame_entry [1542, 4] - [1542, 25] + line: (number [1542, 11] - [1542, 14]) + date: (date [1542, 15] - [1542, 25])) + (blame_entry [1543, 4] - [1543, 25] + line: (number [1543, 11] - [1543, 14]) + date: (date [1543, 15] - [1543, 25])) + (blame_entry [1544, 4] - [1544, 25] + line: (number [1544, 11] - [1544, 14]) + date: (date [1544, 15] - [1544, 25]))) + (file_entry [1545, 0] - [1551, 25] + file_name: (filename [1545, 6] - [1545, 67]) + (blame_entry [1546, 4] - [1546, 25] + line: (number [1546, 11] - [1546, 14]) + date: (date [1546, 15] - [1546, 25])) + (blame_entry [1547, 4] - [1547, 25] + line: (number [1547, 11] - [1547, 14]) + date: (date [1547, 15] - [1547, 25])) + (blame_entry [1548, 4] - [1548, 25] + line: (number [1548, 11] - [1548, 14]) + date: (date [1548, 15] - [1548, 25])) + (blame_entry [1549, 4] - [1549, 25] + line: (number [1549, 11] - [1549, 14]) + date: (date [1549, 15] - [1549, 25])) + (blame_entry [1550, 4] - [1550, 25] + line: (number [1550, 11] - [1550, 14]) + date: (date [1550, 15] - [1550, 25])) + (blame_entry [1551, 4] - [1551, 25] + line: (number [1551, 11] - [1551, 14]) + date: (date [1551, 15] - [1551, 25]))) + (file_entry [1552, 0] - [1553, 23] + file_name: (filename [1552, 6] - [1552, 49]) + (blame_entry [1553, 4] - [1553, 23] + line: (number [1553, 11] - [1553, 12]) + date: (date [1553, 13] - [1553, 23]))) + (file_entry [1554, 0] - [1560, 25] + file_name: (filename [1554, 6] - [1554, 71]) + (blame_entry [1555, 4] - [1555, 24] + line: (number [1555, 11] - [1555, 13]) + date: (date [1555, 14] - [1555, 24])) + (blame_entry [1556, 4] - [1556, 24] + line: (number [1556, 11] - [1556, 13]) + date: (date [1556, 14] - [1556, 24])) + (blame_entry [1557, 4] - [1557, 25] + line: (number [1557, 11] - [1557, 14]) + date: (date [1557, 15] - [1557, 25])) + (blame_entry [1558, 4] - [1558, 25] + line: (number [1558, 11] - [1558, 14]) + date: (date [1558, 15] - [1558, 25])) + (blame_entry [1559, 4] - [1559, 25] + line: (number [1559, 11] - [1559, 14]) + date: (date [1559, 15] - [1559, 25])) + (blame_entry [1560, 4] - [1560, 25] + line: (number [1560, 11] - [1560, 14]) + date: (date [1560, 15] - [1560, 25]))) + (file_entry [1561, 0] - [1566, 24] + file_name: (filename [1561, 6] - [1561, 57]) + (blame_entry [1562, 4] - [1562, 23] + line: (number [1562, 11] - [1562, 12]) + date: (date [1562, 13] - [1562, 23])) + (blame_entry [1563, 4] - [1563, 23] + line: (number [1563, 11] - [1563, 12]) + date: (date [1563, 13] - [1563, 23])) + (blame_entry [1564, 4] - [1564, 24] + line: (number [1564, 11] - [1564, 13]) + date: (date [1564, 14] - [1564, 24])) + (blame_entry [1565, 4] - [1565, 24] + line: (number [1565, 11] - [1565, 13]) + date: (date [1565, 14] - [1565, 24])) + (blame_entry [1566, 4] - [1566, 24] + line: (number [1566, 11] - [1566, 13]) + date: (date [1566, 14] - [1566, 24]))) + (file_entry [1567, 0] - [1574, 24] + file_name: (filename [1567, 6] - [1567, 56]) + (blame_entry [1568, 4] - [1568, 23] + line: (number [1568, 11] - [1568, 12]) + date: (date [1568, 13] - [1568, 23])) + (blame_entry [1569, 4] - [1569, 23] + line: (number [1569, 11] - [1569, 12]) + date: (date [1569, 13] - [1569, 23])) + (blame_entry [1570, 4] - [1570, 24] + line: (number [1570, 11] - [1570, 13]) + date: (date [1570, 14] - [1570, 24])) + (blame_entry [1571, 4] - [1571, 24] + line: (number [1571, 11] - [1571, 13]) + date: (date [1571, 14] - [1571, 24])) + (blame_entry [1572, 4] - [1572, 24] + line: (number [1572, 11] - [1572, 13]) + date: (date [1572, 14] - [1572, 24])) + (blame_entry [1573, 4] - [1573, 24] + line: (number [1573, 11] - [1573, 13]) + date: (date [1573, 14] - [1573, 24])) + (blame_entry [1574, 4] - [1574, 24] + line: (number [1574, 11] - [1574, 13]) + date: (date [1574, 14] - [1574, 24]))) + (file_entry [1575, 0] - [1579, 25] + file_name: (filename [1575, 6] - [1575, 74]) + (blame_entry [1576, 4] - [1576, 24] + line: (number [1576, 11] - [1576, 13]) + date: (date [1576, 14] - [1576, 24])) + (blame_entry [1577, 4] - [1577, 25] + line: (number [1577, 11] - [1577, 14]) + date: (date [1577, 15] - [1577, 25])) + (blame_entry [1578, 4] - [1578, 25] + line: (number [1578, 11] - [1578, 14]) + date: (date [1578, 15] - [1578, 25])) + (blame_entry [1579, 4] - [1579, 25] + line: (number [1579, 11] - [1579, 14]) + date: (date [1579, 15] - [1579, 25]))) + (file_entry [1580, 0] - [1581, 24] + file_name: (filename [1580, 6] - [1580, 74]) + (blame_entry [1581, 4] - [1581, 24] + line: (number [1581, 11] - [1581, 13]) + date: (date [1581, 14] - [1581, 24]))) + (file_entry [1582, 0] - [1584, 24] + file_name: (filename [1582, 6] - [1582, 74]) + (blame_entry [1583, 4] - [1583, 24] + line: (number [1583, 11] - [1583, 13]) + date: (date [1583, 14] - [1583, 24])) + (blame_entry [1584, 4] - [1584, 24] + line: (number [1584, 11] - [1584, 13]) + date: (date [1584, 14] - [1584, 24]))) + (file_entry [1585, 0] - [1586, 24] + file_name: (filename [1585, 6] - [1585, 72]) + (blame_entry [1586, 4] - [1586, 24] + line: (number [1586, 11] - [1586, 13]) + date: (date [1586, 14] - [1586, 24]))) + (file_entry [1587, 0] - [1588, 24] + file_name: (filename [1587, 6] - [1587, 63]) + (blame_entry [1588, 4] - [1588, 24] + line: (number [1588, 11] - [1588, 13]) + date: (date [1588, 14] - [1588, 24]))) + (file_entry [1589, 0] - [1591, 25] + file_name: (filename [1589, 6] - [1589, 66]) + (blame_entry [1590, 4] - [1590, 25] + line: (number [1590, 11] - [1590, 14]) + date: (date [1590, 15] - [1590, 25])) + (blame_entry [1591, 4] - [1591, 25] + line: (number [1591, 11] - [1591, 14]) + date: (date [1591, 15] - [1591, 25]))) + (file_entry [1592, 0] - [1595, 24] + file_name: (filename [1592, 6] - [1592, 55]) + (blame_entry [1593, 4] - [1593, 23] + line: (number [1593, 11] - [1593, 12]) + date: (date [1593, 13] - [1593, 23])) + (blame_entry [1594, 4] - [1594, 24] + line: (number [1594, 11] - [1594, 13]) + date: (date [1594, 14] - [1594, 24])) + (blame_entry [1595, 4] - [1595, 24] + line: (number [1595, 11] - [1595, 13]) + date: (date [1595, 14] - [1595, 24]))) + (file_entry [1596, 0] - [1597, 24] + file_name: (filename [1596, 6] - [1596, 74]) + (blame_entry [1597, 4] - [1597, 24] + line: (number [1597, 11] - [1597, 13]) + date: (date [1597, 14] - [1597, 24]))) + (file_entry [1598, 0] - [1600, 24] + file_name: (filename [1598, 6] - [1598, 55]) + (blame_entry [1599, 4] - [1599, 23] + line: (number [1599, 11] - [1599, 12]) + date: (date [1599, 13] - [1599, 23])) + (blame_entry [1600, 4] - [1600, 24] + line: (number [1600, 11] - [1600, 13]) + date: (date [1600, 14] - [1600, 24]))) + (file_entry [1601, 0] - [1602, 24] + file_name: (filename [1601, 6] - [1601, 77]) + (blame_entry [1602, 4] - [1602, 24] + line: (number [1602, 11] - [1602, 13]) + date: (date [1602, 14] - [1602, 24]))) + (file_entry [1603, 0] - [1604, 25] + file_name: (filename [1603, 6] - [1603, 65]) + (blame_entry [1604, 4] - [1604, 25] + line: (number [1604, 11] - [1604, 14]) + date: (date [1604, 15] - [1604, 25]))) + (file_entry [1605, 0] - [1618, 25] + file_name: (filename [1605, 6] - [1605, 49]) + (blame_entry [1606, 4] - [1606, 24] + line: (number [1606, 11] - [1606, 13]) + date: (date [1606, 14] - [1606, 24])) + (blame_entry [1607, 4] - [1607, 24] + line: (number [1607, 11] - [1607, 13]) + date: (date [1607, 14] - [1607, 24])) + (blame_entry [1608, 4] - [1608, 25] + line: (number [1608, 11] - [1608, 14]) + date: (date [1608, 15] - [1608, 25])) + (blame_entry [1609, 4] - [1609, 25] + line: (number [1609, 11] - [1609, 14]) + date: (date [1609, 15] - [1609, 25])) + (blame_entry [1610, 4] - [1610, 25] + line: (number [1610, 11] - [1610, 14]) + date: (date [1610, 15] - [1610, 25])) + (blame_entry [1611, 4] - [1611, 25] + line: (number [1611, 11] - [1611, 14]) + date: (date [1611, 15] - [1611, 25])) + (blame_entry [1612, 4] - [1612, 25] + line: (number [1612, 11] - [1612, 14]) + date: (date [1612, 15] - [1612, 25])) + (blame_entry [1613, 4] - [1613, 25] + line: (number [1613, 11] - [1613, 14]) + date: (date [1613, 15] - [1613, 25])) + (blame_entry [1614, 4] - [1614, 25] + line: (number [1614, 11] - [1614, 14]) + date: (date [1614, 15] - [1614, 25])) + (blame_entry [1615, 4] - [1615, 25] + line: (number [1615, 11] - [1615, 14]) + date: (date [1615, 15] - [1615, 25])) + (blame_entry [1616, 4] - [1616, 25] + line: (number [1616, 11] - [1616, 14]) + date: (date [1616, 15] - [1616, 25])) + (blame_entry [1617, 4] - [1617, 25] + line: (number [1617, 11] - [1617, 14]) + date: (date [1617, 15] - [1617, 25])) + (blame_entry [1618, 4] - [1618, 25] + line: (number [1618, 11] - [1618, 14]) + date: (date [1618, 15] - [1618, 25]))) + (file_entry [1619, 0] - [1622, 25] + file_name: (filename [1619, 6] - [1619, 72]) + (blame_entry [1620, 4] - [1620, 24] + line: (number [1620, 11] - [1620, 13]) + date: (date [1620, 14] - [1620, 24])) + (blame_entry [1621, 4] - [1621, 24] + line: (number [1621, 11] - [1621, 13]) + date: (date [1621, 14] - [1621, 24])) + (blame_entry [1622, 4] - [1622, 25] + line: (number [1622, 11] - [1622, 14]) + date: (date [1622, 15] - [1622, 25]))) + (file_entry [1623, 0] - [1630, 25] + file_name: (filename [1623, 6] - [1623, 60]) + (blame_entry [1624, 4] - [1624, 24] + line: (number [1624, 11] - [1624, 13]) + date: (date [1624, 14] - [1624, 24])) + (blame_entry [1625, 4] - [1625, 24] + line: (number [1625, 11] - [1625, 13]) + date: (date [1625, 14] - [1625, 24])) + (blame_entry [1626, 4] - [1626, 24] + line: (number [1626, 11] - [1626, 13]) + date: (date [1626, 14] - [1626, 24])) + (blame_entry [1627, 4] - [1627, 25] + line: (number [1627, 11] - [1627, 14]) + date: (date [1627, 15] - [1627, 25])) + (blame_entry [1628, 4] - [1628, 25] + line: (number [1628, 11] - [1628, 14]) + date: (date [1628, 15] - [1628, 25])) + (blame_entry [1629, 4] - [1629, 25] + line: (number [1629, 11] - [1629, 14]) + date: (date [1629, 15] - [1629, 25])) + (blame_entry [1630, 4] - [1630, 25] + line: (number [1630, 11] - [1630, 14]) + date: (date [1630, 15] - [1630, 25]))) + (file_entry [1631, 0] - [1634, 25] + file_name: (filename [1631, 6] - [1631, 46]) + (blame_entry [1632, 4] - [1632, 24] + line: (number [1632, 11] - [1632, 13]) + date: (date [1632, 14] - [1632, 24])) + (blame_entry [1633, 4] - [1633, 24] + line: (number [1633, 11] - [1633, 13]) + date: (date [1633, 14] - [1633, 24])) + (blame_entry [1634, 4] - [1634, 25] + line: (number [1634, 11] - [1634, 14]) + date: (date [1634, 15] - [1634, 25]))) + (file_entry [1635, 0] - [1636, 24] + file_name: (filename [1635, 6] - [1635, 65]) + (blame_entry [1636, 4] - [1636, 24] + line: (number [1636, 11] - [1636, 13]) + date: (date [1636, 14] - [1636, 24]))) + (file_entry [1637, 0] - [1638, 26] + file_name: (filename [1637, 6] - [1637, 70]) + (blame_entry [1638, 4] - [1638, 26] + line: (number [1638, 11] - [1638, 15]) + date: (date [1638, 16] - [1638, 26]))) + (file_entry [1639, 0] - [1640, 24] + file_name: (filename [1639, 6] - [1639, 83]) + (blame_entry [1640, 4] - [1640, 24] + line: (number [1640, 11] - [1640, 13]) + date: (date [1640, 14] - [1640, 24]))) + (file_entry [1641, 0] - [1643, 24] + file_name: (filename [1641, 6] - [1641, 57]) + (blame_entry [1642, 4] - [1642, 24] + line: (number [1642, 11] - [1642, 13]) + date: (date [1642, 14] - [1642, 24])) + (blame_entry [1643, 4] - [1643, 24] + line: (number [1643, 11] - [1643, 13]) + date: (date [1643, 14] - [1643, 24]))) + (file_entry [1644, 0] - [1645, 24] + file_name: (filename [1644, 6] - [1644, 43]) + (blame_entry [1645, 4] - [1645, 24] + line: (number [1645, 11] - [1645, 13]) + date: (date [1645, 14] - [1645, 24]))) + (file_entry [1646, 0] - [1648, 24] + file_name: (filename [1646, 6] - [1646, 54]) + (blame_entry [1647, 4] - [1647, 24] + line: (number [1647, 11] - [1647, 13]) + date: (date [1647, 14] - [1647, 24])) + (blame_entry [1648, 4] - [1648, 24] + line: (number [1648, 11] - [1648, 13]) + date: (date [1648, 14] - [1648, 24]))) + (file_entry [1649, 0] - [1650, 25] + file_name: (filename [1649, 6] - [1649, 43]) + (blame_entry [1650, 4] - [1650, 25] + line: (number [1650, 11] - [1650, 14]) + date: (date [1650, 15] - [1650, 25]))) + (file_entry [1651, 0] - [1653, 24] + file_name: (filename [1651, 6] - [1651, 57]) + (blame_entry [1652, 4] - [1652, 23] + line: (number [1652, 11] - [1652, 12]) + date: (date [1652, 13] - [1652, 23])) + (blame_entry [1653, 4] - [1653, 24] + line: (number [1653, 11] - [1653, 13]) + date: (date [1653, 14] - [1653, 24]))) + (file_entry [1654, 0] - [1655, 24] + file_name: (filename [1654, 6] - [1654, 61]) + (blame_entry [1655, 4] - [1655, 24] + line: (number [1655, 11] - [1655, 13]) + date: (date [1655, 14] - [1655, 24]))) + (file_entry [1656, 0] - [1658, 25] + file_name: (filename [1656, 6] - [1656, 86]) + (blame_entry [1657, 4] - [1657, 25] + line: (number [1657, 11] - [1657, 14]) + date: (date [1657, 15] - [1657, 25])) + (blame_entry [1658, 4] - [1658, 25] + line: (number [1658, 11] - [1658, 14]) + date: (date [1658, 15] - [1658, 25]))) + (file_entry [1659, 0] - [1660, 25] + file_name: (filename [1659, 6] - [1659, 82]) + (blame_entry [1660, 4] - [1660, 25] + line: (number [1660, 11] - [1660, 14]) + date: (date [1660, 15] - [1660, 25]))) + (file_entry [1661, 0] - [1662, 24] + file_name: (filename [1661, 6] - [1661, 70]) + (blame_entry [1662, 4] - [1662, 24] + line: (number [1662, 11] - [1662, 13]) + date: (date [1662, 14] - [1662, 24]))) + (file_entry [1663, 0] - [1671, 25] + file_name: (filename [1663, 6] - [1663, 46]) + (blame_entry [1664, 4] - [1664, 24] + line: (number [1664, 11] - [1664, 13]) + date: (date [1664, 14] - [1664, 24])) + (blame_entry [1665, 4] - [1665, 25] + line: (number [1665, 11] - [1665, 14]) + date: (date [1665, 15] - [1665, 25])) + (blame_entry [1666, 4] - [1666, 25] + line: (number [1666, 11] - [1666, 14]) + date: (date [1666, 15] - [1666, 25])) + (blame_entry [1667, 4] - [1667, 25] + line: (number [1667, 11] - [1667, 14]) + date: (date [1667, 15] - [1667, 25])) + (blame_entry [1668, 4] - [1668, 25] + line: (number [1668, 11] - [1668, 14]) + date: (date [1668, 15] - [1668, 25])) + (blame_entry [1669, 4] - [1669, 25] + line: (number [1669, 11] - [1669, 14]) + date: (date [1669, 15] - [1669, 25])) + (blame_entry [1670, 4] - [1670, 25] + line: (number [1670, 11] - [1670, 14]) + date: (date [1670, 15] - [1670, 25])) + (blame_entry [1671, 4] - [1671, 25] + line: (number [1671, 11] - [1671, 14]) + date: (date [1671, 15] - [1671, 25]))) + (file_entry [1672, 0] - [1675, 24] + file_name: (filename [1672, 6] - [1672, 44]) + (blame_entry [1673, 4] - [1673, 23] + line: (number [1673, 11] - [1673, 12]) + date: (date [1673, 13] - [1673, 23])) + (blame_entry [1674, 4] - [1674, 24] + line: (number [1674, 11] - [1674, 13]) + date: (date [1674, 14] - [1674, 24])) + (blame_entry [1675, 4] - [1675, 24] + line: (number [1675, 11] - [1675, 13]) + date: (date [1675, 14] - [1675, 24]))) + (file_entry [1676, 0] - [1679, 24] + file_name: (filename [1676, 6] - [1676, 68]) + (blame_entry [1677, 4] - [1677, 23] + line: (number [1677, 11] - [1677, 12]) + date: (date [1677, 13] - [1677, 23])) + (blame_entry [1678, 4] - [1678, 24] + line: (number [1678, 11] - [1678, 13]) + date: (date [1678, 14] - [1678, 24])) + (blame_entry [1679, 4] - [1679, 24] + line: (number [1679, 11] - [1679, 13]) + date: (date [1679, 14] - [1679, 24]))) + (file_entry [1680, 0] - [1684, 25] + file_name: (filename [1680, 6] - [1680, 80]) + (blame_entry [1681, 4] - [1681, 25] + line: (number [1681, 11] - [1681, 14]) + date: (date [1681, 15] - [1681, 25])) + (blame_entry [1682, 4] - [1682, 25] + line: (number [1682, 11] - [1682, 14]) + date: (date [1682, 15] - [1682, 25])) + (blame_entry [1683, 4] - [1683, 25] + line: (number [1683, 11] - [1683, 14]) + date: (date [1683, 15] - [1683, 25])) + (blame_entry [1684, 4] - [1684, 25] + line: (number [1684, 11] - [1684, 14]) + date: (date [1684, 15] - [1684, 25]))) + (file_entry [1685, 0] - [1688, 25] + file_name: (filename [1685, 6] - [1685, 92]) + (blame_entry [1686, 4] - [1686, 24] + line: (number [1686, 11] - [1686, 13]) + date: (date [1686, 14] - [1686, 24])) + (blame_entry [1687, 4] - [1687, 25] + line: (number [1687, 11] - [1687, 14]) + date: (date [1687, 15] - [1687, 25])) + (blame_entry [1688, 4] - [1688, 25] + line: (number [1688, 11] - [1688, 14]) + date: (date [1688, 15] - [1688, 25]))) + (file_entry [1689, 0] - [1690, 23] + file_name: (filename [1689, 6] - [1689, 72]) + (blame_entry [1690, 4] - [1690, 23] + line: (number [1690, 11] - [1690, 12]) + date: (date [1690, 13] - [1690, 23]))) + (file_entry [1691, 0] - [1692, 24] + file_name: (filename [1691, 6] - [1691, 92]) + (blame_entry [1692, 4] - [1692, 24] + line: (number [1692, 11] - [1692, 13]) + date: (date [1692, 14] - [1692, 24]))) + (file_entry [1693, 0] - [1695, 24] + file_name: (filename [1693, 6] - [1693, 65]) + (blame_entry [1694, 4] - [1694, 24] + line: (number [1694, 11] - [1694, 13]) + date: (date [1694, 14] - [1694, 24])) + (blame_entry [1695, 4] - [1695, 24] + line: (number [1695, 11] - [1695, 13]) + date: (date [1695, 14] - [1695, 24]))) + (file_entry [1696, 0] - [1698, 24] + file_name: (filename [1696, 6] - [1696, 62]) + (blame_entry [1697, 4] - [1697, 24] + line: (number [1697, 11] - [1697, 13]) + date: (date [1697, 14] - [1697, 24])) + (blame_entry [1698, 4] - [1698, 24] + line: (number [1698, 11] - [1698, 13]) + date: (date [1698, 14] - [1698, 24]))) + (file_entry [1699, 0] - [1703, 25] + file_name: (filename [1699, 6] - [1699, 93]) + (blame_entry [1700, 4] - [1700, 25] + line: (number [1700, 11] - [1700, 14]) + date: (date [1700, 15] - [1700, 25])) + (blame_entry [1701, 4] - [1701, 25] + line: (number [1701, 11] - [1701, 14]) + date: (date [1701, 15] - [1701, 25])) + (blame_entry [1702, 4] - [1702, 25] + line: (number [1702, 11] - [1702, 14]) + date: (date [1702, 15] - [1702, 25])) + (blame_entry [1703, 4] - [1703, 25] + line: (number [1703, 11] - [1703, 14]) + date: (date [1703, 15] - [1703, 25]))) + (file_entry [1704, 0] - [1708, 25] + file_name: (filename [1704, 6] - [1704, 71]) + (blame_entry [1705, 4] - [1705, 24] + line: (number [1705, 11] - [1705, 13]) + date: (date [1705, 14] - [1705, 24])) + (blame_entry [1706, 4] - [1706, 25] + line: (number [1706, 11] - [1706, 14]) + date: (date [1706, 15] - [1706, 25])) + (blame_entry [1707, 4] - [1707, 25] + line: (number [1707, 11] - [1707, 14]) + date: (date [1707, 15] - [1707, 25])) + (blame_entry [1708, 4] - [1708, 25] + line: (number [1708, 11] - [1708, 14]) + date: (date [1708, 15] - [1708, 25]))) + (file_entry [1709, 0] - [1710, 24] + file_name: (filename [1709, 6] - [1709, 68]) + (blame_entry [1710, 4] - [1710, 24] + line: (number [1710, 11] - [1710, 13]) + date: (date [1710, 14] - [1710, 24]))) + (file_entry [1711, 0] - [1715, 26] + file_name: (filename [1711, 6] - [1711, 52]) + (blame_entry [1712, 4] - [1712, 26] + line: (number [1712, 11] - [1712, 15]) + date: (date [1712, 16] - [1712, 26])) + (blame_entry [1713, 4] - [1713, 26] + line: (number [1713, 11] - [1713, 15]) + date: (date [1713, 16] - [1713, 26])) + (blame_entry [1714, 4] - [1714, 26] + line: (number [1714, 11] - [1714, 15]) + date: (date [1714, 16] - [1714, 26])) + (blame_entry [1715, 4] - [1715, 26] + line: (number [1715, 11] - [1715, 15]) + date: (date [1715, 16] - [1715, 26]))) + (file_entry [1716, 0] - [1719, 25] + file_name: (filename [1716, 6] - [1716, 58]) + (blame_entry [1717, 4] - [1717, 25] + line: (number [1717, 11] - [1717, 14]) + date: (date [1717, 15] - [1717, 25])) + (blame_entry [1718, 4] - [1718, 25] + line: (number [1718, 11] - [1718, 14]) + date: (date [1718, 15] - [1718, 25])) + (blame_entry [1719, 4] - [1719, 25] + line: (number [1719, 11] - [1719, 14]) + date: (date [1719, 15] - [1719, 25]))) + (file_entry [1720, 0] - [1722, 24] + file_name: (filename [1720, 6] - [1720, 101]) + (blame_entry [1721, 4] - [1721, 23] + line: (number [1721, 11] - [1721, 12]) + date: (date [1721, 13] - [1721, 23])) + (blame_entry [1722, 4] - [1722, 24] + line: (number [1722, 11] - [1722, 13]) + date: (date [1722, 14] - [1722, 24]))) + (file_entry [1723, 0] - [1725, 24] + file_name: (filename [1723, 6] - [1723, 62]) + (blame_entry [1724, 4] - [1724, 24] + line: (number [1724, 11] - [1724, 13]) + date: (date [1724, 14] - [1724, 24])) + (blame_entry [1725, 4] - [1725, 24] + line: (number [1725, 11] - [1725, 13]) + date: (date [1725, 14] - [1725, 24]))) + (file_entry [1726, 0] - [1728, 24] + file_name: (filename [1726, 6] - [1726, 82]) + (blame_entry [1727, 4] - [1727, 24] + line: (number [1727, 11] - [1727, 13]) + date: (date [1727, 14] - [1727, 24])) + (blame_entry [1728, 4] - [1728, 24] + line: (number [1728, 11] - [1728, 13]) + date: (date [1728, 14] - [1728, 24]))) + (file_entry [1729, 0] - [1730, 23] + file_name: (filename [1729, 6] - [1729, 64]) + (blame_entry [1730, 4] - [1730, 23] + line: (number [1730, 11] - [1730, 12]) + date: (date [1730, 13] - [1730, 23]))) + (file_entry [1731, 0] - [1732, 23] + file_name: (filename [1731, 6] - [1731, 61]) + (blame_entry [1732, 4] - [1732, 23] + line: (number [1732, 11] - [1732, 12]) + date: (date [1732, 13] - [1732, 23]))) + (file_entry [1733, 0] - [1744, 24] + file_name: (filename [1733, 6] - [1733, 55]) + (blame_entry [1734, 4] - [1734, 23] + line: (number [1734, 11] - [1734, 12]) + date: (date [1734, 13] - [1734, 23])) + (blame_entry [1735, 4] - [1735, 23] + line: (number [1735, 11] - [1735, 12]) + date: (date [1735, 13] - [1735, 23])) + (blame_entry [1736, 4] - [1736, 24] + line: (number [1736, 11] - [1736, 13]) + date: (date [1736, 14] - [1736, 24])) + (blame_entry [1737, 4] - [1737, 24] + line: (number [1737, 11] - [1737, 13]) + date: (date [1737, 14] - [1737, 24])) + (blame_entry [1738, 4] - [1738, 24] + line: (number [1738, 11] - [1738, 13]) + date: (date [1738, 14] - [1738, 24])) + (blame_entry [1739, 4] - [1739, 24] + line: (number [1739, 11] - [1739, 13]) + date: (date [1739, 14] - [1739, 24])) + (blame_entry [1740, 4] - [1740, 24] + line: (number [1740, 11] - [1740, 13]) + date: (date [1740, 14] - [1740, 24])) + (blame_entry [1741, 4] - [1741, 24] + line: (number [1741, 11] - [1741, 13]) + date: (date [1741, 14] - [1741, 24])) + (blame_entry [1742, 4] - [1742, 24] + line: (number [1742, 11] - [1742, 13]) + date: (date [1742, 14] - [1742, 24])) + (blame_entry [1743, 4] - [1743, 24] + line: (number [1743, 11] - [1743, 13]) + date: (date [1743, 14] - [1743, 24])) + (blame_entry [1744, 4] - [1744, 24] + line: (number [1744, 11] - [1744, 13]) + date: (date [1744, 14] - [1744, 24]))) + (file_entry [1745, 0] - [1748, 24] + file_name: (filename [1745, 6] - [1745, 63]) + (blame_entry [1746, 4] - [1746, 24] + line: (number [1746, 11] - [1746, 13]) + date: (date [1746, 14] - [1746, 24])) + (blame_entry [1747, 4] - [1747, 24] + line: (number [1747, 11] - [1747, 13]) + date: (date [1747, 14] - [1747, 24])) + (blame_entry [1748, 4] - [1748, 24] + line: (number [1748, 11] - [1748, 13]) + date: (date [1748, 14] - [1748, 24]))) + (file_entry [1749, 0] - [1753, 25] + file_name: (filename [1749, 6] - [1749, 90]) + (blame_entry [1750, 4] - [1750, 25] + line: (number [1750, 11] - [1750, 14]) + date: (date [1750, 15] - [1750, 25])) + (blame_entry [1751, 4] - [1751, 25] + line: (number [1751, 11] - [1751, 14]) + date: (date [1751, 15] - [1751, 25])) + (blame_entry [1752, 4] - [1752, 25] + line: (number [1752, 11] - [1752, 14]) + date: (date [1752, 15] - [1752, 25])) + (blame_entry [1753, 4] - [1753, 25] + line: (number [1753, 11] - [1753, 14]) + date: (date [1753, 15] - [1753, 25]))) + (file_entry [1754, 0] - [1765, 25] + file_name: (filename [1754, 6] - [1754, 70]) + (blame_entry [1755, 4] - [1755, 23] + line: (number [1755, 11] - [1755, 12]) + date: (date [1755, 13] - [1755, 23])) + (blame_entry [1756, 4] - [1756, 24] + line: (number [1756, 11] - [1756, 13]) + date: (date [1756, 14] - [1756, 24])) + (blame_entry [1757, 4] - [1757, 24] + line: (number [1757, 11] - [1757, 13]) + date: (date [1757, 14] - [1757, 24])) + (blame_entry [1758, 4] - [1758, 24] + line: (number [1758, 11] - [1758, 13]) + date: (date [1758, 14] - [1758, 24])) + (blame_entry [1759, 4] - [1759, 24] + line: (number [1759, 11] - [1759, 13]) + date: (date [1759, 14] - [1759, 24])) + (blame_entry [1760, 4] - [1760, 24] + line: (number [1760, 11] - [1760, 13]) + date: (date [1760, 14] - [1760, 24])) + (blame_entry [1761, 4] - [1761, 24] + line: (number [1761, 11] - [1761, 13]) + date: (date [1761, 14] - [1761, 24])) + (blame_entry [1762, 4] - [1762, 24] + line: (number [1762, 11] - [1762, 13]) + date: (date [1762, 14] - [1762, 24])) + (blame_entry [1763, 4] - [1763, 24] + line: (number [1763, 11] - [1763, 13]) + date: (date [1763, 14] - [1763, 24])) + (blame_entry [1764, 4] - [1764, 24] + line: (number [1764, 11] - [1764, 13]) + date: (date [1764, 14] - [1764, 24])) + (blame_entry [1765, 4] - [1765, 25] + line: (number [1765, 11] - [1765, 14]) + date: (date [1765, 15] - [1765, 25]))) + (file_entry [1766, 0] - [1768, 24] + file_name: (filename [1766, 6] - [1766, 62]) + (blame_entry [1767, 4] - [1767, 24] + line: (number [1767, 11] - [1767, 13]) + date: (date [1767, 14] - [1767, 24])) + (blame_entry [1768, 4] - [1768, 24] + line: (number [1768, 11] - [1768, 13]) + date: (date [1768, 14] - [1768, 24]))) + (file_entry [1769, 0] - [1773, 25] + file_name: (filename [1769, 6] - [1769, 67]) + (blame_entry [1770, 4] - [1770, 24] + line: (number [1770, 11] - [1770, 13]) + date: (date [1770, 14] - [1770, 24])) + (blame_entry [1771, 4] - [1771, 25] + line: (number [1771, 11] - [1771, 14]) + date: (date [1771, 15] - [1771, 25])) + (blame_entry [1772, 4] - [1772, 25] + line: (number [1772, 11] - [1772, 14]) + date: (date [1772, 15] - [1772, 25])) + (blame_entry [1773, 4] - [1773, 25] + line: (number [1773, 11] - [1773, 14]) + date: (date [1773, 15] - [1773, 25]))) + (file_entry [1774, 0] - [1780, 25] + file_name: (filename [1774, 6] - [1774, 55]) + (blame_entry [1775, 4] - [1775, 25] + line: (number [1775, 11] - [1775, 14]) + date: (date [1775, 15] - [1775, 25])) + (blame_entry [1776, 4] - [1776, 25] + line: (number [1776, 11] - [1776, 14]) + date: (date [1776, 15] - [1776, 25])) + (blame_entry [1777, 4] - [1777, 25] + line: (number [1777, 11] - [1777, 14]) + date: (date [1777, 15] - [1777, 25])) + (blame_entry [1778, 4] - [1778, 25] + line: (number [1778, 11] - [1778, 14]) + date: (date [1778, 15] - [1778, 25])) + (blame_entry [1779, 4] - [1779, 25] + line: (number [1779, 11] - [1779, 14]) + date: (date [1779, 15] - [1779, 25])) + (blame_entry [1780, 4] - [1780, 25] + line: (number [1780, 11] - [1780, 14]) + date: (date [1780, 15] - [1780, 25]))) + (file_entry [1781, 0] - [1783, 24] + file_name: (filename [1781, 6] - [1781, 64]) + (blame_entry [1782, 4] - [1782, 24] + line: (number [1782, 11] - [1782, 13]) + date: (date [1782, 14] - [1782, 24])) + (blame_entry [1783, 4] - [1783, 24] + line: (number [1783, 11] - [1783, 13]) + date: (date [1783, 14] - [1783, 24]))) + (file_entry [1784, 0] - [1785, 23] + file_name: (filename [1784, 6] - [1784, 83]) + (blame_entry [1785, 4] - [1785, 23] + line: (number [1785, 11] - [1785, 12]) + date: (date [1785, 13] - [1785, 23]))) + (file_entry [1786, 0] - [1789, 24] + file_name: (filename [1786, 6] - [1786, 75]) + (blame_entry [1787, 4] - [1787, 24] + line: (number [1787, 11] - [1787, 13]) + date: (date [1787, 14] - [1787, 24])) + (blame_entry [1788, 4] - [1788, 24] + line: (number [1788, 11] - [1788, 13]) + date: (date [1788, 14] - [1788, 24])) + (blame_entry [1789, 4] - [1789, 24] + line: (number [1789, 11] - [1789, 13]) + date: (date [1789, 14] - [1789, 24]))) + (file_entry [1790, 0] - [1792, 24] + file_name: (filename [1790, 6] - [1790, 62]) + (blame_entry [1791, 4] - [1791, 24] + line: (number [1791, 11] - [1791, 13]) + date: (date [1791, 14] - [1791, 24])) + (blame_entry [1792, 4] - [1792, 24] + line: (number [1792, 11] - [1792, 13]) + date: (date [1792, 14] - [1792, 24]))) + (file_entry [1793, 0] - [1794, 24] + file_name: (filename [1793, 6] - [1793, 52]) + (blame_entry [1794, 4] - [1794, 24] + line: (number [1794, 11] - [1794, 13]) + date: (date [1794, 14] - [1794, 24]))) + (file_entry [1795, 0] - [1797, 25] + file_name: (filename [1795, 6] - [1795, 55]) + (blame_entry [1796, 4] - [1796, 24] + line: (number [1796, 11] - [1796, 13]) + date: (date [1796, 14] - [1796, 24])) + (blame_entry [1797, 4] - [1797, 25] + line: (number [1797, 11] - [1797, 14]) + date: (date [1797, 15] - [1797, 25]))) + (file_entry [1798, 0] - [1799, 23] + file_name: (filename [1798, 6] - [1798, 70]) + (blame_entry [1799, 4] - [1799, 23] + line: (number [1799, 11] - [1799, 12]) + date: (date [1799, 13] - [1799, 23]))) + (file_entry [1800, 0] - [1801, 24] + file_name: (filename [1800, 6] - [1800, 75]) + (blame_entry [1801, 4] - [1801, 24] + line: (number [1801, 11] - [1801, 13]) + date: (date [1801, 14] - [1801, 24]))) + (file_entry [1802, 0] - [1805, 25] + file_name: (filename [1802, 6] - [1802, 79]) + (blame_entry [1803, 4] - [1803, 24] + line: (number [1803, 11] - [1803, 13]) + date: (date [1803, 14] - [1803, 24])) + (blame_entry [1804, 4] - [1804, 24] + line: (number [1804, 11] - [1804, 13]) + date: (date [1804, 14] - [1804, 24])) + (blame_entry [1805, 4] - [1805, 25] + line: (number [1805, 11] - [1805, 14]) + date: (date [1805, 15] - [1805, 25]))) + (file_entry [1806, 0] - [1810, 25] + file_name: (filename [1806, 6] - [1806, 66]) + (blame_entry [1807, 4] - [1807, 24] + line: (number [1807, 11] - [1807, 13]) + date: (date [1807, 14] - [1807, 24])) + (blame_entry [1808, 4] - [1808, 25] + line: (number [1808, 11] - [1808, 14]) + date: (date [1808, 15] - [1808, 25])) + (blame_entry [1809, 4] - [1809, 25] + line: (number [1809, 11] - [1809, 14]) + date: (date [1809, 15] - [1809, 25])) + (blame_entry [1810, 4] - [1810, 25] + line: (number [1810, 11] - [1810, 14]) + date: (date [1810, 15] - [1810, 25]))) + (file_entry [1811, 0] - [1820, 25] + file_name: (filename [1811, 6] - [1811, 68]) + (blame_entry [1812, 4] - [1812, 24] + line: (number [1812, 11] - [1812, 13]) + date: (date [1812, 14] - [1812, 24])) + (blame_entry [1813, 4] - [1813, 24] + line: (number [1813, 11] - [1813, 13]) + date: (date [1813, 14] - [1813, 24])) + (blame_entry [1814, 4] - [1814, 24] + line: (number [1814, 11] - [1814, 13]) + date: (date [1814, 14] - [1814, 24])) + (blame_entry [1815, 4] - [1815, 24] + line: (number [1815, 11] - [1815, 13]) + date: (date [1815, 14] - [1815, 24])) + (blame_entry [1816, 4] - [1816, 24] + line: (number [1816, 11] - [1816, 13]) + date: (date [1816, 14] - [1816, 24])) + (blame_entry [1817, 4] - [1817, 25] + line: (number [1817, 11] - [1817, 14]) + date: (date [1817, 15] - [1817, 25])) + (blame_entry [1818, 4] - [1818, 25] + line: (number [1818, 11] - [1818, 14]) + date: (date [1818, 15] - [1818, 25])) + (blame_entry [1819, 4] - [1819, 25] + line: (number [1819, 11] - [1819, 14]) + date: (date [1819, 15] - [1819, 25])) + (blame_entry [1820, 4] - [1820, 25] + line: (number [1820, 11] - [1820, 14]) + date: (date [1820, 15] - [1820, 25]))) + (file_entry [1821, 0] - [1824, 24] + file_name: (filename [1821, 6] - [1821, 87]) + (blame_entry [1822, 4] - [1822, 24] + line: (number [1822, 11] - [1822, 13]) + date: (date [1822, 14] - [1822, 24])) + (blame_entry [1823, 4] - [1823, 24] + line: (number [1823, 11] - [1823, 13]) + date: (date [1823, 14] - [1823, 24])) + (blame_entry [1824, 4] - [1824, 24] + line: (number [1824, 11] - [1824, 13]) + date: (date [1824, 14] - [1824, 24]))) + (file_entry [1825, 0] - [1829, 25] + file_name: (filename [1825, 6] - [1825, 71]) + (blame_entry [1826, 4] - [1826, 24] + line: (number [1826, 11] - [1826, 13]) + date: (date [1826, 14] - [1826, 24])) + (blame_entry [1827, 4] - [1827, 25] + line: (number [1827, 11] - [1827, 14]) + date: (date [1827, 15] - [1827, 25])) + (blame_entry [1828, 4] - [1828, 25] + line: (number [1828, 11] - [1828, 14]) + date: (date [1828, 15] - [1828, 25])) + (blame_entry [1829, 4] - [1829, 25] + line: (number [1829, 11] - [1829, 14]) + date: (date [1829, 15] - [1829, 25]))) + (file_entry [1830, 0] - [1831, 23] + file_name: (filename [1830, 6] - [1830, 78]) + (blame_entry [1831, 4] - [1831, 23] + line: (number [1831, 11] - [1831, 12]) + date: (date [1831, 13] - [1831, 23]))) + (file_entry [1832, 0] - [1841, 25] + file_name: (filename [1832, 6] - [1832, 86]) + (blame_entry [1833, 4] - [1833, 24] + line: (number [1833, 11] - [1833, 13]) + date: (date [1833, 14] - [1833, 24])) + (blame_entry [1834, 4] - [1834, 25] + line: (number [1834, 11] - [1834, 14]) + date: (date [1834, 15] - [1834, 25])) + (blame_entry [1835, 4] - [1835, 25] + line: (number [1835, 11] - [1835, 14]) + date: (date [1835, 15] - [1835, 25])) + (blame_entry [1836, 4] - [1836, 25] + line: (number [1836, 11] - [1836, 14]) + date: (date [1836, 15] - [1836, 25])) + (blame_entry [1837, 4] - [1837, 25] + line: (number [1837, 11] - [1837, 14]) + date: (date [1837, 15] - [1837, 25])) + (blame_entry [1838, 4] - [1838, 25] + line: (number [1838, 11] - [1838, 14]) + date: (date [1838, 15] - [1838, 25])) + (blame_entry [1839, 4] - [1839, 25] + line: (number [1839, 11] - [1839, 14]) + date: (date [1839, 15] - [1839, 25])) + (blame_entry [1840, 4] - [1840, 25] + line: (number [1840, 11] - [1840, 14]) + date: (date [1840, 15] - [1840, 25])) + (blame_entry [1841, 4] - [1841, 25] + line: (number [1841, 11] - [1841, 14]) + date: (date [1841, 15] - [1841, 25]))) + (file_entry [1842, 0] - [1843, 26] + file_name: (filename [1842, 6] - [1842, 83]) + (blame_entry [1843, 4] - [1843, 26] + line: (number [1843, 11] - [1843, 15]) + date: (date [1843, 16] - [1843, 26]))) + (file_entry [1844, 0] - [1845, 23] + file_name: (filename [1844, 6] - [1844, 76]) + (blame_entry [1845, 4] - [1845, 23] + line: (number [1845, 11] - [1845, 12]) + date: (date [1845, 13] - [1845, 23]))) + (file_entry [1846, 0] - [1853, 25] + file_name: (filename [1846, 6] - [1846, 49]) + (blame_entry [1847, 4] - [1847, 25] + line: (number [1847, 11] - [1847, 14]) + date: (date [1847, 15] - [1847, 25])) + (blame_entry [1848, 4] - [1848, 25] + line: (number [1848, 11] - [1848, 14]) + date: (date [1848, 15] - [1848, 25])) + (blame_entry [1849, 4] - [1849, 25] + line: (number [1849, 11] - [1849, 14]) + date: (date [1849, 15] - [1849, 25])) + (blame_entry [1850, 4] - [1850, 25] + line: (number [1850, 11] - [1850, 14]) + date: (date [1850, 15] - [1850, 25])) + (blame_entry [1851, 4] - [1851, 25] + line: (number [1851, 11] - [1851, 14]) + date: (date [1851, 15] - [1851, 25])) + (blame_entry [1852, 4] - [1852, 25] + line: (number [1852, 11] - [1852, 14]) + date: (date [1852, 15] - [1852, 25])) + (blame_entry [1853, 4] - [1853, 25] + line: (number [1853, 11] - [1853, 14]) + date: (date [1853, 15] - [1853, 25]))) + (file_entry [1854, 0] - [1856, 24] + file_name: (filename [1854, 6] - [1854, 57]) + (blame_entry [1855, 4] - [1855, 23] + line: (number [1855, 11] - [1855, 12]) + date: (date [1855, 13] - [1855, 23])) + (blame_entry [1856, 4] - [1856, 24] + line: (number [1856, 11] - [1856, 13]) + date: (date [1856, 14] - [1856, 24]))) + (file_entry [1857, 0] - [1858, 23] + file_name: (filename [1857, 6] - [1857, 48]) + (blame_entry [1858, 4] - [1858, 23] + line: (number [1858, 11] - [1858, 12]) + date: (date [1858, 13] - [1858, 23]))) + (file_entry [1859, 0] - [1861, 25] + file_name: (filename [1859, 6] - [1859, 70]) + (blame_entry [1860, 4] - [1860, 25] + line: (number [1860, 11] - [1860, 14]) + date: (date [1860, 15] - [1860, 25])) + (blame_entry [1861, 4] - [1861, 25] + line: (number [1861, 11] - [1861, 14]) + date: (date [1861, 15] - [1861, 25]))) + (file_entry [1862, 0] - [1866, 24] + file_name: (filename [1862, 6] - [1862, 56]) + (blame_entry [1863, 4] - [1863, 23] + line: (number [1863, 11] - [1863, 12]) + date: (date [1863, 13] - [1863, 23])) + (blame_entry [1864, 4] - [1864, 23] + line: (number [1864, 11] - [1864, 12]) + date: (date [1864, 13] - [1864, 23])) + (blame_entry [1865, 4] - [1865, 24] + line: (number [1865, 11] - [1865, 13]) + date: (date [1865, 14] - [1865, 24])) + (blame_entry [1866, 4] - [1866, 24] + line: (number [1866, 11] - [1866, 13]) + date: (date [1866, 14] - [1866, 24]))) + (file_entry [1867, 0] - [1871, 24] + file_name: (filename [1867, 6] - [1867, 60]) + (blame_entry [1868, 4] - [1868, 24] + line: (number [1868, 11] - [1868, 13]) + date: (date [1868, 14] - [1868, 24])) + (blame_entry [1869, 4] - [1869, 24] + line: (number [1869, 11] - [1869, 13]) + date: (date [1869, 14] - [1869, 24])) + (blame_entry [1870, 4] - [1870, 24] + line: (number [1870, 11] - [1870, 13]) + date: (date [1870, 14] - [1870, 24])) + (blame_entry [1871, 4] - [1871, 24] + line: (number [1871, 11] - [1871, 13]) + date: (date [1871, 14] - [1871, 24]))) + (file_entry [1872, 0] - [1873, 25] + file_name: (filename [1872, 6] - [1872, 74]) + (blame_entry [1873, 4] - [1873, 25] + line: (number [1873, 11] - [1873, 14]) + date: (date [1873, 15] - [1873, 25]))) + (file_entry [1874, 0] - [1878, 25] + file_name: (filename [1874, 6] - [1874, 87]) + (blame_entry [1875, 4] - [1875, 24] + line: (number [1875, 11] - [1875, 13]) + date: (date [1875, 14] - [1875, 24])) + (blame_entry [1876, 4] - [1876, 25] + line: (number [1876, 11] - [1876, 14]) + date: (date [1876, 15] - [1876, 25])) + (blame_entry [1877, 4] - [1877, 25] + line: (number [1877, 11] - [1877, 14]) + date: (date [1877, 15] - [1877, 25])) + (blame_entry [1878, 4] - [1878, 25] + line: (number [1878, 11] - [1878, 14]) + date: (date [1878, 15] - [1878, 25]))) + (file_entry [1879, 0] - [1880, 24] + file_name: (filename [1879, 6] - [1879, 84]) + (blame_entry [1880, 4] - [1880, 24] + line: (number [1880, 11] - [1880, 13]) + date: (date [1880, 14] - [1880, 24]))) + (file_entry [1881, 0] - [1886, 26] + file_name: (filename [1881, 6] - [1881, 37]) + (blame_entry [1882, 4] - [1882, 26] + line: (number [1882, 11] - [1882, 15]) + date: (date [1882, 16] - [1882, 26])) + (blame_entry [1883, 4] - [1883, 26] + line: (number [1883, 11] - [1883, 15]) + date: (date [1883, 16] - [1883, 26])) + (blame_entry [1884, 4] - [1884, 26] + line: (number [1884, 11] - [1884, 15]) + date: (date [1884, 16] - [1884, 26])) + (blame_entry [1885, 4] - [1885, 26] + line: (number [1885, 11] - [1885, 15]) + date: (date [1885, 16] - [1885, 26])) + (blame_entry [1886, 4] - [1886, 26] + line: (number [1886, 11] - [1886, 15]) + date: (date [1886, 16] - [1886, 26]))) + (file_entry [1887, 0] - [1891, 25] + file_name: (filename [1887, 6] - [1887, 53]) + (blame_entry [1888, 4] - [1888, 23] + line: (number [1888, 11] - [1888, 12]) + date: (date [1888, 13] - [1888, 23])) + (blame_entry [1889, 4] - [1889, 24] + line: (number [1889, 11] - [1889, 13]) + date: (date [1889, 14] - [1889, 24])) + (blame_entry [1890, 4] - [1890, 24] + line: (number [1890, 11] - [1890, 13]) + date: (date [1890, 14] - [1890, 24])) + (blame_entry [1891, 4] - [1891, 25] + line: (number [1891, 11] - [1891, 14]) + date: (date [1891, 15] - [1891, 25]))) + (file_entry [1892, 0] - [1899, 25] + file_name: (filename [1892, 6] - [1892, 34]) + (blame_entry [1893, 4] - [1893, 24] + line: (number [1893, 11] - [1893, 13]) + date: (date [1893, 14] - [1893, 24])) + (blame_entry [1894, 4] - [1894, 24] + line: (number [1894, 11] - [1894, 13]) + date: (date [1894, 14] - [1894, 24])) + (blame_entry [1895, 4] - [1895, 24] + line: (number [1895, 11] - [1895, 13]) + date: (date [1895, 14] - [1895, 24])) + (blame_entry [1896, 4] - [1896, 24] + line: (number [1896, 11] - [1896, 13]) + date: (date [1896, 14] - [1896, 24])) + (blame_entry [1897, 4] - [1897, 25] + line: (number [1897, 11] - [1897, 14]) + date: (date [1897, 15] - [1897, 25])) + (blame_entry [1898, 4] - [1898, 25] + line: (number [1898, 11] - [1898, 14]) + date: (date [1898, 15] - [1898, 25])) + (blame_entry [1899, 4] - [1899, 25] + line: (number [1899, 11] - [1899, 14]) + date: (date [1899, 15] - [1899, 25]))) + (file_entry [1900, 0] - [1901, 23] + file_name: (filename [1900, 6] - [1900, 90]) + (blame_entry [1901, 4] - [1901, 23] + line: (number [1901, 11] - [1901, 12]) + date: (date [1901, 13] - [1901, 23]))) + (file_entry [1902, 0] - [1903, 25] + file_name: (filename [1902, 6] - [1902, 67]) + (blame_entry [1903, 4] - [1903, 25] + line: (number [1903, 11] - [1903, 14]) + date: (date [1903, 15] - [1903, 25]))) + (file_entry [1904, 0] - [1906, 26] + file_name: (filename [1904, 6] - [1904, 60]) + (blame_entry [1905, 4] - [1905, 26] + line: (number [1905, 11] - [1905, 15]) + date: (date [1905, 16] - [1905, 26])) + (blame_entry [1906, 4] - [1906, 26] + line: (number [1906, 11] - [1906, 15]) + date: (date [1906, 16] - [1906, 26]))) + (file_entry [1907, 0] - [1911, 25] + file_name: (filename [1907, 6] - [1907, 84]) + (blame_entry [1908, 4] - [1908, 24] + line: (number [1908, 11] - [1908, 13]) + date: (date [1908, 14] - [1908, 24])) + (blame_entry [1909, 4] - [1909, 25] + line: (number [1909, 11] - [1909, 14]) + date: (date [1909, 15] - [1909, 25])) + (blame_entry [1910, 4] - [1910, 25] + line: (number [1910, 11] - [1910, 14]) + date: (date [1910, 15] - [1910, 25])) + (blame_entry [1911, 4] - [1911, 25] + line: (number [1911, 11] - [1911, 14]) + date: (date [1911, 15] - [1911, 25]))) + (file_entry [1912, 0] - [1914, 24] + file_name: (filename [1912, 6] - [1912, 62]) + (blame_entry [1913, 4] - [1913, 24] + line: (number [1913, 11] - [1913, 13]) + date: (date [1913, 14] - [1913, 24])) + (blame_entry [1914, 4] - [1914, 24] + line: (number [1914, 11] - [1914, 13]) + date: (date [1914, 14] - [1914, 24]))) + (file_entry [1915, 0] - [1917, 24] + file_name: (filename [1915, 6] - [1915, 60]) + (blame_entry [1916, 4] - [1916, 23] + line: (number [1916, 11] - [1916, 12]) + date: (date [1916, 13] - [1916, 23])) + (blame_entry [1917, 4] - [1917, 24] + line: (number [1917, 11] - [1917, 13]) + date: (date [1917, 14] - [1917, 24]))) + (file_entry [1918, 0] - [1919, 24] + file_name: (filename [1918, 6] - [1918, 64]) + (blame_entry [1919, 4] - [1919, 24] + line: (number [1919, 11] - [1919, 13]) + date: (date [1919, 14] - [1919, 24]))) + (file_entry [1920, 0] - [1922, 25] + file_name: (filename [1920, 6] - [1920, 53]) + (blame_entry [1921, 4] - [1921, 25] + line: (number [1921, 11] - [1921, 14]) + date: (date [1921, 15] - [1921, 25])) + (blame_entry [1922, 4] - [1922, 25] + line: (number [1922, 11] - [1922, 14]) + date: (date [1922, 15] - [1922, 25]))) + (file_entry [1923, 0] - [1924, 24] + file_name: (filename [1923, 6] - [1923, 76]) + (blame_entry [1924, 4] - [1924, 24] + line: (number [1924, 11] - [1924, 13]) + date: (date [1924, 14] - [1924, 24]))) + (file_entry [1925, 0] - [1926, 24] + file_name: (filename [1925, 6] - [1925, 78]) + (blame_entry [1926, 4] - [1926, 24] + line: (number [1926, 11] - [1926, 13]) + date: (date [1926, 14] - [1926, 24]))) + (file_entry [1927, 0] - [1944, 25] + file_name: (filename [1927, 6] - [1927, 63]) + (blame_entry [1928, 4] - [1928, 23] + line: (number [1928, 11] - [1928, 12]) + date: (date [1928, 13] - [1928, 23])) + (blame_entry [1929, 4] - [1929, 24] + line: (number [1929, 11] - [1929, 13]) + date: (date [1929, 14] - [1929, 24])) + (blame_entry [1930, 4] - [1930, 24] + line: (number [1930, 11] - [1930, 13]) + date: (date [1930, 14] - [1930, 24])) + (blame_entry [1931, 4] - [1931, 24] + line: (number [1931, 11] - [1931, 13]) + date: (date [1931, 14] - [1931, 24])) + (blame_entry [1932, 4] - [1932, 24] + line: (number [1932, 11] - [1932, 13]) + date: (date [1932, 14] - [1932, 24])) + (blame_entry [1933, 4] - [1933, 24] + line: (number [1933, 11] - [1933, 13]) + date: (date [1933, 14] - [1933, 24])) + (blame_entry [1934, 4] - [1934, 25] + line: (number [1934, 11] - [1934, 14]) + date: (date [1934, 15] - [1934, 25])) + (blame_entry [1935, 4] - [1935, 25] + line: (number [1935, 11] - [1935, 14]) + date: (date [1935, 15] - [1935, 25])) + (blame_entry [1936, 4] - [1936, 25] + line: (number [1936, 11] - [1936, 14]) + date: (date [1936, 15] - [1936, 25])) + (blame_entry [1937, 4] - [1937, 25] + line: (number [1937, 11] - [1937, 14]) + date: (date [1937, 15] - [1937, 25])) + (blame_entry [1938, 4] - [1938, 25] + line: (number [1938, 11] - [1938, 14]) + date: (date [1938, 15] - [1938, 25])) + (blame_entry [1939, 4] - [1939, 25] + line: (number [1939, 11] - [1939, 14]) + date: (date [1939, 15] - [1939, 25])) + (blame_entry [1940, 4] - [1940, 25] + line: (number [1940, 11] - [1940, 14]) + date: (date [1940, 15] - [1940, 25])) + (blame_entry [1941, 4] - [1941, 25] + line: (number [1941, 11] - [1941, 14]) + date: (date [1941, 15] - [1941, 25])) + (blame_entry [1942, 4] - [1942, 25] + line: (number [1942, 11] - [1942, 14]) + date: (date [1942, 15] - [1942, 25])) + (blame_entry [1943, 4] - [1943, 25] + line: (number [1943, 11] - [1943, 14]) + date: (date [1943, 15] - [1943, 25])) + (blame_entry [1944, 4] - [1944, 25] + line: (number [1944, 11] - [1944, 14]) + date: (date [1944, 15] - [1944, 25]))) + (file_entry [1945, 0] - [1949, 24] + file_name: (filename [1945, 6] - [1945, 55]) + (blame_entry [1946, 4] - [1946, 24] + line: (number [1946, 11] - [1946, 13]) + date: (date [1946, 14] - [1946, 24])) + (blame_entry [1947, 4] - [1947, 24] + line: (number [1947, 11] - [1947, 13]) + date: (date [1947, 14] - [1947, 24])) + (blame_entry [1948, 4] - [1948, 24] + line: (number [1948, 11] - [1948, 13]) + date: (date [1948, 14] - [1948, 24])) + (blame_entry [1949, 4] - [1949, 24] + line: (number [1949, 11] - [1949, 13]) + date: (date [1949, 14] - [1949, 24]))) + (file_entry [1950, 0] - [1953, 24] + file_name: (filename [1950, 6] - [1950, 67]) + (blame_entry [1951, 4] - [1951, 23] + line: (number [1951, 11] - [1951, 12]) + date: (date [1951, 13] - [1951, 23])) + (blame_entry [1952, 4] - [1952, 24] + line: (number [1952, 11] - [1952, 13]) + date: (date [1952, 14] - [1952, 24])) + (blame_entry [1953, 4] - [1953, 24] + line: (number [1953, 11] - [1953, 13]) + date: (date [1953, 14] - [1953, 24]))) + (file_entry [1954, 0] - [1965, 25] + file_name: (filename [1954, 6] - [1954, 49]) + (blame_entry [1955, 4] - [1955, 24] + line: (number [1955, 11] - [1955, 13]) + date: (date [1955, 14] - [1955, 24])) + (blame_entry [1956, 4] - [1956, 24] + line: (number [1956, 11] - [1956, 13]) + date: (date [1956, 14] - [1956, 24])) + (blame_entry [1957, 4] - [1957, 24] + line: (number [1957, 11] - [1957, 13]) + date: (date [1957, 14] - [1957, 24])) + (blame_entry [1958, 4] - [1958, 24] + line: (number [1958, 11] - [1958, 13]) + date: (date [1958, 14] - [1958, 24])) + (blame_entry [1959, 4] - [1959, 24] + line: (number [1959, 11] - [1959, 13]) + date: (date [1959, 14] - [1959, 24])) + (blame_entry [1960, 4] - [1960, 24] + line: (number [1960, 11] - [1960, 13]) + date: (date [1960, 14] - [1960, 24])) + (blame_entry [1961, 4] - [1961, 24] + line: (number [1961, 11] - [1961, 13]) + date: (date [1961, 14] - [1961, 24])) + (blame_entry [1962, 4] - [1962, 25] + line: (number [1962, 11] - [1962, 14]) + date: (date [1962, 15] - [1962, 25])) + (blame_entry [1963, 4] - [1963, 25] + line: (number [1963, 11] - [1963, 14]) + date: (date [1963, 15] - [1963, 25])) + (blame_entry [1964, 4] - [1964, 25] + line: (number [1964, 11] - [1964, 14]) + date: (date [1964, 15] - [1964, 25])) + (blame_entry [1965, 4] - [1965, 25] + line: (number [1965, 11] - [1965, 14]) + date: (date [1965, 15] - [1965, 25]))) + (file_entry [1966, 0] - [1970, 24] + file_name: (filename [1966, 6] - [1966, 60]) + (blame_entry [1967, 4] - [1967, 24] + line: (number [1967, 11] - [1967, 13]) + date: (date [1967, 14] - [1967, 24])) + (blame_entry [1968, 4] - [1968, 24] + line: (number [1968, 11] - [1968, 13]) + date: (date [1968, 14] - [1968, 24])) + (blame_entry [1969, 4] - [1969, 24] + line: (number [1969, 11] - [1969, 13]) + date: (date [1969, 14] - [1969, 24])) + (blame_entry [1970, 4] - [1970, 24] + line: (number [1970, 11] - [1970, 13]) + date: (date [1970, 14] - [1970, 24]))) + (file_entry [1971, 0] - [1974, 24] + file_name: (filename [1971, 6] - [1971, 72]) + (blame_entry [1972, 4] - [1972, 24] + line: (number [1972, 11] - [1972, 13]) + date: (date [1972, 14] - [1972, 24])) + (blame_entry [1973, 4] - [1973, 24] + line: (number [1973, 11] - [1973, 13]) + date: (date [1973, 14] - [1973, 24])) + (blame_entry [1974, 4] - [1974, 24] + line: (number [1974, 11] - [1974, 13]) + date: (date [1974, 14] - [1974, 24]))) + (file_entry [1975, 0] - [1976, 25] + file_name: (filename [1975, 6] - [1975, 64]) + (blame_entry [1976, 4] - [1976, 25] + line: (number [1976, 11] - [1976, 14]) + date: (date [1976, 15] - [1976, 25]))) + (file_entry [1977, 0] - [1981, 25] + file_name: (filename [1977, 6] - [1977, 84]) + (blame_entry [1978, 4] - [1978, 24] + line: (number [1978, 11] - [1978, 13]) + date: (date [1978, 14] - [1978, 24])) + (blame_entry [1979, 4] - [1979, 25] + line: (number [1979, 11] - [1979, 14]) + date: (date [1979, 15] - [1979, 25])) + (blame_entry [1980, 4] - [1980, 25] + line: (number [1980, 11] - [1980, 14]) + date: (date [1980, 15] - [1980, 25])) + (blame_entry [1981, 4] - [1981, 25] + line: (number [1981, 11] - [1981, 14]) + date: (date [1981, 15] - [1981, 25]))) + (file_entry [1982, 0] - [1991, 26] + file_name: (filename [1982, 6] - [1982, 42]) + (blame_entry [1983, 4] - [1983, 25] + line: (number [1983, 11] - [1983, 14]) + date: (date [1983, 15] - [1983, 25])) + (blame_entry [1984, 4] - [1984, 25] + line: (number [1984, 11] - [1984, 14]) + date: (date [1984, 15] - [1984, 25])) + (blame_entry [1985, 4] - [1985, 25] + line: (number [1985, 11] - [1985, 14]) + date: (date [1985, 15] - [1985, 25])) + (blame_entry [1986, 4] - [1986, 25] + line: (number [1986, 11] - [1986, 14]) + date: (date [1986, 15] - [1986, 25])) + (blame_entry [1987, 4] - [1987, 25] + line: (number [1987, 11] - [1987, 14]) + date: (date [1987, 15] - [1987, 25])) + (blame_entry [1988, 4] - [1988, 25] + line: (number [1988, 11] - [1988, 14]) + date: (date [1988, 15] - [1988, 25])) + (blame_entry [1989, 4] - [1989, 25] + line: (number [1989, 11] - [1989, 14]) + date: (date [1989, 15] - [1989, 25])) + (blame_entry [1990, 4] - [1990, 26] + line: (number [1990, 11] - [1990, 15]) + date: (date [1990, 16] - [1990, 26])) + (blame_entry [1991, 4] - [1991, 26] + line: (number [1991, 11] - [1991, 15]) + date: (date [1991, 16] - [1991, 26]))) + (file_entry [1992, 0] - [1993, 24] + file_name: (filename [1992, 6] - [1992, 80]) + (blame_entry [1993, 4] - [1993, 24] + line: (number [1993, 11] - [1993, 13]) + date: (date [1993, 14] - [1993, 24]))) + (file_entry [1994, 0] - [1996, 25] + file_name: (filename [1994, 6] - [1994, 49]) + (blame_entry [1995, 4] - [1995, 25] + line: (number [1995, 11] - [1995, 14]) + date: (date [1995, 15] - [1995, 25])) + (blame_entry [1996, 4] - [1996, 25] + line: (number [1996, 11] - [1996, 14]) + date: (date [1996, 15] - [1996, 25]))) + (file_entry [1997, 0] - [1999, 24] + file_name: (filename [1997, 6] - [1997, 77]) + (blame_entry [1998, 4] - [1998, 24] + line: (number [1998, 11] - [1998, 13]) + date: (date [1998, 14] - [1998, 24])) + (blame_entry [1999, 4] - [1999, 24] + line: (number [1999, 11] - [1999, 13]) + date: (date [1999, 14] - [1999, 24]))) + (file_entry [2000, 0] - [2007, 24] + file_name: (filename [2000, 6] - [2000, 55]) + (blame_entry [2001, 4] - [2001, 23] + line: (number [2001, 11] - [2001, 12]) + date: (date [2001, 13] - [2001, 23])) + (blame_entry [2002, 4] - [2002, 23] + line: (number [2002, 11] - [2002, 12]) + date: (date [2002, 13] - [2002, 23])) + (blame_entry [2003, 4] - [2003, 24] + line: (number [2003, 11] - [2003, 13]) + date: (date [2003, 14] - [2003, 24])) + (blame_entry [2004, 4] - [2004, 24] + line: (number [2004, 11] - [2004, 13]) + date: (date [2004, 14] - [2004, 24])) + (blame_entry [2005, 4] - [2005, 24] + line: (number [2005, 11] - [2005, 13]) + date: (date [2005, 14] - [2005, 24])) + (blame_entry [2006, 4] - [2006, 24] + line: (number [2006, 11] - [2006, 13]) + date: (date [2006, 14] - [2006, 24])) + (blame_entry [2007, 4] - [2007, 24] + line: (number [2007, 11] - [2007, 13]) + date: (date [2007, 14] - [2007, 24]))) + (file_entry [2008, 0] - [2010, 25] + file_name: (filename [2008, 6] - [2008, 59]) + (blame_entry [2009, 4] - [2009, 24] + line: (number [2009, 11] - [2009, 13]) + date: (date [2009, 14] - [2009, 24])) + (blame_entry [2010, 4] - [2010, 25] + line: (number [2010, 11] - [2010, 14]) + date: (date [2010, 15] - [2010, 25]))) + (file_entry [2011, 0] - [2014, 25] + file_name: (filename [2011, 6] - [2011, 61]) + (blame_entry [2012, 4] - [2012, 24] + line: (number [2012, 11] - [2012, 13]) + date: (date [2012, 14] - [2012, 24])) + (blame_entry [2013, 4] - [2013, 25] + line: (number [2013, 11] - [2013, 14]) + date: (date [2013, 15] - [2013, 25])) + (blame_entry [2014, 4] - [2014, 25] + line: (number [2014, 11] - [2014, 14]) + date: (date [2014, 15] - [2014, 25]))) + (file_entry [2015, 0] - [2016, 24] + file_name: (filename [2015, 6] - [2015, 77]) + (blame_entry [2016, 4] - [2016, 24] + line: (number [2016, 11] - [2016, 13]) + date: (date [2016, 14] - [2016, 24]))) + (file_entry [2017, 0] - [2018, 23] + file_name: (filename [2017, 6] - [2017, 52]) + (blame_entry [2018, 4] - [2018, 23] + line: (number [2018, 11] - [2018, 12]) + date: (date [2018, 13] - [2018, 23]))) + (file_entry [2019, 0] - [2025, 25] + file_name: (filename [2019, 6] - [2019, 35]) + (blame_entry [2020, 4] - [2020, 25] + line: (number [2020, 11] - [2020, 14]) + date: (date [2020, 15] - [2020, 25])) + (blame_entry [2021, 4] - [2021, 25] + line: (number [2021, 11] - [2021, 14]) + date: (date [2021, 15] - [2021, 25])) + (blame_entry [2022, 4] - [2022, 25] + line: (number [2022, 11] - [2022, 14]) + date: (date [2022, 15] - [2022, 25])) + (blame_entry [2023, 4] - [2023, 25] + line: (number [2023, 11] - [2023, 14]) + date: (date [2023, 15] - [2023, 25])) + (blame_entry [2024, 4] - [2024, 25] + line: (number [2024, 11] - [2024, 14]) + date: (date [2024, 15] - [2024, 25])) + (blame_entry [2025, 4] - [2025, 25] + line: (number [2025, 11] - [2025, 14]) + date: (date [2025, 15] - [2025, 25]))) + (file_entry [2026, 0] - [2034, 25] + file_name: (filename [2026, 6] - [2026, 56]) + (blame_entry [2027, 4] - [2027, 23] + line: (number [2027, 11] - [2027, 12]) + date: (date [2027, 13] - [2027, 23])) + (blame_entry [2028, 4] - [2028, 24] + line: (number [2028, 11] - [2028, 13]) + date: (date [2028, 14] - [2028, 24])) + (blame_entry [2029, 4] - [2029, 24] + line: (number [2029, 11] - [2029, 13]) + date: (date [2029, 14] - [2029, 24])) + (blame_entry [2030, 4] - [2030, 24] + line: (number [2030, 11] - [2030, 13]) + date: (date [2030, 14] - [2030, 24])) + (blame_entry [2031, 4] - [2031, 24] + line: (number [2031, 11] - [2031, 13]) + date: (date [2031, 14] - [2031, 24])) + (blame_entry [2032, 4] - [2032, 24] + line: (number [2032, 11] - [2032, 13]) + date: (date [2032, 14] - [2032, 24])) + (blame_entry [2033, 4] - [2033, 24] + line: (number [2033, 11] - [2033, 13]) + date: (date [2033, 14] - [2033, 24])) + (blame_entry [2034, 4] - [2034, 25] + line: (number [2034, 11] - [2034, 14]) + date: (date [2034, 15] - [2034, 25]))) + (file_entry [2035, 0] - [2037, 24] + file_name: (filename [2035, 6] - [2035, 61]) + (blame_entry [2036, 4] - [2036, 24] + line: (number [2036, 11] - [2036, 13]) + date: (date [2036, 14] - [2036, 24])) + (blame_entry [2037, 4] - [2037, 24] + line: (number [2037, 11] - [2037, 13]) + date: (date [2037, 14] - [2037, 24]))) + (file_entry [2038, 0] - [2040, 24] + file_name: (filename [2038, 6] - [2038, 85]) + (blame_entry [2039, 4] - [2039, 24] + line: (number [2039, 11] - [2039, 13]) + date: (date [2039, 14] - [2039, 24])) + (blame_entry [2040, 4] - [2040, 24] + line: (number [2040, 11] - [2040, 13]) + date: (date [2040, 14] - [2040, 24]))) + (file_entry [2041, 0] - [2043, 24] + file_name: (filename [2041, 6] - [2041, 58]) + (blame_entry [2042, 4] - [2042, 24] + line: (number [2042, 11] - [2042, 13]) + date: (date [2042, 14] - [2042, 24])) + (blame_entry [2043, 4] - [2043, 24] + line: (number [2043, 11] - [2043, 13]) + date: (date [2043, 14] - [2043, 24]))) + (file_entry [2044, 0] - [2045, 24] + file_name: (filename [2044, 6] - [2044, 60]) + (blame_entry [2045, 4] - [2045, 24] + line: (number [2045, 11] - [2045, 13]) + date: (date [2045, 14] - [2045, 24]))) + (file_entry [2046, 0] - [2054, 25] + file_name: (filename [2046, 6] - [2046, 76]) + (blame_entry [2047, 4] - [2047, 24] + line: (number [2047, 11] - [2047, 13]) + date: (date [2047, 14] - [2047, 24])) + (blame_entry [2048, 4] - [2048, 24] + line: (number [2048, 11] - [2048, 13]) + date: (date [2048, 14] - [2048, 24])) + (blame_entry [2049, 4] - [2049, 24] + line: (number [2049, 11] - [2049, 13]) + date: (date [2049, 14] - [2049, 24])) + (blame_entry [2050, 4] - [2050, 24] + line: (number [2050, 11] - [2050, 13]) + date: (date [2050, 14] - [2050, 24])) + (blame_entry [2051, 4] - [2051, 24] + line: (number [2051, 11] - [2051, 13]) + date: (date [2051, 14] - [2051, 24])) + (blame_entry [2052, 4] - [2052, 24] + line: (number [2052, 11] - [2052, 13]) + date: (date [2052, 14] - [2052, 24])) + (blame_entry [2053, 4] - [2053, 25] + line: (number [2053, 11] - [2053, 14]) + date: (date [2053, 15] - [2053, 25])) + (blame_entry [2054, 4] - [2054, 25] + line: (number [2054, 11] - [2054, 14]) + date: (date [2054, 15] - [2054, 25]))) + (file_entry [2055, 0] - [2058, 24] + file_name: (filename [2055, 6] - [2055, 57]) + (blame_entry [2056, 4] - [2056, 24] + line: (number [2056, 11] - [2056, 13]) + date: (date [2056, 14] - [2056, 24])) + (blame_entry [2057, 4] - [2057, 24] + line: (number [2057, 11] - [2057, 13]) + date: (date [2057, 14] - [2057, 24])) + (blame_entry [2058, 4] - [2058, 24] + line: (number [2058, 11] - [2058, 13]) + date: (date [2058, 14] - [2058, 24]))) + (file_entry [2059, 0] - [2064, 24] + file_name: (filename [2059, 6] - [2059, 57]) + (blame_entry [2060, 4] - [2060, 24] + line: (number [2060, 11] - [2060, 13]) + date: (date [2060, 14] - [2060, 24])) + (blame_entry [2061, 4] - [2061, 24] + line: (number [2061, 11] - [2061, 13]) + date: (date [2061, 14] - [2061, 24])) + (blame_entry [2062, 4] - [2062, 24] + line: (number [2062, 11] - [2062, 13]) + date: (date [2062, 14] - [2062, 24])) + (blame_entry [2063, 4] - [2063, 24] + line: (number [2063, 11] - [2063, 13]) + date: (date [2063, 14] - [2063, 24])) + (blame_entry [2064, 4] - [2064, 24] + line: (number [2064, 11] - [2064, 13]) + date: (date [2064, 14] - [2064, 24]))) + (file_entry [2065, 0] - [2067, 25] + file_name: (filename [2065, 6] - [2065, 76]) + (blame_entry [2066, 4] - [2066, 24] + line: (number [2066, 11] - [2066, 13]) + date: (date [2066, 14] - [2066, 24])) + (blame_entry [2067, 4] - [2067, 25] + line: (number [2067, 11] - [2067, 14]) + date: (date [2067, 15] - [2067, 25]))) + (file_entry [2068, 0] - [2072, 25] + file_name: (filename [2068, 6] - [2068, 73]) + (blame_entry [2069, 4] - [2069, 24] + line: (number [2069, 11] - [2069, 13]) + date: (date [2069, 14] - [2069, 24])) + (blame_entry [2070, 4] - [2070, 25] + line: (number [2070, 11] - [2070, 14]) + date: (date [2070, 15] - [2070, 25])) + (blame_entry [2071, 4] - [2071, 25] + line: (number [2071, 11] - [2071, 14]) + date: (date [2071, 15] - [2071, 25])) + (blame_entry [2072, 4] - [2072, 25] + line: (number [2072, 11] - [2072, 14]) + date: (date [2072, 15] - [2072, 25]))) + (file_entry [2073, 0] - [2077, 25] + file_name: (filename [2073, 6] - [2073, 68]) + (blame_entry [2074, 4] - [2074, 24] + line: (number [2074, 11] - [2074, 13]) + date: (date [2074, 14] - [2074, 24])) + (blame_entry [2075, 4] - [2075, 25] + line: (number [2075, 11] - [2075, 14]) + date: (date [2075, 15] - [2075, 25])) + (blame_entry [2076, 4] - [2076, 25] + line: (number [2076, 11] - [2076, 14]) + date: (date [2076, 15] - [2076, 25])) + (blame_entry [2077, 4] - [2077, 25] + line: (number [2077, 11] - [2077, 14]) + date: (date [2077, 15] - [2077, 25]))) + (file_entry [2078, 0] - [2090, 26] + file_name: (filename [2078, 6] - [2078, 55]) + (blame_entry [2079, 4] - [2079, 25] + line: (number [2079, 11] - [2079, 14]) + date: (date [2079, 15] - [2079, 25])) + (blame_entry [2080, 4] - [2080, 25] + line: (number [2080, 11] - [2080, 14]) + date: (date [2080, 15] - [2080, 25])) + (blame_entry [2081, 4] - [2081, 25] + line: (number [2081, 11] - [2081, 14]) + date: (date [2081, 15] - [2081, 25])) + (blame_entry [2082, 4] - [2082, 25] + line: (number [2082, 11] - [2082, 14]) + date: (date [2082, 15] - [2082, 25])) + (blame_entry [2083, 4] - [2083, 25] + line: (number [2083, 11] - [2083, 14]) + date: (date [2083, 15] - [2083, 25])) + (blame_entry [2084, 4] - [2084, 26] + line: (number [2084, 11] - [2084, 15]) + date: (date [2084, 16] - [2084, 26])) + (blame_entry [2085, 4] - [2085, 26] + line: (number [2085, 11] - [2085, 15]) + date: (date [2085, 16] - [2085, 26])) + (blame_entry [2086, 4] - [2086, 26] + line: (number [2086, 11] - [2086, 15]) + date: (date [2086, 16] - [2086, 26])) + (blame_entry [2087, 4] - [2087, 26] + line: (number [2087, 11] - [2087, 15]) + date: (date [2087, 16] - [2087, 26])) + (blame_entry [2088, 4] - [2088, 26] + line: (number [2088, 11] - [2088, 15]) + date: (date [2088, 16] - [2088, 26])) + (blame_entry [2089, 4] - [2089, 26] + line: (number [2089, 11] - [2089, 15]) + date: (date [2089, 16] - [2089, 26])) + (blame_entry [2090, 4] - [2090, 26] + line: (number [2090, 11] - [2090, 15]) + date: (date [2090, 16] - [2090, 26]))) + (file_entry [2091, 0] - [2092, 24] + file_name: (filename [2091, 6] - [2091, 46]) + (blame_entry [2092, 4] - [2092, 24] + line: (number [2092, 11] - [2092, 13]) + date: (date [2092, 14] - [2092, 24]))) + (file_entry [2093, 0] - [2097, 25] + file_name: (filename [2093, 6] - [2093, 93]) + (blame_entry [2094, 4] - [2094, 25] + line: (number [2094, 11] - [2094, 14]) + date: (date [2094, 15] - [2094, 25])) + (blame_entry [2095, 4] - [2095, 25] + line: (number [2095, 11] - [2095, 14]) + date: (date [2095, 15] - [2095, 25])) + (blame_entry [2096, 4] - [2096, 25] + line: (number [2096, 11] - [2096, 14]) + date: (date [2096, 15] - [2096, 25])) + (blame_entry [2097, 4] - [2097, 25] + line: (number [2097, 11] - [2097, 14]) + date: (date [2097, 15] - [2097, 25]))) + (file_entry [2098, 0] - [2100, 24] + file_name: (filename [2098, 6] - [2098, 69]) + (blame_entry [2099, 4] - [2099, 23] + line: (number [2099, 11] - [2099, 12]) + date: (date [2099, 13] - [2099, 23])) + (blame_entry [2100, 4] - [2100, 24] + line: (number [2100, 11] - [2100, 13]) + date: (date [2100, 14] - [2100, 24]))) + (file_entry [2101, 0] - [2102, 24] + file_name: (filename [2101, 6] - [2101, 47]) + (blame_entry [2102, 4] - [2102, 24] + line: (number [2102, 11] - [2102, 13]) + date: (date [2102, 14] - [2102, 24]))) + (file_entry [2103, 0] - [2104, 25] + file_name: (filename [2103, 6] - [2103, 66]) + (blame_entry [2104, 4] - [2104, 25] + line: (number [2104, 11] - [2104, 14]) + date: (date [2104, 15] - [2104, 25]))) + (file_entry [2105, 0] - [2106, 23] + file_name: (filename [2105, 6] - [2105, 64]) + (blame_entry [2106, 4] - [2106, 23] + line: (number [2106, 11] - [2106, 12]) + date: (date [2106, 13] - [2106, 23]))) + (file_entry [2107, 0] - [2108, 23] + file_name: (filename [2107, 6] - [2107, 75]) + (blame_entry [2108, 4] - [2108, 23] + line: (number [2108, 11] - [2108, 12]) + date: (date [2108, 13] - [2108, 23]))) + (file_entry [2109, 0] - [2110, 25] + file_name: (filename [2109, 6] - [2109, 60]) + (blame_entry [2110, 4] - [2110, 25] + line: (number [2110, 11] - [2110, 14]) + date: (date [2110, 15] - [2110, 25]))) + (file_entry [2111, 0] - [2115, 25] + file_name: (filename [2111, 6] - [2111, 88]) + (blame_entry [2112, 4] - [2112, 24] + line: (number [2112, 11] - [2112, 13]) + date: (date [2112, 14] - [2112, 24])) + (blame_entry [2113, 4] - [2113, 25] + line: (number [2113, 11] - [2113, 14]) + date: (date [2113, 15] - [2113, 25])) + (blame_entry [2114, 4] - [2114, 25] + line: (number [2114, 11] - [2114, 14]) + date: (date [2114, 15] - [2114, 25])) + (blame_entry [2115, 4] - [2115, 25] + line: (number [2115, 11] - [2115, 14]) + date: (date [2115, 15] - [2115, 25]))) + (file_entry [2116, 0] - [2121, 24] + file_name: (filename [2116, 6] - [2116, 69]) + (blame_entry [2117, 4] - [2117, 24] + line: (number [2117, 11] - [2117, 13]) + date: (date [2117, 14] - [2117, 24])) + (blame_entry [2118, 4] - [2118, 24] + line: (number [2118, 11] - [2118, 13]) + date: (date [2118, 14] - [2118, 24])) + (blame_entry [2119, 4] - [2119, 24] + line: (number [2119, 11] - [2119, 13]) + date: (date [2119, 14] - [2119, 24])) + (blame_entry [2120, 4] - [2120, 24] + line: (number [2120, 11] - [2120, 13]) + date: (date [2120, 14] - [2120, 24])) + (blame_entry [2121, 4] - [2121, 24] + line: (number [2121, 11] - [2121, 13]) + date: (date [2121, 14] - [2121, 24]))) + (file_entry [2122, 0] - [2126, 25] + file_name: (filename [2122, 6] - [2122, 65]) + (blame_entry [2123, 4] - [2123, 24] + line: (number [2123, 11] - [2123, 13]) + date: (date [2123, 14] - [2123, 24])) + (blame_entry [2124, 4] - [2124, 25] + line: (number [2124, 11] - [2124, 14]) + date: (date [2124, 15] - [2124, 25])) + (blame_entry [2125, 4] - [2125, 25] + line: (number [2125, 11] - [2125, 14]) + date: (date [2125, 15] - [2125, 25])) + (blame_entry [2126, 4] - [2126, 25] + line: (number [2126, 11] - [2126, 14]) + date: (date [2126, 15] - [2126, 25]))) + (file_entry [2127, 0] - [2131, 25] + file_name: (filename [2127, 6] - [2127, 74]) + (blame_entry [2128, 4] - [2128, 24] + line: (number [2128, 11] - [2128, 13]) + date: (date [2128, 14] - [2128, 24])) + (blame_entry [2129, 4] - [2129, 25] + line: (number [2129, 11] - [2129, 14]) + date: (date [2129, 15] - [2129, 25])) + (blame_entry [2130, 4] - [2130, 25] + line: (number [2130, 11] - [2130, 14]) + date: (date [2130, 15] - [2130, 25])) + (blame_entry [2131, 4] - [2131, 25] + line: (number [2131, 11] - [2131, 14]) + date: (date [2131, 15] - [2131, 25]))) + (file_entry [2132, 0] - [2155, 25] + file_name: (filename [2132, 6] - [2132, 51]) + (blame_entry [2133, 4] - [2133, 24] + line: (number [2133, 11] - [2133, 13]) + date: (date [2133, 14] - [2133, 24])) + (blame_entry [2134, 4] - [2134, 24] + line: (number [2134, 11] - [2134, 13]) + date: (date [2134, 14] - [2134, 24])) + (blame_entry [2135, 4] - [2135, 24] + line: (number [2135, 11] - [2135, 13]) + date: (date [2135, 14] - [2135, 24])) + (blame_entry [2136, 4] - [2136, 24] + line: (number [2136, 11] - [2136, 13]) + date: (date [2136, 14] - [2136, 24])) + (blame_entry [2137, 4] - [2137, 24] + line: (number [2137, 11] - [2137, 13]) + date: (date [2137, 14] - [2137, 24])) + (blame_entry [2138, 4] - [2138, 24] + line: (number [2138, 11] - [2138, 13]) + date: (date [2138, 14] - [2138, 24])) + (blame_entry [2139, 4] - [2139, 24] + line: (number [2139, 11] - [2139, 13]) + date: (date [2139, 14] - [2139, 24])) + (blame_entry [2140, 4] - [2140, 24] + line: (number [2140, 11] - [2140, 13]) + date: (date [2140, 14] - [2140, 24])) + (blame_entry [2141, 4] - [2141, 25] + line: (number [2141, 11] - [2141, 14]) + date: (date [2141, 15] - [2141, 25])) + (blame_entry [2142, 4] - [2142, 25] + line: (number [2142, 11] - [2142, 14]) + date: (date [2142, 15] - [2142, 25])) + (blame_entry [2143, 4] - [2143, 25] + line: (number [2143, 11] - [2143, 14]) + date: (date [2143, 15] - [2143, 25])) + (blame_entry [2144, 4] - [2144, 25] + line: (number [2144, 11] - [2144, 14]) + date: (date [2144, 15] - [2144, 25])) + (blame_entry [2145, 4] - [2145, 25] + line: (number [2145, 11] - [2145, 14]) + date: (date [2145, 15] - [2145, 25])) + (blame_entry [2146, 4] - [2146, 25] + line: (number [2146, 11] - [2146, 14]) + date: (date [2146, 15] - [2146, 25])) + (blame_entry [2147, 4] - [2147, 25] + line: (number [2147, 11] - [2147, 14]) + date: (date [2147, 15] - [2147, 25])) + (blame_entry [2148, 4] - [2148, 25] + line: (number [2148, 11] - [2148, 14]) + date: (date [2148, 15] - [2148, 25])) + (blame_entry [2149, 4] - [2149, 25] + line: (number [2149, 11] - [2149, 14]) + date: (date [2149, 15] - [2149, 25])) + (blame_entry [2150, 4] - [2150, 25] + line: (number [2150, 11] - [2150, 14]) + date: (date [2150, 15] - [2150, 25])) + (blame_entry [2151, 4] - [2151, 25] + line: (number [2151, 11] - [2151, 14]) + date: (date [2151, 15] - [2151, 25])) + (blame_entry [2152, 4] - [2152, 25] + line: (number [2152, 11] - [2152, 14]) + date: (date [2152, 15] - [2152, 25])) + (blame_entry [2153, 4] - [2153, 25] + line: (number [2153, 11] - [2153, 14]) + date: (date [2153, 15] - [2153, 25])) + (blame_entry [2154, 4] - [2154, 25] + line: (number [2154, 11] - [2154, 14]) + date: (date [2154, 15] - [2154, 25])) + (blame_entry [2155, 4] - [2155, 25] + line: (number [2155, 11] - [2155, 14]) + date: (date [2155, 15] - [2155, 25]))) + (file_entry [2156, 0] - [2157, 23] + file_name: (filename [2156, 6] - [2156, 70]) + (blame_entry [2157, 4] - [2157, 23] + line: (number [2157, 11] - [2157, 12]) + date: (date [2157, 13] - [2157, 23]))) + (file_entry [2158, 0] - [2159, 24] + file_name: (filename [2158, 6] - [2158, 54]) + (blame_entry [2159, 4] - [2159, 24] + line: (number [2159, 11] - [2159, 13]) + date: (date [2159, 14] - [2159, 24]))) + (file_entry [2160, 0] - [2178, 25] + file_name: (filename [2160, 6] - [2160, 50]) + (blame_entry [2161, 4] - [2161, 24] + line: (number [2161, 11] - [2161, 13]) + date: (date [2161, 14] - [2161, 24])) + (blame_entry [2162, 4] - [2162, 25] + line: (number [2162, 11] - [2162, 14]) + date: (date [2162, 15] - [2162, 25])) + (blame_entry [2163, 4] - [2163, 25] + line: (number [2163, 11] - [2163, 14]) + date: (date [2163, 15] - [2163, 25])) + (blame_entry [2164, 4] - [2164, 25] + line: (number [2164, 11] - [2164, 14]) + date: (date [2164, 15] - [2164, 25])) + (blame_entry [2165, 4] - [2165, 25] + line: (number [2165, 11] - [2165, 14]) + date: (date [2165, 15] - [2165, 25])) + (blame_entry [2166, 4] - [2166, 25] + line: (number [2166, 11] - [2166, 14]) + date: (date [2166, 15] - [2166, 25])) + (blame_entry [2167, 4] - [2167, 25] + line: (number [2167, 11] - [2167, 14]) + date: (date [2167, 15] - [2167, 25])) + (blame_entry [2168, 4] - [2168, 25] + line: (number [2168, 11] - [2168, 14]) + date: (date [2168, 15] - [2168, 25])) + (blame_entry [2169, 4] - [2169, 25] + line: (number [2169, 11] - [2169, 14]) + date: (date [2169, 15] - [2169, 25])) + (blame_entry [2170, 4] - [2170, 25] + line: (number [2170, 11] - [2170, 14]) + date: (date [2170, 15] - [2170, 25])) + (blame_entry [2171, 4] - [2171, 25] + line: (number [2171, 11] - [2171, 14]) + date: (date [2171, 15] - [2171, 25])) + (blame_entry [2172, 4] - [2172, 25] + line: (number [2172, 11] - [2172, 14]) + date: (date [2172, 15] - [2172, 25])) + (blame_entry [2173, 4] - [2173, 25] + line: (number [2173, 11] - [2173, 14]) + date: (date [2173, 15] - [2173, 25])) + (blame_entry [2174, 4] - [2174, 25] + line: (number [2174, 11] - [2174, 14]) + date: (date [2174, 15] - [2174, 25])) + (blame_entry [2175, 4] - [2175, 25] + line: (number [2175, 11] - [2175, 14]) + date: (date [2175, 15] - [2175, 25])) + (blame_entry [2176, 4] - [2176, 25] + line: (number [2176, 11] - [2176, 14]) + date: (date [2176, 15] - [2176, 25])) + (blame_entry [2177, 4] - [2177, 25] + line: (number [2177, 11] - [2177, 14]) + date: (date [2177, 15] - [2177, 25])) + (blame_entry [2178, 4] - [2178, 25] + line: (number [2178, 11] - [2178, 14]) + date: (date [2178, 15] - [2178, 25]))) + (file_entry [2179, 0] - [2181, 24] + file_name: (filename [2179, 6] - [2179, 55]) + (blame_entry [2180, 4] - [2180, 24] + line: (number [2180, 11] - [2180, 13]) + date: (date [2180, 14] - [2180, 24])) + (blame_entry [2181, 4] - [2181, 24] + line: (number [2181, 11] - [2181, 13]) + date: (date [2181, 14] - [2181, 24]))) + (file_entry [2182, 0] - [2183, 23] + file_name: (filename [2182, 6] - [2182, 90]) + (blame_entry [2183, 4] - [2183, 23] + line: (number [2183, 11] - [2183, 12]) + date: (date [2183, 13] - [2183, 23]))) + (file_entry [2184, 0] - [2185, 23] + file_name: (filename [2184, 6] - [2184, 78]) + (blame_entry [2185, 4] - [2185, 23] + line: (number [2185, 11] - [2185, 12]) + date: (date [2185, 13] - [2185, 23]))) + (file_entry [2186, 0] - [2190, 25] + file_name: (filename [2186, 6] - [2186, 87]) + (blame_entry [2187, 4] - [2187, 25] + line: (number [2187, 11] - [2187, 14]) + date: (date [2187, 15] - [2187, 25])) + (blame_entry [2188, 4] - [2188, 25] + line: (number [2188, 11] - [2188, 14]) + date: (date [2188, 15] - [2188, 25])) + (blame_entry [2189, 4] - [2189, 25] + line: (number [2189, 11] - [2189, 14]) + date: (date [2189, 15] - [2189, 25])) + (blame_entry [2190, 4] - [2190, 25] + line: (number [2190, 11] - [2190, 14]) + date: (date [2190, 15] - [2190, 25]))) + (file_entry [2191, 0] - [2192, 24] + file_name: (filename [2191, 6] - [2191, 59]) + (blame_entry [2192, 4] - [2192, 24] + line: (number [2192, 11] - [2192, 13]) + date: (date [2192, 14] - [2192, 24]))) + (file_entry [2193, 0] - [2194, 24] + file_name: (filename [2193, 6] - [2193, 58]) + (blame_entry [2194, 4] - [2194, 24] + line: (number [2194, 11] - [2194, 13]) + date: (date [2194, 14] - [2194, 24]))) + (file_entry [2195, 0] - [2196, 25] + file_name: (filename [2195, 6] - [2195, 62]) + (blame_entry [2196, 4] - [2196, 25] + line: (number [2196, 11] - [2196, 14]) + date: (date [2196, 15] - [2196, 25]))) + (file_entry [2197, 0] - [2202, 24] + file_name: (filename [2197, 6] - [2197, 56]) + (blame_entry [2198, 4] - [2198, 23] + line: (number [2198, 11] - [2198, 12]) + date: (date [2198, 13] - [2198, 23])) + (blame_entry [2199, 4] - [2199, 23] + line: (number [2199, 11] - [2199, 12]) + date: (date [2199, 13] - [2199, 23])) + (blame_entry [2200, 4] - [2200, 24] + line: (number [2200, 11] - [2200, 13]) + date: (date [2200, 14] - [2200, 24])) + (blame_entry [2201, 4] - [2201, 24] + line: (number [2201, 11] - [2201, 13]) + date: (date [2201, 14] - [2201, 24])) + (blame_entry [2202, 4] - [2202, 24] + line: (number [2202, 11] - [2202, 13]) + date: (date [2202, 14] - [2202, 24]))) + (file_entry [2203, 0] - [2207, 24] + file_name: (filename [2203, 6] - [2203, 56]) + (blame_entry [2204, 4] - [2204, 24] + line: (number [2204, 11] - [2204, 13]) + date: (date [2204, 14] - [2204, 24])) + (blame_entry [2205, 4] - [2205, 24] + line: (number [2205, 11] - [2205, 13]) + date: (date [2205, 14] - [2205, 24])) + (blame_entry [2206, 4] - [2206, 24] + line: (number [2206, 11] - [2206, 13]) + date: (date [2206, 14] - [2206, 24])) + (blame_entry [2207, 4] - [2207, 24] + line: (number [2207, 11] - [2207, 13]) + date: (date [2207, 14] - [2207, 24]))) + (file_entry [2208, 0] - [2210, 24] + file_name: (filename [2208, 6] - [2208, 57]) + (blame_entry [2209, 4] - [2209, 24] + line: (number [2209, 11] - [2209, 13]) + date: (date [2209, 14] - [2209, 24])) + (blame_entry [2210, 4] - [2210, 24] + line: (number [2210, 11] - [2210, 13]) + date: (date [2210, 14] - [2210, 24]))) + (file_entry [2211, 0] - [2221, 24] + file_name: (filename [2211, 6] - [2211, 60]) + (blame_entry [2212, 4] - [2212, 24] + line: (number [2212, 11] - [2212, 13]) + date: (date [2212, 14] - [2212, 24])) + (blame_entry [2213, 4] - [2213, 24] + line: (number [2213, 11] - [2213, 13]) + date: (date [2213, 14] - [2213, 24])) + (blame_entry [2214, 4] - [2214, 24] + line: (number [2214, 11] - [2214, 13]) + date: (date [2214, 14] - [2214, 24])) + (blame_entry [2215, 4] - [2215, 24] + line: (number [2215, 11] - [2215, 13]) + date: (date [2215, 14] - [2215, 24])) + (blame_entry [2216, 4] - [2216, 24] + line: (number [2216, 11] - [2216, 13]) + date: (date [2216, 14] - [2216, 24])) + (blame_entry [2217, 4] - [2217, 24] + line: (number [2217, 11] - [2217, 13]) + date: (date [2217, 14] - [2217, 24])) + (blame_entry [2218, 4] - [2218, 24] + line: (number [2218, 11] - [2218, 13]) + date: (date [2218, 14] - [2218, 24])) + (blame_entry [2219, 4] - [2219, 24] + line: (number [2219, 11] - [2219, 13]) + date: (date [2219, 14] - [2219, 24])) + (blame_entry [2220, 4] - [2220, 24] + line: (number [2220, 11] - [2220, 13]) + date: (date [2220, 14] - [2220, 24])) + (blame_entry [2221, 4] - [2221, 24] + line: (number [2221, 11] - [2221, 13]) + date: (date [2221, 14] - [2221, 24]))) + (file_entry [2222, 0] - [2223, 23] + file_name: (filename [2222, 6] - [2222, 59]) + (blame_entry [2223, 4] - [2223, 23] + line: (number [2223, 11] - [2223, 12]) + date: (date [2223, 13] - [2223, 23]))) + (file_entry [2224, 0] - [2225, 25] + file_name: (filename [2224, 6] - [2224, 58]) + (blame_entry [2225, 4] - [2225, 25] + line: (number [2225, 11] - [2225, 14]) + date: (date [2225, 15] - [2225, 25]))) + (file_entry [2226, 0] - [2228, 24] + file_name: (filename [2226, 6] - [2226, 52]) + (blame_entry [2227, 4] - [2227, 23] + line: (number [2227, 11] - [2227, 12]) + date: (date [2227, 13] - [2227, 23])) + (blame_entry [2228, 4] - [2228, 24] + line: (number [2228, 11] - [2228, 13]) + date: (date [2228, 14] - [2228, 24]))) + (file_entry [2229, 0] - [2230, 23] + file_name: (filename [2229, 6] - [2229, 85]) + (blame_entry [2230, 4] - [2230, 23] + line: (number [2230, 11] - [2230, 12]) + date: (date [2230, 13] - [2230, 23]))) + (file_entry [2231, 0] - [2234, 24] + file_name: (filename [2231, 6] - [2231, 63]) + (blame_entry [2232, 4] - [2232, 24] + line: (number [2232, 11] - [2232, 13]) + date: (date [2232, 14] - [2232, 24])) + (blame_entry [2233, 4] - [2233, 24] + line: (number [2233, 11] - [2233, 13]) + date: (date [2233, 14] - [2233, 24])) + (blame_entry [2234, 4] - [2234, 24] + line: (number [2234, 11] - [2234, 13]) + date: (date [2234, 14] - [2234, 24]))) + (file_entry [2235, 0] - [2237, 25] + file_name: (filename [2235, 6] - [2235, 71]) + (blame_entry [2236, 4] - [2236, 25] + line: (number [2236, 11] - [2236, 14]) + date: (date [2236, 15] - [2236, 25])) + (blame_entry [2237, 4] - [2237, 25] + line: (number [2237, 11] - [2237, 14]) + date: (date [2237, 15] - [2237, 25]))) + (file_entry [2238, 0] - [2239, 24] + file_name: (filename [2238, 6] - [2238, 51]) + (blame_entry [2239, 4] - [2239, 24] + line: (number [2239, 11] - [2239, 13]) + date: (date [2239, 14] - [2239, 24]))) + (file_entry [2240, 0] - [2241, 24] + file_name: (filename [2240, 6] - [2240, 51]) + (blame_entry [2241, 4] - [2241, 24] + line: (number [2241, 11] - [2241, 13]) + date: (date [2241, 14] - [2241, 24]))) + (file_entry [2242, 0] - [2244, 25] + file_name: (filename [2242, 6] - [2242, 100]) + (blame_entry [2243, 4] - [2243, 25] + line: (number [2243, 11] - [2243, 14]) + date: (date [2243, 15] - [2243, 25])) + (blame_entry [2244, 4] - [2244, 25] + line: (number [2244, 11] - [2244, 14]) + date: (date [2244, 15] - [2244, 25]))) + (file_entry [2245, 0] - [2246, 24] + file_name: (filename [2245, 6] - [2245, 67]) + (blame_entry [2246, 4] - [2246, 24] + line: (number [2246, 11] - [2246, 13]) + date: (date [2246, 14] - [2246, 24]))) + (file_entry [2247, 0] - [2251, 25] + file_name: (filename [2247, 6] - [2247, 71]) + (blame_entry [2248, 4] - [2248, 24] + line: (number [2248, 11] - [2248, 13]) + date: (date [2248, 14] - [2248, 24])) + (blame_entry [2249, 4] - [2249, 25] + line: (number [2249, 11] - [2249, 14]) + date: (date [2249, 15] - [2249, 25])) + (blame_entry [2250, 4] - [2250, 25] + line: (number [2250, 11] - [2250, 14]) + date: (date [2250, 15] - [2250, 25])) + (blame_entry [2251, 4] - [2251, 25] + line: (number [2251, 11] - [2251, 14]) + date: (date [2251, 15] - [2251, 25]))) + (file_entry [2252, 0] - [2253, 24] + file_name: (filename [2252, 6] - [2252, 79]) + (blame_entry [2253, 4] - [2253, 24] + line: (number [2253, 11] - [2253, 13]) + date: (date [2253, 14] - [2253, 24]))) + (file_entry [2254, 0] - [2256, 24] + file_name: (filename [2254, 6] - [2254, 61]) + (blame_entry [2255, 4] - [2255, 23] + line: (number [2255, 11] - [2255, 12]) + date: (date [2255, 13] - [2255, 23])) + (blame_entry [2256, 4] - [2256, 24] + line: (number [2256, 11] - [2256, 13]) + date: (date [2256, 14] - [2256, 24]))) + (file_entry [2257, 0] - [2258, 23] + file_name: (filename [2257, 6] - [2257, 51]) + (blame_entry [2258, 4] - [2258, 23] + line: (number [2258, 11] - [2258, 12]) + date: (date [2258, 13] - [2258, 23]))) + (file_entry [2259, 0] - [2260, 24] + file_name: (filename [2259, 6] - [2259, 69]) + (blame_entry [2260, 4] - [2260, 24] + line: (number [2260, 11] - [2260, 13]) + date: (date [2260, 14] - [2260, 24]))) + (file_entry [2261, 0] - [2278, 26] + file_name: (filename [2261, 6] - [2261, 55]) + (blame_entry [2262, 4] - [2262, 25] + line: (number [2262, 11] - [2262, 14]) + date: (date [2262, 15] - [2262, 25])) + (blame_entry [2263, 4] - [2263, 26] + line: (number [2263, 11] - [2263, 15]) + date: (date [2263, 16] - [2263, 26])) + (blame_entry [2264, 4] - [2264, 26] + line: (number [2264, 11] - [2264, 15]) + date: (date [2264, 16] - [2264, 26])) + (blame_entry [2265, 4] - [2265, 26] + line: (number [2265, 11] - [2265, 15]) + date: (date [2265, 16] - [2265, 26])) + (blame_entry [2266, 4] - [2266, 26] + line: (number [2266, 11] - [2266, 15]) + date: (date [2266, 16] - [2266, 26])) + (blame_entry [2267, 4] - [2267, 26] + line: (number [2267, 11] - [2267, 15]) + date: (date [2267, 16] - [2267, 26])) + (blame_entry [2268, 4] - [2268, 26] + line: (number [2268, 11] - [2268, 15]) + date: (date [2268, 16] - [2268, 26])) + (blame_entry [2269, 4] - [2269, 26] + line: (number [2269, 11] - [2269, 15]) + date: (date [2269, 16] - [2269, 26])) + (blame_entry [2270, 4] - [2270, 26] + line: (number [2270, 11] - [2270, 15]) + date: (date [2270, 16] - [2270, 26])) + (blame_entry [2271, 4] - [2271, 26] + line: (number [2271, 11] - [2271, 15]) + date: (date [2271, 16] - [2271, 26])) + (blame_entry [2272, 4] - [2272, 26] + line: (number [2272, 11] - [2272, 15]) + date: (date [2272, 16] - [2272, 26])) + (blame_entry [2273, 4] - [2273, 26] + line: (number [2273, 11] - [2273, 15]) + date: (date [2273, 16] - [2273, 26])) + (blame_entry [2274, 4] - [2274, 26] + line: (number [2274, 11] - [2274, 15]) + date: (date [2274, 16] - [2274, 26])) + (blame_entry [2275, 4] - [2275, 26] + line: (number [2275, 11] - [2275, 15]) + date: (date [2275, 16] - [2275, 26])) + (blame_entry [2276, 4] - [2276, 26] + line: (number [2276, 11] - [2276, 15]) + date: (date [2276, 16] - [2276, 26])) + (blame_entry [2277, 4] - [2277, 26] + line: (number [2277, 11] - [2277, 15]) + date: (date [2277, 16] - [2277, 26])) + (blame_entry [2278, 4] - [2278, 26] + line: (number [2278, 11] - [2278, 15]) + date: (date [2278, 16] - [2278, 26]))) + (file_entry [2279, 0] - [2280, 24] + file_name: (filename [2279, 6] - [2279, 73]) + (blame_entry [2280, 4] - [2280, 24] + line: (number [2280, 11] - [2280, 13]) + date: (date [2280, 14] - [2280, 24]))) + (file_entry [2281, 0] - [2282, 24] + file_name: (filename [2281, 6] - [2281, 62]) + (blame_entry [2282, 4] - [2282, 24] + line: (number [2282, 11] - [2282, 13]) + date: (date [2282, 14] - [2282, 24]))) + (file_entry [2283, 0] - [2284, 24] + file_name: (filename [2283, 6] - [2283, 78]) + (blame_entry [2284, 4] - [2284, 24] + line: (number [2284, 11] - [2284, 13]) + date: (date [2284, 14] - [2284, 24]))) + (file_entry [2285, 0] - [2287, 25] + file_name: (filename [2285, 6] - [2285, 64]) + (blame_entry [2286, 4] - [2286, 24] + line: (number [2286, 11] - [2286, 13]) + date: (date [2286, 14] - [2286, 24])) + (blame_entry [2287, 4] - [2287, 25] + line: (number [2287, 11] - [2287, 14]) + date: (date [2287, 15] - [2287, 25]))) + (file_entry [2288, 0] - [2292, 25] + file_name: (filename [2288, 6] - [2288, 86]) + (blame_entry [2289, 4] - [2289, 25] + line: (number [2289, 11] - [2289, 14]) + date: (date [2289, 15] - [2289, 25])) + (blame_entry [2290, 4] - [2290, 25] + line: (number [2290, 11] - [2290, 14]) + date: (date [2290, 15] - [2290, 25])) + (blame_entry [2291, 4] - [2291, 25] + line: (number [2291, 11] - [2291, 14]) + date: (date [2291, 15] - [2291, 25])) + (blame_entry [2292, 4] - [2292, 25] + line: (number [2292, 11] - [2292, 14]) + date: (date [2292, 15] - [2292, 25]))) + (file_entry [2293, 0] - [2295, 24] + file_name: (filename [2293, 6] - [2293, 54]) + (blame_entry [2294, 4] - [2294, 24] + line: (number [2294, 11] - [2294, 13]) + date: (date [2294, 14] - [2294, 24])) + (blame_entry [2295, 4] - [2295, 24] + line: (number [2295, 11] - [2295, 13]) + date: (date [2295, 14] - [2295, 24]))) + (file_entry [2296, 0] - [2297, 25] + file_name: (filename [2296, 6] - [2296, 65]) + (blame_entry [2297, 4] - [2297, 25] + line: (number [2297, 11] - [2297, 14]) + date: (date [2297, 15] - [2297, 25]))) + (file_entry [2298, 0] - [2302, 25] + file_name: (filename [2298, 6] - [2298, 64]) + (blame_entry [2299, 4] - [2299, 24] + line: (number [2299, 11] - [2299, 13]) + date: (date [2299, 14] - [2299, 24])) + (blame_entry [2300, 4] - [2300, 25] + line: (number [2300, 11] - [2300, 14]) + date: (date [2300, 15] - [2300, 25])) + (blame_entry [2301, 4] - [2301, 25] + line: (number [2301, 11] - [2301, 14]) + date: (date [2301, 15] - [2301, 25])) + (blame_entry [2302, 4] - [2302, 25] + line: (number [2302, 11] - [2302, 14]) + date: (date [2302, 15] - [2302, 25]))) + (file_entry [2303, 0] - [2304, 23] + file_name: (filename [2303, 6] - [2303, 69]) + (blame_entry [2304, 4] - [2304, 23] + line: (number [2304, 11] - [2304, 12]) + date: (date [2304, 13] - [2304, 23]))) + (file_entry [2305, 0] - [2306, 24] + file_name: (filename [2305, 6] - [2305, 73]) + (blame_entry [2306, 4] - [2306, 24] + line: (number [2306, 11] - [2306, 13]) + date: (date [2306, 14] - [2306, 24]))) + (file_entry [2307, 0] - [2311, 25] + file_name: (filename [2307, 6] - [2307, 73]) + (blame_entry [2308, 4] - [2308, 24] + line: (number [2308, 11] - [2308, 13]) + date: (date [2308, 14] - [2308, 24])) + (blame_entry [2309, 4] - [2309, 25] + line: (number [2309, 11] - [2309, 14]) + date: (date [2309, 15] - [2309, 25])) + (blame_entry [2310, 4] - [2310, 25] + line: (number [2310, 11] - [2310, 14]) + date: (date [2310, 15] - [2310, 25])) + (blame_entry [2311, 4] - [2311, 25] + line: (number [2311, 11] - [2311, 14]) + date: (date [2311, 15] - [2311, 25]))) + (file_entry [2312, 0] - [2317, 25] + file_name: (filename [2312, 6] - [2312, 92]) + (blame_entry [2313, 4] - [2313, 25] + line: (number [2313, 11] - [2313, 14]) + date: (date [2313, 15] - [2313, 25])) + (blame_entry [2314, 4] - [2314, 25] + line: (number [2314, 11] - [2314, 14]) + date: (date [2314, 15] - [2314, 25])) + (blame_entry [2315, 4] - [2315, 25] + line: (number [2315, 11] - [2315, 14]) + date: (date [2315, 15] - [2315, 25])) + (blame_entry [2316, 4] - [2316, 25] + line: (number [2316, 11] - [2316, 14]) + date: (date [2316, 15] - [2316, 25])) + (blame_entry [2317, 4] - [2317, 25] + line: (number [2317, 11] - [2317, 14]) + date: (date [2317, 15] - [2317, 25]))) + (file_entry [2318, 0] - [2319, 24] + file_name: (filename [2318, 6] - [2318, 44]) + (blame_entry [2319, 4] - [2319, 24] + line: (number [2319, 11] - [2319, 13]) + date: (date [2319, 14] - [2319, 24]))) + (file_entry [2320, 0] - [2322, 24] + file_name: (filename [2320, 6] - [2320, 53]) + (blame_entry [2321, 4] - [2321, 23] + line: (number [2321, 11] - [2321, 12]) + date: (date [2321, 13] - [2321, 23])) + (blame_entry [2322, 4] - [2322, 24] + line: (number [2322, 11] - [2322, 13]) + date: (date [2322, 14] - [2322, 24]))) + (file_entry [2323, 0] - [2330, 25] + file_name: (filename [2323, 6] - [2323, 79]) + (blame_entry [2324, 4] - [2324, 24] + line: (number [2324, 11] - [2324, 13]) + date: (date [2324, 14] - [2324, 24])) + (blame_entry [2325, 4] - [2325, 24] + line: (number [2325, 11] - [2325, 13]) + date: (date [2325, 14] - [2325, 24])) + (blame_entry [2326, 4] - [2326, 25] + line: (number [2326, 11] - [2326, 14]) + date: (date [2326, 15] - [2326, 25])) + (blame_entry [2327, 4] - [2327, 25] + line: (number [2327, 11] - [2327, 14]) + date: (date [2327, 15] - [2327, 25])) + (blame_entry [2328, 4] - [2328, 25] + line: (number [2328, 11] - [2328, 14]) + date: (date [2328, 15] - [2328, 25])) + (blame_entry [2329, 4] - [2329, 25] + line: (number [2329, 11] - [2329, 14]) + date: (date [2329, 15] - [2329, 25])) + (blame_entry [2330, 4] - [2330, 25] + line: (number [2330, 11] - [2330, 14]) + date: (date [2330, 15] - [2330, 25]))) + (file_entry [2331, 0] - [2333, 25] + file_name: (filename [2331, 6] - [2331, 66]) + (blame_entry [2332, 4] - [2332, 24] + line: (number [2332, 11] - [2332, 13]) + date: (date [2332, 14] - [2332, 24])) + (blame_entry [2333, 4] - [2333, 25] + line: (number [2333, 11] - [2333, 14]) + date: (date [2333, 15] - [2333, 25]))) + (file_entry [2334, 0] - [2339, 25] + file_name: (filename [2334, 6] - [2334, 91]) + (blame_entry [2335, 4] - [2335, 24] + line: (number [2335, 11] - [2335, 13]) + date: (date [2335, 14] - [2335, 24])) + (blame_entry [2336, 4] - [2336, 25] + line: (number [2336, 11] - [2336, 14]) + date: (date [2336, 15] - [2336, 25])) + (blame_entry [2337, 4] - [2337, 25] + line: (number [2337, 11] - [2337, 14]) + date: (date [2337, 15] - [2337, 25])) + (blame_entry [2338, 4] - [2338, 25] + line: (number [2338, 11] - [2338, 14]) + date: (date [2338, 15] - [2338, 25])) + (blame_entry [2339, 4] - [2339, 25] + line: (number [2339, 11] - [2339, 14]) + date: (date [2339, 15] - [2339, 25]))) + (file_entry [2340, 0] - [2353, 25] + file_name: (filename [2340, 6] - [2340, 41]) + (blame_entry [2341, 4] - [2341, 24] + line: (number [2341, 11] - [2341, 13]) + date: (date [2341, 14] - [2341, 24])) + (blame_entry [2342, 4] - [2342, 24] + line: (number [2342, 11] - [2342, 13]) + date: (date [2342, 14] - [2342, 24])) + (blame_entry [2343, 4] - [2343, 25] + line: (number [2343, 11] - [2343, 14]) + date: (date [2343, 15] - [2343, 25])) + (blame_entry [2344, 4] - [2344, 25] + line: (number [2344, 11] - [2344, 14]) + date: (date [2344, 15] - [2344, 25])) + (blame_entry [2345, 4] - [2345, 25] + line: (number [2345, 11] - [2345, 14]) + date: (date [2345, 15] - [2345, 25])) + (blame_entry [2346, 4] - [2346, 25] + line: (number [2346, 11] - [2346, 14]) + date: (date [2346, 15] - [2346, 25])) + (blame_entry [2347, 4] - [2347, 25] + line: (number [2347, 11] - [2347, 14]) + date: (date [2347, 15] - [2347, 25])) + (blame_entry [2348, 4] - [2348, 25] + line: (number [2348, 11] - [2348, 14]) + date: (date [2348, 15] - [2348, 25])) + (blame_entry [2349, 4] - [2349, 25] + line: (number [2349, 11] - [2349, 14]) + date: (date [2349, 15] - [2349, 25])) + (blame_entry [2350, 4] - [2350, 25] + line: (number [2350, 11] - [2350, 14]) + date: (date [2350, 15] - [2350, 25])) + (blame_entry [2351, 4] - [2351, 25] + line: (number [2351, 11] - [2351, 14]) + date: (date [2351, 15] - [2351, 25])) + (blame_entry [2352, 4] - [2352, 25] + line: (number [2352, 11] - [2352, 14]) + date: (date [2352, 15] - [2352, 25])) + (blame_entry [2353, 4] - [2353, 25] + line: (number [2353, 11] - [2353, 14]) + date: (date [2353, 15] - [2353, 25]))) + (file_entry [2354, 0] - [2356, 24] + file_name: (filename [2354, 6] - [2354, 69]) + (blame_entry [2355, 4] - [2355, 23] + line: (number [2355, 11] - [2355, 12]) + date: (date [2355, 13] - [2355, 23])) + (blame_entry [2356, 4] - [2356, 24] + line: (number [2356, 11] - [2356, 13]) + date: (date [2356, 14] - [2356, 24]))) + (file_entry [2357, 0] - [2360, 24] + file_name: (filename [2357, 6] - [2357, 57]) + (blame_entry [2358, 4] - [2358, 23] + line: (number [2358, 11] - [2358, 12]) + date: (date [2358, 13] - [2358, 23])) + (blame_entry [2359, 4] - [2359, 24] + line: (number [2359, 11] - [2359, 13]) + date: (date [2359, 14] - [2359, 24])) + (blame_entry [2360, 4] - [2360, 24] + line: (number [2360, 11] - [2360, 13]) + date: (date [2360, 14] - [2360, 24]))) + (file_entry [2361, 0] - [2363, 25] + file_name: (filename [2361, 6] - [2361, 91]) + (blame_entry [2362, 4] - [2362, 24] + line: (number [2362, 11] - [2362, 13]) + date: (date [2362, 14] - [2362, 24])) + (blame_entry [2363, 4] - [2363, 25] + line: (number [2363, 11] - [2363, 14]) + date: (date [2363, 15] - [2363, 25]))) + (file_entry [2364, 0] - [2367, 24] + file_name: (filename [2364, 6] - [2364, 58]) + (blame_entry [2365, 4] - [2365, 23] + line: (number [2365, 11] - [2365, 12]) + date: (date [2365, 13] - [2365, 23])) + (blame_entry [2366, 4] - [2366, 24] + line: (number [2366, 11] - [2366, 13]) + date: (date [2366, 14] - [2366, 24])) + (blame_entry [2367, 4] - [2367, 24] + line: (number [2367, 11] - [2367, 13]) + date: (date [2367, 14] - [2367, 24]))) + (file_entry [2368, 0] - [2369, 25] + file_name: (filename [2368, 6] - [2368, 69]) + (blame_entry [2369, 4] - [2369, 25] + line: (number [2369, 11] - [2369, 14]) + date: (date [2369, 15] - [2369, 25]))) + (file_entry [2370, 0] - [2374, 25] + file_name: (filename [2370, 6] - [2370, 72]) + (blame_entry [2371, 4] - [2371, 24] + line: (number [2371, 11] - [2371, 13]) + date: (date [2371, 14] - [2371, 24])) + (blame_entry [2372, 4] - [2372, 24] + line: (number [2372, 11] - [2372, 13]) + date: (date [2372, 14] - [2372, 24])) + (blame_entry [2373, 4] - [2373, 25] + line: (number [2373, 11] - [2373, 14]) + date: (date [2373, 15] - [2373, 25])) + (blame_entry [2374, 4] - [2374, 25] + line: (number [2374, 11] - [2374, 14]) + date: (date [2374, 15] - [2374, 25]))) + (file_entry [2375, 0] - [2376, 24] + file_name: (filename [2375, 6] - [2375, 83]) + (blame_entry [2376, 4] - [2376, 24] + line: (number [2376, 11] - [2376, 13]) + date: (date [2376, 14] - [2376, 24]))) + (file_entry [2377, 0] - [2378, 25] + file_name: (filename [2377, 6] - [2377, 85]) + (blame_entry [2378, 4] - [2378, 25] + line: (number [2378, 11] - [2378, 14]) + date: (date [2378, 15] - [2378, 25]))) + (file_entry [2379, 0] - [2380, 25] + file_name: (filename [2379, 6] - [2379, 79]) + (blame_entry [2380, 4] - [2380, 25] + line: (number [2380, 11] - [2380, 14]) + date: (date [2380, 15] - [2380, 25]))) + (file_entry [2381, 0] - [2382, 24] + file_name: (filename [2381, 6] - [2381, 67]) + (blame_entry [2382, 4] - [2382, 24] + line: (number [2382, 11] - [2382, 13]) + date: (date [2382, 14] - [2382, 24]))) + (file_entry [2383, 0] - [2384, 24] + file_name: (filename [2383, 6] - [2383, 74]) + (blame_entry [2384, 4] - [2384, 24] + line: (number [2384, 11] - [2384, 13]) + date: (date [2384, 14] - [2384, 24]))) + (file_entry [2385, 0] - [2387, 24] + file_name: (filename [2385, 6] - [2385, 57]) + (blame_entry [2386, 4] - [2386, 24] + line: (number [2386, 11] - [2386, 13]) + date: (date [2386, 14] - [2386, 24])) + (blame_entry [2387, 4] - [2387, 24] + line: (number [2387, 11] - [2387, 13]) + date: (date [2387, 14] - [2387, 24]))) + (file_entry [2388, 0] - [2389, 24] + file_name: (filename [2388, 6] - [2388, 52]) + (blame_entry [2389, 4] - [2389, 24] + line: (number [2389, 11] - [2389, 13]) + date: (date [2389, 14] - [2389, 24]))) + (file_entry [2390, 0] - [2391, 24] + file_name: (filename [2390, 6] - [2390, 56]) + (blame_entry [2391, 4] - [2391, 24] + line: (number [2391, 11] - [2391, 13]) + date: (date [2391, 14] - [2391, 24]))) + (file_entry [2392, 0] - [2393, 24] + file_name: (filename [2392, 6] - [2392, 84]) + (blame_entry [2393, 4] - [2393, 24] + line: (number [2393, 11] - [2393, 13]) + date: (date [2393, 14] - [2393, 24]))) + (file_entry [2394, 0] - [2395, 24] + file_name: (filename [2394, 6] - [2394, 84]) + (blame_entry [2395, 4] - [2395, 24] + line: (number [2395, 11] - [2395, 13]) + date: (date [2395, 14] - [2395, 24]))) + (file_entry [2396, 0] - [2401, 25] + file_name: (filename [2396, 6] - [2396, 52]) + (blame_entry [2397, 4] - [2397, 25] + line: (number [2397, 11] - [2397, 14]) + date: (date [2397, 15] - [2397, 25])) + (blame_entry [2398, 4] - [2398, 25] + line: (number [2398, 11] - [2398, 14]) + date: (date [2398, 15] - [2398, 25])) + (blame_entry [2399, 4] - [2399, 25] + line: (number [2399, 11] - [2399, 14]) + date: (date [2399, 15] - [2399, 25])) + (blame_entry [2400, 4] - [2400, 25] + line: (number [2400, 11] - [2400, 14]) + date: (date [2400, 15] - [2400, 25])) + (blame_entry [2401, 4] - [2401, 25] + line: (number [2401, 11] - [2401, 14]) + date: (date [2401, 15] - [2401, 25]))) + (file_entry [2402, 0] - [2405, 24] + file_name: (filename [2402, 6] - [2402, 72]) + (blame_entry [2403, 4] - [2403, 24] + line: (number [2403, 11] - [2403, 13]) + date: (date [2403, 14] - [2403, 24])) + (blame_entry [2404, 4] - [2404, 24] + line: (number [2404, 11] - [2404, 13]) + date: (date [2404, 14] - [2404, 24])) + (blame_entry [2405, 4] - [2405, 24] + line: (number [2405, 11] - [2405, 13]) + date: (date [2405, 14] - [2405, 24]))) + (file_entry [2406, 0] - [2409, 25] + file_name: (filename [2406, 6] - [2406, 94]) + (blame_entry [2407, 4] - [2407, 24] + line: (number [2407, 11] - [2407, 13]) + date: (date [2407, 14] - [2407, 24])) + (blame_entry [2408, 4] - [2408, 24] + line: (number [2408, 11] - [2408, 13]) + date: (date [2408, 14] - [2408, 24])) + (blame_entry [2409, 4] - [2409, 25] + line: (number [2409, 11] - [2409, 14]) + date: (date [2409, 15] - [2409, 25]))) + (file_entry [2410, 0] - [2414, 25] + file_name: (filename [2410, 6] - [2410, 89]) + (blame_entry [2411, 4] - [2411, 25] + line: (number [2411, 11] - [2411, 14]) + date: (date [2411, 15] - [2411, 25])) + (blame_entry [2412, 4] - [2412, 25] + line: (number [2412, 11] - [2412, 14]) + date: (date [2412, 15] - [2412, 25])) + (blame_entry [2413, 4] - [2413, 25] + line: (number [2413, 11] - [2413, 14]) + date: (date [2413, 15] - [2413, 25])) + (blame_entry [2414, 4] - [2414, 25] + line: (number [2414, 11] - [2414, 14]) + date: (date [2414, 15] - [2414, 25]))) + (file_entry [2415, 0] - [2416, 24] + file_name: (filename [2415, 6] - [2415, 71]) + (blame_entry [2416, 4] - [2416, 24] + line: (number [2416, 11] - [2416, 13]) + date: (date [2416, 14] - [2416, 24]))) + (file_entry [2417, 0] - [2418, 24] + file_name: (filename [2417, 6] - [2417, 56]) + (blame_entry [2418, 4] - [2418, 24] + line: (number [2418, 11] - [2418, 13]) + date: (date [2418, 14] - [2418, 24]))) + (file_entry [2419, 0] - [2421, 24] + file_name: (filename [2419, 6] - [2419, 70]) + (blame_entry [2420, 4] - [2420, 23] + line: (number [2420, 11] - [2420, 12]) + date: (date [2420, 13] - [2420, 23])) + (blame_entry [2421, 4] - [2421, 24] + line: (number [2421, 11] - [2421, 13]) + date: (date [2421, 14] - [2421, 24]))) + (file_entry [2422, 0] - [2423, 24] + file_name: (filename [2422, 6] - [2422, 61]) + (blame_entry [2423, 4] - [2423, 24] + line: (number [2423, 11] - [2423, 13]) + date: (date [2423, 14] - [2423, 24]))) + (file_entry [2424, 0] - [2426, 24] + file_name: (filename [2424, 6] - [2424, 79]) + (blame_entry [2425, 4] - [2425, 24] + line: (number [2425, 11] - [2425, 13]) + date: (date [2425, 14] - [2425, 24])) + (blame_entry [2426, 4] - [2426, 24] + line: (number [2426, 11] - [2426, 13]) + date: (date [2426, 14] - [2426, 24]))) + (file_entry [2427, 0] - [2428, 25] + file_name: (filename [2427, 6] - [2427, 47]) + (blame_entry [2428, 4] - [2428, 25] + line: (number [2428, 11] - [2428, 14]) + date: (date [2428, 15] - [2428, 25]))) + (file_entry [2429, 0] - [2433, 25] + file_name: (filename [2429, 6] - [2429, 86]) + (blame_entry [2430, 4] - [2430, 24] + line: (number [2430, 11] - [2430, 13]) + date: (date [2430, 14] - [2430, 24])) + (blame_entry [2431, 4] - [2431, 25] + line: (number [2431, 11] - [2431, 14]) + date: (date [2431, 15] - [2431, 25])) + (blame_entry [2432, 4] - [2432, 25] + line: (number [2432, 11] - [2432, 14]) + date: (date [2432, 15] - [2432, 25])) + (blame_entry [2433, 4] - [2433, 25] + line: (number [2433, 11] - [2433, 14]) + date: (date [2433, 15] - [2433, 25]))) + (file_entry [2434, 0] - [2435, 25] + file_name: (filename [2434, 6] - [2434, 51]) + (blame_entry [2435, 4] - [2435, 25] + line: (number [2435, 11] - [2435, 14]) + date: (date [2435, 15] - [2435, 25]))) + (file_entry [2436, 0] - [2437, 23] + file_name: (filename [2436, 6] - [2436, 57]) + (blame_entry [2437, 4] - [2437, 23] + line: (number [2437, 11] - [2437, 12]) + date: (date [2437, 13] - [2437, 23]))) + (file_entry [2438, 0] - [2439, 24] + file_name: (filename [2438, 6] - [2438, 102]) + (blame_entry [2439, 4] - [2439, 24] + line: (number [2439, 11] - [2439, 13]) + date: (date [2439, 14] - [2439, 24]))) + (file_entry [2440, 0] - [2441, 24] + file_name: (filename [2440, 6] - [2440, 55]) + (blame_entry [2441, 4] - [2441, 24] + line: (number [2441, 11] - [2441, 13]) + date: (date [2441, 14] - [2441, 24])))) +today: + 2023-02-16 + + file: + cpp/ql/lib/semmle/code/cpp/valuenumbering/GlobalValueNumberingImpl.qll + + blame: + 186 + + 2023-01-03 + + + blame: + 195 + + 2023-01-03 + + + blame: + 204 + + 2023-01-03 + + + blame: + 205 + + 2023-01-03 + + + blame: + 206 + + 2023-01-03 + + + blame: + 207 + + 2023-01-03 + + + blame: + 230 + + 2022-11-14 + + + blame: + 345 + + 2023-01-03 + + + blame: + 358 + + 2023-01-03 + + + blame: + 371 + + 2023-01-03 + + + blame: + 396 + + 2023-01-03 + + + blame: + 405 + + 2023-01-03 + + + blame: + 439 + + 2023-01-03 + + + blame: + 453 + + 2023-01-03 + + + blame: + 468 + + 2023-01-03 + + + blame: + 491 + + 2023-01-03 + + + blame: + 506 + + 2023-01-03 + + + blame: + 514 + + 2022-11-14 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/NfaUtils.qll + + blame: + 12 + + 2022-11-01 + + + + file: + csharp/ql/lib/semmle/code/cil/Ssa.qll + + blame: + 27 + + 2022-10-11 + + + blame: + 30 + + 2022-10-11 + + + blame: + 61 + + 2022-10-11 + + + + file: + java/ql/lib/semmle/code/java/frameworks/android/Intent.qll + + blame: + 72 + + 2022-09-28 + + + + file: + python/ql/lib/semmle/python/essa/SsaDefinitions.qll + + blame: + 88 + + 2022-09-06 + + + + file: + java/ql/lib/semmle/code/java/JMX.qll + + blame: + 54 + + 2022-08-24 + + + blame: + 94 + + 2022-08-24 + + + blame: + 104 + + 2022-08-24 + + + blame: + 112 + + 2022-08-24 + + + blame: + 120 + + 2022-08-24 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Emscripten.qll + + blame: + 21 + + 2022-08-24 + + + blame: + 38 + + 2022-08-24 + + + + file: + java/ql/lib/semmle/code/java/deadcode/DeadField.qll + + blame: + 101 + + 2022-08-24 + + + blame: + 177 + + 2022-08-24 + + + + file: + python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll + + blame: + 3 + + 2022-05-25 + + + + file: + python/ql/lib/semmle/python/security/dataflow/SqlInjectionQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + cpp/ql/lib/semmle/code/cpp/commons/StringAnalysis.qll + + blame: + 31 + + 2022-05-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/UrlRedirectCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll + + blame: + 214 + + 2022-03-11 + + + blame: + 468 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll + + blame: + 61 + + 2022-03-11 + + + blame: + 99 + + 2022-03-11 + + + blame: + 169 + + 2022-03-11 + + + + file: + csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll + + blame: + 74 + + 2022-03-11 + + + blame: + 109 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll + + blame: + 181 + + 2022-03-11 + + + blame: + 524 + + 2022-03-11 + + + blame: + 558 + + 2022-03-11 + + + blame: + 582 + + 2022-03-11 + + + blame: + 623 + + 2022-03-11 + + + + file: + javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/FunctionBodyFeatures.qll + + blame: + 45 + + 2022-03-11 + + + blame: + 134 + + 2022-03-11 + + + + file: + cpp/ql/src/external/CodeDuplication.qll + + blame: + 5 + + 2022-03-08 + + + blame: + 12 + + 2022-03-08 + + + blame: + 66 + + 2022-03-08 + + + blame: + 77 + + 2022-03-08 + + + blame: + 88 + + 2022-03-08 + + + blame: + 99 + + 2022-03-08 + + + blame: + 107 + + 2022-03-08 + + + blame: + 116 + + 2022-03-08 + + + blame: + 122 + + 2022-03-08 + + + blame: + 141 + + 2022-03-08 + + + blame: + 153 + + 2022-03-08 + + + blame: + 164 + + 2022-03-08 + + + blame: + 168 + + 2022-03-08 + + + blame: + 178 + + 2022-03-08 + + + blame: + 199 + + 2022-03-08 + + + blame: + 220 + + 2022-03-08 + + + blame: + 226 + + 2022-03-08 + + + blame: + 241 + + 2022-03-08 + + + blame: + 270 + + 2022-03-08 + + + blame: + 285 + + 2022-03-08 + + + blame: + 300 + + 2022-03-08 + + + blame: + 322 + + 2022-03-08 + + + blame: + 351 + + 2022-03-08 + + + blame: + 361 + + 2022-03-08 + + + blame: + 371 + + 2022-03-08 + + + + file: + cpp/ql/lib/semmle/code/cpp/File.qll + + blame: + 43 + + 2022-03-07 + + + blame: + 191 + + 2022-03-07 + + + blame: + 220 + + 2022-03-07 + + + + file: + cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll + + blame: + 1389 + + 2022-03-11 + + + blame: + 1402 + + 2022-03-11 + + + blame: + 1415 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/controlflow/SSAUtils.qll + + blame: + 316 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgery.qll + + blame: + 10 + + 2022-03-21 + + + blame: + 17 + + 2022-03-21 + + + blame: + 21 + + 2022-03-21 + + + + file: + javascript/ql/lib/semmle/javascript/NPM.qll + + blame: + 177 + + 2022-08-24 + + + blame: + 187 + + 2022-08-24 + + + blame: + 248 + + 2022-03-11 + + + blame: + 356 + + 2022-03-11 + + + blame: + 397 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll + + blame: + 425 + + 2022-03-11 + + + blame: + 995 + + 2022-03-11 + + + blame: + 1007 + + 2022-03-11 + + + blame: + 1120 + + 2022-03-11 + + + blame: + 1139 + + 2022-09-09 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + go/ql/lib/semmle/go/security/FlowSources.qll + + blame: + 33 + + 2022-12-19 + + + + file: + python/ql/lib/semmle/python/security/Exceptions.qll + + blame: + 10 + + 2022-01-19 + + + blame: + 18 + + 2022-01-19 + + + blame: + 28 + + 2022-01-19 + + + blame: + 33 + + 2022-01-19 + + + blame: + 49 + + 2022-01-19 + + + blame: + 68 + + 2022-01-19 + + + blame: + 76 + + 2022-01-19 + + + blame: + 97 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/frameworks/spring/SpringAutowire.qll + + blame: + 104 + + 2022-03-11 + + + + file: + csharp/ql/lib/semmle/code/cil/DataFlow.qll + + blame: + 23 + + 2022-10-11 + + + blame: + 29 + + 2022-10-11 + + + blame: + 34 + + 2022-10-11 + + + blame: + 43 + + 2022-10-11 + + + blame: + 48 + + 2022-10-11 + + + blame: + 57 + + 2022-10-11 + + + blame: + 60 + + 2022-10-11 + + + blame: + 62 + + 2022-10-11 + + + blame: + 81 + + 2022-10-11 + + + blame: + 108 + + 2022-10-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/DOM.qll + + blame: + 22 + + 2022-03-11 + + + blame: + 28 + + 2022-03-30 + + + blame: + 39 + + 2022-03-30 + + + blame: + 52 + + 2022-03-13 + + + blame: + 58 + + 2022-03-13 + + + blame: + 64 + + 2022-03-14 + + + blame: + 67 + + 2022-03-11 + + + blame: + 77 + + 2022-03-30 + + + blame: + 87 + + 2022-03-30 + + + blame: + 93 + + 2022-03-30 + + + blame: + 98 + + 2022-03-30 + + + blame: + 103 + + 2022-03-30 + + + blame: + 158 + + 2022-04-28 + + + blame: + 163 + + 2022-04-28 + + + blame: + 172 + + 2022-03-30 + + + blame: + 183 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/Concepts.qll + + blame: + 603 + + 2022-09-09 + + + blame: + 1059 + + 2022-09-09 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + javascript/ql/src/Expressions/TypoDatabase.qll + + blame: + 4 + + 2022-09-08 + + + + file: + csharp/ql/lib/semmle/code/csharp/commons/Assertions.qll + + blame: + 45 + + 2021-10-14 + + + blame: + 58 + + 2021-10-14 + + + + file: + python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll + + blame: + 13 + + 2021-09-01 + + + blame: + 173 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll + + blame: + 3 + + 2022-08-16 + + + + file: + csharp/ql/lib/semmle/code/csharp/XML.qll + + blame: + 36 + + 2022-08-16 + + + blame: + 99 + + 2022-08-16 + + + blame: + 116 + + 2021-10-14 + + + blame: + 123 + + 2021-10-14 + + + blame: + 138 + + 2022-08-23 + + + blame: + 142 + + 2022-08-16 + + + blame: + 181 + + 2022-08-23 + + + blame: + 239 + + 2022-08-16 + + + blame: + 272 + + 2022-08-16 + + + blame: + 291 + + 2022-08-22 + + + blame: + 304 + + 2022-08-16 + + + blame: + 327 + + 2022-08-16 + + + blame: + 354 + + 2022-08-16 + + + + file: + csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll + + blame: + 196 + + 2023-01-06 + + + blame: + 208 + + 2023-01-06 + + + + file: + csharp/ql/lib/semmle/code/cil/internal/SsaImpl.qll + + blame: + 81 + + 2022-10-21 + + + blame: + 89 + + 2022-10-21 + + + blame: + 97 + + 2022-10-21 + + + + file: + go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-17 + + + blame: + 126 + + 2022-06-17 + + + blame: + 136 + + 2022-10-20 + + + blame: + 140 + + 2022-10-20 + + + + file: + python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll + + blame: + 40 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/security/OverlyLargeRangeQuery.qll + + blame: + 7 + + 2022-11-22 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Fastify.qll + + blame: + 161 + + 2022-03-30 + + + + file: + ruby/ql/lib/codeql/ruby/security/OpenSSL.qll + + blame: + 143 + + 2022-08-18 + + + blame: + 273 + + 2022-08-18 + + + blame: + 286 + + 2022-08-18 + + + blame: + 338 + + 2022-08-18 + + + + file: + javascript/ql/lib/semmle/javascript/security/regexp/SuperlinearBackTracking.qll + + blame: + 40 + + 2022-11-01 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-09-09 + + + blame: + 106 + + 2022-09-09 + + + blame: + 358 + + 2022-09-09 + + + blame: + 365 + + 2022-09-09 + + + + file: + go/ql/lib/semmle/go/security/XPathInjectionCustomizations.qll + + blame: + 32 + + 2022-06-17 + + + + file: + java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJB.qll + + blame: + 116 + + 2022-08-18 + + + blame: + 136 + + 2022-08-18 + + + blame: + 156 + + 2022-08-18 + + + blame: + 194 + + 2022-08-18 + + + blame: + 249 + + 2022-08-22 + + + blame: + 278 + + 2022-08-22 + + + blame: + 317 + + 2022-08-22 + + + blame: + 454 + + 2022-08-22 + + + blame: + 474 + + 2022-08-22 + + + blame: + 499 + + 2022-08-22 + + + blame: + 527 + + 2022-08-22 + + + blame: + 547 + + 2022-08-22 + + + blame: + 572 + + 2022-08-22 + + + blame: + 597 + + 2022-08-22 + + + blame: + 864 + + 2022-08-18 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Electron.qll + + blame: + 136 + + 2022-08-24 + + + blame: + 175 + + 2022-08-24 + + + + file: + python/ql/lib/semmle/python/security/dataflow/RegexInjectionQuery.qll + + blame: + 27 + + 2022-06-17 + + + + file: + java/ql/lib/semmle/code/java/security/regexp/NfaUtils.qll + + blame: + 12 + + 2022-11-01 + + + + file: + java/ql/lib/semmle/code/java/security/IntentUriPermissionManipulationQuery.qll + + blame: + 27 + + 2022-06-15 + + + + file: + ruby/ql/lib/codeql/ruby/security/PathInjectionQuery.qll + + blame: + 30 + + 2022-06-20 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll + + blame: + 116 + + 2022-01-19 + + + blame: + 211 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/strings/Basic.qll + + blame: + 6 + + 2022-01-19 + + + blame: + 45 + + 2022-01-19 + + + blame: + 67 + + 2022-01-19 + + + blame: + 73 + + 2022-01-19 + + + blame: + 87 + + 2022-01-19 + + + blame: + 97 + + 2022-01-19 + + + blame: + 107 + + 2022-01-19 + + + blame: + 113 + + 2022-01-19 + + + blame: + 122 + + 2022-01-19 + + + + file: + ruby/ql/lib/codeql/ruby/security/CodeInjectionQuery.qll + + blame: + 39 + + 2022-06-20 + + + + file: + cpp/ql/lib/semmle/code/cpp/commons/Synchronization.qll + + blame: + 66 + + 2021-10-14 + + + blame: + 71 + + 2021-10-14 + + + blame: + 76 + + 2021-10-14 + + + blame: + 81 + + 2021-10-14 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/PolynomialReDoSCustomizations.qll + + blame: + 57 + + 2022-06-20 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll + + blame: + 214 + + 2022-03-11 + + + blame: + 468 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/LogInjection.qll + + blame: + 8 + + 2022-03-21 + + + + file: + python/ql/src/experimental/semmle/python/templates/Cheetah.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 27 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/security/dataflow/StackTraceExposure.qll + + blame: + 8 + + 2022-03-21 + + + blame: + 13 + + 2022-03-21 + + + + file: + cpp/ql/lib/semmle/code/cpp/Class.qll + + blame: + 191 + + 2022-01-20 + + + blame: + 234 + + 2021-10-14 + + + blame: + 240 + + 2021-10-14 + + + blame: + 410 + + 2022-08-24 + + + + file: + go/ql/lib/semmle/go/security/XPathInjection.qll + + blame: + 31 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/E4X.qll + + blame: + 20 + + 2022-03-11 + + + blame: + 61 + + 2022-03-11 + + + blame: + 93 + + 2022-03-11 + + + blame: + 121 + + 2022-03-11 + + + blame: + 149 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/SensitiveData.qll + + blame: + 18 + + 2022-01-19 + + + blame: + 26 + + 2022-01-19 + + + blame: + 118 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/frameworks/Starlette.qll + + blame: + 164 + + 2022-09-09 + + + + file: + python/ql/lib/semmle/python/web/turbogears/TurboGears.qll + + blame: + 4 + + 2022-01-19 + + + blame: + 8 + + 2022-01-19 + + + blame: + 12 + + 2022-01-19 + + + + file: + ruby/ql/lib/codeql/ruby/ast/Pattern.qll + + blame: + 13 + + 2021-12-14 + + + blame: + 35 + + 2021-12-14 + + + blame: + 51 + + 2021-12-14 + + + blame: + 450 + + 2022-01-27 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/RegexpMatching.qll + + blame: + 8 + + 2022-11-01 + + + + file: + go/ql/lib/semmle/go/dataflow/barrierguardutil/RegexpCheck.qll + + blame: + 42 + + 2022-06-17 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/ExponentialBackTracking.qll + + blame: + 67 + + 2022-11-01 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll + + blame: + 45 + + 2022-03-11 + + + blame: + 234 + + 2022-03-11 + + + blame: + 263 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll + + blame: + 145 + + 2022-03-30 + + + blame: + 1821 + + 2022-03-13 + + + + file: + java/ql/lib/semmle/code/java/J2EE.qll + + blame: + 29 + + 2022-08-18 + + + blame: + 39 + + 2022-08-18 + + + blame: + 49 + + 2022-08-18 + + + blame: + 59 + + 2022-08-18 + + + + file: + python/ql/lib/semmle/python/pointsto/Filters.qll + + blame: + 16 + + 2022-09-06 + + + blame: + 29 + + 2022-09-06 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll + + blame: + 68 + + 2022-03-11 + + + blame: + 87 + + 2022-03-11 + + + blame: + 376 + + 2022-03-11 + + + + file: + csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll + + blame: + 214 + + 2022-03-11 + + + blame: + 468 + + 2022-03-11 + + + + file: + ql/ql/src/queries/style/docs/PredicateDocs.ql + + blame: + 21 + + 2022-08-15 + + + + file: + shared/regex/codeql/regex/nfa/NfaUtils.qll + + blame: + 80 + + 2022-11-01 + + + + file: + csharp/ql/lib/semmle/code/csharp/security/dataflow/ExternalAPIsQuery.qll + + blame: + 18 + + 2022-03-11 + + + blame: + 83 + + 2022-11-24 + + + blame: + 91 + + 2022-03-11 + + + blame: + 103 + + 2022-03-11 + + + blame: + 116 + + 2022-03-11 + + + blame: + 154 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/dataflow/barrierguardutil/RedirectCheckBarrierGuard.qll + + blame: + 30 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/injection/RegexInjection.qll + + blame: + 6 + + 2022-01-19 + + + + file: + ruby/ql/lib/codeql/ruby/security/ServerSideRequestForgeryCustomizations.qll + + blame: + 39 + + 2022-06-20 + + + + file: + ruby/ql/lib/codeql/ruby/frameworks/core/internal/IOOrFile.qll + + blame: + 67 + + 2022-04-01 + + + blame: + 119 + + 2022-04-01 + + + blame: + 163 + + 2022-04-01 + + + + file: + ql/ql/src/queries/style/NameCasing.ql + + blame: + 42 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/OverlyLargeRangeQuery.qll + + blame: + 7 + + 2022-11-01 + + + + file: + python/ql/lib/semmle/python/protocols.qll + + blame: + 4 + + 2022-09-06 + + + blame: + 7 + + 2022-09-06 + + + blame: + 10 + + 2022-09-06 + + + blame: + 13 + + 2022-09-06 + + + blame: + 16 + + 2022-09-06 + + + blame: + 19 + + 2022-09-06 + + + + file: + javascript/ql/lib/semmle/javascript/ApiGraphs.qll + + blame: + 157 + + 2022-05-23 + + + blame: + 160 + + 2022-04-05 + + + blame: + 216 + + 2022-05-23 + + + blame: + 219 + + 2022-04-05 + + + blame: + 585 + + 2022-04-05 + + + blame: + 588 + + 2022-04-05 + + + blame: + 600 + + 2022-03-16 + + + + file: + cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll + + blame: + 22 + + 2022-03-11 + + + blame: + 58 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/security/XSS.qll + + blame: + 113 + + 2021-09-14 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/SocketIO.qll + + blame: + 274 + + 2021-11-01 + + + blame: + 365 + + 2021-11-01 + + + blame: + 651 + + 2021-11-01 + + + + file: + csharp/ql/lib/semmle/code/csharp/Callable.qll + + blame: + 804 + + 2023-01-09 + + + blame: + 824 + + 2023-01-09 + + + + file: + java/ql/lib/semmle/code/java/security/ExternalAPIs.qll + + blame: + 16 + + 2022-03-11 + + + blame: + 99 + + 2022-03-11 + + + blame: + 111 + + 2022-03-11 + + + blame: + 124 + + 2022-03-11 + + + blame: + 161 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/UrlRedirect.qll + + blame: + 8 + + 2022-03-21 + + + blame: + 13 + + 2022-03-21 + + + + file: + python/ql/lib/semmle/python/security/injection/Deserialization.qll + + blame: + 5 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/web/falcon/Response.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 12 + + 2022-01-19 + + + blame: + 20 + + 2022-01-19 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + go/ql/lib/semmle/go/security/ReflectedXssCustomizations.qll + + blame: + 27 + + 2022-06-17 + + + blame: + 33 + + 2022-06-17 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedDeclaration.qll + + blame: + 35 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/PolynomialReDoS.qll + + blame: + 8 + + 2022-03-21 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + ruby/ql/lib/codeql/ruby/security/performance/RegExpInjectionCustomizations.qll + + blame: + 3 + + 2022-05-25 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedCondition.qll + + blame: + 21 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/frameworks/struts/StrutsXML.qll + + blame: + 9 + + 2022-03-11 + + + blame: + 55 + + 2022-03-11 + + + blame: + 70 + + 2022-03-11 + + + blame: + 80 + + 2022-03-11 + + + blame: + 120 + + 2022-03-11 + + + blame: + 145 + + 2022-03-11 + + + blame: + 196 + + 2022-03-11 + + + blame: + 210 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + ruby/ql/lib/codeql/ruby/ast/Expr.qll + + blame: + 19 + + 2022-01-20 + + + blame: + 26 + + 2021-11-09 + + + + file: + go/ql/lib/semmle/go/Util.qll + + blame: + 21 + + 2022-08-24 + + + + file: + java/ql/lib/semmle/code/java/frameworks/UnboundId.qll + + blame: + 33 + + 2022-03-11 + + + blame: + 69 + + 2022-08-24 + + + blame: + 80 + + 2022-08-24 + + + blame: + 107 + + 2022-03-11 + + + blame: + 118 + + 2022-03-11 + + + blame: + 130 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll + + blame: + 34 + + 2022-10-11 + + + blame: + 47 + + 2022-10-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/UrlRedirectQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + java/ql/lib/semmle/code/java/security/performance/PolynomialReDoSQuery.qll + + blame: + 3 + + 2022-05-25 + + + + file: + python/ql/lib/semmle/python/security/dataflow/XpathInjectionQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + go/ql/lib/semmle/go/security/RequestForgeryCustomizations.qll + + blame: + 40 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CommandInjectionQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/pointsto/PointsToContext.qll + + blame: + 125 + + 2022-09-06 + + + + file: + java/ql/lib/semmle/code/java/Annotation.qll + + blame: + 61 + + 2022-03-28 + + + blame: + 163 + + 2022-04-02 + + + + file: + csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll + + blame: + 9 + + 2022-08-18 + + + blame: + 16 + + 2022-08-18 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/RegExpInjectionQuery.qll + + blame: + 23 + + 2022-06-20 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + java/ql/lib/semmle/code/java/security/Encryption.qll + + blame: + 17 + + 2022-08-18 + + + blame: + 29 + + 2022-03-11 + + + blame: + 36 + + 2022-08-18 + + + blame: + 43 + + 2022-08-18 + + + blame: + 51 + + 2022-08-18 + + + blame: + 59 + + 2022-08-18 + + + blame: + 67 + + 2022-08-18 + + + blame: + 75 + + 2022-08-18 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/dataflow/UnsafeDeserialization.qll + + blame: + 8 + + 2022-03-21 + + + blame: + 13 + + 2022-03-21 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + java/ql/lib/semmle/code/xml/MavenPom.qll + + blame: + 460 + + 2021-10-15 + + + blame: + 470 + + 2021-10-15 + + + blame: + 488 + + 2021-10-15 + + + + file: + ql/ql/src/codeql_ql/style/MisspellingQuery.qll + + blame: + 68 + + 2022-05-12 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll + + blame: + 74 + + 2022-03-30 + + + blame: + 93 + + 2022-03-30 + + + blame: + 175 + + 2022-03-30 + + + blame: + 190 + + 2022-03-30 + + + blame: + 295 + + 2022-03-30 + + + + file: + javascript/ql/lib/semmle/javascript/dependencies/FrameworkLibraries.qll + + blame: + 142 + + 2022-03-11 + + + blame: + 146 + + 2022-03-11 + + + blame: + 180 + + 2022-03-11 + + + blame: + 184 + + 2022-03-11 + + + blame: + 286 + + 2022-03-11 + + + blame: + 953 + + 2022-03-11 + + + blame: + 974 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/PrintAST.qll + + blame: + 31 + + 2022-03-11 + + + blame: + 241 + + 2022-03-11 + + + blame: + 284 + + 2022-03-11 + + + blame: + 288 + + 2022-03-11 + + + blame: + 298 + + 2022-03-11 + + + + file: + python/ql/src/experimental/semmle/python/templates/Chevron.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 16 + + 2022-01-20 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll + + blame: + 367 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/security/ExternalAPIs.qll + + blame: + 20 + + 2022-08-18 + + + blame: + 109 + + 2022-08-18 + + + blame: + 159 + + 2022-08-18 + + + blame: + 171 + + 2022-08-18 + + + blame: + 183 + + 2022-08-18 + + + blame: + 196 + + 2022-08-18 + + + blame: + 234 + + 2022-08-18 + + + + file: + go/ql/lib/semmle/go/security/RequestForgery.qll + + blame: + 46 + + 2022-06-17 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/web/pyramid/View.qll + + blame: + 3 + + 2022-01-19 + + + blame: + 5 + + 2022-01-19 + + + blame: + 7 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/XML.qll + + blame: + 36 + + 2022-08-16 + + + blame: + 99 + + 2022-08-16 + + + blame: + 116 + + 2021-10-14 + + + blame: + 123 + + 2021-10-14 + + + blame: + 138 + + 2022-08-23 + + + blame: + 142 + + 2022-08-16 + + + blame: + 181 + + 2022-08-23 + + + blame: + 239 + + 2022-08-16 + + + blame: + 272 + + 2022-08-16 + + + blame: + 291 + + 2022-08-22 + + + blame: + 304 + + 2022-08-16 + + + blame: + 327 + + 2022-08-16 + + + blame: + 354 + + 2022-08-16 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssQuery.qll + + blame: + 12 + + 2022-03-01 + + + blame: + 15 + + 2022-03-01 + + + blame: + 29 + + 2022-08-18 + + + + file: + python/ql/lib/semmle/python/security/ClearText.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 29 + + 2022-01-19 + + + + file: + ql/ql/src/queries/style/LibraryAnnotation.ql + + blame: + 17 + + 2022-06-21 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll + + blame: + 80 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/ReflectedXssQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + python/ql/src/experimental/semmle/python/Concepts.qll + + blame: + 94 + + 2022-03-11 + + + blame: + 110 + + 2022-03-11 + + + blame: + 129 + + 2022-03-11 + + + blame: + 145 + + 2022-03-11 + + + blame: + 172 + + 2022-08-18 + + + blame: + 177 + + 2022-03-11 + + + blame: + 202 + + 2022-08-18 + + + blame: + 206 + + 2022-03-11 + + + blame: + 225 + + 2022-03-11 + + + blame: + 241 + + 2022-03-11 + + + blame: + 258 + + 2022-03-11 + + + blame: + 272 + + 2022-03-11 + + + blame: + 289 + + 2022-03-11 + + + blame: + 303 + + 2022-03-11 + + + blame: + 454 + + 2022-03-11 + + + blame: + 485 + + 2022-03-11 + + + blame: + 529 + + 2022-03-11 + + + blame: + 570 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/frameworks/Rails.qll + + blame: + 60 + + 2022-10-14 + + + + file: + java/ql/lib/semmle/code/java/dataflow/FlowSources.qll + + blame: + 240 + + 2022-08-24 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll + + blame: + 95 + + 2021-10-14 + + + blame: + 104 + + 2021-10-14 + + + + file: + python/ql/src/experimental/semmle/python/templates/TRender.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 16 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/security/dataflow/LdapInjection.qll + + blame: + 10 + + 2022-03-21 + + + + file: + python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + java/ql/src/experimental/Security/CWE/CWE-611/XXELib.qll + + blame: + 193 + + 2022-03-11 + + + blame: + 211 + + 2022-03-11 + + + blame: + 241 + + 2022-03-11 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedStmt.qll + + blame: + 30 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Micro.qll + + blame: + 65 + + 2022-03-30 + + + blame: + 73 + + 2022-03-30 + + + + file: + python/ql/lib/semmle/python/web/django/Model.qll + + blame: + 8 + + 2022-01-19 + + + blame: + 13 + + 2022-01-19 + + + blame: + 27 + + 2022-01-19 + + + blame: + 41 + + 2022-01-19 + + + blame: + 58 + + 2022-01-19 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll + + blame: + 425 + + 2022-03-11 + + + blame: + 995 + + 2022-03-11 + + + blame: + 1007 + + 2022-03-11 + + + blame: + 1120 + + 2022-03-11 + + + blame: + 1139 + + 2022-09-09 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + javascript/ql/lib/semmle/javascript/NodeModuleResolutionImpl.qll + + blame: + 202 + + 2022-03-11 + + + blame: + 263 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-06-17 + + + blame: + 106 + + 2022-10-20 + + + blame: + 358 + + 2022-06-17 + + + blame: + 365 + + 2022-10-20 + + + + file: + csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll + + blame: + 50 + + 2022-03-11 + + + blame: + 78 + + 2022-03-11 + + + blame: + 84 + + 2022-03-11 + + + + file: + cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll + + blame: + 22 + + 2022-03-11 + + + blame: + 58 + + 2022-03-11 + + + + file: + cpp/ql/src/Security/CWE/CWE-020/SafeExternalAPIFunction.qll + + blame: + 14 + + 2022-03-11 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll + + blame: + 27 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll + + blame: + 214 + + 2022-03-11 + + + blame: + 468 + + 2022-03-11 + + + + file: + java/ql/src/experimental/semmle/code/xml/StrutsXML.qll + + blame: + 14 + + 2022-03-11 + + + blame: + 29 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CommandInjectionCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/LogInjectionCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Next.qll + + blame: + 244 + + 2022-03-11 + + + + file: + python/ql/src/experimental/semmle/python/templates/DjangoTemplate.qll + + blame: + 7 + + 2022-01-20 + + + blame: + 15 + + 2022-01-20 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/HTTP.qll + + blame: + 72 + + 2022-03-30 + + + blame: + 83 + + 2022-03-30 + + + blame: + 210 + + 2022-03-30 + + + blame: + 223 + + 2022-03-30 + + + blame: + 272 + + 2022-03-30 + + + blame: + 285 + + 2022-03-30 + + + blame: + 317 + + 2022-03-30 + + + blame: + 351 + + 2021-11-01 + + + blame: + 376 + + 2021-11-01 + + + blame: + 414 + + 2022-03-30 + + + blame: + 425 + + 2022-03-30 + + + blame: + 697 + + 2022-09-09 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll + + blame: + 124 + + 2022-09-09 + + + blame: + 126 + + 2022-09-09 + + + blame: + 136 + + 2022-09-09 + + + blame: + 140 + + 2022-09-09 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll + + blame: + 74 + + 2022-03-11 + + + blame: + 109 + + 2022-03-11 + + + + file: + python/ql/src/experimental/semmle/python/security/InsecureRandomness.qll + + blame: + 33 + + 2022-06-17 + + + + file: + cpp/ql/lib/semmle/code/cpp/exprs/Expr.qll + + blame: + 727 + + 2021-10-14 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + ql/ql/src/queries/bugs/InconsistentDeprecation.ql + + blame: + 21 + + 2022-03-16 + + + blame: + 22 + + 2022-03-16 + + + blame: + 23 + + 2022-03-16 + + + blame: + 24 + + 2022-03-16 + + + + file: + ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll + + blame: + 29 + + 2022-10-04 + + + blame: + 34 + + 2022-10-04 + + + blame: + 95 + + 2022-10-18 + + + + file: + python/ql/lib/semmle/python/dataflow/old/TaintTracking.qll + + blame: + 667 + + 2022-03-07 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Express.qll + + blame: + 62 + + 2022-03-30 + + + blame: + 74 + + 2019-04-03 + + + blame: + 155 + + 2022-04-28 + + + blame: + 181 + + 2022-03-30 + + + blame: + 192 + + 2022-03-30 + + + blame: + 302 + + 2022-03-30 + + + blame: + 308 + + 2022-03-30 + + + blame: + 311 + + 2022-03-30 + + + blame: + 314 + + 2022-03-30 + + + blame: + 317 + + 2022-03-30 + + + blame: + 322 + + 2022-03-30 + + + blame: + 330 + + 2022-03-30 + + + blame: + 335 + + 2022-03-30 + + + blame: + 588 + + 2022-03-30 + + + blame: + 603 + + 2022-03-30 + + + + file: + java/ql/lib/semmle/code/java/JDKAnnotations.qll + + blame: + 27 + + 2022-03-28 + + + blame: + 46 + + 2022-03-28 + + + blame: + 70 + + 2022-04-01 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll + + blame: + 8 + + 2022-08-18 + + + blame: + 15 + + 2022-08-18 + + + + file: + python/ql/lib/semmle/python/web/stdlib/Request.qll + + blame: + 12 + + 2022-01-19 + + + blame: + 27 + + 2022-01-19 + + + blame: + 43 + + 2022-01-19 + + + blame: + 66 + + 2022-01-19 + + + blame: + 73 + + 2022-01-19 + + + blame: + 118 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/security/XmlParsers.qll + + blame: + 338 + + 2022-08-18 + + + blame: + 372 + + 2022-03-11 + + + blame: + 394 + + 2022-03-11 + + + blame: + 424 + + 2022-03-11 + + + blame: + 442 + + 2022-03-11 + + + blame: + 458 + + 2022-03-11 + + + blame: + 466 + + 2022-03-11 + + + blame: + 486 + + 2022-03-11 + + + blame: + 500 + + 2022-03-11 + + + blame: + 536 + + 2022-03-11 + + + blame: + 583 + + 2022-03-11 + + + blame: + 594 + + 2022-03-11 + + + blame: + 614 + + 2022-03-11 + + + blame: + 628 + + 2022-03-11 + + + blame: + 671 + + 2022-03-11 + + + blame: + 680 + + 2022-03-11 + + + blame: + 701 + + 2022-03-11 + + + blame: + 715 + + 2022-03-11 + + + blame: + 739 + + 2022-03-11 + + + blame: + 782 + + 2022-03-11 + + + blame: + 826 + + 2022-03-11 + + + blame: + 839 + + 2022-03-11 + + + blame: + 862 + + 2022-03-11 + + + blame: + 876 + + 2022-03-11 + + + blame: + 895 + + 2022-03-11 + + + blame: + 925 + + 2022-08-18 + + + blame: + 1093 + + 2022-03-11 + + + blame: + 1218 + + 2022-03-11 + + + blame: + 1239 + + 2022-03-11 + + + blame: + 1257 + + 2022-03-11 + + + blame: + 1275 + + 2022-03-11 + + + + file: + cpp/ql/src/Likely Bugs/Protocols/UseOfDeprecatedHardcodedProtocol.ql + + blame: + 27 + + 2019-10-11 + + + + file: + cpp/ql/test/library-tests/dataflow/fields/ASTConfiguration.qll + + blame: + 35 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll + + blame: + 308 + + 2022-09-07 + + + + file: + python/ql/lib/semmle/python/frameworks/Tornado.qll + + blame: + 68 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/dataflow/LdapInjectionCustomizations.qll + + blame: + 49 + + 2022-06-17 + + + blame: + 56 + + 2022-06-17 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll + + blame: + 124 + + 2022-09-09 + + + blame: + 126 + + 2022-09-09 + + + blame: + 136 + + 2022-09-09 + + + blame: + 140 + + 2022-09-09 + + + + file: + go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-17 + + + blame: + 126 + + 2022-06-17 + + + blame: + 136 + + 2022-10-20 + + + blame: + 140 + + 2022-10-20 + + + + file: + javascript/ql/src/Security/CWE-020/HostnameRegexpShared.qll + + blame: + 6 + + 2022-12-15 + + + + file: + csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll + + blame: + 425 + + 2022-03-11 + + + blame: + 995 + + 2022-03-11 + + + blame: + 1007 + + 2022-03-11 + + + blame: + 1120 + + 2022-03-11 + + + blame: + 1139 + + 2022-09-09 + + + + file: + ruby/ql/lib/codeql/ruby/security/PathInjectionCustomizations.qll + + blame: + 36 + + 2022-06-20 + + + + file: + python/ql/src/Imports/DeprecatedModule.ql + + blame: + 19 + + 2018-11-19 + + + blame: + 62 + + 2020-07-07 + + + blame: + 64 + + 2020-07-07 + + + blame: + 70 + + 2020-07-07 + + + blame: + 80 + + 2020-07-07 + + + + file: + csharp/ql/lib/semmle/code/csharp/dispatch/OverridableCallable.qll + + blame: + 166 + + 2021-12-13 + + + blame: + 169 + + 2021-12-13 + + + + file: + python/ql/lib/semmle/python/xml/XML.qll + + blame: + 36 + + 2022-08-16 + + + blame: + 99 + + 2022-08-16 + + + blame: + 116 + + 2021-10-14 + + + blame: + 123 + + 2021-10-14 + + + blame: + 138 + + 2022-08-23 + + + blame: + 142 + + 2022-08-16 + + + blame: + 181 + + 2022-08-23 + + + blame: + 239 + + 2022-08-16 + + + blame: + 272 + + 2022-08-16 + + + blame: + 291 + + 2022-08-22 + + + blame: + 304 + + 2022-08-16 + + + blame: + 327 + + 2022-08-16 + + + blame: + 354 + + 2022-08-16 + + + + file: + ruby/ql/lib/codeql/ruby/ast/Parameter.qll + + blame: + 78 + + 2021-12-14 + + + blame: + 87 + + 2021-12-14 + + + + file: + python/ql/lib/semmle/python/security/regexp/NfaUtils.qll + + blame: + 12 + + 2022-11-01 + + + + file: + java/ql/lib/semmle/code/java/frameworks/javaee/PersistenceXML.qll + + blame: + 30 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/deadcode/EntryPoints.qll + + blame: + 138 + + 2022-08-24 + + + blame: + 324 + + 2022-08-18 + + + blame: + 336 + + 2022-08-18 + + + blame: + 361 + + 2022-08-24 + + + blame: + 459 + + 2022-03-11 + + + + file: + python/ql/src/experimental/semmle/python/templates/FlaskTemplate.qll + + blame: + 7 + + 2022-01-20 + + + blame: + 17 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/web/twisted/Twisted.qll + + blame: + 4 + + 2022-01-19 + + + blame: + 8 + + 2022-01-19 + + + blame: + 12 + + 2022-01-19 + + + blame: + 16 + + 2022-01-19 + + + blame: + 21 + + 2022-01-19 + + + blame: + 30 + + 2022-01-19 + + + + file: + ruby/ql/lib/codeql/ruby/ApiGraphs.qll + + blame: + 156 + + 2022-05-30 + + + blame: + 159 + + 2022-05-30 + + + blame: + 162 + + 2022-05-30 + + + blame: + 165 + + 2022-05-30 + + + blame: + 411 + + 2022-09-02 + + + blame: + 414 + + 2022-09-02 + + + + file: + javascript/ql/lib/semmle/javascript/PrintAst.qll + + blame: + 395 + + 2022-03-11 + + + blame: + 413 + + 2022-03-11 + + + blame: + 421 + + 2022-03-11 + + + blame: + 439 + + 2022-03-11 + + + blame: + 447 + + 2022-03-11 + + + blame: + 586 + + 2022-03-11 + + + blame: + 659 + + 2022-03-11 + + + blame: + 675 + + 2022-03-11 + + + blame: + 708 + + 2022-03-11 + + + blame: + 712 + + 2022-03-11 + + + blame: + 745 + + 2022-03-11 + + + blame: + 761 + + 2022-03-11 + + + blame: + 789 + + 2022-03-11 + + + blame: + 817 + + 2022-03-11 + + + blame: + 842 + + 2022-03-11 + + + blame: + 867 + + 2022-03-11 + + + blame: + 871 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/SqlInjection.qll + + blame: + 8 + + 2022-03-21 + + + blame: + 13 + + 2022-03-21 + + + blame: + 16 + + 2022-03-21 + + + + file: + csharp/ql/src/experimental/ir/implementation/internal/TInstructionInternal.qll + + blame: + 7 + + 2022-08-18 + + + + file: + java/ql/lib/semmle/code/java/frameworks/Networking.qll + + blame: + 42 + + 2022-03-11 + + + + file: + python/ql/test/experimental/dataflow/TestUtil/NormalDataflowTest.qll + + blame: + 37 + + 2022-08-24 + + + + file: + python/ql/lib/semmle/python/web/django/Db.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 11 + + 2022-01-19 + + + blame: + 18 + + 2022-01-19 + + + blame: + 31 + + 2022-01-19 + + + blame: + 39 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/web/cherrypy/Response.qll + + blame: + 7 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/dataflow/SSA.qll + + blame: + 933 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstructionInternal.qll + + blame: + 7 + + 2022-08-18 + + + + file: + java/ql/lib/semmle/code/java/regex/RegexTreeView.qll + + blame: + 1201 + + 2022-11-23 + + + + file: + ruby/ql/lib/codeql/ruby/dataflow/BarrierGuards.qll + + blame: + 94 + + 2022-06-20 + + + blame: + 162 + + 2022-06-20 + + + + file: + csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll + + blame: + 39 + + 2021-10-14 + + + blame: + 79 + + 2021-10-14 + + + blame: + 190 + + 2021-10-14 + + + blame: + 215 + + 2021-10-14 + + + blame: + 243 + + 2021-10-14 + + + + file: + csharp/ql/lib/semmle/code/csharp/frameworks/microsoft/Owin.qll + + blame: + 128 + + 2022-08-22 + + + + file: + python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryCustomizations.qll + + blame: + 51 + + 2022-06-17 + + + + file: + ruby/ql/src/queries/security/cwe-020/HostnameRegexpShared.qll + + blame: + 7 + + 2022-12-15 + + + + file: + python/ql/lib/semmle/python/pointsto/PointsTo.qll + + blame: + 1448 + + 2022-01-13 + + + blame: + 1492 + + 2022-01-13 + + + blame: + 1524 + + 2022-01-13 + + + blame: + 1548 + + 2022-01-13 + + + blame: + 1580 + + 2022-01-13 + + + blame: + 1606 + + 2022-01-13 + + + + file: + python/ql/lib/semmle/python/security/injection/Sql.qll + + blame: + 14 + + 2022-01-19 + + + blame: + 29 + + 2022-01-19 + + + blame: + 42 + + 2022-01-19 + + + blame: + 53 + + 2022-01-19 + + + blame: + 65 + + 2022-01-19 + + + blame: + 71 + + 2022-01-19 + + + + file: + python/ql/src/experimental/Security/CWE-074/TemplateInjection.ql + + blame: + 25 + + 2022-01-20 + + + blame: + 29 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/security/regexp/RegexpMatching.qll + + blame: + 8 + + 2022-11-01 + + + + file: + csharp/ql/lib/semmle/code/dotnet/Element.qll + + blame: + 104 + + 2022-11-07 + + + + file: + python/ql/src/experimental/semmle/python/security/injection/XSLT.qll + + blame: + 22 + + 2022-08-18 + + + blame: + 27 + + 2022-01-20 + + + blame: + 121 + + 2022-08-18 + + + + file: + python/ql/lib/semmle/python/security/dataflow/PathInjection.qll + + blame: + 9 + + 2022-03-21 + + + blame: + 14 + + 2022-03-21 + + + blame: + 29 + + 2022-03-21 + + + blame: + 53 + + 2022-03-21 + + + blame: + 65 + + 2022-03-21 + + + blame: + 86 + + 2022-03-21 + + + blame: + 110 + + 2022-03-21 + + + blame: + 129 + + 2022-03-21 + + + + file: + go/ql/lib/semmle/go/dataflow/internal/DataFlowImplForStringsNewReplacer.qll + + blame: + 98 + + 2023-01-19 + + + blame: + 106 + + 2023-01-19 + + + blame: + 358 + + 2023-01-19 + + + blame: + 365 + + 2023-01-19 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + javascript/ql/lib/semmle/javascript/internal/CachedStages.qll + + blame: + 289 + + 2022-03-11 + + + + file: + javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/ATMConfig.qll + + blame: + 171 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/controlflow/internal/Preconditions.qll + + blame: + 14 + + 2022-03-22 + + + blame: + 113 + + 2022-03-31 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + go/ql/lib/semmle/go/security/SqlInjection.qll + + blame: + 35 + + 2022-06-17 + + + + file: + ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll + + blame: + 7 + + 2022-11-01 + + + + file: + ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll + + blame: + 121 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/web/django/Request.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 23 + + 2022-01-19 + + + blame: + 29 + + 2022-01-19 + + + blame: + 43 + + 2022-01-19 + + + blame: + 58 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/injection/Command.qll + + blame: + 14 + + 2022-01-19 + + + blame: + 16 + + 2022-01-19 + + + blame: + 18 + + 2022-01-19 + + + blame: + 25 + + 2022-01-19 + + + blame: + 34 + + 2022-01-19 + + + blame: + 46 + + 2022-01-19 + + + blame: + 84 + + 2022-01-19 + + + blame: + 114 + + 2022-01-19 + + + blame: + 130 + + 2022-01-19 + + + blame: + 135 + + 2022-01-19 + + + blame: + 161 + + 2022-01-19 + + + blame: + 190 + + 2022-01-19 + + + blame: + 206 + + 2022-01-19 + + + blame: + 231 + + 2022-01-19 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/AngularJS/ServiceDefinitions.qll + + blame: + 452 + + 2022-03-30 + + + blame: + 458 + + 2022-03-30 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll + + blame: + 61 + + 2022-03-11 + + + blame: + 99 + + 2022-03-11 + + + blame: + 169 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplForRegExp.qll + + blame: + 98 + + 2023-01-06 + + + blame: + 106 + + 2023-01-06 + + + blame: + 358 + + 2023-01-06 + + + blame: + 365 + + 2023-01-06 + + + + file: + java/ql/lib/semmle/code/java/frameworks/spring/SpringXMLElement.qll + + blame: + 42 + + 2022-03-11 + + + + file: + ql/ql/src/queries/style/ConsistentCasing.ql + + blame: + 19 + + 2022-08-29 + + + + file: + csharp/ql/lib/semmle/code/cil/Instructions.qll + + blame: + 792 + + 2022-09-09 + + + blame: + 858 + + 2022-09-09 + + + + file: + ruby/ql/lib/codeql/ruby/security/StoredXSSQuery.qll + + blame: + 33 + + 2022-06-20 + + + blame: + 44 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/security/UrlRedirectCustomizations.qll + + blame: + 41 + + 2022-06-20 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll + + blame: + 8 + + 2022-03-11 + + + blame: + 77 + + 2022-03-11 + + + blame: + 105 + + 2022-03-11 + + + blame: + 133 + + 2022-03-11 + + + blame: + 173 + + 2022-03-11 + + + blame: + 206 + + 2022-03-11 + + + blame: + 234 + + 2022-03-11 + + + blame: + 260 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CleartextLogging.qll + + blame: + 12 + + 2022-03-21 + + + + file: + ruby/ql/lib/codeql/ruby/ast/Literal.qll + + blame: + 174 + + 2022-01-20 + + + blame: + 219 + + 2022-01-20 + + + blame: + 266 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/web/tornado/Request.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 33 + + 2022-01-19 + + + blame: + 41 + + 2022-01-19 + + + blame: + 55 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CleartextStorage.qll + + blame: + 12 + + 2022-03-21 + + + + file: + python/ql/lib/semmle/python/frameworks/internal/SubclassFinder.qll + + blame: + 77 + + 2022-07-18 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedData.qll + + blame: + 7 + + 2022-08-18 + + + blame: + 10 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/security/performance/RegExpInjectionQuery.qll + + blame: + 3 + + 2022-05-25 + + + + file: + ruby/ql/lib/codeql/ruby/ast/internal/Pattern.qll + + blame: + 7 + + 2021-12-14 + + + + file: + ruby/ql/lib/codeql/ruby/security/CodeInjectionCustomizations.qll + + blame: + 55 + + 2022-06-20 + + + + file: + csharp/ql/lib/semmle/code/csharp/commons/StructuralComparison.qll + + blame: + 215 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/ApiGraphs.qll + + blame: + 159 + + 2022-05-30 + + + blame: + 162 + + 2022-05-30 + + + blame: + 165 + + 2022-05-30 + + + blame: + 168 + + 2022-05-30 + + + + file: + python/ql/lib/semmle/python/web/pyramid/Response.qll + + blame: + 11 + + 2022-01-19 + + + blame: + 24 + + 2022-01-19 + + + + file: + go/ql/lib/semmle/go/frameworks/NoSQL.qll + + blame: + 120 + + 2022-08-18 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll + + blame: + 124 + + 2022-04-20 + + + + file: + csharp/ql/lib/semmle/code/csharp/security/dataflow/ZipSlipQuery.qll + + blame: + 28 + + 2022-06-15 + + + blame: + 40 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/web/bottle/Redirect.qll + + blame: + 12 + + 2022-01-19 + + + blame: + 17 + + 2022-01-19 + + + + file: + javascript/ql/lib/semmle/javascript/JSON.qll + + blame: + 65 + + 2022-03-11 + + + blame: + 89 + + 2022-03-11 + + + blame: + 105 + + 2022-03-11 + + + blame: + 122 + + 2022-03-11 + + + blame: + 139 + + 2022-03-11 + + + blame: + 155 + + 2022-03-11 + + + blame: + 174 + + 2022-03-11 + + + blame: + 193 + + 2022-03-11 + + + blame: + 205 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataQuery.qll + + blame: + 65 + + 2022-03-11 + + + blame: + 76 + + 2022-03-11 + + + blame: + 107 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/cherrypy/General.qll + + blame: + 4 + + 2022-01-19 + + + blame: + 8 + + 2022-01-19 + + + blame: + 16 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/dataflow/UnsafeDeserializationCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/WeakSensitiveDataHashing.qll + + blame: + 12 + + 2022-03-21 + + + blame: + 17 + + 2022-03-21 + + + + file: + swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll + + blame: + 204 + + 2022-06-20 + + + + file: + python/ql/src/experimental/Security/CWE-091/Xslt.ql + + blame: + 24 + + 2022-01-20 + + + blame: + 28 + + 2022-01-20 + + + + file: + go/ql/lib/semmle/go/security/CommandInjectionCustomizations.qll + + blame: + 37 + + 2022-06-17 + + + + file: + java/ql/lib/semmle/code/java/Expr.qll + + blame: + 507 + + 2023-01-10 + + + blame: + 517 + + 2023-01-10 + + + blame: + 527 + + 2023-01-10 + + + blame: + 615 + + 2022-05-16 + + + blame: + 710 + + 2021-10-29 + + + blame: + 797 + + 2023-01-10 + + + blame: + 807 + + 2023-01-10 + + + blame: + 817 + + 2023-01-10 + + + blame: + 1820 + + 2022-03-11 + + + + file: + javascript/ql/test/tutorials/Validating RAML-based APIs/RAML.qll + + blame: + 12 + + 2022-03-11 + + + blame: + 42 + + 2022-03-11 + + + blame: + 62 + + 2022-03-11 + + + + file: + python/ql/src/Security/CWE-020/HostnameRegexpShared.qll + + blame: + 7 + + 2022-12-15 + + + + file: + go/ql/lib/semmle/go/security/LogInjection.qll + + blame: + 29 + + 2022-06-17 + + + + file: + ruby/ql/lib/codeql/ruby/Regexp.qll + + blame: + 20 + + 2022-12-15 + + + blame: + 25 + + 2022-12-15 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Files.qll + + blame: + 254 + + 2022-03-11 + + + blame: + 272 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/regexp/ExponentialBackTracking.qll + + blame: + 67 + + 2022-11-01 + + + + file: + python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll + + blame: + 67 + + 2022-03-11 + + + + file: + python/ql/src/experimental/semmle/python/templates/Mako.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 16 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll + + blame: + 330 + + 2022-10-03 + + + + file: + ruby/ql/lib/codeql/ruby/frameworks/StandardLibrary.qll + + blame: + 12 + + 2022-02-15 + + + blame: + 17 + + 2022-02-15 + + + blame: + 22 + + 2022-02-15 + + + blame: + 27 + + 2022-02-15 + + + blame: + 32 + + 2022-02-15 + + + blame: + 37 + + 2022-02-15 + + + blame: + 42 + + 2022-02-15 + + + blame: + 47 + + 2022-02-15 + + + blame: + 52 + + 2022-02-15 + + + blame: + 57 + + 2022-02-15 + + + blame: + 62 + + 2022-02-15 + + + blame: + 67 + + 2022-02-15 + + + blame: + 72 + + 2022-02-15 + + + blame: + 77 + + 2022-02-15 + + + blame: + 82 + + 2022-02-15 + + + blame: + 87 + + 2022-02-15 + + + blame: + 92 + + 2022-02-15 + + + blame: + 97 + + 2022-02-15 + + + + file: + csharp/ql/lib/semmle/code/cil/Types.qll + + blame: + 64 + + 2022-01-14 + + + + file: + go/ql/lib/semmle/go/security/StringBreakCustomizations.qll + + blame: + 47 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/Stmt.qll + + blame: + 299 + + 2022-08-24 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll + + blame: + 13 + + 2022-04-04 + + + blame: + 22 + + 2022-04-04 + + + + file: + python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll + + blame: + 49 + + 2022-03-11 + + + blame: + 107 + + 2022-03-11 + + + blame: + 119 + + 2022-03-11 + + + blame: + 132 + + 2022-03-11 + + + blame: + 187 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/security/ServerSideRequestForgeryQuery.qll + + blame: + 31 + + 2022-06-20 + + + + file: + cpp/ql/lib/semmle/code/cpp/PODType03.qll + + blame: + 108 + + 2022-08-24 + + + blame: + 131 + + 2022-08-24 + + + + file: + javascript/ql/lib/semmle/javascript/SSA.qll + + blame: + 752 + + 2022-09-09 + + + + file: + go/ql/lib/semmle/go/security/StoredXss.qll + + blame: + 34 + + 2022-06-17 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/RegExpInjectionCustomizations.qll + + blame: + 35 + + 2022-06-20 + + + + file: + javascript/ql/lib/semmle/javascript/security/regexp/NfaUtils.qll + + blame: + 12 + + 2022-11-01 + + + + file: + go/ql/lib/semmle/go/security/TaintedPathCustomizations.qll + + blame: + 55 + + 2022-06-17 + + + + file: + go/ql/lib/semmle/go/security/UnsafeUnzipSymlinkCustomizations.qll + + blame: + 47 + + 2022-06-17 + + + blame: + 67 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/RegexInjectionCustomizations.qll + + blame: + 47 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/WebSocket.qll + + blame: + 253 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/security/performance/PolynomialReDoSCustomizations.qll + + blame: + 3 + + 2022-05-25 + + + + file: + java/ql/lib/semmle/code/java/frameworks/camel/CamelJavaDSL.qll + + blame: + 47 + + 2022-08-18 + + + blame: + 51 + + 2022-08-24 + + + blame: + 78 + + 2022-08-24 + + + blame: + 108 + + 2022-08-24 + + + blame: + 143 + + 2022-08-24 + + + + file: + python/ql/src/experimental/semmle/python/templates/Genshi.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 13 + + 2022-01-20 + + + blame: + 23 + + 2022-01-20 + + + blame: + 42 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/web/tornado/Response.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 11 + + 2022-01-19 + + + blame: + 21 + + 2022-01-19 + + + blame: + 35 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CommandInjection.qll + + blame: + 8 + + 2022-03-21 + + + blame: + 13 + + 2022-03-21 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll + + blame: + 98 + + 2022-09-09 + + + blame: + 106 + + 2022-09-09 + + + blame: + 358 + + 2022-09-09 + + + blame: + 365 + + 2022-09-09 + + + + file: + python/ql/lib/semmle/python/security/injection/Marshal.qll + + blame: + 14 + + 2022-01-19 + + + blame: + 22 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll + + blame: + 3 + + 2022-05-25 + + + + file: + go/ql/lib/semmle/go/security/OpenUrlRedirectCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll + + blame: + 427 + + 2022-03-13 + + + blame: + 1248 + + 2022-03-13 + + + + file: + python/ql/src/experimental/semmle/python/templates/Jinja.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 11 + + 2022-01-20 + + + blame: + 19 + + 2022-01-20 + + + blame: + 38 + + 2022-01-20 + + + + file: + ruby/ql/lib/codeql/ruby/security/ReflectedXSSQuery.qll + + blame: + 31 + + 2022-06-20 + + + blame: + 42 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/Files.qll + + blame: + 161 + + 2022-03-07 + + + + file: + javascript/ql/lib/semmle/javascript/security/performance/PolynomialReDoSCustomizations.qll + + blame: + 3 + + 2022-11-22 + + + + file: + go/ql/lib/semmle/go/security/Xss.qll + + blame: + 13 + + 2022-09-19 + + + blame: + 42 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/dataflow/new/BarrierGuards.qll + + blame: + 43 + + 2022-06-17 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-09-09 + + + blame: + 126 + + 2022-09-09 + + + blame: + 136 + + 2022-09-09 + + + blame: + 140 + + 2022-09-09 + + + + file: + java/ql/lib/semmle/code/java/security/IntentUriPermissionManipulation.qll + + blame: + 34 + + 2022-06-15 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll + + blame: + 48 + + 2021-10-07 + + + blame: + 107 + + 2021-10-07 + + + + file: + java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBJarXML.qll + + blame: + 39 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/SensitiveActions.qll + + blame: + 20 + + 2022-04-04 + + + blame: + 26 + + 2022-04-04 + + + blame: + 29 + + 2022-04-04 + + + + file: + python/ql/lib/semmle/python/security/injection/Yaml.qll + + blame: + 14 + + 2022-01-19 + + + blame: + 17 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/types/Extensions.qll + + blame: + 56 + + 2022-01-20 + + + + file: + ruby/ql/lib/codeql/ruby/security/UrlRedirectQuery.qll + + blame: + 26 + + 2022-06-20 + + + + file: + python/ql/lib/semmle/python/security/injection/Path.qll + + blame: + 9 + + 2022-01-19 + + + blame: + 18 + + 2022-01-19 + + + blame: + 27 + + 2022-01-19 + + + blame: + 33 + + 2022-01-19 + + + blame: + 38 + + 2022-01-19 + + + blame: + 48 + + 2022-01-19 + + + blame: + 62 + + 2022-01-19 + + + + file: + ruby/ql/lib/codeql/ruby/ast/Control.qll + + blame: + 388 + + 2021-12-21 + + + blame: + 391 + + 2021-12-21 + + + blame: + 419 + + 2021-12-21 + + + + file: + java/ql/src/experimental/Security/CWE/CWE-089/MyBatisCommonLib.qll + + blame: + 60 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/security/LogInjectionCustomizations.qll + + blame: + 33 + + 2022-06-17 + + + + file: + go/ql/lib/semmle/go/security/OpenUrlRedirect.qll + + blame: + 62 + + 2022-06-17 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll + + blame: + 61 + + 2022-03-11 + + + blame: + 99 + + 2022-03-11 + + + blame: + 169 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll + + blame: + 3 + + 2022-11-22 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Operand.qll + + blame: + 95 + + 2021-10-14 + + + blame: + 104 + + 2021-10-14 + + + + file: + python/ql/lib/semmle/python/web/HttpConstants.qll + + blame: + 2 + + 2022-01-19 + + + blame: + 7 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/web/django/Response.qll + + blame: + 8 + + 2022-01-19 + + + blame: + 13 + + 2022-01-19 + + + blame: + 22 + + 2022-01-19 + + + blame: + 39 + + 2022-01-19 + + + blame: + 56 + + 2022-01-19 + + + blame: + 69 + + 2022-01-19 + + + + file: + cpp/ql/src/Security/CWE/CWE-497/SystemData.qll + + blame: + 59 + + 2022-08-18 + + + blame: + 81 + + 2022-08-18 + + + + file: + python/ql/lib/semmle/python/web/Http.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 13 + + 2022-01-19 + + + blame: + 46 + + 2022-01-19 + + + blame: + 56 + + 2022-01-19 + + + blame: + 65 + + 2022-01-19 + + + blame: + 74 + + 2022-01-19 + + + blame: + 76 + + 2022-01-19 + + + blame: + 79 + + 2022-01-19 + + + blame: + 83 + + 2022-01-19 + + + blame: + 87 + + 2022-01-19 + + + + file: + javascript/ql/lib/semmle/javascript/TypeScript.qll + + blame: + 15 + + 2021-11-01 + + + blame: + 197 + + 2021-11-01 + + + + file: + python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll + + blame: + 3 + + 2022-05-25 + + + + file: + cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIsSpecific.qll + + blame: + 45 + + 2022-03-11 + + + blame: + 57 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll + + blame: + 95 + + 2021-10-14 + + + blame: + 104 + + 2021-10-14 + + + + file: + python/ql/lib/semmle/python/objects/TObject.qll + + blame: + 337 + + 2022-09-06 + + + blame: + 360 + + 2022-09-06 + + + + file: + go/ql/lib/semmle/go/frameworks/Stdlib.qll + + blame: + 269 + + 2022-09-09 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCondition.qll + + blame: + 25 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/ast/internal/AST.qll + + blame: + 878 + + 2021-12-14 + + + blame: + 884 + + 2021-12-14 + + + + file: + go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll + + blame: + 423 + + 2022-06-17 + + + blame: + 433 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/PolynomialReDoSCustomizations.qll + + blame: + 55 + + 2022-06-17 + + + + file: + javascript/ql/src/experimental/semmle/javascript/Actions.qll + + blame: + 2 + + 2022-05-03 + + + + file: + python/ql/lib/semmle/python/web/flask/Redirect.qll + + blame: + 12 + + 2022-01-19 + + + blame: + 17 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/web/twisted/Response.qll + + blame: + 8 + + 2022-01-19 + + + blame: + 28 + + 2022-01-19 + + + + file: + go/ql/lib/semmle/go/dataflow/barrierguardutil/UrlCheck.qll + + blame: + 44 + + 2022-06-17 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRVariable.qll + + blame: + 61 + + 2022-03-11 + + + blame: + 99 + + 2022-03-11 + + + blame: + 169 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll + + blame: + 819 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll + + blame: + 43 + + 2022-03-11 + + + blame: + 87 + + 2022-03-11 + + + + file: + python/tools/recorded-call-graph-metrics/ql/lib/RecordedCalls.qll + + blame: + 14 + + 2022-08-16 + + + blame: + 23 + + 2022-08-16 + + + blame: + 61 + + 2022-03-11 + + + blame: + 114 + + 2022-03-11 + + + blame: + 120 + + 2022-03-11 + + + blame: + 144 + + 2022-03-11 + + + blame: + 165 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/filters/ClassifyFiles.qll + + blame: + 79 + + 2022-05-24 + + + + file: + ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/security/TaintTrackingImpl.qll + + blame: + 124 + + 2022-11-25 + + + blame: + 167 + + 2022-11-25 + + + blame: + 173 + + 2022-11-25 + + + blame: + 184 + + 2022-11-25 + + + blame: + 188 + + 2022-11-25 + + + blame: + 329 + + 2022-11-25 + + + blame: + 358 + + 2022-11-25 + + + blame: + 400 + + 2022-11-25 + + + blame: + 415 + + 2022-11-25 + + + blame: + 546 + + 2022-11-25 + + + blame: + 553 + + 2022-11-25 + + + blame: + 584 + + 2022-11-25 + + + blame: + 593 + + 2022-11-25 + + + + file: + go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-17 + + + blame: + 106 + + 2022-10-20 + + + blame: + 358 + + 2022-06-17 + + + blame: + 365 + + 2022-10-20 + + + + file: + python/ql/lib/semmle/python/security/strings/Untrusted.qll + + blame: + 8 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/dataflow/StackTraceExposureCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + + file: + ql/ql/src/queries/bugs/MissingSanitizerGuardCase.ql + + blame: + 27 + + 2022-09-12 + + + + file: + ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll + + blame: + 37 + + 2022-03-03 + + + + file: + java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll + + blame: + 3 + + 2022-05-25 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/IRConstruction.qll + + blame: + 383 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/webob/Request.qll + + blame: + 5 + + 2022-01-19 + + + blame: + 34 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/security/OverlyLargeRangeQuery.qll + + blame: + 7 + + 2022-11-01 + + + + file: + python/ql/src/experimental/semmle/python/frameworks/Django.qll + + blame: + 32 + + 2022-08-24 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedFunction.qll + + blame: + 34 + + 2022-03-11 + + + blame: + 291 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/JSX.qll + + blame: + 34 + + 2022-03-11 + + + blame: + 79 + + 2022-03-11 + + + blame: + 83 + + 2022-03-11 + + + blame: + 107 + + 2022-03-11 + + + blame: + 156 + + 2022-03-11 + + + blame: + 177 + + 2022-03-11 + + + blame: + 203 + + 2022-03-11 + + + blame: + 246 + + 2022-03-11 + + + blame: + 262 + + 2022-03-11 + + + blame: + 283 + + 2022-03-11 + + + blame: + 287 + + 2022-03-11 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/internal/TranslatedCompilerGeneratedElement.qll + + blame: + 24 + + 2022-03-11 + + + + file: + python/ql/src/experimental/semmle/python/templates/SSTISink.qll + + blame: + 7 + + 2022-01-20 + + + + file: + python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql + + blame: + 15 + + 2021-03-09 + + + blame: + 29 + + 2021-03-10 + + + + file: + csharp/ql/lib/semmle/code/csharp/security/cryptography/EncryptionKeyDataFlowQuery.qll + + blame: + 9 + + 2022-09-27 + + + + file: + javascript/ql/lib/semmle/javascript/security/performance/PolynomialReDoS.qll + + blame: + 7 + + 2022-05-25 + + + + file: + java/ql/lib/semmle/code/java/security/regexp/ExponentialBackTracking.qll + + blame: + 67 + + 2022-11-01 + + + + file: + java/ql/lib/semmle/code/java/frameworks/gwt/GWT.qll + + blame: + 103 + + 2022-08-18 + + + blame: + 116 + + 2022-08-18 + + + + file: + python/ql/lib/semmle/python/web/falcon/Request.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 31 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll + + blame: + 101 + + 2022-03-11 + + + blame: + 149 + + 2022-04-20 + + + blame: + 157 + + 2022-04-20 + + + blame: + 165 + + 2022-04-20 + + + blame: + 173 + + 2022-04-20 + + + blame: + 181 + + 2022-04-20 + + + + file: + cpp/ql/lib/semmle/code/cpp/commons/NULL.qll + + blame: + 9 + + 2022-08-24 + + + + file: + javascript/ql/lib/semmle/javascript/dependencies/Dependencies.qll + + blame: + 43 + + 2022-03-11 + + + blame: + 66 + + 2022-03-11 + + + blame: + 109 + + 2022-03-11 + + + blame: + 121 + + 2022-03-11 + + + blame: + 143 + + 2022-03-11 + + + blame: + 170 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/tornado/Tornado.qll + + blame: + 5 + + 2022-01-19 + + + blame: + 9 + + 2022-01-19 + + + blame: + 17 + + 2022-01-19 + + + blame: + 33 + + 2022-01-19 + + + blame: + 37 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/web/bottle/Request.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 9 + + 2022-01-19 + + + blame: + 24 + + 2022-01-19 + + + blame: + 30 + + 2022-01-19 + + + blame: + 51 + + 2022-01-19 + + + blame: + 63 + + 2022-01-19 + + + blame: + 72 + + 2022-01-19 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CodeInjectionQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/LdapInjectionQuery.qll + + blame: + 29 + + 2022-06-17 + + + blame: + 47 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll + + blame: + 46 + + 2021-07-02 + + + + file: + cpp/ql/lib/semmle/code/cpp/controlflow/SubBasicBlocks.qll + + blame: + 83 + + 2021-10-14 + + + + file: + python/ql/src/experimental/semmle/python/frameworks/LDAP.qll + + blame: + 129 + + 2022-08-22 + + + blame: + 224 + + 2022-08-22 + + + + file: + python/ql/lib/semmle/python/web/django/Shared.qll + + blame: + 4 + + 2022-01-19 + + + blame: + 22 + + 2022-01-19 + + + blame: + 50 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/frameworks/struts/StrutsConventions.qll + + blame: + 81 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/client/StdLib.qll + + blame: + 4 + + 2022-01-19 + + + blame: + 21 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/regexp/ExponentialBackTracking.qll + + blame: + 67 + + 2022-11-01 + + + + file: + java/ql/lib/semmle/code/java/deadcode/SpringEntryPoints.qll + + blame: + 118 + + 2022-08-24 + + + + file: + javascript/ql/lib/semmle/javascript/XML.qll + + blame: + 36 + + 2022-08-16 + + + blame: + 99 + + 2022-08-16 + + + blame: + 116 + + 2021-10-14 + + + blame: + 123 + + 2021-10-14 + + + blame: + 138 + + 2022-08-23 + + + blame: + 142 + + 2022-08-16 + + + blame: + 181 + + 2022-08-23 + + + blame: + 239 + + 2022-08-16 + + + blame: + 272 + + 2022-08-16 + + + blame: + 291 + + 2022-08-22 + + + blame: + 304 + + 2022-08-16 + + + blame: + 327 + + 2022-08-16 + + + blame: + 354 + + 2022-08-16 + + + + file: + csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll + + blame: + 63 + + 2022-03-11 + + + blame: + 73 + + 2022-03-11 + + + blame: + 161 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Koa.qll + + blame: + 52 + + 2022-03-30 + + + blame: + 69 + + 2022-03-30 + + + blame: + 86 + + 2022-03-30 + + + blame: + 280 + + 2022-03-30 + + + blame: + 286 + + 2022-03-30 + + + blame: + 307 + + 2022-03-30 + + + blame: + 322 + + 2022-03-30 + + + + file: + ruby/ql/lib/codeql/ruby/ast/Constant.qll + + blame: + 84 + + 2022-03-24 + + + blame: + 87 + + 2022-03-24 + + + blame: + 406 + + 2021-12-22 + + + + file: + go/ql/lib/semmle/go/security/SqlInjectionCustomizations.qll + + blame: + 33 + + 2022-06-17 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll + + blame: + 1153 + + 2022-06-16 + + + + file: + python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll + + blame: + 50 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/web/django/Redirect.qll + + blame: + 16 + + 2022-01-19 + + + blame: + 27 + + 2022-01-19 + + + + file: + java/ql/src/Telemetry/ExternalApi.qll + + blame: + 99 + + 2022-03-29 + + + + file: + java/ql/src/semmle/code/xml/MyBatisMapperXML.qll + + blame: + 18 + + 2022-03-11 + + + blame: + 40 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/concepts/HTTP.qll + + blame: + 351 + + 2022-09-09 + + + + file: + python/ql/lib/semmle/python/web/pyramid/Request.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 14 + + 2022-01-19 + + + + file: + python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql + + blame: + 33 + + 2019-02-26 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll + + blame: + 139 + + 2022-03-11 + + + blame: + 578 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll + + blame: + 242 + + 2022-03-11 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/PolynomialReDoSQuery.qll + + blame: + 33 + + 2022-06-20 + + + + file: + ruby/ql/lib/codeql/ruby/security/XSS.qll + + blame: + 44 + + 2022-06-20 + + + blame: + 246 + + 2022-03-11 + + + blame: + 269 + + 2022-06-20 + + + blame: + 277 + + 2022-03-11 + + + blame: + 288 + + 2022-03-11 + + + blame: + 326 + + 2022-06-20 + + + blame: + 334 + + 2022-03-11 + + + blame: + 351 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/xml/WebXML.qll + + blame: + 9 + + 2022-03-11 + + + blame: + 35 + + 2022-03-11 + + + blame: + 50 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/ReflectedXSS.qll + + blame: + 8 + + 2022-03-21 + + + blame: + 13 + + 2022-03-21 + + + blame: + 16 + + 2022-03-21 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll + + blame: + 627 + + 2022-03-30 + + + blame: + 633 + + 2022-03-30 + + + blame: + 636 + + 2022-03-30 + + + blame: + 639 + + 2022-03-30 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedInitialization.qll + + blame: + 56 + + 2022-03-11 + + + blame: + 214 + + 2022-03-11 + + + blame: + 321 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll + + blame: + 7 + + 2022-11-22 + + + + file: + python/ql/src/experimental/semmle/python/security/InsecureRandomnessCustomizations.qll + + blame: + 37 + + 2022-06-17 + + + + file: + csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll + + blame: + 51 + + 2023-01-06 + + + blame: + 63 + + 2023-01-06 + + + + file: + javascript/ql/src/LanguageFeatures/ExpressionClosures.ql + + blame: + 21 + + 2022-03-11 + + + blame: + 42 + + 2018-08-02 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + cpp/ql/src/Security/CWE/CWE-020/ir/SafeExternalAPIFunction.qll + + blame: + 14 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/Regexp.qll + + blame: + 1009 + + 2022-12-15 + + + blame: + 1014 + + 2022-12-15 + + + blame: + 1023 + + 2022-08-24 + + + blame: + 1026 + + 2022-08-24 + + + + file: + java/ql/lib/semmle/code/java/frameworks/Servlets.qll + + blame: + 132 + + 2022-03-11 + + + blame: + 146 + + 2022-08-18 + + + blame: + 343 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll + + blame: + 9 + + 2022-08-18 + + + blame: + 16 + + 2022-08-18 + + + + file: + java/ql/lib/semmle/code/java/deadcode/WebEntryPoints.qll + + blame: + 61 + + 2022-08-24 + + + blame: + 83 + + 2022-08-24 + + + + file: + python/ql/lib/semmle/python/security/dataflow/ReflectedXSSCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + blame: + 81 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/BadTagFilterQuery.qll + + blame: + 7 + + 2022-11-01 + + + + file: + python/ql/lib/semmle/python/security/strings/Common.qll + + blame: + 4 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/web/flask/General.qll + + blame: + 6 + + 2022-01-19 + + + blame: + 9 + + 2022-01-19 + + + blame: + 11 + + 2022-01-19 + + + blame: + 17 + + 2022-01-19 + + + blame: + 27 + + 2022-01-19 + + + blame: + 38 + + 2022-01-19 + + + blame: + 54 + + 2022-01-19 + + + blame: + 61 + + 2022-01-19 + + + blame: + 71 + + 2022-01-19 + + + blame: + 76 + + 2022-01-19 + + + blame: + 94 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/injection/Pickle.qll + + blame: + 14 + + 2022-01-19 + + + blame: + 22 + + 2022-01-19 + + + blame: + 25 + + 2022-01-19 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + python/tools/recorded-call-graph-metrics/ql/lib/BytecodeExpr.qll + + blame: + 6 + + 2022-03-11 + + + blame: + 15 + + 2022-03-11 + + + blame: + 24 + + 2022-03-11 + + + blame: + 35 + + 2022-03-11 + + + blame: + 46 + + 2022-03-11 + + + blame: + 57 + + 2022-03-11 + + + blame: + 68 + + 2022-03-11 + + + blame: + 77 + + 2022-03-11 + + + blame: + 86 + + 2022-03-11 + + + blame: + 97 + + 2022-03-11 + + + blame: + 106 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/JsonStringifiers.qll + + blame: + 63 + + 2022-08-24 + + + blame: + 82 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + csharp/ql/lib/semmle/code/csharp/exprs/Access.qll + + blame: + 177 + + 2022-10-12 + + + blame: + 205 + + 2022-10-12 + + + blame: + 247 + + 2022-10-12 + + + blame: + 302 + + 2022-10-12 + + + blame: + 447 + + 2022-10-12 + + + blame: + 588 + + 2022-10-12 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Restify.qll + + blame: + 79 + + 2022-03-30 + + + blame: + 94 + + 2022-03-30 + + + + file: + java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll + + blame: + 3 + + 2022-05-25 + + + + file: + java/ql/src/Advisory/Deprecated Code/AvoidDeprecatedCallableAccess.ql + + blame: + 18 + + 2018-08-30 + + + blame: + 25 + + 2018-08-30 + + + blame: + 27 + + 2018-10-10 + + + + file: + go/ql/lib/semmle/go/security/StoredXssCustomizations.qll + + blame: + 24 + + 2022-06-17 + + + blame: + 30 + + 2022-06-17 + + + + file: + cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll + + blame: + 18 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/security/CommandInjection.qll + + blame: + 37 + + 2022-06-17 + + + blame: + 100 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/XpathInjection.qll + + blame: + 8 + + 2022-03-21 + + + + file: + go/ql/lib/semmle/go/security/AllocationSizeOverflowCustomizations.qll + + blame: + 32 + + 2022-06-17 + + + + file: + csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll + + blame: + 61 + + 2022-03-11 + + + blame: + 99 + + 2022-03-11 + + + blame: + 169 + + 2022-03-11 + + + + file: + swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + java/ql/lib/semmle/code/java/frameworks/spring/SpringCamel.qll + + blame: + 17 + + 2022-03-11 + + + blame: + 29 + + 2022-03-11 + + + blame: + 42 + + 2022-03-11 + + + blame: + 62 + + 2022-03-11 + + + blame: + 75 + + 2022-03-11 + + + blame: + 102 + + 2022-03-11 + + + blame: + 120 + + 2022-08-18 + + + blame: + 124 + + 2022-03-11 + + + blame: + 152 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll + + blame: + 50 + + 2022-03-11 + + + blame: + 78 + + 2022-03-11 + + + blame: + 84 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll + + blame: + 3 + + 2022-05-25 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll + + blame: + 71 + + 2022-03-11 + + + blame: + 466 + + 2022-03-11 + + + blame: + 501 + + 2022-03-11 + + + blame: + 541 + + 2022-03-11 + + + blame: + 579 + + 2022-03-11 + + + blame: + 650 + + 2022-03-11 + + + blame: + 698 + + 2022-03-11 + + + blame: + 785 + + 2022-03-11 + + + blame: + 811 + + 2022-03-11 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll + + blame: + 1415 + + 2022-09-09 + + + + file: + javascript/ql/lib/semmle/javascript/security/regexp/RegexpMatching.qll + + blame: + 8 + + 2022-11-22 + + + + file: + ql/ql/src/codeql_ql/style/DeadCodeQuery.qll + + blame: + 191 + + 2022-03-11 + + + blame: + 192 + + 2022-03-11 + + + blame: + 194 + + 2022-03-11 + + + blame: + 196 + + 2022-03-11 + + + blame: + 198 + + 2022-03-11 + + + blame: + 235 + + 2022-03-13 + + + blame: + 271 + + 2022-03-13 + + + + file: + python/ql/lib/semmle/python/web/twisted/Request.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 24 + + 2022-01-19 + + + + file: + ql/ql/src/codeql_ql/style/TypoDatabase.qll + + blame: + 4 + + 2022-09-08 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll + + blame: + 214 + + 2022-03-11 + + + blame: + 468 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/bottle/General.qll + + blame: + 6 + + 2022-01-19 + + + blame: + 9 + + 2022-01-19 + + + blame: + 15 + + 2022-01-19 + + + blame: + 27 + + 2022-01-19 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/GWT.qll + + blame: + 15 + + 2022-08-24 + + + blame: + 36 + + 2022-08-24 + + + blame: + 40 + + 2022-08-24 + + + blame: + 50 + + 2022-08-24 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll + + blame: + 655 + + 2022-06-23 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll + + blame: + 43 + + 2022-08-24 + + + + file: + ql/ql/src/codeql_ql/ast/Ast.qll + + blame: + 2585 + + 2022-08-24 + + + blame: + 2597 + + 2022-03-11 + + + blame: + 2627 + + 2022-03-11 + + + blame: + 2666 + + 2022-03-11 + + + blame: + 2683 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/Crypto.qll + + blame: + 6 + + 2022-01-19 + + + blame: + 11 + + 2022-01-19 + + + blame: + 61 + + 2022-01-19 + + + blame: + 131 + + 2022-01-19 + + + + file: + cpp/ql/src/Microsoft/SAL.qll + + blame: + 26 + + 2022-08-24 + + + blame: + 54 + + 2022-08-24 + + + blame: + 67 + + 2022-08-24 + + + blame: + 93 + + 2022-08-24 + + + blame: + 109 + + 2022-08-24 + + + blame: + 128 + + 2022-08-24 + + + blame: + 203 + + 2022-08-24 + + + + file: + javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll + + blame: + 3 + + 2022-11-22 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll + + blame: + 889 + + 2022-06-16 + + + + file: + javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll + + blame: + 1159 + + 2022-03-30 + + + blame: + 1175 + + 2022-03-30 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-09-09 + + + blame: + 106 + + 2022-09-09 + + + blame: + 358 + + 2022-09-09 + + + blame: + 365 + + 2022-09-09 + + + + file: + cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll + + blame: + 45 + + 2022-03-11 + + + blame: + 62 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/turbogears/Request.qll + + blame: + 6 + + 2022-01-19 + + + blame: + 15 + + 2022-01-19 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Testing.qll + + blame: + 41 + + 2022-08-24 + + + + file: + csharp/ql/lib/semmle/code/csharp/Assignable.qll + + blame: + 128 + + 2022-10-12 + + + blame: + 499 + + 2022-10-12 + + + + file: + java/ql/lib/semmle/code/java/frameworks/spring/SpringComponentScan.qll + + blame: + 27 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/security/regexp/SuperlinearBackTracking.qll + + blame: + 40 + + 2022-11-01 + + + + file: + python/ql/lib/semmle/python/security/strings/External.qll + + blame: + 8 + + 2022-01-19 + + + blame: + 33 + + 2022-01-19 + + + blame: + 41 + + 2022-01-19 + + + blame: + 64 + + 2022-01-19 + + + blame: + 72 + + 2022-01-19 + + + blame: + 77 + + 2022-01-19 + + + blame: + 100 + + 2022-01-19 + + + blame: + 124 + + 2022-01-19 + + + blame: + 132 + + 2022-01-19 + + + blame: + 137 + + 2022-01-19 + + + blame: + 156 + + 2022-01-19 + + + blame: + 175 + + 2022-01-19 + + + blame: + 186 + + 2020-07-07 + + + blame: + 201 + + 2022-01-19 + + + blame: + 212 + + 2020-07-07 + + + blame: + 228 + + 2022-01-19 + + + blame: + 256 + + 2022-01-19 + + + + file: + ruby/ql/lib/codeql/ruby/frameworks/ActionView.qll + + blame: + 17 + + 2022-10-04 + + + blame: + 22 + + 2022-10-04 + + + blame: + 27 + + 2022-10-04 + + + blame: + 32 + + 2022-10-04 + + + + file: + python/ql/src/experimental/semmle/python/templates/Bottle.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 18 + + 2022-01-20 + + + blame: + 37 + + 2022-01-20 + + + + file: + csharp/ql/lib/semmle/code/asp/WebConfig.qll + + blame: + 15 + + 2022-03-11 + + + blame: + 23 + + 2022-03-11 + + + blame: + 34 + + 2022-03-11 + + + blame: + 49 + + 2022-03-11 + + + blame: + 64 + + 2022-03-11 + + + blame: + 75 + + 2022-03-11 + + + blame: + 86 + + 2022-03-11 + + + blame: + 102 + + 2022-08-22 + + + blame: + 110 + + 2022-08-22 + + + blame: + 137 + + 2022-08-22 + + + blame: + 150 + + 2022-08-22 + + + + file: + java/ql/lib/semmle/code/java/NumberFormatException.qll + + blame: + 38 + + 2022-08-24 + + + blame: + 59 + + 2022-08-24 + + + blame: + 77 + + 2022-08-24 + + + blame: + 85 + + 2022-08-24 + + + + file: + python/ql/lib/semmle/python/security/dataflow/ChainedConfigs12.qll + + blame: + 37 + + 2022-01-31 + + + blame: + 76 + + 2022-01-31 + + + blame: + 89 + + 2022-01-31 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll + + blame: + 486 + + 2022-03-11 + + + + file: + cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll + + blame: + 98 + + 2022-09-09 + + + blame: + 106 + + 2022-09-09 + + + blame: + 358 + + 2022-09-09 + + + blame: + 365 + + 2022-09-09 + + + + file: + ruby/ql/lib/codeql/ruby/Concepts.qll + + blame: + 688 + + 2022-08-18 + + + blame: + 697 + + 2022-08-18 + + + blame: + 722 + + 2022-03-22 + + + blame: + 731 + + 2022-08-18 + + + blame: + 747 + + 2022-09-09 + + + blame: + 914 + + 2022-08-18 + + + blame: + 934 + + 2022-08-18 + + + blame: + 1042 + + 2022-05-23 + + + blame: + 1056 + + 2022-05-23 + + + + file: + java/ql/lib/semmle/code/java/frameworks/jackson/JacksonSerializability.qll + + blame: + 25 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/AST.qll + + blame: + 188 + + 2022-03-11 + + + blame: + 343 + + 2022-03-11 + + + + file: + csharp/ql/lib/semmle/code/csharp/security/dataflow/UrlRedirectQuery.qll + + blame: + 33 + + 2022-06-15 + + + blame: + 47 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/web/flask/Request.qll + + blame: + 6 + + 2022-01-19 + + + blame: + 9 + + 2022-01-19 + + + blame: + 15 + + 2022-01-19 + + + blame: + 29 + + 2022-01-19 + + + blame: + 42 + + 2022-01-19 + + + blame: + 60 + + 2022-01-19 + + + blame: + 75 + + 2022-01-19 + + + + file: + cpp/ql/lib/semmle/code/cpp/rangeanalysis/RangeSSA.qll + + blame: + 44 + + 2022-03-11 + + + blame: + 104 + + 2021-09-13 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Hapi.qll + + blame: + 94 + + 2022-03-30 + + + blame: + 109 + + 2022-03-30 + + + blame: + 258 + + 2022-03-30 + + + + file: + python/ql/lib/semmle/python/security/regexp/SuperlinearBackTracking.qll + + blame: + 40 + + 2022-11-01 + + + + file: + javascript/ql/src/Declarations/Definitions.qll + + blame: + 7 + + 2022-03-13 + + + + file: + shared/ssa/codeql/ssa/Ssa.qll + + blame: + 737 + + 2022-11-01 + + + blame: + 744 + + 2022-11-01 + + + blame: + 766 + + 2022-11-01 + + + blame: + 833 + + 2022-11-01 + + + blame: + 846 + + 2022-11-01 + + + blame: + 909 + + 2022-11-01 + + + + file: + python/ql/lib/semmle/python/web/django/General.qll + + blame: + 8 + + 2022-01-19 + + + blame: + 29 + + 2022-01-19 + + + blame: + 39 + + 2022-01-19 + + + blame: + 47 + + 2022-01-19 + + + blame: + 60 + + 2022-01-19 + + + blame: + 73 + + 2022-01-19 + + + blame: + 77 + + 2022-01-19 + + + blame: + 112 + + 2022-01-19 + + + + file: + go/ql/lib/semmle/go/security/AllocationSizeOverflow.qll + + blame: + 26 + + 2022-06-17 + + + blame: + 67 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/dataflow/ServerSideRequestForgeryQuery.qll + + blame: + 37 + + 2022-06-17 + + + blame: + 68 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/web/pyramid/Redirect.qll + + blame: + 12 + + 2022-01-19 + + + blame: + 23 + + 2022-01-19 + + + + file: + go/ql/lib/semmle/go/security/ZipSlipCustomizations.qll + + blame: + 35 + + 2022-06-17 + + + + file: + python/ql/src/experimental/semmle/python/security/LDAPInsecureAuth.qll + + blame: + 33 + + 2022-03-11 + + + blame: + 40 + + 2022-03-11 + + + blame: + 47 + + 2022-03-11 + + + blame: + 60 + + 2022-03-11 + + + blame: + 77 + + 2022-03-11 + + + blame: + 93 + + 2022-03-11 + + + blame: + 107 + + 2022-03-11 + + + blame: + 130 + + 2022-03-11 + + + + file: + cpp/ql/test/library-tests/dataflow/fields/Nodes.qll + + blame: + 17 + + 2022-03-11 + + + blame: + 32 + + 2022-03-11 + + + blame: + 38 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/bottle/Response.qll + + blame: + 12 + + 2022-01-19 + + + blame: + 16 + + 2022-01-19 + + + blame: + 18 + + 2022-01-19 + + + blame: + 29 + + 2022-01-19 + + + blame: + 42 + + 2022-01-19 + + + + file: + csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll + + blame: + 95 + + 2021-10-14 + + + blame: + 104 + + 2021-10-14 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/frameworks/Django.qll + + blame: + 538 + + 2022-03-11 + + + blame: + 556 + + 2022-03-11 + + + blame: + 575 + + 2022-03-11 + + + blame: + 823 + + 2022-03-11 + + + blame: + 863 + + 2022-03-11 + + + blame: + 1103 + + 2022-03-11 + + + blame: + 1127 + + 2022-03-11 + + + blame: + 1132 + + 2022-03-11 + + + blame: + 1159 + + 2022-09-09 + + + blame: + 1170 + + 2022-03-11 + + + blame: + 1332 + + 2022-03-11 + + + blame: + 2185 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/security/ZipSlip.qll + + blame: + 29 + + 2022-06-17 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + python/ql/src/experimental/semmle/python/templates/Airspeed.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 16 + + 2022-01-20 + + + + file: + ql/ql/src/queries/style/docs/ClassDocs.ql + + blame: + 26 + + 2022-08-15 + + + + file: + ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll + + blame: + 687 + + 2022-06-20 + + + + file: + ruby/ql/lib/codeql/ruby/security/OverlyLargeRangeQuery.qll + + blame: + 7 + + 2022-11-01 + + + + file: + ruby/ql/lib/codeql/ruby/security/performance/PolynomialReDoSQuery.qll + + blame: + 3 + + 2022-05-25 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Vue.qll + + blame: + 194 + + 2022-05-23 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll + + blame: + 12 + + 2022-11-25 + + + blame: + 14 + + 2022-11-25 + + + blame: + 16 + + 2022-11-25 + + + blame: + 19 + + 2022-11-25 + + + blame: + 21 + + 2022-11-25 + + + + file: + ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/pointsto/Base.qll + + blame: + 16 + + 2022-09-06 + + + blame: + 30 + + 2022-09-06 + + + blame: + 36 + + 2022-09-06 + + + blame: + 48 + + 2022-09-06 + + + blame: + 62 + + 2022-09-06 + + + blame: + 72 + + 2022-09-06 + + + blame: + 82 + + 2022-09-06 + + + blame: + 92 + + 2022-09-06 + + + blame: + 105 + + 2022-09-06 + + + blame: + 116 + + 2022-09-06 + + + blame: + 125 + + 2022-09-06 + + + blame: + 163 + + 2022-09-06 + + + blame: + 175 + + 2022-09-06 + + + blame: + 191 + + 2022-09-06 + + + blame: + 213 + + 2022-09-06 + + + blame: + 229 + + 2022-09-06 + + + blame: + 254 + + 2022-09-06 + + + blame: + 260 + + 2022-09-06 + + + blame: + 274 + + 2022-09-06 + + + blame: + 336 + + 2022-09-06 + + + blame: + 354 + + 2022-09-06 + + + blame: + 366 + + 2022-09-06 + + + blame: + 372 + + 2022-09-06 + + + + file: + python/ql/lib/semmle/python/security/dataflow/RegexInjection.qll + + blame: + 8 + + 2022-03-21 + + + + file: + python/ql/src/Functions/DeprecatedSliceMethod.ql + + blame: + 24 + + 2022-10-07 + + + + file: + javascript/ql/lib/semmle/javascript/YAML.qll + + blame: + 93 + + 2022-08-24 + + + blame: + 111 + + 2022-08-24 + + + blame: + 160 + + 2022-08-24 + + + blame: + 182 + + 2022-08-24 + + + blame: + 204 + + 2022-08-24 + + + blame: + 225 + + 2022-08-24 + + + blame: + 246 + + 2022-08-24 + + + blame: + 262 + + 2022-08-24 + + + blame: + 278 + + 2022-08-24 + + + blame: + 295 + + 2022-08-24 + + + blame: + 327 + + 2022-08-24 + + + blame: + 351 + + 2022-08-24 + + + blame: + 408 + + 2022-08-24 + + + blame: + 436 + + 2022-08-24 + + + blame: + 462 + + 2022-08-24 + + + blame: + 480 + + 2022-08-24 + + + blame: + 494 + + 2022-08-24 + + + blame: + 568 + + 2022-08-24 + + + + file: + java/ql/lib/semmle/code/java/frameworks/Camel.qll + + blame: + 21 + + 2022-08-18 + + + blame: + 58 + + 2022-08-18 + + + + file: + javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll + + blame: + 3 + + 2022-11-22 + + + + file: + ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll + + blame: + 3 + + 2022-05-25 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + cpp/ql/test/TestUtilities/dataflow/FlowTestCommon.qll + + blame: + 74 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/tornado/Redirect.qll + + blame: + 16 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/frameworks/RestFramework.qll + + blame: + 360 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/falcon/General.qll + + blame: + 5 + + 2022-01-19 + + + blame: + 8 + + 2022-01-19 + + + blame: + 17 + + 2022-01-19 + + + blame: + 21 + + 2022-01-19 + + + blame: + 36 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/web/flask/Response.qll + + blame: + 10 + + 2022-01-19 + + + blame: + 23 + + 2022-01-19 + + + blame: + 40 + + 2022-01-19 + + + blame: + 44 + + 2022-01-19 + + + + file: + go/ql/lib/semmle/go/security/UnsafeUnzipSymlink.qll + + blame: + 31 + + 2022-06-17 + + + blame: + 62 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/security/injection/Xml.qll + + blame: + 14 + + 2022-01-19 + + + blame: + 18 + + 2022-01-19 + + + blame: + 20 + + 2022-01-19 + + + blame: + 22 + + 2022-01-19 + + + blame: + 24 + + 2022-01-19 + + + blame: + 28 + + 2022-01-19 + + + blame: + 32 + + 2022-01-19 + + + blame: + 40 + + 2022-01-19 + + + blame: + 51 + + 2022-01-19 + + + blame: + 59 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/flow/AnyCall.qll + + blame: + 5 + + 2022-01-19 + + + + file: + ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll + + blame: + 330 + + 2022-10-03 + + + + file: + python/ql/lib/semmle/python/security/Paths.qll + + blame: + 3 + + 2022-01-19 + + + blame: + 14 + + 2022-01-19 + + + + file: + python/ql/lib/semmle/python/security/injection/RegexInjectionCustomizations.qll + + blame: + 6 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/frameworks/j2objc/J2ObjC.qll + + blame: + 20 + + 2022-08-18 + + + blame: + 44 + + 2022-08-18 + + + blame: + 59 + + 2022-08-18 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll + + blame: + 635 + + 2022-03-11 + + + blame: + 818 + + 2022-03-11 + + + + file: + ql/ql/src/codeql_ql/ast/internal/AstNodes.qll + + blame: + 97 + + 2022-03-11 + + + + file: + go/ql/lib/semmle/go/security/ReflectedXss.qll + + blame: + 34 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeHtmlConstructionCustomizations.qll + + blame: + 149 + + 2022-03-11 + + + blame: + 166 + + 2022-03-11 + + + + file: + java/ql/src/Security/CWE/CWE-1104/MavenPomDependsOnBintray.ql + + blame: + 23 + + 2022-04-06 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + python/ql/lib/semmle/python/security/dataflow/StackTraceExposureQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/web/turbogears/Response.qll + + blame: + 7 + + 2022-01-19 + + + blame: + 20 + + 2022-01-19 + + + + file: + cpp/ql/lib/semmle/code/cpp/commons/Strcat.qll + + blame: + 9 + + 2022-09-26 + + + + file: + cpp/ql/lib/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll + + blame: + 83 + + 2021-10-14 + + + + file: + python/ql/lib/semmle/python/frameworks/Stdlib.qll + + blame: + 134 + + 2022-03-11 + + + blame: + 1790 + + 2022-03-11 + + + blame: + 1803 + + 2022-03-11 + + + blame: + 1807 + + 2022-03-11 + + + blame: + 1816 + + 2022-03-11 + + + blame: + 1829 + + 2022-03-11 + + + blame: + 1833 + + 2022-03-11 + + + blame: + 1842 + + 2022-03-11 + + + blame: + 1855 + + 2022-08-18 + + + blame: + 1859 + + 2022-08-18 + + + blame: + 1888 + + 2022-03-11 + + + blame: + 1901 + + 2022-03-11 + + + blame: + 1914 + + 2022-08-18 + + + blame: + 1947 + + 2022-03-11 + + + blame: + 2104 + + 2022-08-24 + + + blame: + 2315 + + 2022-03-11 + + + blame: + 2386 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/LogInjectionQuery.qll + + blame: + 26 + + 2022-06-17 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll + + blame: + 21 + + 2022-03-11 + + + + file: + csharp/ql/src/experimental/ir/implementation/internal/AliasedSSAStub.qll + + blame: + 22 + + 2022-09-09 + + + + file: + javascript/ql/lib/semmle/javascript/frameworks/Connect.qll + + blame: + 95 + + 2022-03-30 + + + blame: + 121 + + 2022-03-30 + + + + file: + swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + java/ql/lib/semmle/code/java/frameworks/JAXB.qll + + blame: + 13 + + 2022-08-24 + + + blame: + 23 + + 2022-08-24 + + + + file: + go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll + + blame: + 235 + + 2022-06-17 + + + + file: + ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll + + blame: + 3 + + 2022-05-25 + + + + file: + ruby/ql/lib/codeql/ruby/security/regexp/SuperlinearBackTracking.qll + + blame: + 40 + + 2022-11-01 + + + + file: + python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll + + blame: + 98 + + 2022-06-15 + + + blame: + 106 + + 2022-06-15 + + + blame: + 358 + + 2022-06-15 + + + blame: + 365 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedInitialization.qll + + blame: + 148 + + 2022-03-11 + + + blame: + 490 + + 2022-03-11 + + + blame: + 640 + + 2022-03-11 + + + blame: + 827 + + 2022-03-11 + + + blame: + 956 + + 2022-03-11 + + + + file: + ql/ql/src/queries/style/NonDocBlock.ql + + blame: + 85 + + 2022-03-08 + + + + file: + javascript/ql/lib/Expressions/DOMProperties.qll + + blame: + 8 + + 2022-03-11 + + + blame: + 19 + + 2022-03-11 + + + + file: + cpp/ql/lib/semmle/code/cpp/models/interfaces/FunctionInputsAndOutputs.qll + + blame: + 47 + + 2021-10-14 + + + blame: + 93 + + 2021-10-14 + + + blame: + 132 + + 2021-10-14 + + + blame: + 405 + + 2021-10-14 + + + blame: + 444 + + 2021-10-14 + + + blame: + 469 + + 2021-10-14 + + + blame: + 517 + + 2021-10-14 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/Operand.qll + + blame: + 95 + + 2021-10-14 + + + blame: + 104 + + 2021-10-14 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll + + blame: + 23 + + 2022-10-07 + + + blame: + 132 + + 2022-10-07 + + + blame: + 259 + + 2022-03-11 + + + blame: + 320 + + 2022-10-07 + + + blame: + 431 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/xml/XML.qll + + blame: + 36 + + 2022-08-16 + + + blame: + 99 + + 2022-08-16 + + + blame: + 116 + + 2021-10-14 + + + blame: + 123 + + 2021-10-14 + + + blame: + 138 + + 2022-08-23 + + + blame: + 142 + + 2022-08-16 + + + blame: + 181 + + 2022-08-23 + + + blame: + 239 + + 2022-08-16 + + + blame: + 272 + + 2022-08-16 + + + blame: + 291 + + 2022-08-22 + + + blame: + 304 + + 2022-08-16 + + + blame: + 327 + + 2022-08-16 + + + blame: + 354 + + 2022-08-16 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CodeInjection.qll + + blame: + 8 + + 2022-03-21 + + + blame: + 13 + + 2022-03-21 + + + + file: + python/ql/lib/semmle/python/web/stdlib/Response.qll + + blame: + 9 + + 2022-01-19 + + + blame: + 22 + + 2022-01-19 + + + blame: + 34 + + 2022-01-19 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll + + blame: + 91 + + 2022-08-24 + + + blame: + 141 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/web/cherrypy/Request.qll + + blame: + 8 + + 2022-01-19 + + + blame: + 23 + + 2022-01-19 + + + blame: + 37 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll + + blame: + 338 + + 2022-06-15 + + + + file: + cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TOperand.qll + + blame: + 78 + + 2022-03-11 + + + blame: + 88 + + 2022-03-11 + + + blame: + 171 + + 2022-03-11 + + + blame: + 222 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/CodeInjectionCustomizations.qll + + blame: + 39 + + 2022-06-17 + + + + file: + csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll + + blame: + 370 + + 2022-03-11 + + + + file: + csharp/ql/lib/semmle/code/csharp/security/dataflow/LDAPInjectionQuery.qll + + blame: + 125 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/frameworks/spring/SpringFlex.qll + + blame: + 61 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/PathInjectionQuery.qll + + blame: + 54 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/dataflow/new/Regexp.qll + + blame: + 12 + + 2022-12-15 + + + blame: + 17 + + 2022-12-15 + + + + file: + go/ql/lib/semmle/go/security/StoredCommand.qll + + blame: + 38 + + 2022-06-17 + + + + file: + python/ql/lib/semmle/python/frameworks/FastApi.qll + + blame: + 41 + + 2022-03-11 + + + + file: + python/ql/lib/semmle/python/security/dataflow/XpathInjectionCustomizations.qll + + blame: + 37 + + 2022-06-17 + + + + file: + python/ql/src/experimental/semmle/python/security/injection/NoSQLInjection.qll + + blame: + 57 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/DefUse.qll + + blame: + 252 + + 2022-03-14 + + + blame: + 269 + + 2022-03-13 + + + blame: + 280 + + 2022-03-13 + + + blame: + 288 + + 2022-03-14 + + + blame: + 304 + + 2022-03-13 + + + + file: + javascript/ql/test/tutorials/Validating RAML-based APIs/Osprey.qll + + blame: + 34 + + 2022-03-11 + + + blame: + 44 + + 2022-03-11 + + + blame: + 57 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/InsecureDownloadCustomizations.qll + + blame: + 55 + + 2022-03-11 + + + blame: + 65 + + 2022-03-11 + + + blame: + 131 + + 2022-03-11 + + + + file: + java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll + + blame: + 124 + + 2022-06-15 + + + blame: + 126 + + 2022-06-15 + + + blame: + 136 + + 2022-06-15 + + + blame: + 140 + + 2022-06-15 + + + + file: + javascript/ql/test/library-tests/frameworks/ReactJS/ReactName.qll + + blame: + 20 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/SourceMaps.qll + + blame: + 28 + + 2022-03-11 + + + + file: + python/ql/src/experimental/semmle/python/templates/Chameleon.qll + + blame: + 8 + + 2022-01-20 + + + blame: + 18 + + 2022-01-20 + + + + file: + python/ql/lib/semmle/python/security/injection/Exec.qll + + blame: + 17 + + 2022-01-19 + + + + file: + java/ql/lib/semmle/code/java/frameworks/javaee/jsf/JSFFacesContextXML.qll + + blame: + 20 + + 2022-03-11 + + + blame: + 35 + + 2022-03-11 + + + + file: + csharp/ql/lib/semmle/code/csharp/Type.qll + + blame: + 786 + + 2022-01-17 + + + + file: + ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll + + blame: + 98 + + 2022-09-06 + + + blame: + 106 + + 2022-09-06 + + + blame: + 358 + + 2022-09-06 + + + blame: + 365 + + 2022-09-06 + + + + file: + cpp/ql/lib/semmle/code/cpp/MemberFunction.qll + + blame: + 224 + + 2020-11-26 + + + + file: + python/ql/lib/semmle/python/web/client/Requests.qll + + blame: + 9 + + 2022-01-19 + + + + file: + javascript/ql/lib/semmle/javascript/security/dataflow/ImproperCodeSanitizationCustomizations.qll + + blame: + 39 + + 2022-03-11 + + + + file: + javascript/ql/lib/semmle/javascript/Functions.qll + + blame: + 90 + + 2021-11-01 + + + + diff --git a/ql/buramu/tree-sitter-blame/grammar.js b/ql/buramu/tree-sitter-blame/grammar.js new file mode 100644 index 00000000000..7941c0edab3 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/grammar.js @@ -0,0 +1,30 @@ +module.exports = grammar({ + name: "blame", + + extras: $ => [/\s/], + + rules: { + blame_info: $ => seq($._today, repeat(field('file_entry', $.file_entry))), + + _today: $ => seq("today:", field('today', $.date)), + + file_entry: $ => seq( + "file: ", + field('file_name', $.filename), + "\n", + repeat(field('blame_entry', $.blame_entry)) + ), + + blame_entry: $ => seq( + "last_modified:", + field('date', $.date), + repeat(field('line', $.number)), + ), + + date: $ => /\d{4}-\d{2}-\d{2}/, + + filename: $ => /[a-zA-Z0-9_\-\.\/ ]+/, + + number: $ => /\d+/, + } +}); diff --git a/ql/buramu/tree-sitter-blame/package.json b/ql/buramu/tree-sitter-blame/package.json new file mode 100644 index 00000000000..f9517c74da5 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/package.json @@ -0,0 +1,19 @@ +{ + "name": "tree-sitter-blame", + "version": "0.0.1", + "description": "blame grammar for tree-sitter", + "main": "bindings/node", + "keywords": [ + "parsing", + "incremental" + ], + "dependencies": { + "nan": "^2.12.1" + }, + "devDependencies": { + "tree-sitter-cli": "^0.20.7" + }, + "scripts": { + "test": "tree-sitter test" + } +} diff --git a/ql/buramu/tree-sitter-blame/src/grammar.json b/ql/buramu/tree-sitter-blame/src/grammar.json new file mode 100644 index 00000000000..9001554fd16 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/src/grammar.json @@ -0,0 +1,126 @@ +{ + "name": "blame", + "rules": { + "blame_info": { + "type": "SEQ", + "members": [ + { + "type": "SYMBOL", + "name": "_today" + }, + { + "type": "REPEAT", + "content": { + "type": "FIELD", + "name": "file_entry", + "content": { + "type": "SYMBOL", + "name": "file_entry" + } + } + } + ] + }, + "_today": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "today:" + }, + { + "type": "FIELD", + "name": "today", + "content": { + "type": "SYMBOL", + "name": "date" + } + } + ] + }, + "file_entry": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "file: " + }, + { + "type": "FIELD", + "name": "file_name", + "content": { + "type": "SYMBOL", + "name": "filename" + } + }, + { + "type": "STRING", + "value": "\n" + }, + { + "type": "REPEAT", + "content": { + "type": "FIELD", + "name": "blame_entry", + "content": { + "type": "SYMBOL", + "name": "blame_entry" + } + } + } + ] + }, + "blame_entry": { + "type": "SEQ", + "members": [ + { + "type": "STRING", + "value": "last_modified:" + }, + { + "type": "FIELD", + "name": "date", + "content": { + "type": "SYMBOL", + "name": "date" + } + }, + { + "type": "REPEAT", + "content": { + "type": "FIELD", + "name": "line", + "content": { + "type": "SYMBOL", + "name": "number" + } + } + } + ] + }, + "date": { + "type": "PATTERN", + "value": "\\d{4}-\\d{2}-\\d{2}" + }, + "filename": { + "type": "PATTERN", + "value": "[a-zA-Z0-9_\\-\\.\\/ ]+" + }, + "number": { + "type": "PATTERN", + "value": "\\d+" + } + }, + "extras": [ + { + "type": "PATTERN", + "value": "\\s" + } + ], + "conflicts": [], + "precedences": [], + "externals": [], + "inline": [], + "supertypes": [] +} + diff --git a/ql/buramu/tree-sitter-blame/src/node-types.json b/ql/buramu/tree-sitter-blame/src/node-types.json new file mode 100644 index 00000000000..b1ee2ad7224 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/src/node-types.json @@ -0,0 +1,108 @@ +[ + { + "type": "blame_entry", + "named": true, + "fields": { + "date": { + "multiple": false, + "required": true, + "types": [ + { + "type": "date", + "named": true + } + ] + }, + "line": { + "multiple": true, + "required": false, + "types": [ + { + "type": "number", + "named": true + } + ] + } + } + }, + { + "type": "blame_info", + "named": true, + "fields": { + "file_entry": { + "multiple": true, + "required": false, + "types": [ + { + "type": "file_entry", + "named": true + } + ] + }, + "today": { + "multiple": false, + "required": true, + "types": [ + { + "type": "date", + "named": true + } + ] + } + } + }, + { + "type": "file_entry", + "named": true, + "fields": { + "blame_entry": { + "multiple": true, + "required": false, + "types": [ + { + "type": "blame_entry", + "named": true + } + ] + }, + "file_name": { + "multiple": false, + "required": true, + "types": [ + { + "type": "filename", + "named": true + } + ] + } + } + }, + { + "type": "\n", + "named": false + }, + { + "type": "date", + "named": true + }, + { + "type": "file: ", + "named": false + }, + { + "type": "filename", + "named": true + }, + { + "type": "last_modified:", + "named": false + }, + { + "type": "number", + "named": true + }, + { + "type": "today:", + "named": false + } +] \ No newline at end of file diff --git a/ql/buramu/tree-sitter-blame/src/parser.c b/ql/buramu/tree-sitter-blame/src/parser.c new file mode 100644 index 00000000000..4803597f566 --- /dev/null +++ b/ql/buramu/tree-sitter-blame/src/parser.c @@ -0,0 +1,691 @@ +#include + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +#define LANGUAGE_VERSION 14 +#define STATE_COUNT 20 +#define LARGE_STATE_COUNT 2 +#define SYMBOL_COUNT 15 +#define ALIAS_COUNT 0 +#define TOKEN_COUNT 8 +#define EXTERNAL_TOKEN_COUNT 0 +#define FIELD_COUNT 6 +#define MAX_ALIAS_SEQUENCE_LENGTH 4 +#define PRODUCTION_ID_COUNT 14 + +enum { + anon_sym_today_COLON = 1, + anon_sym_file_COLON = 2, + anon_sym_LF = 3, + anon_sym_last_modified_COLON = 4, + sym_date = 5, + sym_filename = 6, + sym_number = 7, + sym_blame_info = 8, + sym__today = 9, + sym_file_entry = 10, + sym_blame_entry = 11, + aux_sym_blame_info_repeat1 = 12, + aux_sym_file_entry_repeat1 = 13, + aux_sym_blame_entry_repeat1 = 14, +}; + +static const char * const ts_symbol_names[] = { + [ts_builtin_sym_end] = "end", + [anon_sym_today_COLON] = "today:", + [anon_sym_file_COLON] = "file: ", + [anon_sym_LF] = "\n", + [anon_sym_last_modified_COLON] = "last_modified:", + [sym_date] = "date", + [sym_filename] = "filename", + [sym_number] = "number", + [sym_blame_info] = "blame_info", + [sym__today] = "_today", + [sym_file_entry] = "file_entry", + [sym_blame_entry] = "blame_entry", + [aux_sym_blame_info_repeat1] = "blame_info_repeat1", + [aux_sym_file_entry_repeat1] = "file_entry_repeat1", + [aux_sym_blame_entry_repeat1] = "blame_entry_repeat1", +}; + +static const TSSymbol ts_symbol_map[] = { + [ts_builtin_sym_end] = ts_builtin_sym_end, + [anon_sym_today_COLON] = anon_sym_today_COLON, + [anon_sym_file_COLON] = anon_sym_file_COLON, + [anon_sym_LF] = anon_sym_LF, + [anon_sym_last_modified_COLON] = anon_sym_last_modified_COLON, + [sym_date] = sym_date, + [sym_filename] = sym_filename, + [sym_number] = sym_number, + [sym_blame_info] = sym_blame_info, + [sym__today] = sym__today, + [sym_file_entry] = sym_file_entry, + [sym_blame_entry] = sym_blame_entry, + [aux_sym_blame_info_repeat1] = aux_sym_blame_info_repeat1, + [aux_sym_file_entry_repeat1] = aux_sym_file_entry_repeat1, + [aux_sym_blame_entry_repeat1] = aux_sym_blame_entry_repeat1, +}; + +static const TSSymbolMetadata ts_symbol_metadata[] = { + [ts_builtin_sym_end] = { + .visible = false, + .named = true, + }, + [anon_sym_today_COLON] = { + .visible = true, + .named = false, + }, + [anon_sym_file_COLON] = { + .visible = true, + .named = false, + }, + [anon_sym_LF] = { + .visible = true, + .named = false, + }, + [anon_sym_last_modified_COLON] = { + .visible = true, + .named = false, + }, + [sym_date] = { + .visible = true, + .named = true, + }, + [sym_filename] = { + .visible = true, + .named = true, + }, + [sym_number] = { + .visible = true, + .named = true, + }, + [sym_blame_info] = { + .visible = true, + .named = true, + }, + [sym__today] = { + .visible = false, + .named = true, + }, + [sym_file_entry] = { + .visible = true, + .named = true, + }, + [sym_blame_entry] = { + .visible = true, + .named = true, + }, + [aux_sym_blame_info_repeat1] = { + .visible = false, + .named = false, + }, + [aux_sym_file_entry_repeat1] = { + .visible = false, + .named = false, + }, + [aux_sym_blame_entry_repeat1] = { + .visible = false, + .named = false, + }, +}; + +enum { + field_blame_entry = 1, + field_date = 2, + field_file_entry = 3, + field_file_name = 4, + field_line = 5, + field_today = 6, +}; + +static const char * const ts_field_names[] = { + [0] = NULL, + [field_blame_entry] = "blame_entry", + [field_date] = "date", + [field_file_entry] = "file_entry", + [field_file_name] = "file_name", + [field_line] = "line", + [field_today] = "today", +}; + +static const TSFieldMapSlice ts_field_map_slices[PRODUCTION_ID_COUNT] = { + [1] = {.index = 0, .length = 1}, + [2] = {.index = 1, .length = 1}, + [3] = {.index = 2, .length = 1}, + [4] = {.index = 3, .length = 2}, + [5] = {.index = 5, .length = 2}, + [6] = {.index = 7, .length = 1}, + [7] = {.index = 8, .length = 1}, + [8] = {.index = 9, .length = 2}, + [9] = {.index = 11, .length = 1}, + [10] = {.index = 12, .length = 2}, + [11] = {.index = 14, .length = 1}, + [12] = {.index = 15, .length = 2}, + [13] = {.index = 17, .length = 2}, +}; + +static const TSFieldMapEntry ts_field_map_entries[] = { + [0] = + {field_today, 0, .inherited = true}, + [1] = + {field_today, 1}, + [2] = + {field_file_entry, 0}, + [3] = + {field_file_entry, 1, .inherited = true}, + {field_today, 0, .inherited = true}, + [5] = + {field_file_entry, 0, .inherited = true}, + {field_file_entry, 1, .inherited = true}, + [7] = + {field_file_name, 1}, + [8] = + {field_blame_entry, 0}, + [9] = + {field_blame_entry, 3, .inherited = true}, + {field_file_name, 1}, + [11] = + {field_date, 1}, + [12] = + {field_blame_entry, 0, .inherited = true}, + {field_blame_entry, 1, .inherited = true}, + [14] = + {field_line, 0}, + [15] = + {field_date, 1}, + {field_line, 2, .inherited = true}, + [17] = + {field_line, 0, .inherited = true}, + {field_line, 1, .inherited = true}, +}; + +static const TSSymbol ts_alias_sequences[PRODUCTION_ID_COUNT][MAX_ALIAS_SEQUENCE_LENGTH] = { + [0] = {0}, +}; + +static const uint16_t ts_non_terminal_alias_map[] = { + 0, +}; + +static const TSStateId ts_primary_state_ids[STATE_COUNT] = { + [0] = 0, + [1] = 1, + [2] = 2, + [3] = 3, + [4] = 4, + [5] = 5, + [6] = 6, + [7] = 7, + [8] = 8, + [9] = 9, + [10] = 10, + [11] = 11, + [12] = 12, + [13] = 13, + [14] = 14, + [15] = 15, + [16] = 16, + [17] = 17, + [18] = 18, + [19] = 19, +}; + +static bool ts_lex(TSLexer *lexer, TSStateId state) { + START_LEXER(); + eof = lexer->eof(lexer); + switch (state) { + case 0: + if (eof) ADVANCE(37); + if (lookahead == 'f') ADVANCE(18); + if (lookahead == 'l') ADVANCE(10); + if (lookahead == 't') ADVANCE(23); + if (lookahead == '\t' || + lookahead == '\n' || + lookahead == '\r' || + lookahead == ' ') SKIP(0) + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(48); + END_STATE(); + case 1: + if (lookahead == '\n') ADVANCE(40); + if (lookahead == '\t' || + lookahead == '\r' || + lookahead == ' ') SKIP(1) + END_STATE(); + case 2: + if (lookahead == ' ') ADVANCE(39); + END_STATE(); + case 3: + if (lookahead == ' ') ADVANCE(43); + if (lookahead == '\t' || + lookahead == '\n' || + lookahead == '\r') SKIP(3) + if (('-' <= lookahead && lookahead <= '9') || + ('A' <= lookahead && lookahead <= 'Z') || + lookahead == '_' || + ('a' <= lookahead && lookahead <= 'z')) ADVANCE(44); + END_STATE(); + case 4: + if (lookahead == '-') ADVANCE(31); + END_STATE(); + case 5: + if (lookahead == '-') ADVANCE(32); + END_STATE(); + case 6: + if (lookahead == ':') ADVANCE(2); + END_STATE(); + case 7: + if (lookahead == ':') ADVANCE(38); + END_STATE(); + case 8: + if (lookahead == ':') ADVANCE(41); + END_STATE(); + case 9: + if (lookahead == '_') ADVANCE(22); + END_STATE(); + case 10: + if (lookahead == 'a') ADVANCE(25); + END_STATE(); + case 11: + if (lookahead == 'a') ADVANCE(27); + END_STATE(); + case 12: + if (lookahead == 'd') ADVANCE(19); + END_STATE(); + case 13: + if (lookahead == 'd') ADVANCE(11); + END_STATE(); + case 14: + if (lookahead == 'd') ADVANCE(8); + END_STATE(); + case 15: + if (lookahead == 'e') ADVANCE(6); + END_STATE(); + case 16: + if (lookahead == 'e') ADVANCE(14); + END_STATE(); + case 17: + if (lookahead == 'f') ADVANCE(20); + END_STATE(); + case 18: + if (lookahead == 'i') ADVANCE(21); + END_STATE(); + case 19: + if (lookahead == 'i') ADVANCE(17); + END_STATE(); + case 20: + if (lookahead == 'i') ADVANCE(16); + END_STATE(); + case 21: + if (lookahead == 'l') ADVANCE(15); + END_STATE(); + case 22: + if (lookahead == 'm') ADVANCE(24); + END_STATE(); + case 23: + if (lookahead == 'o') ADVANCE(13); + END_STATE(); + case 24: + if (lookahead == 'o') ADVANCE(12); + END_STATE(); + case 25: + if (lookahead == 's') ADVANCE(26); + END_STATE(); + case 26: + if (lookahead == 't') ADVANCE(9); + END_STATE(); + case 27: + if (lookahead == 'y') ADVANCE(7); + END_STATE(); + case 28: + if (lookahead == '\t' || + lookahead == '\n' || + lookahead == '\r' || + lookahead == ' ') SKIP(28) + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(35); + END_STATE(); + case 29: + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(5); + END_STATE(); + case 30: + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(42); + END_STATE(); + case 31: + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(29); + END_STATE(); + case 32: + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(30); + END_STATE(); + case 33: + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(4); + END_STATE(); + case 34: + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(33); + END_STATE(); + case 35: + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(34); + END_STATE(); + case 36: + if (eof) ADVANCE(37); + if (lookahead == 'f') ADVANCE(18); + if (lookahead == 'l') ADVANCE(10); + if (lookahead == '\t' || + lookahead == '\n' || + lookahead == '\r' || + lookahead == ' ') SKIP(36) + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(49); + END_STATE(); + case 37: + ACCEPT_TOKEN(ts_builtin_sym_end); + END_STATE(); + case 38: + ACCEPT_TOKEN(anon_sym_today_COLON); + END_STATE(); + case 39: + ACCEPT_TOKEN(anon_sym_file_COLON); + END_STATE(); + case 40: + ACCEPT_TOKEN(anon_sym_LF); + if (lookahead == '\n') ADVANCE(40); + END_STATE(); + case 41: + ACCEPT_TOKEN(anon_sym_last_modified_COLON); + END_STATE(); + case 42: + ACCEPT_TOKEN(sym_date); + END_STATE(); + case 43: + ACCEPT_TOKEN(sym_filename); + if (lookahead == ' ') ADVANCE(43); + if (('-' <= lookahead && lookahead <= '9') || + ('A' <= lookahead && lookahead <= 'Z') || + lookahead == '_' || + ('a' <= lookahead && lookahead <= 'z')) ADVANCE(44); + END_STATE(); + case 44: + ACCEPT_TOKEN(sym_filename); + if (lookahead == ' ' || + ('-' <= lookahead && lookahead <= '9') || + ('A' <= lookahead && lookahead <= 'Z') || + lookahead == '_' || + ('a' <= lookahead && lookahead <= 'z')) ADVANCE(44); + END_STATE(); + case 45: + ACCEPT_TOKEN(sym_number); + if (lookahead == '-') ADVANCE(31); + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(49); + END_STATE(); + case 46: + ACCEPT_TOKEN(sym_number); + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(45); + END_STATE(); + case 47: + ACCEPT_TOKEN(sym_number); + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(46); + END_STATE(); + case 48: + ACCEPT_TOKEN(sym_number); + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(47); + END_STATE(); + case 49: + ACCEPT_TOKEN(sym_number); + if (('0' <= lookahead && lookahead <= '9')) ADVANCE(49); + END_STATE(); + default: + return false; + } +} + +static const TSLexMode ts_lex_modes[STATE_COUNT] = { + [0] = {.lex_state = 0}, + [1] = {.lex_state = 0}, + [2] = {.lex_state = 0}, + [3] = {.lex_state = 0}, + [4] = {.lex_state = 36}, + [5] = {.lex_state = 0}, + [6] = {.lex_state = 36}, + [7] = {.lex_state = 36}, + [8] = {.lex_state = 0}, + [9] = {.lex_state = 0}, + [10] = {.lex_state = 0}, + [11] = {.lex_state = 36}, + [12] = {.lex_state = 0}, + [13] = {.lex_state = 0}, + [14] = {.lex_state = 0}, + [15] = {.lex_state = 28}, + [16] = {.lex_state = 0}, + [17] = {.lex_state = 3}, + [18] = {.lex_state = 1}, + [19] = {.lex_state = 28}, +}; + +static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { + [0] = { + [ts_builtin_sym_end] = ACTIONS(1), + [anon_sym_today_COLON] = ACTIONS(1), + [anon_sym_file_COLON] = ACTIONS(1), + [anon_sym_last_modified_COLON] = ACTIONS(1), + [sym_date] = ACTIONS(1), + [sym_number] = ACTIONS(1), + }, + [1] = { + [sym_blame_info] = STATE(16), + [sym__today] = STATE(8), + [anon_sym_today_COLON] = ACTIONS(3), + }, +}; + +static const uint16_t ts_small_parse_table[] = { + [0] = 4, + ACTIONS(7), 1, + anon_sym_last_modified_COLON, + STATE(3), 1, + aux_sym_file_entry_repeat1, + STATE(12), 1, + sym_blame_entry, + ACTIONS(5), 2, + ts_builtin_sym_end, + anon_sym_file_COLON, + [14] = 4, + ACTIONS(7), 1, + anon_sym_last_modified_COLON, + STATE(5), 1, + aux_sym_file_entry_repeat1, + STATE(12), 1, + sym_blame_entry, + ACTIONS(9), 2, + ts_builtin_sym_end, + anon_sym_file_COLON, + [28] = 3, + ACTIONS(13), 1, + sym_number, + STATE(6), 1, + aux_sym_blame_entry_repeat1, + ACTIONS(11), 3, + ts_builtin_sym_end, + anon_sym_file_COLON, + anon_sym_last_modified_COLON, + [40] = 4, + ACTIONS(17), 1, + anon_sym_last_modified_COLON, + STATE(5), 1, + aux_sym_file_entry_repeat1, + STATE(12), 1, + sym_blame_entry, + ACTIONS(15), 2, + ts_builtin_sym_end, + anon_sym_file_COLON, + [54] = 3, + ACTIONS(13), 1, + sym_number, + STATE(7), 1, + aux_sym_blame_entry_repeat1, + ACTIONS(20), 3, + ts_builtin_sym_end, + anon_sym_file_COLON, + anon_sym_last_modified_COLON, + [66] = 3, + ACTIONS(24), 1, + sym_number, + STATE(7), 1, + aux_sym_blame_entry_repeat1, + ACTIONS(22), 3, + ts_builtin_sym_end, + anon_sym_file_COLON, + anon_sym_last_modified_COLON, + [78] = 4, + ACTIONS(27), 1, + ts_builtin_sym_end, + ACTIONS(29), 1, + anon_sym_file_COLON, + STATE(9), 1, + aux_sym_blame_info_repeat1, + STATE(14), 1, + sym_file_entry, + [91] = 4, + ACTIONS(29), 1, + anon_sym_file_COLON, + ACTIONS(31), 1, + ts_builtin_sym_end, + STATE(10), 1, + aux_sym_blame_info_repeat1, + STATE(14), 1, + sym_file_entry, + [104] = 4, + ACTIONS(33), 1, + ts_builtin_sym_end, + ACTIONS(35), 1, + anon_sym_file_COLON, + STATE(10), 1, + aux_sym_blame_info_repeat1, + STATE(14), 1, + sym_file_entry, + [117] = 1, + ACTIONS(38), 4, + ts_builtin_sym_end, + anon_sym_file_COLON, + anon_sym_last_modified_COLON, + sym_number, + [124] = 1, + ACTIONS(40), 3, + ts_builtin_sym_end, + anon_sym_file_COLON, + anon_sym_last_modified_COLON, + [130] = 1, + ACTIONS(42), 2, + ts_builtin_sym_end, + anon_sym_file_COLON, + [135] = 1, + ACTIONS(44), 2, + ts_builtin_sym_end, + anon_sym_file_COLON, + [140] = 1, + ACTIONS(46), 1, + sym_date, + [144] = 1, + ACTIONS(48), 1, + ts_builtin_sym_end, + [148] = 1, + ACTIONS(50), 1, + sym_filename, + [152] = 1, + ACTIONS(52), 1, + anon_sym_LF, + [156] = 1, + ACTIONS(54), 1, + sym_date, +}; + +static const uint32_t ts_small_parse_table_map[] = { + [SMALL_STATE(2)] = 0, + [SMALL_STATE(3)] = 14, + [SMALL_STATE(4)] = 28, + [SMALL_STATE(5)] = 40, + [SMALL_STATE(6)] = 54, + [SMALL_STATE(7)] = 66, + [SMALL_STATE(8)] = 78, + [SMALL_STATE(9)] = 91, + [SMALL_STATE(10)] = 104, + [SMALL_STATE(11)] = 117, + [SMALL_STATE(12)] = 124, + [SMALL_STATE(13)] = 130, + [SMALL_STATE(14)] = 135, + [SMALL_STATE(15)] = 140, + [SMALL_STATE(16)] = 144, + [SMALL_STATE(17)] = 148, + [SMALL_STATE(18)] = 152, + [SMALL_STATE(19)] = 156, +}; + +static const TSParseActionEntry ts_parse_actions[] = { + [0] = {.entry = {.count = 0, .reusable = false}}, + [1] = {.entry = {.count = 1, .reusable = false}}, RECOVER(), + [3] = {.entry = {.count = 1, .reusable = true}}, SHIFT(15), + [5] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_file_entry, 3, .production_id = 6), + [7] = {.entry = {.count = 1, .reusable = true}}, SHIFT(19), + [9] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_file_entry, 4, .production_id = 8), + [11] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_blame_entry, 2, .production_id = 9), + [13] = {.entry = {.count = 1, .reusable = true}}, SHIFT(11), + [15] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_file_entry_repeat1, 2, .production_id = 10), + [17] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_file_entry_repeat1, 2, .production_id = 10), SHIFT_REPEAT(19), + [20] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_blame_entry, 3, .production_id = 12), + [22] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_blame_entry_repeat1, 2, .production_id = 13), + [24] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_blame_entry_repeat1, 2, .production_id = 13), SHIFT_REPEAT(11), + [27] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_blame_info, 1, .production_id = 1), + [29] = {.entry = {.count = 1, .reusable = true}}, SHIFT(17), + [31] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_blame_info, 2, .production_id = 4), + [33] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_blame_info_repeat1, 2, .production_id = 5), + [35] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_blame_info_repeat1, 2, .production_id = 5), SHIFT_REPEAT(17), + [38] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_blame_entry_repeat1, 1, .production_id = 11), + [40] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_file_entry_repeat1, 1, .production_id = 7), + [42] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym__today, 2, .production_id = 2), + [44] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_blame_info_repeat1, 1, .production_id = 3), + [46] = {.entry = {.count = 1, .reusable = true}}, SHIFT(13), + [48] = {.entry = {.count = 1, .reusable = true}}, ACCEPT_INPUT(), + [50] = {.entry = {.count = 1, .reusable = true}}, SHIFT(18), + [52] = {.entry = {.count = 1, .reusable = true}}, SHIFT(2), + [54] = {.entry = {.count = 1, .reusable = true}}, SHIFT(4), +}; + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef _WIN32 +#define extern __declspec(dllexport) +#endif + +extern const TSLanguage *tree_sitter_blame(void) { + static const TSLanguage language = { + .version = LANGUAGE_VERSION, + .symbol_count = SYMBOL_COUNT, + .alias_count = ALIAS_COUNT, + .token_count = TOKEN_COUNT, + .external_token_count = EXTERNAL_TOKEN_COUNT, + .state_count = STATE_COUNT, + .large_state_count = LARGE_STATE_COUNT, + .production_id_count = PRODUCTION_ID_COUNT, + .field_count = FIELD_COUNT, + .max_alias_sequence_length = MAX_ALIAS_SEQUENCE_LENGTH, + .parse_table = &ts_parse_table[0][0], + .small_parse_table = ts_small_parse_table, + .small_parse_table_map = ts_small_parse_table_map, + .parse_actions = ts_parse_actions, + .symbol_names = ts_symbol_names, + .field_names = ts_field_names, + .field_map_slices = ts_field_map_slices, + .field_map_entries = ts_field_map_entries, + .symbol_metadata = ts_symbol_metadata, + .public_symbol_map = ts_symbol_map, + .alias_map = ts_non_terminal_alias_map, + .alias_sequences = &ts_alias_sequences[0][0], + .lex_modes = ts_lex_modes, + .lex_fn = ts_lex, + .primary_state_ids = ts_primary_state_ids, + }; + return &language; +} +#ifdef __cplusplus +} +#endif diff --git a/ql/buramu/tree-sitter-blame/src/tree_sitter/parser.h b/ql/buramu/tree-sitter-blame/src/tree_sitter/parser.h new file mode 100644 index 00000000000..2b14ac1046b --- /dev/null +++ b/ql/buramu/tree-sitter-blame/src/tree_sitter/parser.h @@ -0,0 +1,224 @@ +#ifndef TREE_SITTER_PARSER_H_ +#define TREE_SITTER_PARSER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define ts_builtin_sym_error ((TSSymbol)-1) +#define ts_builtin_sym_end 0 +#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 + +typedef uint16_t TSStateId; + +#ifndef TREE_SITTER_API_H_ +typedef uint16_t TSSymbol; +typedef uint16_t TSFieldId; +typedef struct TSLanguage TSLanguage; +#endif + +typedef struct { + TSFieldId field_id; + uint8_t child_index; + bool inherited; +} TSFieldMapEntry; + +typedef struct { + uint16_t index; + uint16_t length; +} TSFieldMapSlice; + +typedef struct { + bool visible; + bool named; + bool supertype; +} TSSymbolMetadata; + +typedef struct TSLexer TSLexer; + +struct TSLexer { + int32_t lookahead; + TSSymbol result_symbol; + void (*advance)(TSLexer *, bool); + void (*mark_end)(TSLexer *); + uint32_t (*get_column)(TSLexer *); + bool (*is_at_included_range_start)(const TSLexer *); + bool (*eof)(const TSLexer *); +}; + +typedef enum { + TSParseActionTypeShift, + TSParseActionTypeReduce, + TSParseActionTypeAccept, + TSParseActionTypeRecover, +} TSParseActionType; + +typedef union { + struct { + uint8_t type; + TSStateId state; + bool extra; + bool repetition; + } shift; + struct { + uint8_t type; + uint8_t child_count; + TSSymbol symbol; + int16_t dynamic_precedence; + uint16_t production_id; + } reduce; + uint8_t type; +} TSParseAction; + +typedef struct { + uint16_t lex_state; + uint16_t external_lex_state; +} TSLexMode; + +typedef union { + TSParseAction action; + struct { + uint8_t count; + bool reusable; + } entry; +} TSParseActionEntry; + +struct TSLanguage { + uint32_t version; + uint32_t symbol_count; + uint32_t alias_count; + uint32_t token_count; + uint32_t external_token_count; + uint32_t state_count; + uint32_t large_state_count; + uint32_t production_id_count; + uint32_t field_count; + uint16_t max_alias_sequence_length; + const uint16_t *parse_table; + const uint16_t *small_parse_table; + const uint32_t *small_parse_table_map; + const TSParseActionEntry *parse_actions; + const char * const *symbol_names; + const char * const *field_names; + const TSFieldMapSlice *field_map_slices; + const TSFieldMapEntry *field_map_entries; + const TSSymbolMetadata *symbol_metadata; + const TSSymbol *public_symbol_map; + const uint16_t *alias_map; + const TSSymbol *alias_sequences; + const TSLexMode *lex_modes; + bool (*lex_fn)(TSLexer *, TSStateId); + bool (*keyword_lex_fn)(TSLexer *, TSStateId); + TSSymbol keyword_capture_token; + struct { + const bool *states; + const TSSymbol *symbol_map; + void *(*create)(void); + void (*destroy)(void *); + bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); + unsigned (*serialize)(void *, char *); + void (*deserialize)(void *, const char *, unsigned); + } external_scanner; + const TSStateId *primary_state_ids; +}; + +/* + * Lexer Macros + */ + +#define START_LEXER() \ + bool result = false; \ + bool skip = false; \ + bool eof = false; \ + int32_t lookahead; \ + goto start; \ + next_state: \ + lexer->advance(lexer, skip); \ + start: \ + skip = false; \ + lookahead = lexer->lookahead; + +#define ADVANCE(state_value) \ + { \ + state = state_value; \ + goto next_state; \ + } + +#define SKIP(state_value) \ + { \ + skip = true; \ + state = state_value; \ + goto next_state; \ + } + +#define ACCEPT_TOKEN(symbol_value) \ + result = true; \ + lexer->result_symbol = symbol_value; \ + lexer->mark_end(lexer); + +#define END_STATE() return result; + +/* + * Parse Table Macros + */ + +#define SMALL_STATE(id) id - LARGE_STATE_COUNT + +#define STATE(id) id + +#define ACTIONS(id) id + +#define SHIFT(state_value) \ + {{ \ + .shift = { \ + .type = TSParseActionTypeShift, \ + .state = state_value \ + } \ + }} + +#define SHIFT_REPEAT(state_value) \ + {{ \ + .shift = { \ + .type = TSParseActionTypeShift, \ + .state = state_value, \ + .repetition = true \ + } \ + }} + +#define SHIFT_EXTRA() \ + {{ \ + .shift = { \ + .type = TSParseActionTypeShift, \ + .extra = true \ + } \ + }} + +#define REDUCE(symbol_val, child_count_val, ...) \ + {{ \ + .reduce = { \ + .type = TSParseActionTypeReduce, \ + .symbol = symbol_val, \ + .child_count = child_count_val, \ + __VA_ARGS__ \ + }, \ + }} + +#define RECOVER() \ + {{ \ + .type = TSParseActionTypeRecover \ + }} + +#define ACCEPT_INPUT() \ + {{ \ + .type = TSParseActionTypeAccept \ + }} + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_PARSER_H_ diff --git a/ql/buramu/tree-sitter-blame/test.blame b/ql/buramu/tree-sitter-blame/test.blame new file mode 100644 index 00000000000..a77d99fd51c --- /dev/null +++ b/ql/buramu/tree-sitter-blame/test.blame @@ -0,0 +1,24 @@ +today: 2023-02-16 +file: go/ql/lib/semmle/go/security/FlowSources.qll + blame: 33 2022-12-19 +file: python/ql/lib/semmle/python/security/BadTagFilterQuery.qll + blame: 7 2022-11-01 +file: csharp/ql/lib/semmle/code/csharp/Assignable.qll + blame: 128 2022-10-12 + blame: 499 2022-10-12 +file: python/ql/lib/semmle/python/frameworks/Starlette.qll + blame: 164 2022-09-09 +file: ql/ql/src/queries/style/docs/PredicateDocs.ql + blame: 21 2022-08-15 +file: java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll + blame: 308 2022-09-07 +file: javascript/ql/lib/semmle/javascript/frameworks/AngularJS/AngularJSCore.qll + blame: 627 2022-03-30 + blame: 633 2022-03-30 + blame: 636 2022-03-30 + blame: 639 2022-03-30 +file: javascript/ql/lib/semmle/javascript/frameworks/Testing.qll + blame: 41 2022-08-24 +file: javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll + blame: 145 2022-03-30 + blame: 1821 2022-03-13 From db748fae6b160d2aca220813c5fdcc0c653aa873 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Feb 2023 13:22:18 +0000 Subject: [PATCH 305/415] QL: Integrate blame parser into extractor --- ql/autobuilder/src/main.rs | 1 + ql/extractor/Cargo.toml | 1 + ql/extractor/src/main.rs | 13 ++ ql/generator/Cargo.toml | 3 +- ql/generator/src/main.rs | 4 + .../src/codeql_ql/ast/internal/TreeSitter.qll | 113 ++++++++++++++++++ ql/ql/src/ql.dbscheme | 62 ++++++++++ 7 files changed, 196 insertions(+), 1 deletion(-) diff --git a/ql/autobuilder/src/main.rs b/ql/autobuilder/src/main.rs index df47cc33184..eacb51a50e3 100644 --- a/ql/autobuilder/src/main.rs +++ b/ql/autobuilder/src/main.rs @@ -19,6 +19,7 @@ fn main() -> std::io::Result<()> { .arg("--include-extension=.qll") .arg("--include-extension=.dbscheme") .arg("--include=**/qlpack.yml") + .arg("--include=deprecated.blame") .arg("--size-limit=5m") .arg("--language=ql") .arg("--working-dir=.") diff --git a/ql/extractor/Cargo.toml b/ql/extractor/Cargo.toml index a3c899609e2..c76d824f27f 100644 --- a/ql/extractor/Cargo.toml +++ b/ql/extractor/Cargo.toml @@ -13,6 +13,7 @@ tree-sitter = ">= 0.20, < 0.21" tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", rev = "d08db734f8dc52f6bc04db53a966603122bc6985"} tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} +tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} clap = "2.33" tracing = "0.1" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } diff --git a/ql/extractor/src/main.rs b/ql/extractor/src/main.rs index 45cce6acdd1..6b7a190ac46 100644 --- a/ql/extractor/src/main.rs +++ b/ql/extractor/src/main.rs @@ -87,10 +87,12 @@ fn main() -> std::io::Result<()> { let language = tree_sitter_ql::language(); let dbscheme = tree_sitter_ql_dbscheme::language(); let yaml = tree_sitter_ql_yaml::language(); + let blame = tree_sitter_blame::language(); let schema = node_types::read_node_types_str("ql", tree_sitter_ql::NODE_TYPES)?; let dbscheme_schema = node_types::read_node_types_str("dbscheme", tree_sitter_ql_dbscheme::NODE_TYPES)?; let yaml_schema = node_types::read_node_types_str("yaml", tree_sitter_ql_yaml::NODE_TYPES)?; + let blame_schema = node_types::read_node_types_str("blame", tree_sitter_blame::NODE_TYPES)?; let lines: std::io::Result> = std::io::BufReader::new(file_list).lines().collect(); let lines = lines?; @@ -103,6 +105,7 @@ fn main() -> std::io::Result<()> { && !line.ends_with(".qll") && !line.ends_with(".dbscheme") && !line.ends_with("qlpack.yml") + && !line.ends_with(".blame") { return Ok(()); } @@ -131,6 +134,16 @@ fn main() -> std::io::Result<()> { &source, &code_ranges, )? + } else if line.ends_with(".blame") { + extractor::extract( + blame, + "blame", + &blame_schema, + &mut trap_writer, + &path, + &source, + &code_ranges, + )? } else { extractor::extract( language, diff --git a/ql/generator/Cargo.toml b/ql/generator/Cargo.toml index 95ae810088a..e2e92a59b8a 100644 --- a/ql/generator/Cargo.toml +++ b/ql/generator/Cargo.toml @@ -13,4 +13,5 @@ tracing = "0.1" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", rev = "d08db734f8dc52f6bc04db53a966603122bc6985"} tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} -tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} \ No newline at end of file +tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} +tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} diff --git a/ql/generator/src/main.rs b/ql/generator/src/main.rs index 5fb2cfca53d..d36cb3fb385 100644 --- a/ql/generator/src/main.rs +++ b/ql/generator/src/main.rs @@ -577,6 +577,10 @@ fn main() -> std::io::Result<()> { name: "Yaml".to_owned(), node_types: tree_sitter_ql_yaml::NODE_TYPES, }, + Language { + name: "Blame".to_owned(), + node_types: tree_sitter_blame::NODE_TYPES, + }, ]; let mut dbscheme_writer = LineWriter::new(File::create(dbscheme_path)?); write!( diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index ae5e2acfcf8..8abb5fc6ca3 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -1743,3 +1743,116 @@ module Yaml { final override AstNode getAFieldOrChild() { yaml_yaml_child(this, _, result) } } } + +module Blame { + /** The base class for all AST nodes */ + class AstNode extends @blame_ast_node { + /** Gets a string representation of this element. */ + string toString() { result = this.getAPrimaryQlClass() } + + /** Gets the location of this element. */ + final L::Location getLocation() { blame_ast_node_info(this, _, _, result) } + + /** Gets the parent of this element. */ + final AstNode getParent() { blame_ast_node_info(this, result, _, _) } + + /** Gets the index of this node among the children of its parent. */ + final int getParentIndex() { blame_ast_node_info(this, _, result, _) } + + /** Gets a field or child node of this node. */ + AstNode getAFieldOrChild() { none() } + + /** Gets the name of the primary QL class for this element. */ + string getAPrimaryQlClass() { result = "???" } + + /** Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */ + string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } + } + + /** A token. */ + class Token extends @blame_token, AstNode { + /** Gets the value of this token. */ + final string getValue() { blame_tokeninfo(this, _, result) } + + /** Gets a string representation of this element. */ + final override string toString() { result = this.getValue() } + + /** Gets the name of the primary QL class for this element. */ + override string getAPrimaryQlClass() { result = "Token" } + } + + /** A reserved word. */ + class ReservedWord extends @blame_reserved_word, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReservedWord" } + } + + /** A class representing `blame_entry` nodes. */ + class BlameEntry extends @blame_blame_entry, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BlameEntry" } + + /** Gets the node corresponding to the field `date`. */ + final Date getDate() { blame_blame_entry_def(this, result) } + + /** Gets the node corresponding to the field `line`. */ + final Number getLine(int i) { blame_blame_entry_line(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + blame_blame_entry_def(this, result) or blame_blame_entry_line(this, _, result) + } + } + + /** A class representing `blame_info` nodes. */ + class BlameInfo extends @blame_blame_info, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "BlameInfo" } + + /** Gets the node corresponding to the field `file_entry`. */ + final FileEntry getFileEntry(int i) { blame_blame_info_file_entry(this, i, result) } + + /** Gets the node corresponding to the field `today`. */ + final Date getToday() { blame_blame_info_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + blame_blame_info_file_entry(this, _, result) or blame_blame_info_def(this, result) + } + } + + /** A class representing `date` tokens. */ + class Date extends @blame_token_date, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Date" } + } + + /** A class representing `file_entry` nodes. */ + class FileEntry extends @blame_file_entry, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "FileEntry" } + + /** Gets the node corresponding to the field `blame_entry`. */ + final BlameEntry getBlameEntry(int i) { blame_file_entry_blame_entry(this, i, result) } + + /** Gets the node corresponding to the field `file_name`. */ + final Filename getFileName() { blame_file_entry_def(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + blame_file_entry_blame_entry(this, _, result) or blame_file_entry_def(this, result) + } + } + + /** A class representing `filename` tokens. */ + class Filename extends @blame_token_filename, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Filename" } + } + + /** A class representing `number` tokens. */ + class Number extends @blame_token_number, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Number" } + } +} diff --git a/ql/ql/src/ql.dbscheme b/ql/ql/src/ql.dbscheme index 6ac7bbc82b8..54befe3412b 100644 --- a/ql/ql/src/ql.dbscheme +++ b/ql/ql/src/ql.dbscheme @@ -1187,3 +1187,65 @@ yaml_ast_node_info( int loc: @location ref ); +#keyset[blame_blame_entry, index] +blame_blame_entry_line( + int blame_blame_entry: @blame_blame_entry ref, + int index: int ref, + unique int line: @blame_token_number ref +); + +blame_blame_entry_def( + unique int id: @blame_blame_entry, + int date__: @blame_token_date ref +); + +#keyset[blame_blame_info, index] +blame_blame_info_file_entry( + int blame_blame_info: @blame_blame_info ref, + int index: int ref, + unique int file_entry: @blame_file_entry ref +); + +blame_blame_info_def( + unique int id: @blame_blame_info, + int today: @blame_token_date ref +); + +#keyset[blame_file_entry, index] +blame_file_entry_blame_entry( + int blame_file_entry: @blame_file_entry ref, + int index: int ref, + unique int blame_entry: @blame_blame_entry ref +); + +blame_file_entry_def( + unique int id: @blame_file_entry, + int file_name: @blame_token_filename ref +); + +blame_tokeninfo( + unique int id: @blame_token, + int kind: int ref, + string value: string ref +); + +case @blame_token.kind of + 0 = @blame_reserved_word +| 1 = @blame_token_date +| 2 = @blame_token_filename +| 3 = @blame_token_number +; + + +@blame_ast_node = @blame_blame_entry | @blame_blame_info | @blame_file_entry | @blame_token + +@blame_ast_node_parent = @blame_ast_node | @file + +#keyset[parent, parent_index] +blame_ast_node_info( + unique int node: @blame_ast_node ref, + int parent: @blame_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + From c167919ff68c259515c5aee99e2d441f3782a060 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 17 Feb 2023 14:53:40 +0100 Subject: [PATCH 306/415] CI: make 'codeql query format' less verbose --- .github/workflows/compile-queries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile-queries.yml b/.github/workflows/compile-queries.yml index 96d8e4cc30b..f8cbe6f552c 100644 --- a/.github/workflows/compile-queries.yml +++ b/.github/workflows/compile-queries.yml @@ -24,7 +24,7 @@ jobs: with: key: all-queries - name: check formatting - run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format --check-only + run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format -q --check-only - name: compile queries - check-only # run with --check-only if running in a PR (github.sha != main) if : ${{ github.event_name == 'pull_request' }} From 87cb3fd59fc25d5197e13e485cd5788cccaa5ef0 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 17 Feb 2023 14:58:19 +0100 Subject: [PATCH 307/415] Update .github/workflows/compile-queries.yml Co-authored-by: Erik Krogh Kristensen --- .github/workflows/compile-queries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile-queries.yml b/.github/workflows/compile-queries.yml index f8cbe6f552c..b5a67059322 100644 --- a/.github/workflows/compile-queries.yml +++ b/.github/workflows/compile-queries.yml @@ -24,7 +24,7 @@ jobs: with: key: all-queries - name: check formatting - run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format -q --check-only + run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only - name: compile queries - check-only # run with --check-only if running in a PR (github.sha != main) if : ${{ github.event_name == 'pull_request' }} From 0bceefc930a1ef8b0eda8f329cf6461c91c562fa Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 17 Feb 2023 09:39:26 +0100 Subject: [PATCH 308/415] Java: Update test expectations --- .../apache-commons-lang3/StrBuilderTest.java | 4 +- .../StrBuilderTextTest.java | 4 +- .../TextStringBuilderTest.java | 4 +- .../security/CWE-079/semmle/tests/JsfXSS.java | 4 +- .../debuggable-attribute/AndroidManifest.xml | 4 +- .../Testbuild/AndroidManifest.xml | 4 +- .../security/CWE-524/res/layout/Test.xml | 12 ++--- .../security/CWE-926/AndroidManifest.xml | 48 +++++++++---------- .../AndroidManifest.xml | 8 ++-- 9 files changed, 46 insertions(+), 46 deletions(-) diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTest.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTest.java index 0c0e386e9c2..35a118f8048 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTest.java +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTest.java @@ -145,7 +145,7 @@ class StrBuilderTest { // Test all fluent methods are passing taint through to their result: StrBuilder fluentAllMethodsTest = new StrBuilder(taint()); - sink(fluentAllMethodsTest // $hasTaintFlow + sink(fluentAllMethodsTest .append("text") .appendAll("text") .appendFixedWidthPadLeft("text", 4, ' ') @@ -171,7 +171,7 @@ class StrBuilderTest { .setLength(500) .setNewLineText("newline") .setNullText("NULL") - .trim()); + .trim()); // $hasTaintFlow // Test all fluent methods are passing taint back to their qualifier: StrBuilder fluentAllMethodsTest2 = new StrBuilder(); diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTextTest.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTextTest.java index 74f0f1d17c9..43171647004 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTextTest.java +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/StrBuilderTextTest.java @@ -145,7 +145,7 @@ class StrBuilderTextTest { // Test all fluent methods are passing taint through to their result: StrBuilder fluentAllMethodsTest = new StrBuilder(taint()); - sink(fluentAllMethodsTest // $hasTaintFlow + sink(fluentAllMethodsTest .append("text") .appendAll("text") .appendFixedWidthPadLeft("text", 4, ' ') @@ -171,7 +171,7 @@ class StrBuilderTextTest { .setLength(500) .setNewLineText("newline") .setNullText("NULL") - .trim()); + .trim()); // $hasTaintFlow // Test all fluent methods are passing taint back to their qualifier: StrBuilder fluentAllMethodsTest2 = new StrBuilder(); diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/TextStringBuilderTest.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/TextStringBuilderTest.java index e490c11c7cb..41941cca223 100644 --- a/java/ql/test/library-tests/frameworks/apache-commons-lang3/TextStringBuilderTest.java +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/TextStringBuilderTest.java @@ -146,7 +146,7 @@ class TextStringBuilderTest { // Test all fluent methods are passing taint through to their result: TextStringBuilder fluentAllMethodsTest = new TextStringBuilder(taint()); - sink(fluentAllMethodsTest // $hasTaintFlow + sink(fluentAllMethodsTest .append("text") .appendAll("text") .appendFixedWidthPadLeft("text", 4, ' ') @@ -172,7 +172,7 @@ class TextStringBuilderTest { .setLength(500) .setNewLineText("newline") .setNullText("NULL") - .trim()); + .trim()); // $hasTaintFlow // Test all fluent methods are passing taint back to their qualifier: TextStringBuilder fluentAllMethodsTest2 = new TextStringBuilder(); diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java index 9fd7a1ffcae..281b89720d2 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/JsfXSS.java @@ -24,9 +24,9 @@ public class JsfXSS extends Renderer ResponseWriter writer = facesContext.getResponseWriter(); writer.write(""); diff --git a/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/AndroidManifest.xml index 78d85ecb7a5..9a915624e5e 100644 --- a/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/AndroidManifest.xml +++ b/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/AndroidManifest.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" package="com.example.happybirthday"> - + tools:targetApi="31"> diff --git a/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/Testbuild/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/Testbuild/AndroidManifest.xml index 613bc8aeca1..cb8591f3a70 100644 --- a/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/Testbuild/AndroidManifest.xml +++ b/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/Testbuild/AndroidManifest.xml @@ -3,7 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" package="com.example.happybirthday"> - + tools:targetApi="31"> diff --git a/java/ql/test/query-tests/security/CWE-524/res/layout/Test.xml b/java/ql/test/query-tests/security/CWE-524/res/layout/Test.xml index 107c13dd306..3446d530794 100644 --- a/java/ql/test/query-tests/security/CWE-524/res/layout/Test.xml +++ b/java/ql/test/query-tests/security/CWE-524/res/layout/Test.xml @@ -4,9 +4,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> - + android:inputType="text"/> - + android:inputType="textMultiLine"/> - + diff --git a/java/ql/test/query-tests/security/CWE-926/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-926/AndroidManifest.xml index 210c97b26a2..c759d38e7dd 100644 --- a/java/ql/test/query-tests/security/CWE-926/AndroidManifest.xml +++ b/java/ql/test/query-tests/security/CWE-926/AndroidManifest.xml @@ -14,58 +14,58 @@ android:theme="@style/Theme.HappyBirthday" tools:targetApi="31"> - - + - - + - - + - - + - - + - - + - - + - @@ -73,41 +73,41 @@ - + - - + - - + - - + - - + diff --git a/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/AndroidManifest.xml b/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/AndroidManifest.xml index 928dc72a665..ba2bbbb006b 100644 --- a/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/AndroidManifest.xml +++ b/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/AndroidManifest.xml @@ -17,22 +17,22 @@ - + android:readPermission="android.permission.MANAGE_DOCUMENTS"> - + android:writePermission="android.permission.MANAGE_DOCUMENTS"> From 59efcd593adc3bafef5e888c0dff2667544d56ca Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 17 Feb 2023 09:41:15 +0100 Subject: [PATCH 309/415] Python: Update test expectations --- .../frameworks/django-v2-v3/testproj/settings.py | 4 ++-- python/ql/test/library-tests/frameworks/flask/old_test.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py index f376ae752d8..d88ce4c05e3 100644 --- a/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py +++ b/python/ql/test/library-tests/frameworks/django-v2-v3/testproj/settings.py @@ -40,7 +40,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', ] -MIDDLEWARE = [ # $CsrfProtectionSetting=false +MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -48,7 +48,7 @@ MIDDLEWARE = [ # $CsrfProtectionSetting=false 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] +] # $CsrfProtectionSetting=false ROOT_URLCONF = 'testproj.urls' diff --git a/python/ql/test/library-tests/frameworks/flask/old_test.py b/python/ql/test/library-tests/frameworks/flask/old_test.py index d86c75019e5..556467fad9b 100644 --- a/python/ql/test/library-tests/frameworks/flask/old_test.py +++ b/python/ql/test/library-tests/frameworks/flask/old_test.py @@ -21,8 +21,8 @@ class MyView(MethodView): the_view = MyView.as_view('my_view') -app.add_url_rule('/the/', defaults={'user_id': None}, # $routeSetup="/the/" - view_func=the_view, methods=['GET',]) +app.add_url_rule('/the/', defaults={'user_id': None}, + view_func=the_view, methods=['GET',]) # $routeSetup="/the/" @app.route("/dangerous") # $routeSetup="/dangerous" def dangerous(): # $requestHandler From 94467e638ef359a94b6fab3b25489e2213c5cce3 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Fri, 17 Feb 2023 15:20:31 +0100 Subject: [PATCH 310/415] CI: make 'codeql query compile' less verbose --- .github/workflows/compile-queries.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-queries.yml b/.github/workflows/compile-queries.yml index b5a67059322..ac63af81ccd 100644 --- a/.github/workflows/compile-queries.yml +++ b/.github/workflows/compile-queries.yml @@ -29,9 +29,9 @@ jobs: # run with --check-only if running in a PR (github.sha != main) if : ${{ github.event_name == 'pull_request' }} shell: bash - run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" + run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" - name: compile queries - full # do full compile if running on main - this populates the cache if : ${{ github.event_name != 'pull_request' }} shell: bash - run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" + run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" From 2cfd6c5597d3788cc1a514ebd0327c780c706fd0 Mon Sep 17 00:00:00 2001 From: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Fri, 17 Feb 2023 14:26:58 +0000 Subject: [PATCH 311/415] Update misc/scripts/shared-code-metrics.py Co-authored-by: Anders Peter Fugmann --- misc/scripts/shared-code-metrics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/scripts/shared-code-metrics.py b/misc/scripts/shared-code-metrics.py index 78970b4542b..bfc613e5c87 100644 --- a/misc/scripts/shared-code-metrics.py +++ b/misc/scripts/shared-code-metrics.py @@ -1,3 +1,4 @@ +#!/bin/env python3 # Generates a report on the amount of code sharing in this repo # # The purpose of this is From 9f4f7a76c922b736d35774b90e2a0e5baf66f98c Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 17 Feb 2023 13:22:48 +0000 Subject: [PATCH 312/415] QL: Add query for outdated deprecations --- .../queries/reports/OutdatedDeprecations.ql | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 ql/ql/src/queries/reports/OutdatedDeprecations.ql diff --git a/ql/ql/src/queries/reports/OutdatedDeprecations.ql b/ql/ql/src/queries/reports/OutdatedDeprecations.ql new file mode 100644 index 00000000000..b46114d364f --- /dev/null +++ b/ql/ql/src/queries/reports/OutdatedDeprecations.ql @@ -0,0 +1,24 @@ +import ql +import codeql_ql.ast.internal.TreeSitter + +date today() { result = any(Blame::BlameInfo b).getToday().getValue().toDate() } + +class DatedDeprecation extends Annotation { + date lastModified; + + DatedDeprecation() { + this.getName() = "deprecated" and + exists(Blame::FileEntry f, Blame::BlameEntry b | + f.getFileName().getValue() = this.getLocation().getFile().getRelativePath() and + f.getBlameEntry(_) = b and + b.getLine(_).getValue().toInt() = this.getLocation().getStartLine() and + lastModified = b.getDate().getValue().toDate() + ) + } + + date getLastModified() { result = lastModified } +} + +from DatedDeprecation d +where d.getLastModified().daysTo(today()) > 365 +select d, "This deprecation is over a year old." From a9f1436930d96ebf3e6a46a96e7b61fb6926433f Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Fri, 17 Feb 2023 15:30:06 +0000 Subject: [PATCH 313/415] Test generator fixes - Revert previous change to constructor return values; as constructors are supposed to be modeled using Argument[-1] rather than ReturnValue - Fix generation of ambiguous calls when one of the conflicting methods is overridden --- .../utils/flowtestcasegenerator/FlowTestCase.qll | 2 +- .../flowtestcasegenerator/FlowTestCaseUtils.qll | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll b/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll index 9d72b1a9996..f90bbf2c908 100644 --- a/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll +++ b/java/ql/src/utils/flowtestcasegenerator/FlowTestCase.qll @@ -228,7 +228,7 @@ class TestCase extends TTestCase { */ Type getOutputType() { if baseOutput = SummaryComponentStack::return() - then result = getReturnType(callable) + then result = callable.getReturnType() else exists(int i | baseOutput = SummaryComponentStack::argument(i) and diff --git a/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll b/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll index 4c4979e1285..8855d7af7a6 100644 --- a/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll +++ b/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll @@ -16,11 +16,6 @@ Type getRootSourceDeclaration(Type t) { else result = t } -/** Gets the return type of the callable c, or the constructed tpe if it's a constructor */ -Type getReturnType(Callable c) { - if c instanceof Constructor then result = c.getDeclaringType() else result = c.getReturnType() -} - /** * Holds if type `t` does not clash with another type we want to import that has the same base name. */ @@ -69,11 +64,12 @@ string getZero(PrimitiveType t) { * Holds if `c` may require disambiguation from an overload with the same argument count. */ predicate mayBeAmbiguous(Callable c) { - exists(Callable other, string package, string type, string name | - c.hasQualifiedName(package, type, name) and + exists(Callable other, Callable override, string package, string type, string name | + override = [c, c.(Method).getASourceOverriddenMethod*()] and + override.hasQualifiedName(package, type, name) and other.hasQualifiedName(package, type, name) and - other.getNumberOfParameters() = c.getNumberOfParameters() and - other != c + other.getNumberOfParameters() = override.getNumberOfParameters() and + other != override ) or c.isVarargs() From e400a1ad77d125594d097404eba26f76243e4109 Mon Sep 17 00:00:00 2001 From: Calum Grant <42069085+calumgrant@users.noreply.github.com> Date: Fri, 17 Feb 2023 15:48:24 +0000 Subject: [PATCH 314/415] Update CODEOWNERS As agreed in the retro, we'll make all dynamic team members responsible for PRs --- CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 42fb364418f..27ac245e959 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -2,9 +2,9 @@ /csharp/ @github/codeql-csharp /go/ @github/codeql-go /java/ @github/codeql-java -/javascript/ @github/codeql-javascript -/python/ @github/codeql-python -/ruby/ @github/codeql-ruby +/javascript/ @github/codeql-dynamic +/python/ @github/codeql-dynamic +/ruby/ @github/codeql-dynamic /swift/ @github/codeql-swift /java/kotlin-extractor/ @github/codeql-kotlin /java/kotlin-explorer/ @github/codeql-kotlin From 5d125572ec3daa563ff717b65432804d38036dfe Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 17 Feb 2023 18:01:45 +0000 Subject: [PATCH 315/415] Swift: Test for FileManager taint sources. --- .../dataflow/flowsources/filemanager.swift | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift diff --git a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift new file mode 100644 index 00000000000..374e67e74a6 --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift @@ -0,0 +1,52 @@ +// --- stubs --- + +class NSObject { +} + +struct URL { +} + +struct URLResourceKey { +} + +struct Data { +} + +class FileManager : NSObject { + struct DirectoryEnumerationOptions : OptionSet{ + let rawValue: Int + } + + func contentsOfDirectory(at url: URL, includingPropertyForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL] { return [] } + func contentsOfDirectory(atPath path: String) throws -> [String] { return [] } + func directoryContents(atPath path: String) -> [Any]? { return [] } // returns array of NSString + func subpathsOfDirectory(atPath path: String) throws -> [String] { return [] } + func subpaths(atPath path: String) -> [String]? { return [] } + + func destinationOfSymbolicLink(atPath path: String) throws -> String { return "" } + func pathContentOfSymbolicLink(atPath path: String) -> String? { return "" } + + func contents(atPath path: String) -> Data? { return nil } +} + +// --- tests --- + +func testFileHandle(fm: FileManager, url: URL, path: String) { + do + { + let contents1 = try fm.contentsOfDirectory(at: url, includingPropertyForKeys: nil) // SOURCE + let content1 = contents1[0] + let contents2 = try fm.contentsOfDirectory(atPath: path) // SOURCE + let contents3 = fm.directoryContents(atPath: path)! // SOURCE + + let subpaths1 = try fm.subpathsOfDirectory(atPath: path) // SOURCE + let subpaths2 = fm.subpaths(atPath: path)! // SOURCE + + let link1 = try fm.destinationOfSymbolicLink(atPath: path) // SOURCE + let link2 = fm.pathContentOfSymbolicLink(atPath: path)! // SOURCE + + let data = fm.contents(atPath: path)! // SOURCE + } catch { + // ... + } +} From 4d1608aafa13b44aff11d4694326925a63a5785d Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 17 Feb 2023 18:53:18 +0000 Subject: [PATCH 316/415] Go integer conversion: check against sink, not source signedness --- .../IncorrectIntegerConversionLib.qll | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll b/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll index 060832cfffc..1c0b647e91f 100644 --- a/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll +++ b/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll @@ -56,14 +56,14 @@ private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSiz * integer types, which could cause unexpected values. */ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { - boolean sourceIsSigned; + boolean sinkIsSigned; int sourceBitSize; int sinkBitSize; ConversionWithoutBoundsCheckConfig() { - sourceIsSigned in [true, false] and + sinkIsSigned in [true, false] and isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and - this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sourceIsSigned + sinkBitSize + this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sinkIsSigned + sinkBitSize } /** Gets the bit size of the source. */ @@ -75,11 +75,6 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { | c.getTarget() = ip and source = c.getResult(0) | - ( - if ip.getResultType(0) instanceof SignedIntegerType - then sourceIsSigned = true - else sourceIsSigned = false - ) and ( apparentBitSize = ip.getTargetBitSize() or @@ -112,10 +107,13 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { predicate isSinkWithBitSize(DataFlow::TypeCastNode sink, int bitSize) { sink.asExpr() instanceof ConversionExpr and exists(IntegerType integerType | sink.getResultType().getUnderlyingType() = integerType | - bitSize = integerType.getSize() - or - not exists(integerType.getSize()) and - bitSize = getIntTypeBitSize(sink.getFile()) + ( + bitSize = integerType.getSize() + or + not exists(integerType.getSize()) and + bitSize = getIntTypeBitSize(sink.getFile()) + ) and + if integerType instanceof SignedIntegerType then sinkIsSigned = true else sinkIsSigned = false ) and not exists(ShrExpr shrExpr | shrExpr.getLeftOperand().getGlobalValueNumber() = @@ -134,7 +132,7 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32 | node = DataFlow::BarrierGuard::getABarrierNodeForGuard(g) and - g.isBoundFor(bitSize, sourceIsSigned) + g.isBoundFor(bitSize, sinkIsSigned) ) } From 4e86edf4fe7dea14faddc7b8e35095ee87be3d4a Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 17 Feb 2023 19:16:36 +0000 Subject: [PATCH 317/415] Add test case --- .../query-tests/Security/CWE-681/IncorrectIntegerConversion.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go index 92782b7ad67..e5298cc5644 100644 --- a/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go +++ b/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -264,6 +264,9 @@ func testBoundsChecking(input string) { _ = int16(parsed) } } + if parsed <= math.MaxUint32 { + _ = uint32(parsed) + } } { parsed, err := strconv.ParseUint(input, 10, 32) From be468fe122424b146b855ae911d8ee869b0c1e21 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 17 Feb 2023 19:21:15 +0000 Subject: [PATCH 318/415] Change note --- go/ql/src/change-notes/2023-02-17-integer-conversion-fix.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 go/ql/src/change-notes/2023-02-17-integer-conversion-fix.md diff --git a/go/ql/src/change-notes/2023-02-17-integer-conversion-fix.md b/go/ql/src/change-notes/2023-02-17-integer-conversion-fix.md new file mode 100644 index 00000000000..9fb36271a32 --- /dev/null +++ b/go/ql/src/change-notes/2023-02-17-integer-conversion-fix.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The query `go/incorrect-integer-conversion` now correctly recognises guards of the form `if val <= x` to protect a conversion `uintX(val)` when `x` is in the range `(math.MaxIntX, math.MaxUintX]`. From c7da1c9e0d571a1844a2cb9cc64afcf8cf591a07 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 17 Feb 2023 19:35:04 +0000 Subject: [PATCH 319/415] Use example that compiles on 32-bit arch --- .../Security/CWE-681/IncorrectIntegerConversion.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go b/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go index e5298cc5644..d10d1e47a3b 100644 --- a/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go +++ b/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.go @@ -264,8 +264,8 @@ func testBoundsChecking(input string) { _ = int16(parsed) } } - if parsed <= math.MaxUint32 { - _ = uint32(parsed) + if parsed <= math.MaxUint16 { + _ = uint16(parsed) } } { From 7a9bbb1414b11c135995097389ff0869837f3478 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 17 Feb 2023 17:38:01 +0000 Subject: [PATCH 320/415] Swift: Model FileManager sources. --- .../codeql/swift/dataflow/ExternalFlow.qll | 1 + .../StandardLibrary/FileManager.qll | 25 +++++++++++++++++++ .../dataflow/flowsources/FlowSources.expected | 8 ++++++ .../dataflow/flowsources/filemanager.swift | 5 ++-- 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll index 1a1095dc3df..eda7d314ac3 100644 --- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll +++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll @@ -81,6 +81,7 @@ private module Frameworks { private import codeql.swift.frameworks.StandardLibrary.Collection private import codeql.swift.frameworks.StandardLibrary.CustomUrlSchemes private import codeql.swift.frameworks.StandardLibrary.Data + private import codeql.swift.frameworks.StandardLibrary.FileManager private import codeql.swift.frameworks.StandardLibrary.FilePath private import codeql.swift.frameworks.StandardLibrary.InputStream private import codeql.swift.frameworks.StandardLibrary.NsData diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll new file mode 100644 index 00000000000..931871c6538 --- /dev/null +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/FileManager.qll @@ -0,0 +1,25 @@ +/** + * Provides models for the `FileManager` Swift class. + */ + +import swift +private import codeql.swift.dataflow.ExternalFlow + +/** + * A model for `FileManager` members that are flow sources. + */ +private class FileManagerSource extends SourceModelCsv { + override predicate row(string row) { + row = + [ + ";FileManager;true;contentsOfDirectory(at:includingPropertiesForKeys:options:);;;ReturnValue;local", + ";FileManager;true;contentsOfDirectory(atPath:);;;ReturnValue;local", + ";FileManager;true;directoryContents(atPath:);;;ReturnValue;local", + ";FileManager;true;subpathsOfDirectory(atPath:);;;ReturnValue;local", + ";FileManager;true;subpaths(atPath:);;;ReturnValue;local", + ";FileManager;true;destinationOfSymbolicLink(atPath:);;;ReturnValue;local", + ";FileManager;true;pathContentOfSymbolicLink(atPath:);;;ReturnValue;local", + ";FileManager;true;contents(atPath:);;;ReturnValue;local" + ] + } +} diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected index 8b872c18b11..de8dc32229e 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected @@ -38,6 +38,14 @@ | file://:0:0:0:0 | .source1 | external | | file://:0:0:0:0 | .source4 | external | | file://:0:0:0:0 | .source9 | external | +| filemanager.swift:37:23:37:86 | call to contentsOfDirectory(at:includingPropertiesForKeys:options:) | external | +| filemanager.swift:38:23:38:58 | call to contentsOfDirectory(atPath:) | external | +| filemanager.swift:39:19:39:52 | call to directoryContents(atPath:) | external | +| filemanager.swift:41:23:41:58 | call to subpathsOfDirectory(atPath:) | external | +| filemanager.swift:42:19:42:43 | call to subpaths(atPath:) | external | +| filemanager.swift:44:19:44:60 | call to destinationOfSymbolicLink(atPath:) | external | +| filemanager.swift:45:15:45:56 | call to pathContentOfSymbolicLink(atPath:) | external | +| filemanager.swift:47:14:47:38 | call to contents(atPath:) | external | | generics.swift:10:9:10:16 | .source1 | external | | generics.swift:11:9:11:16 | .source2 | external | | generics.swift:12:9:12:24 | call to source3() | external | diff --git a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift index 374e67e74a6..af1b28664d8 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift @@ -17,7 +17,7 @@ class FileManager : NSObject { let rawValue: Int } - func contentsOfDirectory(at url: URL, includingPropertyForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL] { return [] } + func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL] { return [] } func contentsOfDirectory(atPath path: String) throws -> [String] { return [] } func directoryContents(atPath path: String) -> [Any]? { return [] } // returns array of NSString func subpathsOfDirectory(atPath path: String) throws -> [String] { return [] } @@ -34,8 +34,7 @@ class FileManager : NSObject { func testFileHandle(fm: FileManager, url: URL, path: String) { do { - let contents1 = try fm.contentsOfDirectory(at: url, includingPropertyForKeys: nil) // SOURCE - let content1 = contents1[0] + let contents1 = try fm.contentsOfDirectory(at: url, includingPropertiesForKeys: nil) // SOURCE let contents2 = try fm.contentsOfDirectory(atPath: path) // SOURCE let contents3 = fm.directoryContents(atPath: path)! // SOURCE From 4f97c0470b36233ec3c472c65b200ccc4c0143e6 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Sat, 18 Feb 2023 12:21:35 +0100 Subject: [PATCH 321/415] exclude java integration tests from QL-for-QL --- .github/workflows/ql-for-ql-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml index 8b6e7a56946..c5decb01b92 100644 --- a/.github/workflows/ql-for-ql-build.yml +++ b/.github/workflows/ql-for-ql-build.yml @@ -65,6 +65,7 @@ jobs: LGTM_INDEX_FILTERS: | exclude:ql/ql/test exclude:*/ql/lib/upgrades/ + exclude:java/ql/integration-tests - name: Upload sarif to code-scanning uses: github/codeql-action/upload-sarif@v2 with: From fcff18aa3ced03dc3424bffcfbf93dcc44a3adf8 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Sat, 18 Feb 2023 12:22:34 +0100 Subject: [PATCH 322/415] add query header for OutdatedDeprecations --- ql/ql/src/queries/reports/OutdatedDeprecations.ql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ql/ql/src/queries/reports/OutdatedDeprecations.ql b/ql/ql/src/queries/reports/OutdatedDeprecations.ql index b46114d364f..5e15eafe061 100644 --- a/ql/ql/src/queries/reports/OutdatedDeprecations.ql +++ b/ql/ql/src/queries/reports/OutdatedDeprecations.ql @@ -1,3 +1,13 @@ +/** + * @name Outdated deprecation + * @description Deprecations that are over a year old should be removed. + * @kind problem + * @problem.severity warning + * @id ql/outdated-deprecation + * @tags maintainability + * @precision high + */ + import ql import codeql_ql.ast.internal.TreeSitter From 1a308316c6c597e434fb624adce87bc4af17f833 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Sat, 18 Feb 2023 12:28:06 +0100 Subject: [PATCH 323/415] fix join-order of ql/outdated-deprecation --- ql/ql/src/queries/reports/OutdatedDeprecations.ql | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ql/ql/src/queries/reports/OutdatedDeprecations.ql b/ql/ql/src/queries/reports/OutdatedDeprecations.ql index 5e15eafe061..9c09a73ef7f 100644 --- a/ql/ql/src/queries/reports/OutdatedDeprecations.ql +++ b/ql/ql/src/queries/reports/OutdatedDeprecations.ql @@ -13,15 +13,21 @@ import codeql_ql.ast.internal.TreeSitter date today() { result = any(Blame::BlameInfo b).getToday().getValue().toDate() } +pragma[nomagic] +Annotation getADeprecatedAnnotationAt(string filePath, int line) { + result.getLocation().getFile().getRelativePath() = filePath and + result.getLocation().getStartLine() = line and + result.getName() = "deprecated" +} + class DatedDeprecation extends Annotation { date lastModified; DatedDeprecation() { this.getName() = "deprecated" and exists(Blame::FileEntry f, Blame::BlameEntry b | - f.getFileName().getValue() = this.getLocation().getFile().getRelativePath() and + this = getADeprecatedAnnotationAt(f.getFileName().getValue(), b.getLine(_).getValue().toInt()) and f.getBlameEntry(_) = b and - b.getLine(_).getValue().toInt() = this.getLocation().getStartLine() and lastModified = b.getDate().getValue().toDate() ) } From 6f8ae703ca3defd24e28a3d2c46b62eb7e648dd1 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Sat, 18 Feb 2023 12:31:14 +0100 Subject: [PATCH 324/415] add the deprecation file when running QL-for-QL --- .github/workflows/ql-for-ql-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml index c5decb01b92..db854eea0c8 100644 --- a/.github/workflows/ql-for-ql-build.yml +++ b/.github/workflows/ql-for-ql-build.yml @@ -57,6 +57,7 @@ jobs: key: run-ql-for-ql - name: Make database and analyze run: | + ./ql/target/release/buramu > deprecated.blame # Add a blame file for the extractor to parse. ${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB} ${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" env: From db9a0d1c52e1dc7d5e1ffd5190cfbb0273bc6e9e Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Sat, 18 Feb 2023 12:39:16 +0100 Subject: [PATCH 325/415] make the deprecation query calculate based on months, and adjust the cutoff to 14 months --- ql/ql/src/queries/reports/OutdatedDeprecations.ql | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ql/ql/src/queries/reports/OutdatedDeprecations.ql b/ql/ql/src/queries/reports/OutdatedDeprecations.ql index 9c09a73ef7f..5d5e92f41ff 100644 --- a/ql/ql/src/queries/reports/OutdatedDeprecations.ql +++ b/ql/ql/src/queries/reports/OutdatedDeprecations.ql @@ -2,7 +2,7 @@ * @name Outdated deprecation * @description Deprecations that are over a year old should be removed. * @kind problem - * @problem.severity warning + * @problem.severity recommendation * @id ql/outdated-deprecation * @tags maintainability * @precision high @@ -32,9 +32,14 @@ class DatedDeprecation extends Annotation { ) } - date getLastModified() { result = lastModified } + /** Gets how long ago this deprecation was added, in months. */ + int getMonthsOld() { + exists(float month | + month = 365 / 12 and result = (lastModified.daysTo(today()) / month).floor() + ) + } } from DatedDeprecation d -where d.getLastModified().daysTo(today()) > 365 -select d, "This deprecation is over a year old." +where d.getMonthsOld() >= 14 +select d, "This deprecation is over 14 months old." From 52a9d5379b04efc84e6788f9467a31911d87def7 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Sat, 18 Feb 2023 13:14:57 +0100 Subject: [PATCH 326/415] add buramu to the files cached for the extractor --- .github/workflows/ql-for-ql-build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml index db854eea0c8..f854965be4e 100644 --- a/.github/workflows/ql-for-ql-build.yml +++ b/.github/workflows/ql-for-ql-build.yml @@ -34,7 +34,9 @@ jobs: id: cache-extractor uses: actions/cache@v3 with: - path: ql/extractor-pack/ + path: | + ql/extractor-pack/ + ql/target/release/buramu 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' From cd823d749543dab76607c5ac97c1b421188e2750 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Sat, 18 Feb 2023 13:38:53 +0100 Subject: [PATCH 327/415] add git info to the checkout --- .github/workflows/ql-for-ql-build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml index f854965be4e..0959589aa26 100644 --- a/.github/workflows/ql-for-ql-build.yml +++ b/.github/workflows/ql-for-ql-build.yml @@ -22,6 +22,8 @@ jobs: steps: ### Build the queries ### - uses: actions/checkout@v3 + with: + fetch-depth: 0 - name: Find codeql id: find-codeql uses: github/codeql-action/init@v2 @@ -59,7 +61,7 @@ jobs: key: run-ql-for-ql - name: Make database and analyze run: | - ./ql/target/release/buramu > deprecated.blame # Add a blame file for the extractor to parse. + ./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse. ${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB} ${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" env: From 4e07fd3eb14d7d6811c582814543051adc37d558 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Wed, 1 Feb 2023 15:50:09 +1300 Subject: [PATCH 328/415] Ruby: Model ApplicationController.renderer --- .../2023-02-03-applicationcontroller-render.md | 4 ++++ .../ruby/frameworks/ActionController.qll | 15 +++++++++++++++ .../ActionController.expected | 17 ++++++++++------- .../action_controller/Filters.expected | 18 +++++++++--------- .../controllers/posts_controller.rb | 9 +++++++++ 5 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 ruby/ql/lib/change-notes/2023-02-03-applicationcontroller-render.md diff --git a/ruby/ql/lib/change-notes/2023-02-03-applicationcontroller-render.md b/ruby/ql/lib/change-notes/2023-02-03-applicationcontroller-render.md new file mode 100644 index 00000000000..6e5abaec42f --- /dev/null +++ b/ruby/ql/lib/change-notes/2023-02-03-applicationcontroller-render.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Calls to `ApplicationController#render` and `ApplicationController::Renderer#render` are recognized as Rails rendering calls. diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll index ba365af167d..a56f6445d8f 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll @@ -364,6 +364,21 @@ private class ActionControllerRenderToCall extends RenderToCallImpl { } } +/** A call to `ActionController::Renderer#render`. */ +private class RendererRenderCall extends RenderCallImpl { + RendererRenderCall() { + this = + [ + // ActionController#render is an alias for ActionController::Renderer#render + any(ActionControllerClass c).getAnImmediateReference().getAMethodCall("render"), + any(ActionControllerClass c) + .getAnImmediateReference() + .getAMethodCall("renderer") + .getAMethodCall("render") + ].asExpr().getExpr() + } +} + /** A call to `html_escape` from within a controller. */ private class ActionControllerHtmlEscapeCall extends HtmlEscapeCallImpl { ActionControllerHtmlEscapeCall() { diff --git a/ruby/ql/test/library-tests/frameworks/action_controller/ActionController.expected b/ruby/ql/test/library-tests/frameworks/action_controller/ActionController.expected index e17f691b149..4e122b5ba21 100644 --- a/ruby/ql/test/library-tests/frameworks/action_controller/ActionController.expected +++ b/ruby/ql/test/library-tests/frameworks/action_controller/ActionController.expected @@ -3,7 +3,7 @@ actionControllerControllerClasses | controllers/comments_controller.rb:1:1:104:3 | CommentsController | | controllers/foo/bars_controller.rb:3:1:46:3 | BarsController | | controllers/photos_controller.rb:1:1:10:3 | PhotosController | -| controllers/posts_controller.rb:1:1:30:3 | PostsController | +| controllers/posts_controller.rb:1:1:32:3 | PostsController | | controllers/tags_controller.rb:1:1:2:3 | TagsController | | controllers/users/notifications_controller.rb:2:3:5:5 | Users::NotificationsController | | input_access.rb:1:1:50:3 | UsersController | @@ -23,9 +23,9 @@ actionControllerActionMethods | controllers/foo/bars_controller.rb:34:3:39:5 | show_2 | | controllers/photos_controller.rb:3:3:6:5 | show | | controllers/photos_controller.rb:8:3:9:5 | foo | -| controllers/posts_controller.rb:12:3:13:5 | index | -| controllers/posts_controller.rb:15:3:16:5 | show | -| controllers/posts_controller.rb:18:3:19:5 | upvote | +| controllers/posts_controller.rb:12:3:15:5 | index | +| controllers/posts_controller.rb:17:3:18:5 | show | +| controllers/posts_controller.rb:20:3:21:5 | upvote | | controllers/users/notifications_controller.rb:3:5:4:7 | mark_as_read | | input_access.rb:2:3:49:5 | index | | logging.rb:2:5:8:7 | index | @@ -71,7 +71,7 @@ paramsCalls | controllers/foo/bars_controller.rb:14:10:14:15 | call to params | | controllers/foo/bars_controller.rb:21:21:21:26 | call to params | | controllers/foo/bars_controller.rb:22:10:22:15 | call to params | -| controllers/posts_controller.rb:24:23:24:28 | call to params | +| controllers/posts_controller.rb:26:23:26:28 | call to params | | params_flow.rb:3:10:3:15 | call to params | | params_flow.rb:7:10:7:15 | call to params | | params_flow.rb:11:10:11:15 | call to params | @@ -126,7 +126,7 @@ paramsSources | controllers/foo/bars_controller.rb:14:10:14:15 | call to params | | controllers/foo/bars_controller.rb:21:21:21:26 | call to params | | controllers/foo/bars_controller.rb:22:10:22:15 | call to params | -| controllers/posts_controller.rb:24:23:24:28 | call to params | +| controllers/posts_controller.rb:26:23:26:28 | call to params | | params_flow.rb:3:10:3:15 | call to params | | params_flow.rb:7:10:7:15 | call to params | | params_flow.rb:11:10:11:15 | call to params | @@ -191,7 +191,7 @@ httpInputAccesses | controllers/foo/bars_controller.rb:14:10:14:15 | call to params | ActionController::Metal#params | | controllers/foo/bars_controller.rb:21:21:21:26 | call to params | ActionController::Metal#params | | controllers/foo/bars_controller.rb:22:10:22:15 | call to params | ActionController::Metal#params | -| controllers/posts_controller.rb:24:23:24:28 | call to params | ActionController::Metal#params | +| controllers/posts_controller.rb:26:23:26:28 | call to params | ActionController::Metal#params | | input_access.rb:3:5:3:18 | call to params | ActionDispatch::Request#params | | input_access.rb:4:5:4:22 | call to parameters | ActionDispatch::Request#parameters | | input_access.rb:5:5:5:15 | call to GET | ActionDispatch::Request#GET | @@ -297,6 +297,9 @@ renderCalls | controllers/foo/bars_controller.rb:35:5:35:33 | call to render | | controllers/foo/bars_controller.rb:38:5:38:50 | call to render | | controllers/foo/bars_controller.rb:44:5:44:17 | call to render | +| controllers/posts_controller.rb:13:5:13:51 | call to render | +| controllers/posts_controller.rb:14:5:14:127 | call to render | +| controllers/posts_controller.rb:36:5:36:51 | call to render | httpResponses | controllers/comments_controller.rb:26:5:26:17 | call to body= | controllers/comments_controller.rb:26:21:26:34 | ... = ... | | controllers/comments_controller.rb:36:5:36:37 | call to send_file | controllers/comments_controller.rb:36:24:36:36 | "my-file.ext" | diff --git a/ruby/ql/test/library-tests/frameworks/action_controller/Filters.expected b/ruby/ql/test/library-tests/frameworks/action_controller/Filters.expected index 260a818fc41..ad000553281 100644 --- a/ruby/ql/test/library-tests/frameworks/action_controller/Filters.expected +++ b/ruby/ql/test/library-tests/frameworks/action_controller/Filters.expected @@ -42,12 +42,12 @@ | controllers/comments_controller.rb:68:3:70:5 | destroy | controllers/comments_controller.rb:102:3:103:5 | bar | controllers/comments_controller.rb:68:3:70:5 | destroy | | controllers/photos_controller.rb:3:3:6:5 | show | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/photos_controller.rb:3:3:6:5 | show | | controllers/photos_controller.rb:3:3:6:5 | show | controllers/photos_controller.rb:3:3:6:5 | show | controllers/photos_controller.rb:8:3:9:5 | foo | -| controllers/posts_controller.rb:12:3:13:5 | index | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:12:3:13:5 | index | -| controllers/posts_controller.rb:12:3:13:5 | index | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user | -| controllers/posts_controller.rb:15:3:16:5 | show | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:15:3:16:5 | show | -| controllers/posts_controller.rb:15:3:16:5 | show | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/posts_controller.rb:23:3:25:5 | set_post | -| controllers/posts_controller.rb:15:3:16:5 | show | controllers/posts_controller.rb:23:3:25:5 | set_post | controllers/application_controller.rb:6:3:8:5 | set_user | -| controllers/posts_controller.rb:18:3:19:5 | upvote | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:18:3:19:5 | upvote | -| controllers/posts_controller.rb:18:3:19:5 | upvote | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/posts_controller.rb:23:3:25:5 | set_post | -| controllers/posts_controller.rb:18:3:19:5 | upvote | controllers/posts_controller.rb:18:3:19:5 | upvote | controllers/posts_controller.rb:27:3:29:5 | log_upvote | -| controllers/posts_controller.rb:18:3:19:5 | upvote | controllers/posts_controller.rb:23:3:25:5 | set_post | controllers/application_controller.rb:6:3:8:5 | set_user | +| controllers/posts_controller.rb:12:3:15:5 | index | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:12:3:15:5 | index | +| controllers/posts_controller.rb:12:3:15:5 | index | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/application_controller.rb:6:3:8:5 | set_user | +| controllers/posts_controller.rb:17:3:18:5 | show | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:17:3:18:5 | show | +| controllers/posts_controller.rb:17:3:18:5 | show | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/posts_controller.rb:25:3:27:5 | set_post | +| controllers/posts_controller.rb:17:3:18:5 | show | controllers/posts_controller.rb:25:3:27:5 | set_post | controllers/application_controller.rb:6:3:8:5 | set_user | +| controllers/posts_controller.rb:20:3:21:5 | upvote | controllers/application_controller.rb:6:3:8:5 | set_user | controllers/posts_controller.rb:20:3:21:5 | upvote | +| controllers/posts_controller.rb:20:3:21:5 | upvote | controllers/application_controller.rb:10:3:12:5 | log_request | controllers/posts_controller.rb:25:3:27:5 | set_post | +| controllers/posts_controller.rb:20:3:21:5 | upvote | controllers/posts_controller.rb:20:3:21:5 | upvote | controllers/posts_controller.rb:29:3:31:5 | log_upvote | +| controllers/posts_controller.rb:20:3:21:5 | upvote | controllers/posts_controller.rb:25:3:27:5 | set_post | controllers/application_controller.rb:6:3:8:5 | set_user | diff --git a/ruby/ql/test/library-tests/frameworks/action_controller/controllers/posts_controller.rb b/ruby/ql/test/library-tests/frameworks/action_controller/controllers/posts_controller.rb index ed1fa22c2fa..99412d311a1 100644 --- a/ruby/ql/test/library-tests/frameworks/action_controller/controllers/posts_controller.rb +++ b/ruby/ql/test/library-tests/frameworks/action_controller/controllers/posts_controller.rb @@ -10,6 +10,8 @@ class PostsController < ApplicationController before_action :set_user def index + PostsController.render(template: "posts/index") + PostsController.renderer.render(template: "posts/index", locals: { show_full_post: true }, assigns: { @posts => Post.all }) end def show @@ -28,3 +30,10 @@ class PostsController < ApplicationController Rails.logger.info("Post upvoted: #{@post.id}") end end + +class NotAController + def foo + PostsController.render(template: "posts/index") + end +end + From 6cec8ece3ffeafd7ce62a71b9538262d86debb99 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 10:15:41 +0000 Subject: [PATCH 329/415] Swift: Split off FlowConfig.qll. --- .../dataflow/flowsources/FlowConfig.qll | 36 +++++++++++++++++++ .../dataflow/flowsources/FlowSources.ql | 34 +----------------- 2 files changed, 37 insertions(+), 33 deletions(-) create mode 100644 swift/ql/test/library-tests/dataflow/flowsources/FlowConfig.qll diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowConfig.qll b/swift/ql/test/library-tests/dataflow/flowsources/FlowConfig.qll new file mode 100644 index 00000000000..889dfd3481a --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowConfig.qll @@ -0,0 +1,36 @@ +import swift +import codeql.swift.dataflow.FlowSources +import codeql.swift.dataflow.ExternalFlow + +/** + * A models-as-data class expressing custom flow sources for this test. These + * cases ensure that MaD source definitions are able to successfully match a + * range of class fields and member functions. + */ +class CustomTestSourcesCsv extends SourceModelCsv { + override predicate row(string row) { + row = + [ + ";MySimpleClass;true;source1;;;;remote", ";MySimpleClass;true;source2;;;;remote", + ";MySimpleClass;true;source3();;;ReturnValue;remote", + // --- + ";MyGeneric;true;source1;;;;remote", ";MyGeneric;true;source2;;;;remote", + ";MyGeneric;true;source3();;;ReturnValue;remote", ";MyDerived;true;source4;;;;remote", + ";MyDerived;true;source5;;;;remote", ";MyDerived;true;source6();;;ReturnValue;remote", + ";MyDerived;true;source7;;;;remote", ";MyDerived;true;source8();;;ReturnValue;remote", + ";MyDerived2;true;source9;;;;remote", ";MyDerived2;true;source10;;;;remote", + ";MyDerived2;true;source11();;;ReturnValue;remote", ";MyDerived2;true;source12;;;;remote", + ";MyDerived2;true;source13();;;ReturnValue;remote", + // --- + ";MyParentProtocol;true;source0;;;;remote", ";MyProtocol;true;source1;;;;remote", + ";MyProtocol;true;source2;;;;remote", + // --- + ";MyParentProtocol2;true;source0;;;;remote", ";MyProtocol2;true;source1;;;;remote", + ";MyProtocol2;true;source2;;;;remote", + // --- + ";MyProtocol3;true;source1();;;ReturnValue;remote", + ";MyProtocol3;true;source2();;;ReturnValue;remote", + ";MyProtocol3;true;source3();;;ReturnValue;remote" + ] + } +} diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql index c53471ec190..65fbeeb3edb 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql @@ -1,39 +1,7 @@ import swift import codeql.swift.dataflow.FlowSources import codeql.swift.dataflow.ExternalFlow - -/** - * A models-as-data class expressing custom flow sources for this test. These - * cases ensure that MaD source definitions are able to successfully match a - * range of class fields and member functions. - */ -class CustomTestSourcesCsv extends SourceModelCsv { - override predicate row(string row) { - row = - [ - ";MySimpleClass;true;source1;;;;remote", ";MySimpleClass;true;source2;;;;remote", - ";MySimpleClass;true;source3();;;ReturnValue;remote", - // --- - ";MyGeneric;true;source1;;;;remote", ";MyGeneric;true;source2;;;;remote", - ";MyGeneric;true;source3();;;ReturnValue;remote", ";MyDerived;true;source4;;;;remote", - ";MyDerived;true;source5;;;;remote", ";MyDerived;true;source6();;;ReturnValue;remote", - ";MyDerived;true;source7;;;;remote", ";MyDerived;true;source8();;;ReturnValue;remote", - ";MyDerived2;true;source9;;;;remote", ";MyDerived2;true;source10;;;;remote", - ";MyDerived2;true;source11();;;ReturnValue;remote", ";MyDerived2;true;source12;;;;remote", - ";MyDerived2;true;source13();;;ReturnValue;remote", - // --- - ";MyParentProtocol;true;source0;;;;remote", ";MyProtocol;true;source1;;;;remote", - ";MyProtocol;true;source2;;;;remote", - // --- - ";MyParentProtocol2;true;source0;;;;remote", ";MyProtocol2;true;source1;;;;remote", - ";MyProtocol2;true;source2;;;;remote", - // --- - ";MyProtocol3;true;source1();;;ReturnValue;remote", - ";MyProtocol3;true;source2();;;ReturnValue;remote", - ";MyProtocol3;true;source3();;;ReturnValue;remote" - ] - } -} +import FlowConfig from RemoteFlowSource source select source, concat(source.getSourceType(), ", ") From dbe0797063cd06177514c42803e07fd29b04bdb3 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 17 Feb 2023 10:10:22 +0000 Subject: [PATCH 330/415] Add Gradle wrappers for Kotlin tests This avoids tests' behaviour changing due to environmental Gradle version changes --- .../kotlin/gradle_groovy_app/.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../kotlin/gradle_groovy_app/gradlew | 244 ++++++++++++++++++ .../kotlin/gradle_groovy_app/gradlew.bat | 92 +++++++ .../kotlin/gradle_groovy_app/test.py | 7 +- .../.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../gradle_kotlinx_serialization/gradlew | 244 ++++++++++++++++++ .../gradle_kotlinx_serialization/gradlew.bat | 92 +++++++ .../gradle_kotlinx_serialization/test.py | 7 +- 12 files changed, 706 insertions(+), 4 deletions(-) create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/.gitattributes create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew.bat create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/.gitattributes create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew create mode 100644 java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew.bat diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/.gitattributes b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew new file mode 100755 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew.bat b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/test.py b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/test.py index 7f44398cd12..359771ac6c0 100644 --- a/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/test.py +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_groovy_app/test.py @@ -1,4 +1,7 @@ +import platform from create_database_utils import * -run_codeql_database_create(["gradle build --no-daemon --no-build-cache"], lang="java") -runSuccessfully(["gradle", "clean"]) +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + +run_codeql_database_create( + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/.gitattributes b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew new file mode 100755 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew.bat b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/test.py b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/test.py index 7f44398cd12..359771ac6c0 100644 --- a/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/test.py +++ b/java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/test.py @@ -1,4 +1,7 @@ +import platform from create_database_utils import * -run_codeql_database_create(["gradle build --no-daemon --no-build-cache"], lang="java") -runSuccessfully(["gradle", "clean"]) +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + +run_codeql_database_create( + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") From d9f2d348f425f2bba6ae6e8d0c995664762b32c0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:03:10 +0000 Subject: [PATCH 331/415] Swift: Add an inline expectations test for flow sources. --- .../flowsources/FlowSourcesInline.expected | 110 ++++++++++++++++++ .../dataflow/flowsources/FlowSourcesInline.ql | 25 ++++ 2 files changed, 135 insertions(+) create mode 100644 swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected create mode 100644 swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected new file mode 100644 index 00000000000..da0e436f6ab --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected @@ -0,0 +1,110 @@ +| alamofire.swift:91:27:91:27 | .result | Unexpected result: source=remote | +| alamofire.swift:99:27:99:27 | .result | Unexpected result: source=remote | +| alamofire.swift:344:23:344:32 | .data | Unexpected result: source=remote | +| alamofire.swift:351:22:351:31 | .value | Unexpected result: source=remote | +| alamofire.swift:358:23:358:32 | .value | Unexpected result: source=remote | +| alamofire.swift:365:22:365:31 | .value | Unexpected result: source=remote | +| alamofire.swift:372:23:372:32 | .value | Unexpected result: source=remote | +| alamofire.swift:379:28:379:37 | .value | Unexpected result: source=remote | +| alamofire.swift:389:28:389:55 | call to String.init(contentsOfFile:) | Unexpected result: source=remote | +| alamofire.swift:396:22:396:31 | .value | Unexpected result: source=remote | +| alamofire.swift:403:22:403:31 | .value | Unexpected result: source=remote | +| alamofire.swift:404:28:404:50 | call to String.init(contentsOf:) | Unexpected result: source=remote | +| alamofire.swift:411:23:411:32 | .value | Unexpected result: source=remote | +| alamofire.swift:418:22:418:31 | .value | Unexpected result: source=remote | +| alamofire.swift:425:23:425:32 | .value | Unexpected result: source=remote | +| alamofire.swift:431:28:431:37 | .value | Unexpected result: source=remote | +| alamofire.swift:448:20:448:49 | call to String.init(contentsOfFile:) | Unexpected result: source=remote | +| alamofire.swift:455:23:455:32 | .data | Unexpected result: source=remote | +| alamofire.swift:461:23:461:32 | .data | Unexpected result: source=remote | +| customurlschemes.swift:53:44:53:54 | url | Unexpected result: source=remote | +| customurlschemes.swift:57:52:57:68 | url | Unexpected result: source=remote | +| customurlschemes.swift:61:52:61:62 | url | Unexpected result: source=remote | +| customurlschemes.swift:66:9:66:28 | ...[...] | Unexpected result: source=remote | +| customurlschemes.swift:71:9:71:28 | ...[...] | Unexpected result: source=remote | +| customurlschemes.swift:77:59:77:76 | options | Unexpected result: source=remote | +| customurlschemes.swift:78:28:78:38 | continue | Unexpected result: source=remote | +| customurlschemes.swift:79:28:79:39 | didUpdate | Unexpected result: source=remote | +| customurlschemes.swift:80:28:80:65 | openURLContexts | Unexpected result: source=remote | +| customurlschemes.swift:86:59:86:76 | options | Unexpected result: source=remote | +| customurlschemes.swift:87:28:87:38 | continue | Unexpected result: source=remote | +| customurlschemes.swift:88:28:88:39 | didUpdate | Unexpected result: source=remote | +| customurlschemes.swift:89:28:89:65 | openURLContexts | Unexpected result: source=remote | +| data.swift:18:20:18:54 | call to Data.init(contentsOf:options:) | Unexpected result: source=remote | +| filemanager.swift:37:23:37:86 | call to contentsOfDirectory(at:includingPropertiesForKeys:options:) | Unexpected result: source=remote | +| filemanager.swift:38:23:38:58 | call to contentsOfDirectory(atPath:) | Unexpected result: source=remote | +| filemanager.swift:39:19:39:52 | call to directoryContents(atPath:) | Unexpected result: source=remote | +| filemanager.swift:41:23:41:58 | call to subpathsOfDirectory(atPath:) | Unexpected result: source=remote | +| filemanager.swift:42:19:42:43 | call to subpaths(atPath:) | Unexpected result: source=remote | +| filemanager.swift:44:19:44:60 | call to destinationOfSymbolicLink(atPath:) | Unexpected result: source=remote | +| filemanager.swift:45:15:45:56 | call to pathContentOfSymbolicLink(atPath:) | Unexpected result: source=remote | +| filemanager.swift:47:14:47:38 | call to contents(atPath:) | Unexpected result: source=remote | +| generics.swift:10:9:10:16 | .source1 | Unexpected result: source=remote | +| generics.swift:11:9:11:16 | .source2 | Unexpected result: source=remote | +| generics.swift:12:9:12:24 | call to source3() | Unexpected result: source=remote | +| generics.swift:48:9:48:17 | .source1 | Unexpected result: source=remote | +| generics.swift:49:9:49:17 | .source2 | Unexpected result: source=remote | +| generics.swift:50:9:50:25 | call to source3() | Unexpected result: source=remote | +| generics.swift:51:9:51:18 | .source1 | Unexpected result: source=remote | +| generics.swift:52:9:52:18 | .source2 | Unexpected result: source=remote | +| generics.swift:53:9:53:26 | call to source3() | Unexpected result: source=remote | +| generics.swift:54:9:54:17 | .source1 | Unexpected result: source=remote | +| generics.swift:55:9:55:17 | .source2 | Unexpected result: source=remote | +| generics.swift:56:9:56:25 | call to source3() | Unexpected result: source=remote | +| generics.swift:57:9:57:17 | .source4 | Unexpected result: source=remote | +| generics.swift:58:9:58:17 | .source5 | Unexpected result: source=remote | +| generics.swift:59:9:59:25 | call to source6() | Unexpected result: source=remote | +| generics.swift:60:9:60:17 | .source7 | Unexpected result: source=remote | +| generics.swift:61:9:61:25 | call to source8() | Unexpected result: source=remote | +| generics.swift:62:9:62:18 | .source1 | Unexpected result: source=remote | +| generics.swift:63:9:63:18 | .source2 | Unexpected result: source=remote | +| generics.swift:64:9:64:26 | call to source3() | Unexpected result: source=remote | +| generics.swift:65:9:65:18 | .source9 | Unexpected result: source=remote | +| generics.swift:66:9:66:18 | .source10 | Unexpected result: source=remote | +| generics.swift:67:9:67:27 | call to source11() | Unexpected result: source=remote | +| generics.swift:68:9:68:18 | .source12 | Unexpected result: source=remote | +| generics.swift:69:9:69:27 | call to source13() | Unexpected result: source=remote | +| generics.swift:93:9:93:15 | .source0 | Unexpected result: source=remote | +| generics.swift:94:9:94:15 | .source1 | Unexpected result: source=remote | +| generics.swift:95:9:95:15 | .source2 | Unexpected result: source=remote | +| generics.swift:96:9:96:14 | .source0 | Unexpected result: source=remote | +| generics.swift:97:9:97:14 | .source1 | Unexpected result: source=remote | +| generics.swift:98:9:98:14 | .source2 | Unexpected result: source=remote | +| generics.swift:99:9:99:15 | .source0 | Unexpected result: source=remote | +| generics.swift:100:9:100:15 | .source1 | Unexpected result: source=remote | +| generics.swift:101:9:101:15 | .source2 | Unexpected result: source=remote | +| generics.swift:125:9:125:15 | .source0 | Unexpected result: source=remote | +| generics.swift:126:9:126:15 | .source1 | Unexpected result: source=remote | +| generics.swift:127:9:127:15 | .source2 | Unexpected result: source=remote | +| generics.swift:128:9:128:14 | .source0 | Unexpected result: source=remote | +| generics.swift:129:9:129:14 | .source1 | Unexpected result: source=remote | +| generics.swift:130:9:130:14 | .source2 | Unexpected result: source=remote | +| generics.swift:131:9:131:15 | .source0 | Unexpected result: source=remote | +| generics.swift:132:9:132:15 | .source1 | Unexpected result: source=remote | +| generics.swift:133:9:133:15 | .source2 | Unexpected result: source=remote | +| generics.swift:162:9:162:22 | call to source2() | Unexpected result: source=remote | +| generics.swift:163:9:163:22 | call to source3() | Unexpected result: source=remote | +| nsdata.swift:18:17:18:40 | call to NSData.init(contentsOf:) | Unexpected result: source=remote | +| nsdata.swift:19:17:19:53 | call to NSData.init(contentsOf:options:) | Unexpected result: source=remote | +| string.swift:56:21:56:44 | call to String.init(contentsOf:) | Unexpected result: source=remote | +| string.swift:57:21:57:77 | call to String.init(contentsOf:encoding:) | Unexpected result: source=remote | +| string.swift:59:21:59:69 | call to String.init(contentsOf:usedEncoding:) | Unexpected result: source=remote | +| string.swift:62:21:62:48 | call to String.init(contentsOfFile:) | Unexpected result: source=remote | +| string.swift:63:21:63:81 | call to String.init(contentsOfFile:encoding:) | Unexpected result: source=remote | +| string.swift:64:21:64:73 | call to String.init(contentsOfFile:usedEncoding:) | Unexpected result: source=remote | +| url.swift:53:15:53:19 | .resourceBytes | Unexpected result: source=remote | +| url.swift:60:15:60:19 | .lines | Unexpected result: source=remote | +| url.swift:67:16:67:22 | .lines | Unexpected result: source=remote | +| webview.swift:13:32:13:49 | decidePolicyFor | Unexpected result: source=remote | +| webview.swift:14:32:14:49 | decidePolicyFor | Unexpected result: source=remote | +| webview.swift:41:82:41:102 | message | Unexpected result: source=remote | +| webview.swift:46:5:46:13 | .globalObject | Unexpected result: source=remote | +| webview.swift:47:5:47:39 | call to objectForKeyedSubscript(_:) | Unexpected result: source=remote | +| webview.swift:60:9:60:9 | .tainted | Unexpected result: source=remote | +| webview.swift:64:10:64:10 | self | Unexpected result: source=remote | +| webview.swift:64:18:64:24 | arg1 | Unexpected result: source=remote | +| webview.swift:64:29:64:35 | arg2 | Unexpected result: source=remote | +| webview.swift:72:32:72:49 | decidePolicyFor | Unexpected result: source=remote | +| webview.swift:73:32:73:49 | decidePolicyFor | Unexpected result: source=remote | +| webview.swift:79:32:79:49 | decidePolicyFor | Unexpected result: source=remote | +| webview.swift:80:32:80:49 | decidePolicyFor | Unexpected result: source=remote | diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql new file mode 100644 index 00000000000..a15bf2eed89 --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql @@ -0,0 +1,25 @@ +import swift +import TestUtilities.InlineExpectationsTest +import FlowConfig + +string describe(FlowSource source) { + source instanceof RemoteFlowSource and result = "remote" + or + source instanceof LocalFlowSource and result = "local" +} + +class FlowSourcesTest extends InlineExpectationsTest { + FlowSourcesTest() { this = "FlowSourcesTest" } + + override string getARelevantTag() { result = "source" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(FlowSource source | + location = source.getLocation() and + location.getFile().getBaseName() != "" and + element = source.toString() and + tag = "source" and + value = describe(source) + ) + } +} From 9e97877938f7109a1888a3f0e9cf8553b4619c2d Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 20 Feb 2023 12:06:19 +0100 Subject: [PATCH 332/415] python: lower precision as discussed --- python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql index 41d46218ec6..a6a0e06559c 100644 --- a/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql +++ b/python/ql/src/experimental/Security/CWE-022bis/UnsafeUnpack.ql @@ -8,7 +8,7 @@ * @id py/unsafe-unpacking * @problem.severity error * @security-severity 7.5 - * @precision high + * @precision medium * @tags security * experimental * external/cwe/cwe-022 From b66ed57e176f6ed63dd3e04fed6f4f004198e7e2 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:11:46 +0000 Subject: [PATCH 333/415] Swift: Fix a mistake in FlowSources.qll. --- .../lib/codeql/swift/dataflow/FlowSources.qll | 2 +- .../dataflow/flowsources/FlowSources.ql | 2 +- .../flowsources/FlowSourcesInline.expected | 26 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/swift/ql/lib/codeql/swift/dataflow/FlowSources.qll b/swift/ql/lib/codeql/swift/dataflow/FlowSources.qll index 93aeb44618a..c32759c8aa8 100644 --- a/swift/ql/lib/codeql/swift/dataflow/FlowSources.qll +++ b/swift/ql/lib/codeql/swift/dataflow/FlowSources.qll @@ -28,7 +28,7 @@ abstract class RemoteFlowSource extends FlowSource { } /** * A data flow source of local user input that is defined through 'models as data'. */ -private class ExternalLocalFlowSource extends RemoteFlowSource { +private class ExternalLocalFlowSource extends LocalFlowSource { ExternalLocalFlowSource() { sourceNode(this, "local") } override string getSourceType() { result = "external" } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql index 65fbeeb3edb..513961dc16d 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql @@ -3,5 +3,5 @@ import codeql.swift.dataflow.FlowSources import codeql.swift.dataflow.ExternalFlow import FlowConfig -from RemoteFlowSource source +from FlowSource source select source, concat(source.getSourceType(), ", ") diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected index da0e436f6ab..1e905ce8fa8 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected @@ -6,7 +6,7 @@ | alamofire.swift:365:22:365:31 | .value | Unexpected result: source=remote | | alamofire.swift:372:23:372:32 | .value | Unexpected result: source=remote | | alamofire.swift:379:28:379:37 | .value | Unexpected result: source=remote | -| alamofire.swift:389:28:389:55 | call to String.init(contentsOfFile:) | Unexpected result: source=remote | +| alamofire.swift:389:28:389:55 | call to String.init(contentsOfFile:) | Unexpected result: source=local | | alamofire.swift:396:22:396:31 | .value | Unexpected result: source=remote | | alamofire.swift:403:22:403:31 | .value | Unexpected result: source=remote | | alamofire.swift:404:28:404:50 | call to String.init(contentsOf:) | Unexpected result: source=remote | @@ -14,7 +14,7 @@ | alamofire.swift:418:22:418:31 | .value | Unexpected result: source=remote | | alamofire.swift:425:23:425:32 | .value | Unexpected result: source=remote | | alamofire.swift:431:28:431:37 | .value | Unexpected result: source=remote | -| alamofire.swift:448:20:448:49 | call to String.init(contentsOfFile:) | Unexpected result: source=remote | +| alamofire.swift:448:20:448:49 | call to String.init(contentsOfFile:) | Unexpected result: source=local | | alamofire.swift:455:23:455:32 | .data | Unexpected result: source=remote | | alamofire.swift:461:23:461:32 | .data | Unexpected result: source=remote | | customurlschemes.swift:53:44:53:54 | url | Unexpected result: source=remote | @@ -31,14 +31,14 @@ | customurlschemes.swift:88:28:88:39 | didUpdate | Unexpected result: source=remote | | customurlschemes.swift:89:28:89:65 | openURLContexts | Unexpected result: source=remote | | data.swift:18:20:18:54 | call to Data.init(contentsOf:options:) | Unexpected result: source=remote | -| filemanager.swift:37:23:37:86 | call to contentsOfDirectory(at:includingPropertiesForKeys:options:) | Unexpected result: source=remote | -| filemanager.swift:38:23:38:58 | call to contentsOfDirectory(atPath:) | Unexpected result: source=remote | -| filemanager.swift:39:19:39:52 | call to directoryContents(atPath:) | Unexpected result: source=remote | -| filemanager.swift:41:23:41:58 | call to subpathsOfDirectory(atPath:) | Unexpected result: source=remote | -| filemanager.swift:42:19:42:43 | call to subpaths(atPath:) | Unexpected result: source=remote | -| filemanager.swift:44:19:44:60 | call to destinationOfSymbolicLink(atPath:) | Unexpected result: source=remote | -| filemanager.swift:45:15:45:56 | call to pathContentOfSymbolicLink(atPath:) | Unexpected result: source=remote | -| filemanager.swift:47:14:47:38 | call to contents(atPath:) | Unexpected result: source=remote | +| filemanager.swift:37:23:37:86 | call to contentsOfDirectory(at:includingPropertiesForKeys:options:) | Unexpected result: source=local | +| filemanager.swift:38:23:38:58 | call to contentsOfDirectory(atPath:) | Unexpected result: source=local | +| filemanager.swift:39:19:39:52 | call to directoryContents(atPath:) | Unexpected result: source=local | +| filemanager.swift:41:23:41:58 | call to subpathsOfDirectory(atPath:) | Unexpected result: source=local | +| filemanager.swift:42:19:42:43 | call to subpaths(atPath:) | Unexpected result: source=local | +| filemanager.swift:44:19:44:60 | call to destinationOfSymbolicLink(atPath:) | Unexpected result: source=local | +| filemanager.swift:45:15:45:56 | call to pathContentOfSymbolicLink(atPath:) | Unexpected result: source=local | +| filemanager.swift:47:14:47:38 | call to contents(atPath:) | Unexpected result: source=local | | generics.swift:10:9:10:16 | .source1 | Unexpected result: source=remote | | generics.swift:11:9:11:16 | .source2 | Unexpected result: source=remote | | generics.swift:12:9:12:24 | call to source3() | Unexpected result: source=remote | @@ -89,9 +89,9 @@ | string.swift:56:21:56:44 | call to String.init(contentsOf:) | Unexpected result: source=remote | | string.swift:57:21:57:77 | call to String.init(contentsOf:encoding:) | Unexpected result: source=remote | | string.swift:59:21:59:69 | call to String.init(contentsOf:usedEncoding:) | Unexpected result: source=remote | -| string.swift:62:21:62:48 | call to String.init(contentsOfFile:) | Unexpected result: source=remote | -| string.swift:63:21:63:81 | call to String.init(contentsOfFile:encoding:) | Unexpected result: source=remote | -| string.swift:64:21:64:73 | call to String.init(contentsOfFile:usedEncoding:) | Unexpected result: source=remote | +| string.swift:62:21:62:48 | call to String.init(contentsOfFile:) | Unexpected result: source=local | +| string.swift:63:21:63:81 | call to String.init(contentsOfFile:encoding:) | Unexpected result: source=local | +| string.swift:64:21:64:73 | call to String.init(contentsOfFile:usedEncoding:) | Unexpected result: source=local | | url.swift:53:15:53:19 | .resourceBytes | Unexpected result: source=remote | | url.swift:60:15:60:19 | .lines | Unexpected result: source=remote | | url.swift:67:16:67:22 | .lines | Unexpected result: source=remote | From f594411c432c17a68f4ba285d45bf90f642c7eaa Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 20 Feb 2023 13:37:27 +0100 Subject: [PATCH 334/415] C#: Re-factor isSupported for the telemetry queries. --- csharp/ql/src/Telemetry/ExternalApi.qll | 9 ++++++++- csharp/ql/src/Telemetry/SupportedExternalApis.ql | 6 +----- csharp/ql/src/Telemetry/UnsupportedExternalAPIs.ql | 7 +------ csharp/ql/src/meta/frameworks/UnsupportedExternalAPIs.ql | 5 +---- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/csharp/ql/src/Telemetry/ExternalApi.qll b/csharp/ql/src/Telemetry/ExternalApi.qll index 94168e6d3fe..249251dab8e 100644 --- a/csharp/ql/src/Telemetry/ExternalApi.qll +++ b/csharp/ql/src/Telemetry/ExternalApi.qll @@ -8,6 +8,7 @@ private import semmle.code.csharp.dataflow.FlowSummary private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch +private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate private import semmle.code.csharp.security.dataflow.flowsources.Remote @@ -104,8 +105,14 @@ class ExternalApi extends DotNet::Callable { pragma[nomagic] predicate isSink() { sinkNode(this.getAnInput(), _) } + /** Holds if this API is a known neutral. */ + pragma[nomagic] + predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable } + /** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */ - predicate isSupported() { this.hasSummary() or this.isSource() or this.isSink() } + predicate isSupported() { + this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral() + } } /** diff --git a/csharp/ql/src/Telemetry/SupportedExternalApis.ql b/csharp/ql/src/Telemetry/SupportedExternalApis.ql index 7611a367b0a..6d6270fde4e 100644 --- a/csharp/ql/src/Telemetry/SupportedExternalApis.ql +++ b/csharp/ql/src/Telemetry/SupportedExternalApis.ql @@ -8,13 +8,9 @@ private import csharp private import semmle.code.csharp.dispatch.Dispatch -private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl private import ExternalApi -private predicate relevant(ExternalApi api) { - api.isSupported() or - api instanceof FlowSummaryImpl::Public::NeutralCallable -} +private predicate relevant(ExternalApi api) { api.isSupported() } from string info, int usages where Results::restrict(info, usages) diff --git a/csharp/ql/src/Telemetry/UnsupportedExternalAPIs.ql b/csharp/ql/src/Telemetry/UnsupportedExternalAPIs.ql index ee22c960043..99b8eaf74d9 100644 --- a/csharp/ql/src/Telemetry/UnsupportedExternalAPIs.ql +++ b/csharp/ql/src/Telemetry/UnsupportedExternalAPIs.ql @@ -7,14 +7,9 @@ */ private import csharp -private import semmle.code.csharp.dispatch.Dispatch -private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl private import ExternalApi -private predicate relevant(ExternalApi api) { - not api.isSupported() and - not api instanceof FlowSummaryImpl::Public::NeutralCallable -} +private predicate relevant(ExternalApi api) { not api.isSupported() } from string info, int usages where Results::restrict(info, usages) diff --git a/csharp/ql/src/meta/frameworks/UnsupportedExternalAPIs.ql b/csharp/ql/src/meta/frameworks/UnsupportedExternalAPIs.ql index ddfaac675f5..56299f82d9c 100644 --- a/csharp/ql/src/meta/frameworks/UnsupportedExternalAPIs.ql +++ b/csharp/ql/src/meta/frameworks/UnsupportedExternalAPIs.ql @@ -9,13 +9,10 @@ */ private import csharp -private import semmle.code.csharp.dispatch.Dispatch -private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl private import Telemetry.ExternalApi from Call c, ExternalApi api where c.getTarget().getUnboundDeclaration() = api and - not api.isSupported() and - not api instanceof FlowSummaryImpl::Public::NeutralCallable + not api.isSupported() select c, "Call to unsupported external API $@.", api, api.toString() From 86888b894ab273c719cdcc1e67aaaed7867cb043 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 20 Feb 2023 13:49:48 +0100 Subject: [PATCH 335/415] Java: Re-factor isSupported for the telemetry queries. --- java/ql/src/Telemetry/ExternalApi.qll | 9 ++++++++- java/ql/src/Telemetry/SupportedExternalApis.ql | 6 +----- java/ql/src/Telemetry/UnsupportedExternalAPIs.ql | 6 +----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/java/ql/src/Telemetry/ExternalApi.qll b/java/ql/src/Telemetry/ExternalApi.qll index 5e28e540683..9c4a5c1751e 100644 --- a/java/ql/src/Telemetry/ExternalApi.qll +++ b/java/ql/src/Telemetry/ExternalApi.qll @@ -6,6 +6,7 @@ private import semmle.code.java.dataflow.ExternalFlow private import semmle.code.java.dataflow.FlowSources private import semmle.code.java.dataflow.FlowSummary private import semmle.code.java.dataflow.internal.DataFlowPrivate +private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl private import semmle.code.java.dataflow.TaintTracking pragma[nomagic] @@ -91,8 +92,14 @@ class ExternalApi extends Callable { pragma[nomagic] predicate isSink() { sinkNode(this.getAnInput(), _) } + /** Holds if this API is a known neutral. */ + pragma[nomagic] + predicate isNeutral() { this = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable() } + /** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */ - predicate isSupported() { this.hasSummary() or this.isSource() or this.isSink() } + predicate isSupported() { + this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral() + } } /** DEPRECATED: Alias for ExternalApi */ diff --git a/java/ql/src/Telemetry/SupportedExternalApis.ql b/java/ql/src/Telemetry/SupportedExternalApis.ql index ad1554dba91..a28b408cbb5 100644 --- a/java/ql/src/Telemetry/SupportedExternalApis.ql +++ b/java/ql/src/Telemetry/SupportedExternalApis.ql @@ -7,13 +7,9 @@ */ import java -import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl import ExternalApi -private predicate relevant(ExternalApi api) { - api.isSupported() or - api = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable() -} +private predicate relevant(ExternalApi api) { api.isSupported() } from string apiName, int usages where Results::restrict(apiName, usages) diff --git a/java/ql/src/Telemetry/UnsupportedExternalAPIs.ql b/java/ql/src/Telemetry/UnsupportedExternalAPIs.ql index 3031529626d..c4ff31847e3 100644 --- a/java/ql/src/Telemetry/UnsupportedExternalAPIs.ql +++ b/java/ql/src/Telemetry/UnsupportedExternalAPIs.ql @@ -7,13 +7,9 @@ */ import java -import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl import ExternalApi -private predicate relevant(ExternalApi api) { - not api.isSupported() and - not api = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable() -} +private predicate relevant(ExternalApi api) { not api.isSupported() } from string apiName, int usages where Results::restrict(apiName, usages) From dd7f54677b2b112dcf402971ae3cf76434017aa3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 13:31:51 +0000 Subject: [PATCH 336/415] Swift: Add inline expectation tags. --- .../dataflow/flowsources/FlowSources.expected | 26 ++--- .../flowsources/FlowSourcesInline.expected | 110 ------------------ .../dataflow/flowsources/alamofire.swift | 50 ++++---- .../flowsources/customurlschemes.swift | 27 ++--- .../dataflow/flowsources/data.swift | 2 +- .../dataflow/flowsources/filemanager.swift | 16 +-- .../dataflow/flowsources/generics.swift | 90 +++++++------- .../dataflow/flowsources/nsdata.swift | 4 +- .../dataflow/flowsources/string.swift | 12 +- .../dataflow/flowsources/url.swift | 6 +- .../dataflow/flowsources/webview.swift | 27 ++--- 11 files changed, 131 insertions(+), 239 deletions(-) diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected index de8dc32229e..36152e98f87 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected @@ -17,19 +17,19 @@ | alamofire.swift:448:20:448:49 | call to String.init(contentsOfFile:) | external | | alamofire.swift:455:23:455:32 | .data | external | | alamofire.swift:461:23:461:32 | .data | external | -| customurlschemes.swift:53:44:53:54 | url | external | -| customurlschemes.swift:57:52:57:68 | url | external | -| customurlschemes.swift:61:52:61:62 | url | external | -| customurlschemes.swift:66:9:66:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions | -| customurlschemes.swift:71:9:71:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions | -| customurlschemes.swift:77:59:77:76 | options | external | -| customurlschemes.swift:78:28:78:38 | continue | external | -| customurlschemes.swift:79:28:79:39 | didUpdate | external | -| customurlschemes.swift:80:28:80:65 | openURLContexts | external | -| customurlschemes.swift:86:59:86:76 | options | external | -| customurlschemes.swift:87:28:87:38 | continue | external | -| customurlschemes.swift:88:28:88:39 | didUpdate | external | -| customurlschemes.swift:89:28:89:65 | openURLContexts | external | +| customurlschemes.swift:54:44:54:54 | url | external | +| customurlschemes.swift:58:52:58:68 | url | external | +| customurlschemes.swift:62:52:62:62 | url | external | +| customurlschemes.swift:67:9:67:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions | +| customurlschemes.swift:72:9:72:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions | +| customurlschemes.swift:78:59:78:76 | options | external | +| customurlschemes.swift:79:28:79:38 | continue | external | +| customurlschemes.swift:80:28:80:39 | didUpdate | external | +| customurlschemes.swift:81:28:81:65 | openURLContexts | external | +| customurlschemes.swift:87:59:87:76 | options | external | +| customurlschemes.swift:88:28:88:38 | continue | external | +| customurlschemes.swift:89:28:89:39 | didUpdate | external | +| customurlschemes.swift:90:28:90:65 | openURLContexts | external | | data.swift:18:20:18:54 | call to Data.init(contentsOf:options:) | external | | file://:0:0:0:0 | .data | external | | file://:0:0:0:0 | .result | external | diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected index 1e905ce8fa8..e69de29bb2d 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected +++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.expected @@ -1,110 +0,0 @@ -| alamofire.swift:91:27:91:27 | .result | Unexpected result: source=remote | -| alamofire.swift:99:27:99:27 | .result | Unexpected result: source=remote | -| alamofire.swift:344:23:344:32 | .data | Unexpected result: source=remote | -| alamofire.swift:351:22:351:31 | .value | Unexpected result: source=remote | -| alamofire.swift:358:23:358:32 | .value | Unexpected result: source=remote | -| alamofire.swift:365:22:365:31 | .value | Unexpected result: source=remote | -| alamofire.swift:372:23:372:32 | .value | Unexpected result: source=remote | -| alamofire.swift:379:28:379:37 | .value | Unexpected result: source=remote | -| alamofire.swift:389:28:389:55 | call to String.init(contentsOfFile:) | Unexpected result: source=local | -| alamofire.swift:396:22:396:31 | .value | Unexpected result: source=remote | -| alamofire.swift:403:22:403:31 | .value | Unexpected result: source=remote | -| alamofire.swift:404:28:404:50 | call to String.init(contentsOf:) | Unexpected result: source=remote | -| alamofire.swift:411:23:411:32 | .value | Unexpected result: source=remote | -| alamofire.swift:418:22:418:31 | .value | Unexpected result: source=remote | -| alamofire.swift:425:23:425:32 | .value | Unexpected result: source=remote | -| alamofire.swift:431:28:431:37 | .value | Unexpected result: source=remote | -| alamofire.swift:448:20:448:49 | call to String.init(contentsOfFile:) | Unexpected result: source=local | -| alamofire.swift:455:23:455:32 | .data | Unexpected result: source=remote | -| alamofire.swift:461:23:461:32 | .data | Unexpected result: source=remote | -| customurlschemes.swift:53:44:53:54 | url | Unexpected result: source=remote | -| customurlschemes.swift:57:52:57:68 | url | Unexpected result: source=remote | -| customurlschemes.swift:61:52:61:62 | url | Unexpected result: source=remote | -| customurlschemes.swift:66:9:66:28 | ...[...] | Unexpected result: source=remote | -| customurlschemes.swift:71:9:71:28 | ...[...] | Unexpected result: source=remote | -| customurlschemes.swift:77:59:77:76 | options | Unexpected result: source=remote | -| customurlschemes.swift:78:28:78:38 | continue | Unexpected result: source=remote | -| customurlschemes.swift:79:28:79:39 | didUpdate | Unexpected result: source=remote | -| customurlschemes.swift:80:28:80:65 | openURLContexts | Unexpected result: source=remote | -| customurlschemes.swift:86:59:86:76 | options | Unexpected result: source=remote | -| customurlschemes.swift:87:28:87:38 | continue | Unexpected result: source=remote | -| customurlschemes.swift:88:28:88:39 | didUpdate | Unexpected result: source=remote | -| customurlschemes.swift:89:28:89:65 | openURLContexts | Unexpected result: source=remote | -| data.swift:18:20:18:54 | call to Data.init(contentsOf:options:) | Unexpected result: source=remote | -| filemanager.swift:37:23:37:86 | call to contentsOfDirectory(at:includingPropertiesForKeys:options:) | Unexpected result: source=local | -| filemanager.swift:38:23:38:58 | call to contentsOfDirectory(atPath:) | Unexpected result: source=local | -| filemanager.swift:39:19:39:52 | call to directoryContents(atPath:) | Unexpected result: source=local | -| filemanager.swift:41:23:41:58 | call to subpathsOfDirectory(atPath:) | Unexpected result: source=local | -| filemanager.swift:42:19:42:43 | call to subpaths(atPath:) | Unexpected result: source=local | -| filemanager.swift:44:19:44:60 | call to destinationOfSymbolicLink(atPath:) | Unexpected result: source=local | -| filemanager.swift:45:15:45:56 | call to pathContentOfSymbolicLink(atPath:) | Unexpected result: source=local | -| filemanager.swift:47:14:47:38 | call to contents(atPath:) | Unexpected result: source=local | -| generics.swift:10:9:10:16 | .source1 | Unexpected result: source=remote | -| generics.swift:11:9:11:16 | .source2 | Unexpected result: source=remote | -| generics.swift:12:9:12:24 | call to source3() | Unexpected result: source=remote | -| generics.swift:48:9:48:17 | .source1 | Unexpected result: source=remote | -| generics.swift:49:9:49:17 | .source2 | Unexpected result: source=remote | -| generics.swift:50:9:50:25 | call to source3() | Unexpected result: source=remote | -| generics.swift:51:9:51:18 | .source1 | Unexpected result: source=remote | -| generics.swift:52:9:52:18 | .source2 | Unexpected result: source=remote | -| generics.swift:53:9:53:26 | call to source3() | Unexpected result: source=remote | -| generics.swift:54:9:54:17 | .source1 | Unexpected result: source=remote | -| generics.swift:55:9:55:17 | .source2 | Unexpected result: source=remote | -| generics.swift:56:9:56:25 | call to source3() | Unexpected result: source=remote | -| generics.swift:57:9:57:17 | .source4 | Unexpected result: source=remote | -| generics.swift:58:9:58:17 | .source5 | Unexpected result: source=remote | -| generics.swift:59:9:59:25 | call to source6() | Unexpected result: source=remote | -| generics.swift:60:9:60:17 | .source7 | Unexpected result: source=remote | -| generics.swift:61:9:61:25 | call to source8() | Unexpected result: source=remote | -| generics.swift:62:9:62:18 | .source1 | Unexpected result: source=remote | -| generics.swift:63:9:63:18 | .source2 | Unexpected result: source=remote | -| generics.swift:64:9:64:26 | call to source3() | Unexpected result: source=remote | -| generics.swift:65:9:65:18 | .source9 | Unexpected result: source=remote | -| generics.swift:66:9:66:18 | .source10 | Unexpected result: source=remote | -| generics.swift:67:9:67:27 | call to source11() | Unexpected result: source=remote | -| generics.swift:68:9:68:18 | .source12 | Unexpected result: source=remote | -| generics.swift:69:9:69:27 | call to source13() | Unexpected result: source=remote | -| generics.swift:93:9:93:15 | .source0 | Unexpected result: source=remote | -| generics.swift:94:9:94:15 | .source1 | Unexpected result: source=remote | -| generics.swift:95:9:95:15 | .source2 | Unexpected result: source=remote | -| generics.swift:96:9:96:14 | .source0 | Unexpected result: source=remote | -| generics.swift:97:9:97:14 | .source1 | Unexpected result: source=remote | -| generics.swift:98:9:98:14 | .source2 | Unexpected result: source=remote | -| generics.swift:99:9:99:15 | .source0 | Unexpected result: source=remote | -| generics.swift:100:9:100:15 | .source1 | Unexpected result: source=remote | -| generics.swift:101:9:101:15 | .source2 | Unexpected result: source=remote | -| generics.swift:125:9:125:15 | .source0 | Unexpected result: source=remote | -| generics.swift:126:9:126:15 | .source1 | Unexpected result: source=remote | -| generics.swift:127:9:127:15 | .source2 | Unexpected result: source=remote | -| generics.swift:128:9:128:14 | .source0 | Unexpected result: source=remote | -| generics.swift:129:9:129:14 | .source1 | Unexpected result: source=remote | -| generics.swift:130:9:130:14 | .source2 | Unexpected result: source=remote | -| generics.swift:131:9:131:15 | .source0 | Unexpected result: source=remote | -| generics.swift:132:9:132:15 | .source1 | Unexpected result: source=remote | -| generics.swift:133:9:133:15 | .source2 | Unexpected result: source=remote | -| generics.swift:162:9:162:22 | call to source2() | Unexpected result: source=remote | -| generics.swift:163:9:163:22 | call to source3() | Unexpected result: source=remote | -| nsdata.swift:18:17:18:40 | call to NSData.init(contentsOf:) | Unexpected result: source=remote | -| nsdata.swift:19:17:19:53 | call to NSData.init(contentsOf:options:) | Unexpected result: source=remote | -| string.swift:56:21:56:44 | call to String.init(contentsOf:) | Unexpected result: source=remote | -| string.swift:57:21:57:77 | call to String.init(contentsOf:encoding:) | Unexpected result: source=remote | -| string.swift:59:21:59:69 | call to String.init(contentsOf:usedEncoding:) | Unexpected result: source=remote | -| string.swift:62:21:62:48 | call to String.init(contentsOfFile:) | Unexpected result: source=local | -| string.swift:63:21:63:81 | call to String.init(contentsOfFile:encoding:) | Unexpected result: source=local | -| string.swift:64:21:64:73 | call to String.init(contentsOfFile:usedEncoding:) | Unexpected result: source=local | -| url.swift:53:15:53:19 | .resourceBytes | Unexpected result: source=remote | -| url.swift:60:15:60:19 | .lines | Unexpected result: source=remote | -| url.swift:67:16:67:22 | .lines | Unexpected result: source=remote | -| webview.swift:13:32:13:49 | decidePolicyFor | Unexpected result: source=remote | -| webview.swift:14:32:14:49 | decidePolicyFor | Unexpected result: source=remote | -| webview.swift:41:82:41:102 | message | Unexpected result: source=remote | -| webview.swift:46:5:46:13 | .globalObject | Unexpected result: source=remote | -| webview.swift:47:5:47:39 | call to objectForKeyedSubscript(_:) | Unexpected result: source=remote | -| webview.swift:60:9:60:9 | .tainted | Unexpected result: source=remote | -| webview.swift:64:10:64:10 | self | Unexpected result: source=remote | -| webview.swift:64:18:64:24 | arg1 | Unexpected result: source=remote | -| webview.swift:64:29:64:35 | arg2 | Unexpected result: source=remote | -| webview.swift:72:32:72:49 | decidePolicyFor | Unexpected result: source=remote | -| webview.swift:73:32:73:49 | decidePolicyFor | Unexpected result: source=remote | -| webview.swift:79:32:79:49 | decidePolicyFor | Unexpected result: source=remote | -| webview.swift:80:32:80:49 | decidePolicyFor | Unexpected result: source=remote | diff --git a/swift/ql/test/library-tests/dataflow/flowsources/alamofire.swift b/swift/ql/test/library-tests/dataflow/flowsources/alamofire.swift index 5fdfad51534..34f3da01c23 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/alamofire.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/alamofire.swift @@ -88,7 +88,7 @@ struct DataResponse { let result: Result - var value: Success? { result.success } // SOURCE + var value: Success? { result.success } // $ source=remote } struct DownloadResponse { @@ -96,7 +96,7 @@ struct DownloadResponse { let result: Result - var value: Success? { result.success } // SOURCE + var value: Success? { result.success } // $ source=remote } typealias AFDataResponse = DataResponse @@ -341,42 +341,42 @@ func testAlamofire() { AF.request("http://example.com/").response { response in - if let data = response.data { // SOURCE + if let data = response.data { // $ source=remote // ... } } AF.request("http://example.com/").response(responseSerializer: MySerializer()) { response in - if let obj = response.value { // SOURCE + if let obj = response.value { // $ source=remote // ... } } AF.request("http://example.com/").responseData { response in - if let data = response.value { // SOURCE + if let data = response.value { // $ source=remote // ... } } AF.request("http://example.com/").responseString { response in - if let str = response.value { // SOURCE + if let str = response.value { // $ source=remote // ... } } AF.request("http://example.com/").responseJSON { response in - if let json = response.value { // SOURCE + if let json = response.value { // $ source=remote // ... } } AF.request("http://example.com/").responseDecodable(of: MyDecodable.self) { response in - if let decodable = response.value { // SOURCE + if let decodable = response.value { // $ source=remote // ... } } @@ -386,49 +386,49 @@ func testAlamofire() { AF.download("http://example.com/").response { response in if let path = response.fileURL?.path { - let str = try? String(contentsOfFile: path) // SOURCE + let str = try? String(contentsOfFile: path) // $ MISSING: source=remote $ SPURIOUS: source=local // ... } } AF.download("http://example.com/").response(responseSerializer: MySerializer()) { response in - if let obj = response.value { // SOURCE + if let obj = response.value { // $ source=remote // ... } } AF.download("http://example.com/").responseURL { response in - if let url = response.value { // just the URL [FALSE POSITIVE] - let str = try? String(contentsOf: url) // SOURCE + if let url = response.value { // $ SPURIOUS: source=remote (this is just the URL) + let str = try? String(contentsOf: url) // $ source=remote // ... } } AF.download("http://example.com/").responseData { response in - if let data = response.value { // SOURCE + if let data = response.value { // $ source=remote // ... } } AF.download("http://example.com/").responseString { response in - if let str = response.value { // SOURCE + if let str = response.value { // $ source=remote // ... } } AF.download("http://example.com/").responseJSON { response in - if let json = response.value { // SOURCE + if let json = response.value { // $ source=remote } } AF.download("http://example.com/").responseDecodable(of: MyDecodable.self) { response in - if let decodable = response.value { // SOURCE + if let decodable = response.value { // $ source=remote // ... } } @@ -445,20 +445,20 @@ func testAlamofire() { // ... } // ... - let str = try? String(contentsOfFile: myPath) // SOURCE + let str = try? String(contentsOfFile: myPath) // $ MISSING: source=remote SPURIOUS: source=local // chaining // - in practice there are a wide range of calls that can be chained through. AF.request("http://example.com/").response { response in - if let data = response.data { // SOURCE + if let data = response.data { // $ source=remote // ... } } .response { response in - if let data = response.data { // SOURCE + if let data = response.data { // $ source=remote // ... } } @@ -470,7 +470,7 @@ func testAlamofire() { switch stream.event { case let .stream(result): switch result { - case let .success(data): // SOURCE [NOT DETECTED] + case let .success(data): // $ MISSING: source=remote doSomethingWith(data) // ... } @@ -485,7 +485,7 @@ func testAlamofire() { switch stream.event { case let .stream(result): switch result { - case let .success(value): // SOURCE [NOT DETECTED] + case let .success(value): // $ MISSING: source=remote doSomethingWith(value) // ... } @@ -500,7 +500,7 @@ func testAlamofire() { switch stream.event { case let .stream(result): switch result { - case let .success(value): // SOURCE [NOT DETECTED] + case let .success(value): // MISSING: source=remote doSomethingWith(value) // ... } @@ -515,7 +515,7 @@ func testAlamofire() { switch stream.event { case let .stream(result): switch result { - case let .success(value): // SOURCE [NOT DETECTED] + case let .success(value): // MISSING: source=remote doSomethingWith(value) // ... } @@ -530,7 +530,7 @@ func testAlamofire() { AF.streamRequest("http://example.com/").responseStream { stream in if case let .stream(myResult) = stream.event { - if case let .success(myData) = myResult { // SOURCE [NOT DETECTED] + if case let .success(myData) = myResult { // MISSING: source=remote doSomethingWith(myData) } } @@ -539,7 +539,7 @@ func testAlamofire() { AF.streamRequest("http://example.com/").responseStream { stream in if case let .stream(myResult) = stream.event { - doSomethingWith(myResult.success!) // SOURCE [NOT DETECTED] + doSomethingWith(myResult.success!) // MISSING: source=remote } } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift index 0e96677fc2a..4a300dcd217 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift @@ -1,4 +1,5 @@ // --- stubs --- + class UIApplication { struct OpenURLOptionsKey : Hashable { static func == (lhs: OpenURLOptionsKey, rhs: OpenURLOptionsKey) -> Bool { @@ -50,41 +51,41 @@ protocol UISceneDelegate { // --- tests --- class AppDelegate: UIApplicationDelegate { - func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { // SOURCE + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { // $ source=remote return true } - func application(_ application: UIApplication, handleOpen url: URL) -> Bool { // SOURCE + func application(_ application: UIApplication, handleOpen url: URL) -> Bool { // $ source=remote return true } - func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { // SOURCE + func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { // $ source=remote return true } func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool { - launchOptions?[.url] // SOURCE + launchOptions?[.url] // $ source=remote return true } func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool { - launchOptions?[.url] // SOURCE + launchOptions?[.url] // $ source=remote return true } } class SceneDelegate : UISceneDelegate { - func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // SOURCE - func scene(_: UIScene, continue: NSUserActivity) {} // SOURCE - func scene(_: UIScene, didUpdate: NSUserActivity) {} // SOURCE - func scene(_: UIScene, openURLContexts: Set) {} // SOURCE + func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote + func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote + func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote + func scene(_: UIScene, openURLContexts: Set) {} // $ source=remote } class Extended {} extension Extended : UISceneDelegate { - func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // SOURCE - func scene(_: UIScene, continue: NSUserActivity) {} // SOURCE - func scene(_: UIScene, didUpdate: NSUserActivity) {} // SOURCE - func scene(_: UIScene, openURLContexts: Set) {} // SOURCE + func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote + func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote + func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote + func scene(_: UIScene, openURLContexts: Set) {} // $ source=remote } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/data.swift b/swift/ql/test/library-tests/dataflow/flowsources/data.swift index eef374b62a9..b0d9fd9a871 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/data.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/data.swift @@ -15,5 +15,5 @@ struct Data { func testData() { let url = URL(string: "http://example.com/") - let data = try Data(contentsOf: url!, options: []) // SOURCE + let data = try Data(contentsOf: url!, options: []) // $ source=remote } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift index af1b28664d8..869f4e58190 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/filemanager.swift @@ -34,17 +34,17 @@ class FileManager : NSObject { func testFileHandle(fm: FileManager, url: URL, path: String) { do { - let contents1 = try fm.contentsOfDirectory(at: url, includingPropertiesForKeys: nil) // SOURCE - let contents2 = try fm.contentsOfDirectory(atPath: path) // SOURCE - let contents3 = fm.directoryContents(atPath: path)! // SOURCE + let contents1 = try fm.contentsOfDirectory(at: url, includingPropertiesForKeys: nil) // $ source=local + let contents2 = try fm.contentsOfDirectory(atPath: path) // $ source=local + let contents3 = fm.directoryContents(atPath: path)! // $ source=local - let subpaths1 = try fm.subpathsOfDirectory(atPath: path) // SOURCE - let subpaths2 = fm.subpaths(atPath: path)! // SOURCE + let subpaths1 = try fm.subpathsOfDirectory(atPath: path) // $ source=local + let subpaths2 = fm.subpaths(atPath: path)! // $ source=local - let link1 = try fm.destinationOfSymbolicLink(atPath: path) // SOURCE - let link2 = fm.pathContentOfSymbolicLink(atPath: path)! // SOURCE + let link1 = try fm.destinationOfSymbolicLink(atPath: path) // $ source=local + let link2 = fm.pathContentOfSymbolicLink(atPath: path)! // $ source=local - let data = fm.contents(atPath: path)! // SOURCE + let data = fm.contents(atPath: path)! // $ source=local } catch { // ... } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/generics.swift b/swift/ql/test/library-tests/dataflow/flowsources/generics.swift index 9b52d0a27df..0a973b68e72 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/generics.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/generics.swift @@ -7,9 +7,9 @@ class MySimpleClass } func useMySimpleClass(simple: MySimpleClass) { - _ = simple.source1 // SOURCE - _ = simple.source2 // SOURCE - _ = simple.source3() // SOURCE + _ = simple.source1 // $ source=remote + _ = simple.source2 // $ source=remote + _ = simple.source3() // $ source=remote } // --- @@ -45,28 +45,28 @@ extension MyDerived2 } func useDerived(generic: MyGeneric, generic2: MyGeneric, derived: MyDerived, derived2: MyDerived2) { - _ = generic.source1 // SOURCE - _ = generic.source2 // SOURCE - _ = generic.source3() // SOURCE - _ = generic2.source1 // SOURCE - _ = generic2.source2 // SOURCE - _ = generic2.source3() // SOURCE - _ = derived.source1 // SOURCE - _ = derived.source2 // SOURCE - _ = derived.source3() // SOURCE - _ = derived.source4 // SOURCE - _ = derived.source5 // SOURCE - _ = derived.source6() // SOURCE - _ = derived.source7 // SOURCE - _ = derived.source8() // SOURCE - _ = derived2.source1 // SOURCE - _ = derived2.source2 // SOURCE - _ = derived2.source3() // SOURCE - _ = derived2.source9 // SOURCE - _ = derived2.source10 // SOURCE - _ = derived2.source11() // SOURCE - _ = derived2.source12 // SOURCE - _ = derived2.source13() // SOURCE + _ = generic.source1 // $ source=remote + _ = generic.source2 // $ source=remote + _ = generic.source3() // $ source=remote + _ = generic2.source1 // $ source=remote + _ = generic2.source2 // $ source=remote + _ = generic2.source3() // $ source=remote + _ = derived.source1 // $ source=remote + _ = derived.source2 // $ source=remote + _ = derived.source3() // $ source=remote + _ = derived.source4 // $ source=remote + _ = derived.source5 // $ source=remote + _ = derived.source6() // $ source=remote + _ = derived.source7 // $ source=remote + _ = derived.source8() // $ source=remote + _ = derived2.source1 // $ source=remote + _ = derived2.source2 // $ source=remote + _ = derived2.source3() // $ source=remote + _ = derived2.source9 // $ source=remote + _ = derived2.source10 // $ source=remote + _ = derived2.source11() // $ source=remote + _ = derived2.source12 // $ source=remote + _ = derived2.source13() // $ source=remote } // --- @@ -90,15 +90,15 @@ extension MyImpl { } func useProtocol(proto: MyProtocol, impl: MyImpl, impl2: MyImpl) { - _ = proto.source0 // SOURCE - _ = proto.source1 // SOURCE - _ = proto.source2 // SOURCE - _ = impl.source0 // SOURCE - _ = impl.source1 // SOURCE - _ = impl.source2 // SOURCE - _ = impl2.source0 // SOURCE - _ = impl2.source1 // SOURCE - _ = impl2.source2 // SOURCE + _ = proto.source0 // $ source=remote + _ = proto.source1 // $ source=remote + _ = proto.source2 // $ source=remote + _ = impl.source0 // $ source=remote + _ = impl.source1 // $ source=remote + _ = impl.source2 // $ source=remote + _ = impl2.source0 // $ source=remote + _ = impl2.source1 // $ source=remote + _ = impl2.source2 // $ source=remote } // --- @@ -122,15 +122,15 @@ extension MyImpl2 : MyProtocol2 { } func useProtocol2(proto: MyProtocol2, impl: MyImpl2, impl2: MyImpl2) { - _ = proto.source0 // SOURCE - _ = proto.source1 // SOURCE - _ = proto.source2 // SOURCE - _ = impl.source0 // SOURCE - _ = impl.source1 // SOURCE - _ = impl.source2 // SOURCE - _ = impl2.source0 // SOURCE - _ = impl2.source1 // SOURCE - _ = impl2.source2 // SOURCE + _ = proto.source0 // $ source=remote + _ = proto.source1 // $ source=remote + _ = proto.source2 // $ source=remote + _ = impl.source0 // $ source=remote + _ = impl.source1 // $ source=remote + _ = impl.source2 // $ source=remote + _ = impl2.source0 // $ source=remote + _ = impl2.source1 // $ source=remote + _ = impl2.source2 // $ source=remote } // --- @@ -159,6 +159,6 @@ class MyChildClass3: MyClass3 { func useProtocol3(impl: MyChildClass3) { _ = impl.source1() // not a source (`MyProtocol3.source1` is the declared source and `MyParentClass3` doesn't extend it) - _ = impl.source2() // SOURCE - _ = impl.source3() // SOURCE + _ = impl.source2() // $ source=remote + _ = impl.source3() // $ source=remote } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/nsdata.swift b/swift/ql/test/library-tests/dataflow/flowsources/nsdata.swift index d1258f10364..8f37704234c 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/nsdata.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/nsdata.swift @@ -15,6 +15,6 @@ class NSData { func testNSData() { let url = URL(string: "http://example.com/") - let _ = try NSData(contentsOf: url!) // SOURCE - let _ = try NSData(contentsOf: url!, options: []) // SOURCE + let _ = try NSData(contentsOf: url!) // $ source=remote + let _ = try NSData(contentsOf: url!, options: []) // $ source=remote } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/string.swift b/swift/ql/test/library-tests/dataflow/flowsources/string.swift index 24ad9f38a72..9becb5dac00 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/string.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/string.swift @@ -53,15 +53,15 @@ func testStrings() { let string2 = String(repeating: "abc", count: 10) let url = URL(string: "http://example.com/") - let string3 = try String(contentsOf: url!) // SOURCE - let string4 = try String(contentsOf: url!, encoding: String.Encoding.ascii) // SOURCE + let string3 = try String(contentsOf: url!) // $ source=remote + let string4 = try String(contentsOf: url!, encoding: String.Encoding.ascii) // $ source=remote var encoding = String.Encoding.ascii - let string5 = try String(contentsOf: url!, usedEncoding: &encoding) // SOURCE + let string5 = try String(contentsOf: url!, usedEncoding: &encoding) // $ source=remote let path = "file.txt" - let string6 = try String(contentsOfFile: path) // SOURCE - let string7 = try String(contentsOfFile: path, encoding: String.Encoding.ascii) // SOURCE - let string8 = try String(contentsOfFile: path, usedEncoding: &encoding) // SOURCE + let string6 = try String(contentsOfFile: path) // $ source=local + let string7 = try String(contentsOfFile: path, encoding: String.Encoding.ascii) // $ source=local + let string8 = try String(contentsOfFile: path, usedEncoding: &encoding) // $ source=local } catch { // ... } diff --git a/swift/ql/test/library-tests/dataflow/flowsources/url.swift b/swift/ql/test/library-tests/dataflow/flowsources/url.swift index 0eab68736ce..66df5c827db 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/url.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/url.swift @@ -50,21 +50,21 @@ func testURLs() async { do { let url = URL(string: "http://example.com/")! - let bytes = url.resourceBytes // SOURCE + let bytes = url.resourceBytes // $ source=remote for try await byte in bytes { print(byte) } - let lines = url.lines // SOURCE + let lines = url.lines // $ source=remote for try await line in lines { print(line) } - let lines2 = bytes.lines // SOURCE + let lines2 = bytes.lines // $ source=remote for try await line in lines2 { diff --git a/swift/ql/test/library-tests/dataflow/flowsources/webview.swift b/swift/ql/test/library-tests/dataflow/flowsources/webview.swift index 1f949839be1..6fbc2b69721 100644 --- a/swift/ql/test/library-tests/dataflow/flowsources/webview.swift +++ b/swift/ql/test/library-tests/dataflow/flowsources/webview.swift @@ -10,8 +10,8 @@ protocol WKScriptMessageHandler { } protocol WKNavigationDelegate { - func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) - func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) + func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) // $ SPURIOUS?: source=remote + func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) // $ SPURIOUS?: source=remote } class WKWebView {} @@ -30,21 +30,22 @@ class JSValue {} class JSContext { var globalObject: JSValue { get { return JSValue() } } - func objectForKeyedSubscript(_: Any!) -> JSValue! { return JSValue() } + func objectForKeyedSubscript(_: Any!) -> JSValue! { return JSValue() } func setObject(_: Any, forKeyedSubscript: (NSCopying & NSObjectProtocol) ) {} } protocol JSExport {} // --- tests --- + class TestMessageHandler: WKScriptMessageHandler { - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { // SOURCE + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { // $ source=remote } } func testJsContext(context: JSContext) { - context.globalObject // SOURCE - context.objectForKeyedSubscript("") // SOURCE + context.globalObject // $ source=remote + context.objectForKeyedSubscript("") // $ source=remote } protocol Exported : JSExport { @@ -57,25 +58,25 @@ class ExportedImpl : Exported { var notTainted: Any { get { return ""} } func readFields() { - tainted // SOURCE + tainted // $ source=remote notTainted } - func tainted(arg1: Any, arg2: Any) { // SOURCES + func tainted(arg1: Any, arg2: Any) { // $ source=remote } func notTainted(arg1: Any, arg2: Any) { } -} +} class WebViewDelegate : WKNavigationDelegate { - func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {} // SOURCE - func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {} // SOURCE + func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {} // $ source=remote + func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {} // $ source=remote } class Extended {} extension Extended : WKNavigationDelegate { - func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {} // SOURCE - func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {} // SOURCE + func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) {} // $ source=remote + func webView(_: WKWebView, decidePolicyFor: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {} // $ source=remote } From 690b5debf42f918f8c13ab4993ae2e22121d5b46 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 13:58:53 +0000 Subject: [PATCH 337/415] Swift: Remove the old test. --- .../dataflow/flowsources/FlowSources.expected | 117 ------------------ .../dataflow/flowsources/FlowSources.ql | 7 -- 2 files changed, 124 deletions(-) delete mode 100644 swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected delete mode 100644 swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected deleted file mode 100644 index 36152e98f87..00000000000 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.expected +++ /dev/null @@ -1,117 +0,0 @@ -| alamofire.swift:91:27:91:27 | .result | external | -| alamofire.swift:99:27:99:27 | .result | external | -| alamofire.swift:344:23:344:32 | .data | external | -| alamofire.swift:351:22:351:31 | .value | external | -| alamofire.swift:358:23:358:32 | .value | external | -| alamofire.swift:365:22:365:31 | .value | external | -| alamofire.swift:372:23:372:32 | .value | external | -| alamofire.swift:379:28:379:37 | .value | external | -| alamofire.swift:389:28:389:55 | call to String.init(contentsOfFile:) | external | -| alamofire.swift:396:22:396:31 | .value | external | -| alamofire.swift:403:22:403:31 | .value | external | -| alamofire.swift:404:28:404:50 | call to String.init(contentsOf:) | external | -| alamofire.swift:411:23:411:32 | .value | external | -| alamofire.swift:418:22:418:31 | .value | external | -| alamofire.swift:425:23:425:32 | .value | external | -| alamofire.swift:431:28:431:37 | .value | external | -| alamofire.swift:448:20:448:49 | call to String.init(contentsOfFile:) | external | -| alamofire.swift:455:23:455:32 | .data | external | -| alamofire.swift:461:23:461:32 | .data | external | -| customurlschemes.swift:54:44:54:54 | url | external | -| customurlschemes.swift:58:52:58:68 | url | external | -| customurlschemes.swift:62:52:62:62 | url | external | -| customurlschemes.swift:67:9:67:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions | -| customurlschemes.swift:72:9:72:28 | ...[...] | Remote URL in UIApplicationDelegate.application.launchOptions | -| customurlschemes.swift:78:59:78:76 | options | external | -| customurlschemes.swift:79:28:79:38 | continue | external | -| customurlschemes.swift:80:28:80:39 | didUpdate | external | -| customurlschemes.swift:81:28:81:65 | openURLContexts | external | -| customurlschemes.swift:87:59:87:76 | options | external | -| customurlschemes.swift:88:28:88:38 | continue | external | -| customurlschemes.swift:89:28:89:39 | didUpdate | external | -| customurlschemes.swift:90:28:90:65 | openURLContexts | external | -| data.swift:18:20:18:54 | call to Data.init(contentsOf:options:) | external | -| file://:0:0:0:0 | .data | external | -| file://:0:0:0:0 | .result | external | -| file://:0:0:0:0 | .result | external | -| file://:0:0:0:0 | .source1 | external | -| file://:0:0:0:0 | .source1 | external | -| file://:0:0:0:0 | .source4 | external | -| file://:0:0:0:0 | .source9 | external | -| filemanager.swift:37:23:37:86 | call to contentsOfDirectory(at:includingPropertiesForKeys:options:) | external | -| filemanager.swift:38:23:38:58 | call to contentsOfDirectory(atPath:) | external | -| filemanager.swift:39:19:39:52 | call to directoryContents(atPath:) | external | -| filemanager.swift:41:23:41:58 | call to subpathsOfDirectory(atPath:) | external | -| filemanager.swift:42:19:42:43 | call to subpaths(atPath:) | external | -| filemanager.swift:44:19:44:60 | call to destinationOfSymbolicLink(atPath:) | external | -| filemanager.swift:45:15:45:56 | call to pathContentOfSymbolicLink(atPath:) | external | -| filemanager.swift:47:14:47:38 | call to contents(atPath:) | external | -| generics.swift:10:9:10:16 | .source1 | external | -| generics.swift:11:9:11:16 | .source2 | external | -| generics.swift:12:9:12:24 | call to source3() | external | -| generics.swift:48:9:48:17 | .source1 | external | -| generics.swift:49:9:49:17 | .source2 | external | -| generics.swift:50:9:50:25 | call to source3() | external | -| generics.swift:51:9:51:18 | .source1 | external | -| generics.swift:52:9:52:18 | .source2 | external | -| generics.swift:53:9:53:26 | call to source3() | external | -| generics.swift:54:9:54:17 | .source1 | external | -| generics.swift:55:9:55:17 | .source2 | external | -| generics.swift:56:9:56:25 | call to source3() | external | -| generics.swift:57:9:57:17 | .source4 | external | -| generics.swift:58:9:58:17 | .source5 | external | -| generics.swift:59:9:59:25 | call to source6() | external | -| generics.swift:60:9:60:17 | .source7 | external | -| generics.swift:61:9:61:25 | call to source8() | external | -| generics.swift:62:9:62:18 | .source1 | external | -| generics.swift:63:9:63:18 | .source2 | external | -| generics.swift:64:9:64:26 | call to source3() | external | -| generics.swift:65:9:65:18 | .source9 | external | -| generics.swift:66:9:66:18 | .source10 | external | -| generics.swift:67:9:67:27 | call to source11() | external | -| generics.swift:68:9:68:18 | .source12 | external | -| generics.swift:69:9:69:27 | call to source13() | external | -| generics.swift:93:9:93:15 | .source0 | external | -| generics.swift:94:9:94:15 | .source1 | external | -| generics.swift:95:9:95:15 | .source2 | external | -| generics.swift:96:9:96:14 | .source0 | external | -| generics.swift:97:9:97:14 | .source1 | external | -| generics.swift:98:9:98:14 | .source2 | external | -| generics.swift:99:9:99:15 | .source0 | external | -| generics.swift:100:9:100:15 | .source1 | external | -| generics.swift:101:9:101:15 | .source2 | external | -| generics.swift:125:9:125:15 | .source0 | external | -| generics.swift:126:9:126:15 | .source1 | external | -| generics.swift:127:9:127:15 | .source2 | external | -| generics.swift:128:9:128:14 | .source0 | external | -| generics.swift:129:9:129:14 | .source1 | external | -| generics.swift:130:9:130:14 | .source2 | external | -| generics.swift:131:9:131:15 | .source0 | external | -| generics.swift:132:9:132:15 | .source1 | external | -| generics.swift:133:9:133:15 | .source2 | external | -| generics.swift:162:9:162:22 | call to source2() | external | -| generics.swift:163:9:163:22 | call to source3() | external | -| nsdata.swift:18:17:18:40 | call to NSData.init(contentsOf:) | external | -| nsdata.swift:19:17:19:53 | call to NSData.init(contentsOf:options:) | external | -| string.swift:56:21:56:44 | call to String.init(contentsOf:) | external | -| string.swift:57:21:57:77 | call to String.init(contentsOf:encoding:) | external | -| string.swift:59:21:59:69 | call to String.init(contentsOf:usedEncoding:) | external | -| string.swift:62:21:62:48 | call to String.init(contentsOfFile:) | external | -| string.swift:63:21:63:81 | call to String.init(contentsOfFile:encoding:) | external | -| string.swift:64:21:64:73 | call to String.init(contentsOfFile:usedEncoding:) | external | -| url.swift:53:15:53:19 | .resourceBytes | external | -| url.swift:60:15:60:19 | .lines | external | -| url.swift:67:16:67:22 | .lines | external | -| webview.swift:13:32:13:49 | decidePolicyFor | Navigation action of a WebView | -| webview.swift:14:32:14:49 | decidePolicyFor | Navigation action of a WebView | -| webview.swift:41:82:41:102 | message | external | -| webview.swift:46:5:46:13 | .globalObject | external | -| webview.swift:47:5:47:39 | call to objectForKeyedSubscript(_:) | external | -| webview.swift:60:9:60:9 | .tainted | Member of a type exposed through JSExport | -| webview.swift:64:10:64:10 | self | Member of a type exposed through JSExport | -| webview.swift:64:18:64:24 | arg1 | Member of a type exposed through JSExport | -| webview.swift:64:29:64:35 | arg2 | Member of a type exposed through JSExport | -| webview.swift:72:32:72:49 | decidePolicyFor | Navigation action of a WebView | -| webview.swift:73:32:73:49 | decidePolicyFor | Navigation action of a WebView | -| webview.swift:79:32:79:49 | decidePolicyFor | Navigation action of a WebView | -| webview.swift:80:32:80:49 | decidePolicyFor | Navigation action of a WebView | diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql deleted file mode 100644 index 513961dc16d..00000000000 --- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSources.ql +++ /dev/null @@ -1,7 +0,0 @@ -import swift -import codeql.swift.dataflow.FlowSources -import codeql.swift.dataflow.ExternalFlow -import FlowConfig - -from FlowSource source -select source, concat(source.getSourceType(), ", ") From f6fdf45359db9f02cb0bc0b80e3d86f324c40199 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 20 Feb 2023 15:32:50 +0100 Subject: [PATCH 338/415] remember to actually output the compilation dir --- .github/actions/cache-query-compilation/action.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/actions/cache-query-compilation/action.yml b/.github/actions/cache-query-compilation/action.yml index cd5c244f86a..e2d4c0d4a0f 100644 --- a/.github/actions/cache-query-compilation/action.yml +++ b/.github/actions/cache-query-compilation/action.yml @@ -9,7 +9,7 @@ inputs: outputs: cache-dir: description: "The directory where the cache was stored" - value: ${{ steps.fill-compilation-dir.outputs.compdir }} + value: ${{ steps.output-compilation-dir.outputs.compdir }} runs: using: composite @@ -42,7 +42,15 @@ runs: restore-keys: | # restore the latest cache if the exact cache is unavailable, to speed up compilation. codeql-compile-${{ inputs.key }}-${{ github.ref_name }}- codeql-compile-${{ inputs.key }}-main- + - name: Output-compilationdir + id: output-compilation-dir + shell: bash + run: | + echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT + env: + COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir - name: Fill compilation cache directory + id: fill-compilation-dir uses: actions/github-script@v6 env: COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir From 389b7ceff58f569d63aedbe3fcfcf6e8a1d97510 Mon Sep 17 00:00:00 2001 From: erik-krogh Date: Mon, 20 Feb 2023 15:34:03 +0100 Subject: [PATCH 339/415] support the new shared compilation cache directory --- .../cache-query-compilation/action.yml | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/actions/cache-query-compilation/action.yml b/.github/actions/cache-query-compilation/action.yml index e2d4c0d4a0f..0ad0b7da982 100644 --- a/.github/actions/cache-query-compilation/action.yml +++ b/.github/actions/cache-query-compilation/action.yml @@ -27,7 +27,9 @@ runs: if: ${{ github.event_name == 'pull_request' }} uses: actions/cache/restore@v3 with: - path: '**/.cache' + path: | + **/.cache + ~/.codeql/compile-cache key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }} restore-keys: | codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }} @@ -37,7 +39,9 @@ runs: if: ${{ github.event_name != 'pull_request' }} uses: actions/cache@v3 with: - path: '**/.cache' + path: | + **/.cache + ~/.codeql/compile-cache key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main restore-keys: | # restore the latest cache if the exact cache is unavailable, to speed up compilation. codeql-compile-${{ inputs.key }}-${{ github.ref_name }}- @@ -66,6 +70,7 @@ runs: const fs = require("fs"); const path = require("path"); + const os = require("os"); // the first argv is the cache folder to create. const COMBINED_CACHE_DIR = process.env.COMBINED_CACHE_DIR; @@ -105,6 +110,17 @@ runs: console.log(`Found .cache dir at ${dir}`); } + const globalCacheDir = path.join(os.homedir(), ".codeql", "compile-cache"); + if (fs.existsSync(globalCacheDir)) { + console.log("Found global home dir: " + globalCacheDir); + cacheDirs.push(globalCacheDir); + } + + if (cacheDirs.length === 0) { + console.log("No cache dirs found"); + return; + } + // mkdir -p ${COMBINED_CACHE_DIR} fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true }); From 31967cc032cc020303a5940f39000a4cd887f23a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 15:28:45 +0000 Subject: [PATCH 340/415] Swift: Add a couple of dataflow test cases for operators that behave as an identity function. --- .../test/library-tests/dataflow/dataflow/DataFlow.expected | 2 ++ swift/ql/test/library-tests/dataflow/dataflow/test.swift | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected index a4dc26557d5..8158c3d597e 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected @@ -324,6 +324,7 @@ nodes | test.swift:472:20:472:20 | cx [x] : | semmle.label | cx [x] : | | test.swift:472:20:472:23 | .x : | semmle.label | .x : | | test.swift:473:15:473:15 | z1 | semmle.label | z1 | +| test.swift:480:14:480:21 | call to source() | semmle.label | call to source() | 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 ... : | @@ -408,3 +409,4 @@ subpaths | 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:442:19:442:19 | a | test.swift:259:12:259:19 | call to source() : | test.swift:442:19:442:19 | a | result | | test.swift:473:15:473:15 | z1 | test.swift:259:12:259:19 | call to source() : | test.swift:473:15:473:15 | z1 | result | +| test.swift:480:14:480:21 | call to source() | test.swift:480:14:480:21 | call to source() | test.swift:480:14:480:21 | call to source() | result | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift index 57a0a6c64a7..1f48190444d 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift +++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift @@ -474,3 +474,8 @@ func testOptionalPropertyAccess(y: Int?) { guard let z2 = cy.x else { return } sink(arg: z2) } + +func testIdentityArithmetic() { + sink(arg: +source()) // $ MISSING: flow=479 + sink(arg: (source())) // $ flow=480 +} From 3038543242552f3b5044c578e2579dff56b518c0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 17:04:10 +0000 Subject: [PATCH 341/415] Swift: Add UnaryPlusExpr. --- .../swift/dataflow/internal/DataFlowPrivate.qll | 3 +++ .../swift/elements/expr/ArithmeticOperation.qll | 17 ++++++++++++++++- .../dataflow/dataflow/DataFlow.expected | 4 ++++ .../dataflow/dataflow/LocalFlow.expected | 1 + .../library-tests/dataflow/dataflow/test.swift | 2 +- .../arithmeticoperation.expected | 1 + .../arithmeticoperation/arithmeticoperation.ql | 2 ++ .../arithmeticoperation.swift | 1 + 8 files changed, 29 insertions(+), 2 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..059fd4ae26f 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -153,6 +153,9 @@ private module Cached { or nodeFrom.asExpr() = nodeTo.asExpr().(OptionalEvaluationExpr).getSubExpr() or + // flow through unary `+` (which does nothing) + nodeFrom.asExpr() = nodeTo.asExpr().(UnaryPlusExpr).getOperand() + or // flow through nil-coalescing operator `??` exists(BinaryExpr nco | nco.getOperator().(FreeFunctionDecl).getName() = "??(_:_:)" and diff --git a/swift/ql/lib/codeql/swift/elements/expr/ArithmeticOperation.qll b/swift/ql/lib/codeql/swift/elements/expr/ArithmeticOperation.qll index faa2941a637..c2c7dc346a3 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ArithmeticOperation.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ArithmeticOperation.qll @@ -97,7 +97,12 @@ class RemExpr extends BinaryExpr { * -a * ``` */ -class UnaryArithmeticOperation extends PrefixUnaryExpr instanceof UnaryMinusExpr { } +class UnaryArithmeticOperation extends PrefixUnaryExpr { + UnaryArithmeticOperation() { + this instanceof UnaryMinusExpr or + this instanceof UnaryPlusExpr + } +} /** * A unary minus expression. @@ -108,3 +113,13 @@ class UnaryArithmeticOperation extends PrefixUnaryExpr instanceof UnaryMinusExpr class UnaryMinusExpr extends PrefixUnaryExpr { UnaryMinusExpr() { this.getStaticTarget().getName() = "-(_:)" } } + +/** + * A unary plus expression. + * ``` + * +a + * ``` + */ +class UnaryPlusExpr extends PrefixUnaryExpr { + UnaryPlusExpr() { this.getStaticTarget().getName() = "+(_:)" } +} diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected index 8158c3d597e..88674e40dbe 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected @@ -154,6 +154,7 @@ edges | test.swift:472:20:472:20 | cx [x] : | test.swift:462:9:462:9 | self [x] : | | test.swift:472:20:472:20 | cx [x] : | test.swift:472:20:472:23 | .x : | | test.swift:472:20:472:23 | .x : | test.swift:473:15:473:15 | z1 | +| test.swift:479:14:479:21 | call to source() : | test.swift:479:13:479:21 | call to +(_:) | nodes | file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : | | file://:0:0:0:0 | .x : | semmle.label | .x : | @@ -324,6 +325,8 @@ nodes | test.swift:472:20:472:20 | cx [x] : | semmle.label | cx [x] : | | test.swift:472:20:472:23 | .x : | semmle.label | .x : | | test.swift:473:15:473:15 | z1 | semmle.label | z1 | +| test.swift:479:13:479:21 | call to +(_:) | semmle.label | call to +(_:) | +| test.swift:479:14:479:21 | call to source() : | semmle.label | call to source() : | | test.swift:480:14:480:21 | call to source() | semmle.label | call to source() | 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] &... : | @@ -409,4 +412,5 @@ subpaths | 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:442:19:442:19 | a | test.swift:259:12:259:19 | call to source() : | test.swift:442:19:442:19 | a | result | | test.swift:473:15:473:15 | z1 | test.swift:259:12:259:19 | call to source() : | test.swift:473:15:473:15 | z1 | result | +| test.swift:479:13:479:21 | call to +(_:) | test.swift:479:14:479:21 | call to source() : | test.swift:479:13:479:21 | call to +(_:) | result | | test.swift:480:14:480:21 | call to source() | test.swift:480:14:480:21 | call to source() | test.swift:480:14:480:21 | call to source() | result | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected index 9188fff70ef..b78de16c81f 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -390,3 +390,4 @@ | test.swift:472:20:472:23 | .x | test.swift:472:11:472:15 | SSA def(z1) | | test.swift:474:11:474:15 | SSA def(z2) | test.swift:475:15:475:15 | z2 | | test.swift:474:20:474:23 | .x | test.swift:474:11:474:15 | SSA def(z2) | +| test.swift:479:14:479:21 | call to source() | test.swift:479:13:479:21 | call to +(_:) | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift index 1f48190444d..2f298576bc0 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift +++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift @@ -476,6 +476,6 @@ func testOptionalPropertyAccess(y: Int?) { } func testIdentityArithmetic() { - sink(arg: +source()) // $ MISSING: flow=479 + sink(arg: +source()) // $ flow=479 sink(arg: (source())) // $ flow=480 } diff --git a/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.expected b/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.expected index 248df8d5d40..b9e72064b4f 100644 --- a/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.expected +++ b/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.expected @@ -4,3 +4,4 @@ | arithmeticoperation.swift:9:6:9:10 | ... ./(_:_:) ... | BinaryArithmeticOperation, DivExpr | | arithmeticoperation.swift:10:6:10:10 | ... .%(_:_:) ... | BinaryArithmeticOperation, RemExpr | | arithmeticoperation.swift:11:6:11:7 | call to -(_:) | UnaryArithmeticOperation, UnaryMinusExpr | +| arithmeticoperation.swift:12:6:12:7 | call to +(_:) | UnaryArithmeticOperation, UnaryPlusExpr | diff --git a/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.ql b/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.ql index 9d98daa68af..ce0de008255 100644 --- a/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.ql +++ b/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.ql @@ -16,6 +16,8 @@ string describe(ArithmeticOperation e) { e instanceof UnaryArithmeticOperation and result = "UnaryArithmeticOperation" or e instanceof UnaryMinusExpr and result = "UnaryMinusExpr" + or + e instanceof UnaryPlusExpr and result = "UnaryPlusExpr" } from ArithmeticOperation e diff --git a/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.swift b/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.swift index 096b6709600..74b15b2d846 100644 --- a/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.swift +++ b/swift/ql/test/library-tests/elements/expr/arithmeticoperation/arithmeticoperation.swift @@ -9,4 +9,5 @@ func test(c: Bool, x: Int, y: Int, z: Int) { v = 3 / 4; v = x % y; v = -x; + v = +x; } From 87c0b6195fc80480378a295955851592a1be7ba4 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 15:28:02 +0000 Subject: [PATCH 342/415] Swift: Add taint tests for various arithmetic operators. --- .../dataflow/taint/LocalTaint.expected | 59 ++++++++++++++++ .../library-tests/dataflow/taint/simple.swift | 70 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 swift/ql/test/library-tests/dataflow/taint/simple.swift diff --git a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected index 951def0fd91..9ceb0b4aa32 100644 --- a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected @@ -557,6 +557,65 @@ | nsmutabledata.swift:48:9:48:9 | SSA def(nsMutableDataTainted6) | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 | | nsmutabledata.swift:48:33:48:40 | call to source() | nsmutabledata.swift:48:9:48:9 | SSA def(nsMutableDataTainted6) | | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 | nsmutabledata.swift:49:15:49:37 | .mutableBytes | +| simple.swift:36:7:36:7 | SSA def(a) | simple.swift:37:13:37:13 | a | +| simple.swift:36:11:36:11 | 0 | simple.swift:36:7:36:7 | SSA def(a) | +| simple.swift:37:13:37:13 | [post] a | simple.swift:38:3:38:3 | a | +| simple.swift:37:13:37:13 | a | simple.swift:38:3:38:3 | a | +| simple.swift:38:3:38:3 | &... | simple.swift:39:13:39:13 | a | +| simple.swift:38:3:38:3 | [post] &... | simple.swift:39:13:39:13 | a | +| simple.swift:38:3:38:3 | a | simple.swift:38:3:38:3 | &... | +| simple.swift:39:13:39:13 | [post] a | simple.swift:40:3:40:3 | a | +| simple.swift:39:13:39:13 | a | simple.swift:40:3:40:3 | a | +| simple.swift:40:3:40:3 | &... | simple.swift:41:13:41:13 | a | +| simple.swift:40:3:40:3 | [post] &... | simple.swift:41:13:41:13 | a | +| simple.swift:40:3:40:3 | a | simple.swift:40:3:40:3 | &... | +| simple.swift:41:13:41:13 | [post] a | simple.swift:42:3:42:3 | a | +| simple.swift:41:13:41:13 | a | simple.swift:42:3:42:3 | a | +| simple.swift:42:3:42:3 | &... | simple.swift:43:13:43:13 | a | +| simple.swift:42:3:42:3 | [post] &... | simple.swift:43:13:43:13 | a | +| simple.swift:42:3:42:3 | a | simple.swift:42:3:42:3 | &... | +| simple.swift:44:3:44:7 | SSA def(a) | simple.swift:45:13:45:13 | a | +| simple.swift:44:7:44:7 | 0 | simple.swift:44:3:44:7 | SSA def(a) | +| simple.swift:47:7:47:7 | SSA def(b) | simple.swift:48:3:48:3 | b | +| simple.swift:47:11:47:11 | 128 | simple.swift:47:7:47:7 | SSA def(b) | +| simple.swift:48:3:48:3 | &... | simple.swift:49:13:49:13 | b | +| simple.swift:48:3:48:3 | [post] &... | simple.swift:49:13:49:13 | b | +| simple.swift:48:3:48:3 | b | simple.swift:48:3:48:3 | &... | +| simple.swift:49:13:49:13 | [post] b | simple.swift:50:3:50:3 | b | +| simple.swift:49:13:49:13 | b | simple.swift:50:3:50:3 | b | +| simple.swift:50:3:50:3 | &... | simple.swift:51:13:51:13 | b | +| simple.swift:50:3:50:3 | [post] &... | simple.swift:51:13:51:13 | b | +| simple.swift:50:3:50:3 | b | simple.swift:50:3:50:3 | &... | +| simple.swift:53:7:53:7 | SSA def(c) | simple.swift:54:3:54:3 | c | +| simple.swift:53:11:53:11 | 10 | simple.swift:53:7:53:7 | SSA def(c) | +| simple.swift:54:3:54:3 | &... | simple.swift:55:13:55:13 | c | +| simple.swift:54:3:54:3 | [post] &... | simple.swift:55:13:55:13 | c | +| simple.swift:54:3:54:3 | c | simple.swift:54:3:54:3 | &... | +| simple.swift:55:13:55:13 | [post] c | simple.swift:56:3:56:3 | c | +| simple.swift:55:13:55:13 | c | simple.swift:56:3:56:3 | c | +| simple.swift:56:3:56:3 | &... | simple.swift:57:13:57:13 | c | +| simple.swift:56:3:56:3 | [post] &... | simple.swift:57:13:57:13 | c | +| simple.swift:56:3:56:3 | c | simple.swift:56:3:56:3 | &... | +| simple.swift:59:7:59:7 | SSA def(d) | simple.swift:60:3:60:3 | d | +| simple.swift:59:11:59:11 | 100 | simple.swift:59:7:59:7 | SSA def(d) | +| simple.swift:60:3:60:3 | &... | simple.swift:61:13:61:13 | d | +| simple.swift:60:3:60:3 | [post] &... | simple.swift:61:13:61:13 | d | +| simple.swift:60:3:60:3 | d | simple.swift:60:3:60:3 | &... | +| simple.swift:61:13:61:13 | [post] d | simple.swift:62:3:62:3 | d | +| simple.swift:61:13:61:13 | d | simple.swift:62:3:62:3 | d | +| simple.swift:62:3:62:3 | &... | simple.swift:63:13:63:13 | d | +| simple.swift:62:3:62:3 | [post] &... | simple.swift:63:13:63:13 | d | +| simple.swift:62:3:62:3 | d | simple.swift:62:3:62:3 | &... | +| simple.swift:65:7:65:7 | SSA def(e) | simple.swift:66:3:66:3 | e | +| simple.swift:65:11:65:11 | 1000 | simple.swift:65:7:65:7 | SSA def(e) | +| simple.swift:66:3:66:3 | &... | simple.swift:67:13:67:13 | e | +| simple.swift:66:3:66:3 | [post] &... | simple.swift:67:13:67:13 | e | +| simple.swift:66:3:66:3 | e | simple.swift:66:3:66:3 | &... | +| simple.swift:67:13:67:13 | [post] e | simple.swift:68:3:68:3 | e | +| simple.swift:67:13:67:13 | e | simple.swift:68:3:68:3 | e | +| simple.swift:68:3:68:3 | &... | simple.swift:69:13:69:13 | e | +| simple.swift:68:3:68:3 | [post] &... | simple.swift:69:13:69:13 | e | +| simple.swift:68:3:68:3 | e | simple.swift:68:3:68:3 | &... | | string.swift:6:8:6:8 | SSA def(self) | string.swift:6:8:6:8 | self[return] | | string.swift:6:8:6:8 | self | string.swift:6:8:6:8 | SSA def(self) | | string.swift:10:3:10:3 | SSA def(self) | string.swift:10:3:10:27 | self[return] | diff --git a/swift/ql/test/library-tests/dataflow/taint/simple.swift b/swift/ql/test/library-tests/dataflow/taint/simple.swift new file mode 100644 index 00000000000..97941568371 --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/taint/simple.swift @@ -0,0 +1,70 @@ + +// --- stubs --- + +// --- tests --- + +func source() -> Int { return 0; } +func sink(arg: Any) {} + +func taintThroughArithmetic() { + // arithmetic + + sink(arg: 1 + source()) // $ MISSING: tainted= + sink(arg: source() + 1) // $ MISSING: tainted= + sink(arg: 1 - source()) // $ MISSING: tainted= + sink(arg: source() - 1) // $ MISSING: tainted= + sink(arg: 2 * source()) // $ MISSING: tainted= + sink(arg: source() * 2) // $ MISSING: tainted= + sink(arg: 100 / source()) // $ MISSING: tainted= + sink(arg: source() / 100) // $ MISSING: tainted= + sink(arg: 100 % source()) // $ MISSING: tainted= + sink(arg: source() % 100) // $ MISSING: tainted= + + sink(arg: -source()) // $ MISSING: tainted= + + // overflow operators + + sink(arg: 1 &+ source()) // $ MISSING: tainted= + sink(arg: source() &+ 1) // $ MISSING: tainted= + sink(arg: 1 &- source()) // $ MISSING: tainted= + sink(arg: source() &- 1) // $ MISSING: tainted= + sink(arg: 2 &* source()) // $ MISSING: tainted= + sink(arg: source() &* 2) // $ MISSING: tainted= +} + +func taintThroughAssignmentArithmetic() { + var a = 0 + sink(arg: a) + a += 1 + sink(arg: a) + a += source() + sink(arg: a) // $ MISSING: tainted= + a += 1 + sink(arg: a) // $ MISSING: tainted= + a = 0 + sink(arg: a) + + var b = 128 + b -= source() + sink(arg: b) // $ MISSING: tainted= + b -= 1 + sink(arg: b) // $ MISSING: tainted= + + var c = 10 + c *= source() + sink(arg: c) // $ MISSING: tainted= + c *= 2 + sink(arg: c) // $ MISSING: tainted= + + var d = 100 + d /= source() + sink(arg: d) // $ MISSING: tainted= + d /= 2 + sink(arg: d) // $ MISSING: tainted= + + var e = 1000 + e %= source() + sink(arg: e) // $ MISSING: tainted= + e %= 100 + sink(arg: e) // $ MISSING: tainted= +} From 9b117fefd7ef2eb64aecffb6417b2effae31b70d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 20 Feb 2023 16:23:39 +0000 Subject: [PATCH 343/415] Swift: Generalize the arithmetic we allow taint through. --- .../internal/TaintTrackingPrivate.qll | 8 +--- .../dataflow/taint/LocalTaint.expected | 21 +++++++++ .../dataflow/taint/Taint.expected | 44 +++++++++++++++++++ .../library-tests/dataflow/taint/simple.swift | 22 +++++----- 4 files changed, 78 insertions(+), 17 deletions(-) diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/TaintTrackingPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/TaintTrackingPrivate.qll index 6fdcca98c36..911f44627a6 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/TaintTrackingPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/TaintTrackingPrivate.qll @@ -43,12 +43,8 @@ private module Cached { nodeFrom.asExpr() = interpolated.getAppendingExpr() ) or - // allow flow through string concatenation. - exists(AddExpr ae | - ae.getAnOperand() = nodeFrom.asExpr() and - ae = nodeTo.asExpr() and - ae.getType().getName() = "String" - ) + // allow flow through arithmetic (this case includes string concatenation) + nodeTo.asExpr().(ArithmeticOperation).getAnOperand() = nodeFrom.asExpr() or // flow through a subscript access exists(SubscriptExpr se | diff --git a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected index 9ceb0b4aa32..f6dd70752fa 100644 --- a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected @@ -557,6 +557,27 @@ | nsmutabledata.swift:48:9:48:9 | SSA def(nsMutableDataTainted6) | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 | | nsmutabledata.swift:48:33:48:40 | call to source() | nsmutabledata.swift:48:9:48:9 | SSA def(nsMutableDataTainted6) | | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 | nsmutabledata.swift:49:15:49:37 | .mutableBytes | +| simple.swift:12:13:12:13 | 1 | simple.swift:12:13:12:24 | ... .+(_:_:) ... | +| simple.swift:12:17:12:24 | call to source() | simple.swift:12:13:12:24 | ... .+(_:_:) ... | +| simple.swift:13:13:13:20 | call to source() | simple.swift:13:13:13:24 | ... .+(_:_:) ... | +| simple.swift:13:24:13:24 | 1 | simple.swift:13:13:13:24 | ... .+(_:_:) ... | +| simple.swift:14:13:14:13 | 1 | simple.swift:14:13:14:24 | ... .-(_:_:) ... | +| simple.swift:14:17:14:24 | call to source() | simple.swift:14:13:14:24 | ... .-(_:_:) ... | +| simple.swift:15:13:15:20 | call to source() | simple.swift:15:13:15:24 | ... .-(_:_:) ... | +| simple.swift:15:24:15:24 | 1 | simple.swift:15:13:15:24 | ... .-(_:_:) ... | +| simple.swift:16:13:16:13 | 2 | simple.swift:16:13:16:24 | ... .*(_:_:) ... | +| simple.swift:16:17:16:24 | call to source() | simple.swift:16:13:16:24 | ... .*(_:_:) ... | +| simple.swift:17:13:17:20 | call to source() | simple.swift:17:13:17:24 | ... .*(_:_:) ... | +| simple.swift:17:24:17:24 | 2 | simple.swift:17:13:17:24 | ... .*(_:_:) ... | +| simple.swift:18:13:18:13 | 100 | simple.swift:18:13:18:26 | ... ./(_:_:) ... | +| simple.swift:18:19:18:26 | call to source() | simple.swift:18:13:18:26 | ... ./(_:_:) ... | +| simple.swift:19:13:19:20 | call to source() | simple.swift:19:13:19:24 | ... ./(_:_:) ... | +| simple.swift:19:24:19:24 | 100 | simple.swift:19:13:19:24 | ... ./(_:_:) ... | +| simple.swift:20:13:20:13 | 100 | simple.swift:20:13:20:26 | ... .%(_:_:) ... | +| simple.swift:20:19:20:26 | call to source() | simple.swift:20:13:20:26 | ... .%(_:_:) ... | +| simple.swift:21:13:21:20 | call to source() | simple.swift:21:13:21:24 | ... .%(_:_:) ... | +| simple.swift:21:24:21:24 | 100 | simple.swift:21:13:21:24 | ... .%(_:_:) ... | +| simple.swift:23:14:23:21 | call to source() | simple.swift:23:13:23:21 | call to -(_:) | | simple.swift:36:7:36:7 | SSA def(a) | simple.swift:37:13:37:13 | a | | simple.swift:36:11:36:11 | 0 | simple.swift:36:7:36:7 | SSA def(a) | | simple.swift:37:13:37:13 | [post] a | simple.swift:38:3:38:3 | a | diff --git a/swift/ql/test/library-tests/dataflow/taint/Taint.expected b/swift/ql/test/library-tests/dataflow/taint/Taint.expected index fef44d98a5a..1ea47a03460 100644 --- a/swift/ql/test/library-tests/dataflow/taint/Taint.expected +++ b/swift/ql/test/library-tests/dataflow/taint/Taint.expected @@ -331,6 +331,17 @@ edges | nsmutabledata.swift:48:33:48:40 | call to source() : | nsmutabledata.swift:49:15:49:37 | .mutableBytes | | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 : | nsmutabledata.swift:13:9:13:9 | self : | | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 : | nsmutabledata.swift:49:15:49:37 | .mutableBytes | +| simple.swift:12:17:12:24 | call to source() : | simple.swift:12:13:12:24 | ... .+(_:_:) ... | +| simple.swift:13:13:13:20 | call to source() : | simple.swift:13:13:13:24 | ... .+(_:_:) ... | +| simple.swift:14:17:14:24 | call to source() : | simple.swift:14:13:14:24 | ... .-(_:_:) ... | +| simple.swift:15:13:15:20 | call to source() : | simple.swift:15:13:15:24 | ... .-(_:_:) ... | +| simple.swift:16:17:16:24 | call to source() : | simple.swift:16:13:16:24 | ... .*(_:_:) ... | +| simple.swift:17:13:17:20 | call to source() : | simple.swift:17:13:17:24 | ... .*(_:_:) ... | +| simple.swift:18:19:18:26 | call to source() : | simple.swift:18:13:18:26 | ... ./(_:_:) ... | +| simple.swift:19:13:19:20 | call to source() : | simple.swift:19:13:19:24 | ... ./(_:_:) ... | +| simple.swift:20:19:20:26 | call to source() : | simple.swift:20:13:20:26 | ... .%(_:_:) ... | +| simple.swift:21:13:21:20 | call to source() : | simple.swift:21:13:21:24 | ... .%(_:_:) ... | +| simple.swift:23:14:23:21 | call to source() : | simple.swift:23:13:23:21 | call to -(_:) | | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(data:encoding:) : | | string.swift:64:3:64:63 | [summary param] 0 in String.init(format:_:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:_:) : | | string.swift:65:3:65:60 | [summary param] 0 in String.init(format:arguments:) : | file://:0:0:0:0 | [summary] to write: return (return) in String.init(format:arguments:) : | @@ -1370,6 +1381,28 @@ nodes | nsmutabledata.swift:48:33:48:40 | call to source() : | semmle.label | call to source() : | | nsmutabledata.swift:49:15:49:15 | nsMutableDataTainted6 : | semmle.label | nsMutableDataTainted6 : | | nsmutabledata.swift:49:15:49:37 | .mutableBytes | semmle.label | .mutableBytes | +| simple.swift:12:13:12:24 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| simple.swift:12:17:12:24 | call to source() : | semmle.label | call to source() : | +| simple.swift:13:13:13:20 | call to source() : | semmle.label | call to source() : | +| simple.swift:13:13:13:24 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| simple.swift:14:13:14:24 | ... .-(_:_:) ... | semmle.label | ... .-(_:_:) ... | +| simple.swift:14:17:14:24 | call to source() : | semmle.label | call to source() : | +| simple.swift:15:13:15:20 | call to source() : | semmle.label | call to source() : | +| simple.swift:15:13:15:24 | ... .-(_:_:) ... | semmle.label | ... .-(_:_:) ... | +| simple.swift:16:13:16:24 | ... .*(_:_:) ... | semmle.label | ... .*(_:_:) ... | +| simple.swift:16:17:16:24 | call to source() : | semmle.label | call to source() : | +| simple.swift:17:13:17:20 | call to source() : | semmle.label | call to source() : | +| simple.swift:17:13:17:24 | ... .*(_:_:) ... | semmle.label | ... .*(_:_:) ... | +| simple.swift:18:13:18:26 | ... ./(_:_:) ... | semmle.label | ... ./(_:_:) ... | +| simple.swift:18:19:18:26 | call to source() : | semmle.label | call to source() : | +| simple.swift:19:13:19:20 | call to source() : | semmle.label | call to source() : | +| simple.swift:19:13:19:24 | ... ./(_:_:) ... | semmle.label | ... ./(_:_:) ... | +| simple.swift:20:13:20:26 | ... .%(_:_:) ... | semmle.label | ... .%(_:_:) ... | +| simple.swift:20:19:20:26 | call to source() : | semmle.label | call to source() : | +| simple.swift:21:13:21:20 | call to source() : | semmle.label | call to source() : | +| simple.swift:21:13:21:24 | ... .%(_:_:) ... | semmle.label | ... .%(_:_:) ... | +| simple.swift:23:13:23:21 | call to -(_:) | semmle.label | call to -(_:) | +| simple.swift:23:14:23:21 | call to source() : | semmle.label | call to source() : | | string.swift:60:2:60:54 | [summary param] 0 in String.init(data:encoding:) : | semmle.label | [summary param] 0 in String.init(data:encoding:) : | | string.swift:64:3:64:63 | [summary param] 0 in String.init(format:_:) : | semmle.label | [summary param] 0 in String.init(format:_:) : | | string.swift:65:3:65:60 | [summary param] 0 in String.init(format:arguments:) : | semmle.label | [summary param] 0 in String.init(format:arguments:) : | @@ -2084,6 +2117,17 @@ subpaths | nsmutabledata.swift:41:15:41:15 | nsMutableDataTainted4 | nsmutabledata.swift:40:66:40:73 | call to source() : | nsmutabledata.swift:41:15:41:15 | nsMutableDataTainted4 | result | | nsmutabledata.swift:45:15:45:15 | nsMutableDataTainted5 | nsmutabledata.swift:44:35:44:42 | call to source() : | nsmutabledata.swift:45:15:45:15 | nsMutableDataTainted5 | result | | nsmutabledata.swift:49:15:49:37 | .mutableBytes | nsmutabledata.swift:48:33:48:40 | call to source() : | nsmutabledata.swift:49:15:49:37 | .mutableBytes | result | +| simple.swift:12:13:12:24 | ... .+(_:_:) ... | simple.swift:12:17:12:24 | call to source() : | simple.swift:12:13:12:24 | ... .+(_:_:) ... | result | +| simple.swift:13:13:13:24 | ... .+(_:_:) ... | simple.swift:13:13:13:20 | call to source() : | simple.swift:13:13:13:24 | ... .+(_:_:) ... | result | +| simple.swift:14:13:14:24 | ... .-(_:_:) ... | simple.swift:14:17:14:24 | call to source() : | simple.swift:14:13:14:24 | ... .-(_:_:) ... | result | +| simple.swift:15:13:15:24 | ... .-(_:_:) ... | simple.swift:15:13:15:20 | call to source() : | simple.swift:15:13:15:24 | ... .-(_:_:) ... | result | +| simple.swift:16:13:16:24 | ... .*(_:_:) ... | simple.swift:16:17:16:24 | call to source() : | simple.swift:16:13:16:24 | ... .*(_:_:) ... | result | +| simple.swift:17:13:17:24 | ... .*(_:_:) ... | simple.swift:17:13:17:20 | call to source() : | simple.swift:17:13:17:24 | ... .*(_:_:) ... | result | +| simple.swift:18:13:18:26 | ... ./(_:_:) ... | simple.swift:18:19:18:26 | call to source() : | simple.swift:18:13:18:26 | ... ./(_:_:) ... | result | +| simple.swift:19:13:19:24 | ... ./(_:_:) ... | simple.swift:19:13:19:20 | call to source() : | simple.swift:19:13:19:24 | ... ./(_:_:) ... | result | +| simple.swift:20:13:20:26 | ... .%(_:_:) ... | simple.swift:20:19:20:26 | call to source() : | simple.swift:20:13:20:26 | ... .%(_:_:) ... | result | +| simple.swift:21:13:21:24 | ... .%(_:_:) ... | simple.swift:21:13:21:20 | call to source() : | simple.swift:21:13:21:24 | ... .%(_:_:) ... | result | +| simple.swift:23:13:23:21 | call to -(_:) | simple.swift:23:14:23:21 | call to source() : | simple.swift:23:13:23:21 | call to -(_:) | result | | string.swift:139:13:139:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:139:13:139:13 | "..." | result | | string.swift:141:13:141:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:141:13:141:13 | "..." | result | | string.swift:143:13:143:13 | "..." | string.swift:137:11:137:18 | call to source() : | string.swift:143:13:143:13 | "..." | result | diff --git a/swift/ql/test/library-tests/dataflow/taint/simple.swift b/swift/ql/test/library-tests/dataflow/taint/simple.swift index 97941568371..8ede1e6eb0c 100644 --- a/swift/ql/test/library-tests/dataflow/taint/simple.swift +++ b/swift/ql/test/library-tests/dataflow/taint/simple.swift @@ -9,18 +9,18 @@ func sink(arg: Any) {} func taintThroughArithmetic() { // arithmetic - sink(arg: 1 + source()) // $ MISSING: tainted= - sink(arg: source() + 1) // $ MISSING: tainted= - sink(arg: 1 - source()) // $ MISSING: tainted= - sink(arg: source() - 1) // $ MISSING: tainted= - sink(arg: 2 * source()) // $ MISSING: tainted= - sink(arg: source() * 2) // $ MISSING: tainted= - sink(arg: 100 / source()) // $ MISSING: tainted= - sink(arg: source() / 100) // $ MISSING: tainted= - sink(arg: 100 % source()) // $ MISSING: tainted= - sink(arg: source() % 100) // $ MISSING: tainted= + sink(arg: 1 + source()) // $ tainted=12 + sink(arg: source() + 1) // $ tainted=13 + sink(arg: 1 - source()) // $ tainted=14 + sink(arg: source() - 1) // $ tainted=15 + sink(arg: 2 * source()) // $ tainted=16 + sink(arg: source() * 2) // $ tainted=17 + sink(arg: 100 / source()) // $ tainted=18 + sink(arg: source() / 100) // $ tainted=19 + sink(arg: 100 % source()) // $ tainted=20 + sink(arg: source() % 100) // $ tainted=21 - sink(arg: -source()) // $ MISSING: tainted= + sink(arg: -source()) // $ tainted=23 // overflow operators From 814bef021d9a34042767939e0a1421568a9b89cc Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Tue, 21 Feb 2023 13:49:33 +0100 Subject: [PATCH 344/415] Ruby: update tree-sitter-embedded-template --- ruby/Cargo.lock | Bin 18234 -> 18234 bytes ruby/extractor/Cargo.toml | 2 +- ruby/generator/Cargo.toml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/Cargo.lock b/ruby/Cargo.lock index caf9a572718e2ab609dcbdbade7cdbae2b205510..e9c69518d2a214739aed2cf9cd63e62a9f488fe3 100644 GIT binary patch delta 100 zcmdnh$GEGHaYMgDppk)bnt4)+ak61jQd&}qrA1n@p=Dx9ib)cXm1JaSoNQofX=Grk ROsvAmA9ckxe{*nQ0{~yqAI1Ox delta 100 zcmdnh$GEGHaYMgDV4|V1frY7siDhz{nPsYxiGg8ivWZEmu|;xPTC#D9xpA72QJQf| SnliBpCx6rx+x*SJg$)1*xgOR4 diff --git a/ruby/extractor/Cargo.toml b/ruby/extractor/Cargo.toml index 1e72275abc4..9c18d3b4161 100644 --- a/ruby/extractor/Cargo.toml +++ b/ruby/extractor/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" flate2 = "1.0" node-types = { path = "../node-types" } tree-sitter = "0.20" -tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "a13085849cf69e2401ec44e38cffc3d73f22f3df" } +tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "203f7bd3c1bbfbd98fc19add4b8fcb213c059205" } tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "206c7077164372c596ffa8eaadb9435c28941364" } clap = "3.0" tracing = "0.1" diff --git a/ruby/generator/Cargo.toml b/ruby/generator/Cargo.toml index f72099d4142..49745e813a9 100644 --- a/ruby/generator/Cargo.toml +++ b/ruby/generator/Cargo.toml @@ -11,5 +11,5 @@ clap = "3.0" node-types = { path = "../node-types" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } -tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "a13085849cf69e2401ec44e38cffc3d73f22f3df" } +tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "203f7bd3c1bbfbd98fc19add4b8fcb213c059205" } tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "206c7077164372c596ffa8eaadb9435c28941364" } From b5ebd1a0fd420085e36b711cd8ad8d45f936ac8e Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 21 Feb 2023 12:59:30 +0000 Subject: [PATCH 345/415] QL: Add JSON (+C/L) extraction --- ql/Cargo.lock | Bin 21930 -> 22220 bytes ql/autobuilder/src/main.rs | 3 + ql/extractor/Cargo.toml | 1 + ql/extractor/src/main.rs | 15 ++ ql/generator/Cargo.toml | 1 + ql/generator/src/main.rs | 4 + .../src/codeql_ql/ast/internal/TreeSitter.qll | 159 ++++++++++++++++++ ql/ql/src/ql.dbscheme | 92 ++++++++++ 8 files changed, 275 insertions(+) diff --git a/ql/Cargo.lock b/ql/Cargo.lock index 8bcae25b4aa2f4b96581f96c22f382a1dfc51b9f..be8f122d54af7824817eff5888379d8f9a589ccb 100644 GIT binary patch delta 195 zcmZ3rn(@q9#tn%&ELp|*d6NTlK7tvW4RoJKh=PQaxXMzCiZk=`6l@ig4D^f)ChK{q z)|Vuf7ANKDmlUO@>K12~l%y8vf)wkeXO`F(rIy*6m>VXiCMKJhq!=2Rr std::io::Result<()> { .arg("--include-extension=.ql") .arg("--include-extension=.qll") .arg("--include-extension=.dbscheme") + .arg("--include-extension=.json") + .arg("--include-extension=.jsonc") + .arg("--include-extension=.jsonl") .arg("--include=**/qlpack.yml") .arg("--include=deprecated.blame") .arg("--size-limit=5m") diff --git a/ql/extractor/Cargo.toml b/ql/extractor/Cargo.toml index c76d824f27f..dd9ed32552b 100644 --- a/ql/extractor/Cargo.toml +++ b/ql/extractor/Cargo.toml @@ -14,6 +14,7 @@ tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", re tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} +tree-sitter-json = {git = "https://github.com/tausbn/tree-sitter-json.git", rev = "471ceac44d127e609afa349cf0a59370791fe8b3"} clap = "2.33" tracing = "0.1" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } diff --git a/ql/extractor/src/main.rs b/ql/extractor/src/main.rs index 6b7a190ac46..7391f8ab05f 100644 --- a/ql/extractor/src/main.rs +++ b/ql/extractor/src/main.rs @@ -88,11 +88,13 @@ fn main() -> std::io::Result<()> { let dbscheme = tree_sitter_ql_dbscheme::language(); let yaml = tree_sitter_ql_yaml::language(); let blame = tree_sitter_blame::language(); + let json = tree_sitter_json::language(); let schema = node_types::read_node_types_str("ql", tree_sitter_ql::NODE_TYPES)?; let dbscheme_schema = node_types::read_node_types_str("dbscheme", tree_sitter_ql_dbscheme::NODE_TYPES)?; let yaml_schema = node_types::read_node_types_str("yaml", tree_sitter_ql_yaml::NODE_TYPES)?; let blame_schema = node_types::read_node_types_str("blame", tree_sitter_blame::NODE_TYPES)?; + let json_schema = node_types::read_node_types_str("json", tree_sitter_json::NODE_TYPES)?; let lines: std::io::Result> = std::io::BufReader::new(file_list).lines().collect(); let lines = lines?; @@ -134,6 +136,19 @@ fn main() -> std::io::Result<()> { &source, &code_ranges, )? + } else if line.ends_with(".json") + || line.ends_with(".jsonl") + || line.ends_with(".jsonc") + { + extractor::extract( + json, + "json", + &json_schema, + &mut trap_writer, + &path, + &source, + &code_ranges, + )? } else if line.ends_with(".blame") { extractor::extract( blame, diff --git a/ql/generator/Cargo.toml b/ql/generator/Cargo.toml index e2e92a59b8a..43532ae36f2 100644 --- a/ql/generator/Cargo.toml +++ b/ql/generator/Cargo.toml @@ -15,3 +15,4 @@ tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", re tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} +tree-sitter-json = { git = "https://github.com/tausbn/tree-sitter-json.git", rev = "471ceac44d127e609afa349cf0a59370791fe8b3"} diff --git a/ql/generator/src/main.rs b/ql/generator/src/main.rs index d36cb3fb385..8c6bf63d859 100644 --- a/ql/generator/src/main.rs +++ b/ql/generator/src/main.rs @@ -581,6 +581,10 @@ fn main() -> std::io::Result<()> { name: "Blame".to_owned(), node_types: tree_sitter_blame::NODE_TYPES, }, + Language { + name: "JSON".to_owned(), + node_types: tree_sitter_json::NODE_TYPES, + }, ]; let mut dbscheme_writer = LineWriter::new(File::create(dbscheme_path)?); write!( diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index 8abb5fc6ca3..94f7bbfa0c1 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -1856,3 +1856,162 @@ module Blame { final override string getAPrimaryQlClass() { result = "Number" } } } + +module JSON { + /** The base class for all AST nodes */ + class AstNode extends @json_ast_node { + /** Gets a string representation of this element. */ + string toString() { result = this.getAPrimaryQlClass() } + + /** Gets the location of this element. */ + final L::Location getLocation() { json_ast_node_info(this, _, _, result) } + + /** Gets the parent of this element. */ + final AstNode getParent() { json_ast_node_info(this, result, _, _) } + + /** Gets the index of this node among the children of its parent. */ + final int getParentIndex() { json_ast_node_info(this, _, result, _) } + + /** Gets a field or child node of this node. */ + AstNode getAFieldOrChild() { none() } + + /** Gets the name of the primary QL class for this element. */ + string getAPrimaryQlClass() { result = "???" } + + /** Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. */ + string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") } + } + + /** A token. */ + class Token extends @json_token, AstNode { + /** Gets the value of this token. */ + final string getValue() { json_tokeninfo(this, _, result) } + + /** Gets a string representation of this element. */ + final override string toString() { result = this.getValue() } + + /** Gets the name of the primary QL class for this element. */ + override string getAPrimaryQlClass() { result = "Token" } + } + + /** A reserved word. */ + class ReservedWord extends @json_reserved_word, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "ReservedWord" } + } + + /** A class representing `array` nodes. */ + class Array extends @json_array, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Array" } + + /** Gets the `i`th child of this node. */ + final Value getChild(int i) { json_array_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { json_array_child(this, _, result) } + } + + /** A class representing `comment` tokens. */ + class Comment extends @json_token_comment, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Comment" } + } + + /** A class representing `document` nodes. */ + class Document extends @json_document, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Document" } + + /** Gets the `i`th child of this node. */ + final Value getChild(int i) { json_document_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { json_document_child(this, _, result) } + } + + /** A class representing `escape_sequence` tokens. */ + class EscapeSequence extends @json_token_escape_sequence, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "EscapeSequence" } + } + + /** A class representing `false` tokens. */ + class False extends @json_token_false, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "False" } + } + + /** A class representing `null` tokens. */ + class Null extends @json_token_null, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Null" } + } + + /** A class representing `number` tokens. */ + class Number extends @json_token_number, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Number" } + } + + /** A class representing `object` nodes. */ + class Object extends @json_object, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Object" } + + /** Gets the `i`th child of this node. */ + final Pair getChild(int i) { json_object_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { json_object_child(this, _, result) } + } + + /** A class representing `pair` nodes. */ + class Pair extends @json_pair, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "Pair" } + + /** Gets the node corresponding to the field `key`. */ + final AstNode getKey() { json_pair_def(this, result, _) } + + /** Gets the node corresponding to the field `value`. */ + final Value getValue() { json_pair_def(this, _, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { + json_pair_def(this, result, _) or json_pair_def(this, _, result) + } + } + + /** A class representing `string` nodes. */ + class String extends @json_string__, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "String" } + + /** Gets the child of this node. */ + final StringContent getChild() { json_string_child(this, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { json_string_child(this, result) } + } + + /** A class representing `string_content` nodes. */ + class StringContent extends @json_string_content, AstNode { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "StringContent" } + + /** Gets the `i`th child of this node. */ + final EscapeSequence getChild(int i) { json_string_content_child(this, i, result) } + + /** Gets a field or child node of this node. */ + final override AstNode getAFieldOrChild() { json_string_content_child(this, _, result) } + } + + /** A class representing `true` tokens. */ + class True extends @json_token_true, Token { + /** Gets the name of the primary QL class for this element. */ + final override string getAPrimaryQlClass() { result = "True" } + } + + class Value extends @json_value, AstNode { } +} diff --git a/ql/ql/src/ql.dbscheme b/ql/ql/src/ql.dbscheme index 54befe3412b..21174fa5e4e 100644 --- a/ql/ql/src/ql.dbscheme +++ b/ql/ql/src/ql.dbscheme @@ -1249,3 +1249,95 @@ blame_ast_node_info( int loc: @location ref ); +#keyset[json_array, index] +json_array_child( + int json_array: @json_array ref, + int index: int ref, + unique int child: @json_value ref +); + +json_array_def( + unique int id: @json_array +); + +#keyset[json_document, index] +json_document_child( + int json_document: @json_document ref, + int index: int ref, + unique int child: @json_value ref +); + +json_document_def( + unique int id: @json_document +); + +#keyset[json_object, index] +json_object_child( + int json_object: @json_object ref, + int index: int ref, + unique int child: @json_pair ref +); + +json_object_def( + unique int id: @json_object +); + +@json_pair_key_type = @json_string__ | @json_token_number + +json_pair_def( + unique int id: @json_pair, + int key__: @json_pair_key_type ref, + int value: @json_value ref +); + +json_string_child( + unique int json_string__: @json_string__ ref, + unique int child: @json_string_content ref +); + +json_string_def( + unique int id: @json_string__ +); + +#keyset[json_string_content, index] +json_string_content_child( + int json_string_content: @json_string_content ref, + int index: int ref, + unique int child: @json_token_escape_sequence ref +); + +json_string_content_def( + unique int id: @json_string_content +); + +@json_value = @json_array | @json_object | @json_string__ | @json_token_false | @json_token_null | @json_token_number | @json_token_true + +json_tokeninfo( + unique int id: @json_token, + int kind: int ref, + string value: string ref +); + +case @json_token.kind of + 0 = @json_reserved_word +| 1 = @json_token_comment +| 2 = @json_token_escape_sequence +| 3 = @json_token_false +| 4 = @json_token_null +| 5 = @json_token_number +| 6 = @json_token_true +; + + +@json_ast_node = @json_array | @json_document | @json_object | @json_pair | @json_string__ | @json_string_content | @json_token + +@json_ast_node_parent = @file | @json_ast_node + +#keyset[parent, parent_index] +json_ast_node_info( + unique int node: @json_ast_node ref, + int parent: @json_ast_node_parent ref, + int parent_index: int ref, + int loc: @location ref +); + From bab53b5736d3e641f492aebc52bdc956679c1b2b Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 21 Feb 2023 19:50:27 +0000 Subject: [PATCH 346/415] QL: Fix JSON extraction I had forgotten about this extra filtering that takes place in the extractor. --- ql/extractor/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ql/extractor/src/main.rs b/ql/extractor/src/main.rs index 7391f8ab05f..da7f263e7ef 100644 --- a/ql/extractor/src/main.rs +++ b/ql/extractor/src/main.rs @@ -108,6 +108,9 @@ fn main() -> std::io::Result<()> { && !line.ends_with(".dbscheme") && !line.ends_with("qlpack.yml") && !line.ends_with(".blame") + && !line.ends_with(".json") + && !line.ends_with(".jsonl") + && !line.ends_with(".jsonc") { return Ok(()); } From cf734919b9fa34d5a18375eeaaaeddcc8060d0bd Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 21 Feb 2023 20:20:58 +0000 Subject: [PATCH 347/415] QL: Fix bad string grammar What was there before made it so that you couldn't actually extract the contents of a string. --- ql/Cargo.lock | Bin 22220 -> 22220 bytes ql/extractor/Cargo.toml | 2 +- ql/generator/Cargo.toml | 2 +- .../src/codeql_ql/ast/internal/TreeSitter.qll | 16 ++---------- ql/ql/src/ql.dbscheme | 23 +++++------------- 5 files changed, 10 insertions(+), 33 deletions(-) diff --git a/ql/Cargo.lock b/ql/Cargo.lock index be8f122d54af7824817eff5888379d8f9a589ccb..a8d3fc681f43bc9bfdddb517ae0d4f41885eafc8 100644 GIT binary patch delta 102 zcmX@JmhsG5#tk#v0#XwV)67gw%?wPEjg69x(#*{g6H|;5lTuTROe`%DP0dm)4AYDg VEtQE>I9X6lY?7zdW()Tz`~ZyGA0q$& delta 102 zcmX@JmhsG5#tk#v0!+*elT#CuO-xb@jm%Tc3@j7V5{*qPlhX_mO)ZVh4a_YK(^4&x VjFpL0IJr?mY?7zdW()Tz`~Y&q9@zi@ diff --git a/ql/extractor/Cargo.toml b/ql/extractor/Cargo.toml index dd9ed32552b..45bcc5e5d30 100644 --- a/ql/extractor/Cargo.toml +++ b/ql/extractor/Cargo.toml @@ -14,7 +14,7 @@ tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", re tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} -tree-sitter-json = {git = "https://github.com/tausbn/tree-sitter-json.git", rev = "471ceac44d127e609afa349cf0a59370791fe8b3"} +tree-sitter-json = {git = "https://github.com/tausbn/tree-sitter-json.git", rev = "ea1f655604c32c2f76aad2abed2498a56d81f3a9"} clap = "2.33" tracing = "0.1" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } diff --git a/ql/generator/Cargo.toml b/ql/generator/Cargo.toml index 43532ae36f2..92cee7e1257 100644 --- a/ql/generator/Cargo.toml +++ b/ql/generator/Cargo.toml @@ -15,4 +15,4 @@ tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", re tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} -tree-sitter-json = { git = "https://github.com/tausbn/tree-sitter-json.git", rev = "471ceac44d127e609afa349cf0a59370791fe8b3"} +tree-sitter-json = { git = "https://github.com/tausbn/tree-sitter-json.git", rev = "ea1f655604c32c2f76aad2abed2498a56d81f3a9"} diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index 94f7bbfa0c1..d15da37b4f2 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -1930,12 +1930,6 @@ module JSON { final override AstNode getAFieldOrChild() { json_document_child(this, _, result) } } - /** A class representing `escape_sequence` tokens. */ - class EscapeSequence extends @json_token_escape_sequence, Token { - /** Gets the name of the primary QL class for this element. */ - final override string getAPrimaryQlClass() { result = "EscapeSequence" } - } - /** A class representing `false` tokens. */ class False extends @json_token_false, Token { /** Gets the name of the primary QL class for this element. */ @@ -1995,16 +1989,10 @@ module JSON { final override AstNode getAFieldOrChild() { json_string_child(this, result) } } - /** A class representing `string_content` nodes. */ - class StringContent extends @json_string_content, AstNode { + /** A class representing `string_content` tokens. */ + class StringContent extends @json_token_string_content, Token { /** Gets the name of the primary QL class for this element. */ final override string getAPrimaryQlClass() { result = "StringContent" } - - /** Gets the `i`th child of this node. */ - final EscapeSequence getChild(int i) { json_string_content_child(this, i, result) } - - /** Gets a field or child node of this node. */ - final override AstNode getAFieldOrChild() { json_string_content_child(this, _, result) } } /** A class representing `true` tokens. */ diff --git a/ql/ql/src/ql.dbscheme b/ql/ql/src/ql.dbscheme index 21174fa5e4e..2f4f6f7d26f 100644 --- a/ql/ql/src/ql.dbscheme +++ b/ql/ql/src/ql.dbscheme @@ -1292,24 +1292,13 @@ json_pair_def( json_string_child( unique int json_string__: @json_string__ ref, - unique int child: @json_string_content ref + unique int child: @json_token_string_content ref ); json_string_def( unique int id: @json_string__ ); -#keyset[json_string_content, index] -json_string_content_child( - int json_string_content: @json_string_content ref, - int index: int ref, - unique int child: @json_token_escape_sequence ref -); - -json_string_content_def( - unique int id: @json_string_content -); - @json_value = @json_array | @json_object | @json_string__ | @json_token_false | @json_token_null | @json_token_number | @json_token_true json_tokeninfo( @@ -1321,15 +1310,15 @@ json_tokeninfo( case @json_token.kind of 0 = @json_reserved_word | 1 = @json_token_comment -| 2 = @json_token_escape_sequence -| 3 = @json_token_false -| 4 = @json_token_null -| 5 = @json_token_number +| 2 = @json_token_false +| 3 = @json_token_null +| 4 = @json_token_number +| 5 = @json_token_string_content | 6 = @json_token_true ; -@json_ast_node = @json_array | @json_document | @json_object | @json_pair | @json_string__ | @json_string_content | @json_token +@json_ast_node = @json_array | @json_document | @json_object | @json_pair | @json_string__ | @json_token @json_ast_node_parent = @file | @json_ast_node From 729563c9a34ca006fc86d09fdfa70efc2f388f0c Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 21 Feb 2023 21:09:34 +0000 Subject: [PATCH 348/415] QL: Add preliminary support for structured logs --- ql/ql/src/codeql_ql/StructuredLogs.qll | 132 +++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 ql/ql/src/codeql_ql/StructuredLogs.qll diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll new file mode 100644 index 00000000000..9e0efa2e5ea --- /dev/null +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -0,0 +1,132 @@ +private import ql +private import codeql_ql.ast.internal.TreeSitter + +class Object extends JSON::Object { + JSON::Value getValue(string key) { + exists(JSON::Pair p | + p = this.getChild(_) and p.getKey().(JSON::String).getChild().getValue() = key + | + result = p.getValue() + ) + } + + string getString(string key) { result = this.getValue(key).(JSON::String).getChild().getValue() } + + int getNumber(string key) { result = this.getValue(key).(JSON::Number).getValue().toInt() } + + Array getArray(string key) { result = this.getValue(key) } + + string getType() { result = this.getString("type") } + + int getEventId() { result = this.getNumber("event_id") } + + string getTime() { result = this.getString("time") } +} + +class Array extends JSON::Array { + Object getObject(int i) { result = this.getChild(i) } + + string getString(int i) { result = this.getChild(i).(JSON::String).getChild().getValue() } + + int getNumber(int i) { result = this.getChild(i).(JSON::Number).getValue().toInt() } +} + +abstract class LogEntry extends Object { } + +class LogHeader extends LogEntry { + LogHeader() { this.getType() = "LOG_HEADER" } + + string getCodeQLVersion() { result = this.getString("codeqlVersion") } + + string getLogVersion() { result = this.getString("logVersion") } +} + +class QueryStarted extends LogEntry { + QueryStarted() { this.getType() = "QUERY_STARTED" } + + string getQueryName() { result = this.getString("queryName") } + + int getStage(int i) { result = this.getArray("stage").getNumber(i) } +} + +class PredicateStarted extends LogEntry { + PredicateStarted() { this.getType() = "PREDICATE_STARTED" } + + string getPredicateName() { result = this.getString("predicateName") } + + string getPosition() { result = this.getString("position") } + + string getPredicateType() { result = this.getString("predicateType") } + + int getQueryCausingWork() { result = this.getNumber("queryCausingWork") } + + string getRAHash() { result = this.getString("raHash") } + + Object getRA() { result = this.getValue("ra") } +} + +class PipelineStarted extends LogEntry { + PipelineStarted() { this.getType() = "PIPELINE_STARTED" } + + int getPredicateStartEvent() { result = this.getNumber("predicateStartEvent") } + + string getRAReference() { result = this.getString("raReference") } +} + +class PipelineCompleted extends LogEntry { + PipelineCompleted() { this.getType() = "PIPELINE_COMPLETED" } + + int getStartEvent() { result = this.getNumber("startEvent") } + + string getRAReference() { result = this.getString("raReference") } + + int getCount(int i) { result = this.getArray("counts").getNumber(i) } + + int getDuplicationPercentage(int i) { + result = this.getArray("duplicationPercentages").getNumber(i) + } + + int getResultSize() { result = this.getNumber("resultSize") } +} + +class PredicateCompleted extends LogEntry { + PredicateCompleted() { this.getType() = "PREDICATE_COMPLETED" } + + int getStartEvent() { result = this.getNumber("startEvent") } + + int getResultSize() { result = this.getNumber("resultSize") } +} + +class QueryCompleted extends LogEntry { + QueryCompleted() { this.getType() = "QUERY_COMPLETED" } + + int getStartEvent() { result = this.getNumber("startEvent") } + + string getTerminationType() { result = this.getString("terminationType") } +} + +class LogFooter extends LogEntry { + LogFooter() { this.getType() = "LOG_FOOTER" } +} + +class CacheLookup extends LogEntry { + CacheLookup() { this.getType() = "CACHE_LOOKUP" } + + int getRelationSize() { result = this.getNumber("relationSize") } +} + +class SentinelEmpty extends LogEntry { + SentinelEmpty() { this.getType() = "SENTINEL_EMPTY" } +} + +// Stuff to test whether we've covered all event types +private File logFile() { result = any(LogHeader h).getLocation().getFile() } + +private Object missing() { + result = + any(Object o | + o.getLocation().getFile() = logFile() and + not o instanceof LogEntry and + not exists(o.getParent().getParent()) // don't count nested objects + ) +} From 7106f7d52e810cce6a1eee8871c19ea2fb0c3a14 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 21 Feb 2023 21:19:08 +0000 Subject: [PATCH 349/415] Add gradle wrappers to compiler_arguments and kotlin_kfunction tests ` --- .../kotlin/compiler_arguments/.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../kotlin/compiler_arguments/gradlew | 244 ++++++++++++++++++ .../kotlin/compiler_arguments/gradlew.bat | 92 +++++++ .../kotlin/compiler_arguments/test.py | 6 +- .../kotlin/kotlin_kfunction/.gitattributes | 6 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + .../kotlin/kotlin_kfunction/gradlew | 244 ++++++++++++++++++ .../kotlin/kotlin_kfunction/gradlew.bat | 92 +++++++ .../kotlin/kotlin_kfunction/test.py | 6 +- 12 files changed, 704 insertions(+), 4 deletions(-) create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew create mode 100644 java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew create mode 100644 java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew new file mode 100644 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py index c1ba4d3370b..359771ac6c0 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py +++ b/java/ql/integration-tests/all-platforms/kotlin/compiler_arguments/test.py @@ -1,5 +1,7 @@ +import platform from create_database_utils import * +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + run_codeql_database_create( - ["gradle build --no-daemon --no-build-cache"], lang="java") -runSuccessfully([get_cmd("gradle"), "clean"]) + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..f398c33c4b0 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew new file mode 100644 index 00000000000..79a61d421cc --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat new file mode 100644 index 00000000000..93e3f59f135 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py index 0f2facdec07..359771ac6c0 100644 --- a/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py +++ b/java/ql/integration-tests/all-platforms/kotlin/kotlin_kfunction/test.py @@ -1,5 +1,7 @@ +import platform from create_database_utils import * +gradle_cmd = "gradlew.bat" if platform.system() == "Windows" else "./gradlew" + run_codeql_database_create( - ["gradle build --no-daemon --no-build-cache --rerun-tasks"], lang="java") -runSuccessfully([get_cmd("gradle"), "clean"]) + ["%s build --no-daemon --no-build-cache" % gradle_cmd], lang="java") From a3a099cf56da9439f9d587dbffa9ad2b9a9d9a2e Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 21 Feb 2023 21:27:17 +0000 Subject: [PATCH 350/415] QL: Add a few more methods Still need to implement something to encapsulate RA, link it up, etc. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 9e0efa2e5ea..4696b2e22dd 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -16,6 +16,8 @@ class Object extends JSON::Object { Array getArray(string key) { result = this.getValue(key) } + Object getObject(string key) { result = this.getValue(key) } + string getType() { result = this.getString("type") } int getEventId() { result = this.getNumber("event_id") } @@ -29,6 +31,8 @@ class Array extends JSON::Array { string getString(int i) { result = this.getChild(i).(JSON::String).getChild().getValue() } int getNumber(int i) { result = this.getChild(i).(JSON::Number).getValue().toInt() } + + Array getArray(int i) { result = this.getChild(i) } } abstract class LogEntry extends Object { } @@ -63,6 +67,8 @@ class PredicateStarted extends LogEntry { string getRAHash() { result = this.getString("raHash") } Object getRA() { result = this.getValue("ra") } + + string getDependency(string key) { result = this.getObject("dependencies").getString(key) } } class PipelineStarted extends LogEntry { From 540d3a3a993baafa9958ac0037190c9aeba09db5 Mon Sep 17 00:00:00 2001 From: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> Date: Wed, 22 Feb 2023 00:42:50 +0100 Subject: [PATCH 351/415] Fix grammar --- java/ql/lib/semmle/code/java/Type.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/semmle/code/java/Type.qll b/java/ql/lib/semmle/code/java/Type.qll index 13d3a6ea443..dbaaefeb645 100644 --- a/java/ql/lib/semmle/code/java/Type.qll +++ b/java/ql/lib/semmle/code/java/Type.qll @@ -413,7 +413,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { /** * Gets a direct or indirect supertype of this type. - * This does not including itself, unless this type is part of a cycle + * This does not include itself, unless this type is part of a cycle * in the type hierarchy. */ RefType getAStrictAncestor() { result = this.getASupertype().getAnAncestor() } From 3e0aacd36bf8fc1875673c62aed91730e6c49a5e Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 20 Feb 2023 10:59:53 +0100 Subject: [PATCH 352/415] C#: Generalize modifier extraction from symbols. --- .../Semmle.Extraction.CSharp/SymbolExtensions.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs index 6018b9903c1..debb96ca3b6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/SymbolExtensions.cs @@ -77,12 +77,8 @@ namespace Semmle.Extraction.CSharp /// /// Gets the source-level modifiers belonging to this symbol, if any. /// - public static IEnumerable GetSourceLevelModifiers(this ISymbol symbol) - { - var methodModifiers = symbol.GetModifiers(md => md.Modifiers); - var typeModifiers = symbol.GetModifiers(cd => cd.Modifiers); - return methodModifiers.Concat(typeModifiers).Select(m => m.Text); - } + public static IEnumerable GetSourceLevelModifiers(this ISymbol symbol) => + symbol.GetModifiers(md => md.Modifiers).Select(m => m.Text); /// /// Holds if the ID generated for `dependant` will contain a reference to From b4a6d1e1b63881e12617cf0087178a3805a586a7 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 22 Feb 2023 08:59:14 +0100 Subject: [PATCH 353/415] C#: Add change note. --- csharp/ql/lib/change-notes/2023-02-22-modifierextraction.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2023-02-22-modifierextraction.md diff --git a/csharp/ql/lib/change-notes/2023-02-22-modifierextraction.md b/csharp/ql/lib/change-notes/2023-02-22-modifierextraction.md new file mode 100644 index 00000000000..2078c2a9f1e --- /dev/null +++ b/csharp/ql/lib/change-notes/2023-02-22-modifierextraction.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The extraction of member modifiers has been generalised, which could lead to the extraction of more modifiers. \ No newline at end of file From 47c69d924b1a0dbb350b78cf37bcf5e347b23356 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 22 Feb 2023 09:05:28 +0100 Subject: [PATCH 354/415] C#: Update comment on the isSupported predicate. --- csharp/ql/src/Telemetry/ExternalApi.qll | 5 ++++- java/ql/src/Telemetry/ExternalApi.qll | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/Telemetry/ExternalApi.qll b/csharp/ql/src/Telemetry/ExternalApi.qll index 249251dab8e..9358e9ce8e4 100644 --- a/csharp/ql/src/Telemetry/ExternalApi.qll +++ b/csharp/ql/src/Telemetry/ExternalApi.qll @@ -109,7 +109,10 @@ class ExternalApi extends DotNet::Callable { pragma[nomagic] predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable } - /** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */ + /** + * Holds if this API is supported by existing CodeQL libraries, that is, it is either a + * recognized source, sink or neutral or it has a flow summary. + */ predicate isSupported() { this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral() } diff --git a/java/ql/src/Telemetry/ExternalApi.qll b/java/ql/src/Telemetry/ExternalApi.qll index 9c4a5c1751e..1675307e2ef 100644 --- a/java/ql/src/Telemetry/ExternalApi.qll +++ b/java/ql/src/Telemetry/ExternalApi.qll @@ -96,7 +96,10 @@ class ExternalApi extends Callable { pragma[nomagic] predicate isNeutral() { this = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable() } - /** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */ + /** + * Holds if this API is supported by existing CodeQL libraries, that is, it is either a + * recognized source, sink or neutral or it has a flow summary. + */ predicate isSupported() { this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral() } From eb6c8480f838c17859e4767fd8954de31c2beb6a Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 22 Feb 2023 10:02:12 +0100 Subject: [PATCH 355/415] Make "Detecting a potential buffer overflow" example more uniform All queries that use SSA import `semmle.code.cpp.controlflow.SSA` explicitly, except for the last one. Also import the library there. Note that this is not strictly necessary, as the library is transitively imported via `import cpp`. --- .../detecting-a-potential-buffer-overflow.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/codeql/codeql-language-guides/detecting-a-potential-buffer-overflow.rst b/docs/codeql/codeql-language-guides/detecting-a-potential-buffer-overflow.rst index ca52df98f73..9150102f212 100644 --- a/docs/codeql/codeql-language-guides/detecting-a-potential-buffer-overflow.rst +++ b/docs/codeql/codeql-language-guides/detecting-a-potential-buffer-overflow.rst @@ -204,6 +204,7 @@ The completed query will now identify cases where the result of ``strlen`` is st .. code-block:: ql import cpp + import semmle.code.cpp.controlflow.SSA class MallocCall extends FunctionCall { From 5304fe2bcb624ac9fcd2029bc4cfc381d5cf33fd Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 22 Feb 2023 11:07:48 +0000 Subject: [PATCH 356/415] QL: Clean up structured logs module Pushes it into an internal module and removes the abstract class. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 157 +++++++++++++------------ 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 4696b2e22dd..3de170fe350 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -3,9 +3,8 @@ private import codeql_ql.ast.internal.TreeSitter class Object extends JSON::Object { JSON::Value getValue(string key) { - exists(JSON::Pair p | - p = this.getChild(_) and p.getKey().(JSON::String).getChild().getValue() = key - | + exists(JSON::Pair p | p = this.getChild(_) | + key = p.getKey().(JSON::String).getChild().getValue() and result = p.getValue() ) } @@ -35,104 +34,106 @@ class Array extends JSON::Array { Array getArray(int i) { result = this.getChild(i) } } -abstract class LogEntry extends Object { } +module EvaluatorLog { + class Entry extends Object { } -class LogHeader extends LogEntry { - LogHeader() { this.getType() = "LOG_HEADER" } + class LogHeader extends Entry { + LogHeader() { this.getType() = "LOG_HEADER" } - string getCodeQLVersion() { result = this.getString("codeqlVersion") } + string getCodeQLVersion() { result = this.getString("codeqlVersion") } - string getLogVersion() { result = this.getString("logVersion") } -} - -class QueryStarted extends LogEntry { - QueryStarted() { this.getType() = "QUERY_STARTED" } - - string getQueryName() { result = this.getString("queryName") } - - int getStage(int i) { result = this.getArray("stage").getNumber(i) } -} - -class PredicateStarted extends LogEntry { - PredicateStarted() { this.getType() = "PREDICATE_STARTED" } - - string getPredicateName() { result = this.getString("predicateName") } - - string getPosition() { result = this.getString("position") } - - string getPredicateType() { result = this.getString("predicateType") } - - int getQueryCausingWork() { result = this.getNumber("queryCausingWork") } - - string getRAHash() { result = this.getString("raHash") } - - Object getRA() { result = this.getValue("ra") } - - string getDependency(string key) { result = this.getObject("dependencies").getString(key) } -} - -class PipelineStarted extends LogEntry { - PipelineStarted() { this.getType() = "PIPELINE_STARTED" } - - int getPredicateStartEvent() { result = this.getNumber("predicateStartEvent") } - - string getRAReference() { result = this.getString("raReference") } -} - -class PipelineCompleted extends LogEntry { - PipelineCompleted() { this.getType() = "PIPELINE_COMPLETED" } - - int getStartEvent() { result = this.getNumber("startEvent") } - - string getRAReference() { result = this.getString("raReference") } - - int getCount(int i) { result = this.getArray("counts").getNumber(i) } - - int getDuplicationPercentage(int i) { - result = this.getArray("duplicationPercentages").getNumber(i) + string getLogVersion() { result = this.getString("logVersion") } } - int getResultSize() { result = this.getNumber("resultSize") } -} + class QueryStarted extends Entry { + QueryStarted() { this.getType() = "QUERY_STARTED" } -class PredicateCompleted extends LogEntry { - PredicateCompleted() { this.getType() = "PREDICATE_COMPLETED" } + string getQueryName() { result = this.getString("queryName") } - int getStartEvent() { result = this.getNumber("startEvent") } + int getStage(int i) { result = this.getArray("stage").getNumber(i) } + } - int getResultSize() { result = this.getNumber("resultSize") } -} + class PredicateStarted extends Entry { + PredicateStarted() { this.getType() = "PREDICATE_STARTED" } -class QueryCompleted extends LogEntry { - QueryCompleted() { this.getType() = "QUERY_COMPLETED" } + string getPredicateName() { result = this.getString("predicateName") } - int getStartEvent() { result = this.getNumber("startEvent") } + string getPosition() { result = this.getString("position") } - string getTerminationType() { result = this.getString("terminationType") } -} + string getPredicateType() { result = this.getString("predicateType") } -class LogFooter extends LogEntry { - LogFooter() { this.getType() = "LOG_FOOTER" } -} + int getQueryCausingWork() { result = this.getNumber("queryCausingWork") } -class CacheLookup extends LogEntry { - CacheLookup() { this.getType() = "CACHE_LOOKUP" } + string getRAHash() { result = this.getString("raHash") } - int getRelationSize() { result = this.getNumber("relationSize") } -} + Object getRA() { result = this.getValue("ra") } -class SentinelEmpty extends LogEntry { - SentinelEmpty() { this.getType() = "SENTINEL_EMPTY" } + string getDependency(string key) { result = this.getObject("dependencies").getString(key) } + } + + class PipelineStarted extends Entry { + PipelineStarted() { this.getType() = "PIPELINE_STARTED" } + + int getPredicateStartEvent() { result = this.getNumber("predicateStartEvent") } + + string getRAReference() { result = this.getString("raReference") } + } + + class PipelineCompleted extends Entry { + PipelineCompleted() { this.getType() = "PIPELINE_COMPLETED" } + + int getStartEvent() { result = this.getNumber("startEvent") } + + string getRAReference() { result = this.getString("raReference") } + + int getCount(int i) { result = this.getArray("counts").getNumber(i) } + + int getDuplicationPercentage(int i) { + result = this.getArray("duplicationPercentages").getNumber(i) + } + + int getResultSize() { result = this.getNumber("resultSize") } + } + + class PredicateCompleted extends Entry { + PredicateCompleted() { this.getType() = "PREDICATE_COMPLETED" } + + int getStartEvent() { result = this.getNumber("startEvent") } + + int getResultSize() { result = this.getNumber("resultSize") } + } + + class QueryCompleted extends Entry { + QueryCompleted() { this.getType() = "QUERY_COMPLETED" } + + int getStartEvent() { result = this.getNumber("startEvent") } + + string getTerminationType() { result = this.getString("terminationType") } + } + + class LogFooter extends Entry { + LogFooter() { this.getType() = "LOG_FOOTER" } + } + + class CacheLookup extends Entry { + CacheLookup() { this.getType() = "CACHE_LOOKUP" } + + int getRelationSize() { result = this.getNumber("relationSize") } + } + + class SentinelEmpty extends Entry { + SentinelEmpty() { this.getType() = "SENTINEL_EMPTY" } + } } // Stuff to test whether we've covered all event types -private File logFile() { result = any(LogHeader h).getLocation().getFile() } +private File logFile() { result = any(EvaluatorLog::LogHeader h).getLocation().getFile() } private Object missing() { result = any(Object o | o.getLocation().getFile() = logFile() and - not o instanceof LogEntry and + not o instanceof EvaluatorLog::Entry and not exists(o.getParent().getParent()) // don't count nested objects ) } From 2c31d6863c08775ebc452d6b91fc2a907bb440fc Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 22 Feb 2023 13:03:29 +0000 Subject: [PATCH 357/415] QL: Start on the AST for kind: predicates evaluator logs. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 114 +++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 3de170fe350..9003837126d 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -126,6 +126,120 @@ module EvaluatorLog { } } +module KindPredicatesLog { + class SummaryHeader extends Object { + SummaryHeader() { exists(this.getString("summaryLogVersion")) } + + string getSummaryLogVersion() { result = this.getString("summaryLogVersion") } + + string getCodeqlVersion() { result = this.getString("codeqlVersion") } + + private string getStartTimeString() { result = this.getString("startTime") } + + predicate hasStartTime( + int year, string month, int day, int hours, int minute, int second, int millisecond + ) { + exists(string s, string r | + s = this.getStartTimeString() and + r = "(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{3})Z" + | + year = s.regexpCapture(r, 1).toInt() and + month = s.regexpCapture(r, 2) and + day = s.regexpCapture(r, 3).toInt() and + hours = s.regexpCapture(r, 4).toInt() and + minute = s.regexpCapture(r, 5).toInt() and + second = s.regexpCapture(r, 6).toInt() and + millisecond = s.regexpCapture(r, 7).toInt() + ) + } + } + + class AppearsAs extends Object { + SummaryEvent event; + + AppearsAs() { event.getObject("appearsAs") = this } + + SummaryEvent getSummaryEvent() { result = event } + + PredicateName getAPredicateName() { result.getAppearsAs() = this } + } + + class PredicateName extends Object { + AppearsAs appearsAs; + + PredicateName() { pragma[only_bind_out](appearsAs.getObject(_)) = this } + + AppearsAs getAppearsAs() { result = appearsAs } + + Query getAQuery() { result.getPredicateName() = this } + } + + class Query extends Array { + PredicateName predicateName; + + Query() { this = predicateName.getArray(_) } + + PredicateName getPredicateName() { result = predicateName } + } + + class SummaryEvent extends Object { + string evaluationStrategy; + + SummaryEvent() { evaluationStrategy = this.getString("evaluationStrategy") } + + string getEvaluationStrategy() { result = evaluationStrategy } + + string getRaHash() { result = this.getString("raHash") } + + string getPredicateName() { result = this.getString("predicateName") } + + string getCompletionTimeString() { result = this.getString("completionTime") } + + AppearsAs getAppearsAs() { result = this.getObject("appearsAs") } + + predicate hasCompletionTime( + int year, string month, int day, int hours, int minute, int second, int millisecond + ) { + exists(string s, string r | + s = this.getCompletionTimeString() and + r = "(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{3})Z" + | + year = s.regexpCapture(r, 1).toInt() and + month = s.regexpCapture(r, 2) and + day = s.regexpCapture(r, 3).toInt() and + hours = s.regexpCapture(r, 4).toInt() and + minute = s.regexpCapture(r, 5).toInt() and + second = s.regexpCapture(r, 6).toInt() and + millisecond = s.regexpCapture(r, 7).toInt() + ) + } + } + + class SentinelEmpty extends SummaryEvent { + SentinelEmpty() { evaluationStrategy = "SENTINEL_EMPTY" } + } + + class ComputeSimple extends SummaryEvent { + ComputeSimple() { evaluationStrategy = "COMPUTE_SIMPLE" } + } + + class ComputeRecursive extends SummaryEvent { + ComputeRecursive() { evaluationStrategy = "COMPUTE_RECURSIVE" } + } + + class InLayer extends SummaryEvent { + InLayer() { evaluationStrategy = "IN_LAYER" } + } + + class ComputedExtensional extends SummaryEvent { + ComputedExtensional() { evaluationStrategy = "COMPUTED_EXTENSIONAL" } + } + + class Extensional extends SummaryEvent { + Extensional() { evaluationStrategy = "EXTENSIONAL" } + } +} + // Stuff to test whether we've covered all event types private File logFile() { result = any(EvaluatorLog::LogHeader h).getLocation().getFile() } From 161acf0ebe9388fee04d77a21c90488d6b22d00a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 22 Feb 2023 13:43:51 +0000 Subject: [PATCH 358/415] QL: Add more getters. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 9003837126d..3c6e6f895b2 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -213,14 +213,43 @@ module KindPredicatesLog { millisecond = s.regexpCapture(r, 7).toInt() ) } + + int getResultSize() { result = this.getNumber("resultSize") } } class SentinelEmpty extends SummaryEvent { SentinelEmpty() { evaluationStrategy = "SENTINEL_EMPTY" } } + class PipeLineRun extends Object { + PipeLineRuns runs; + int index; + + PipeLineRun() { runs.getObject(index) = this } + + PipeLineRuns getArray() { result = runs } + + string getRaReference() { result = this.getString("raReference") } + + Array getCounts() { result = this.getArray("counts") } + + Array getDuplicationPercentages() { result = this.getArray("duplicationPercentages") } + } + + class PipeLineRuns extends Array { + SummaryEvent event; + + PipeLineRuns() { event.getArray("pipelineRuns") = this } + + SummaryEvent getEvent() { result = event } + + PipeLineRun getRun(int i) { result = this.getObject(i) } + } + class ComputeSimple extends SummaryEvent { ComputeSimple() { evaluationStrategy = "COMPUTE_SIMPLE" } + + PipeLineRun getPipelineRun() { result.getArray() = this.getArray("pipelineRuns") } } class ComputeRecursive extends SummaryEvent { From 2cdec47585458f5a72366adf1140b6659d4350d0 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 22 Feb 2023 13:45:47 +0000 Subject: [PATCH 359/415] QL: Make the JSON parser a bit more robust Updates the grammar to allow trailing commas in objects and arrays. Also bumps the file size limit to 10MB. --- ql/Cargo.lock | Bin 22220 -> 22220 bytes ql/autobuilder/src/main.rs | 2 +- ql/extractor/Cargo.toml | 2 +- ql/generator/Cargo.toml | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ql/Cargo.lock b/ql/Cargo.lock index a8d3fc681f43bc9bfdddb517ae0d4f41885eafc8..ff29ea1c323847f2b870a25d746712aef51c4a4e 100644 GIT binary patch delta 102 zcmX@JmhsG5#tk#v0?bWJ&CHBbQ!Opc(+o|`&C*g0Q_T%6%u~&bP0UjbQj(0#Qj^US VEtQE>I9X6lY?7zdW()Tz`~X1=9r*wN delta 102 zcmX@JmhsG5#tk#v0#XwV)67gw%?wPEjg69x(#*{g6H|;5lTuTROe`%DP0dm)4AYDg VEtQE>I9X6lY?7zdW()Tz`~ZyGA0q$& diff --git a/ql/autobuilder/src/main.rs b/ql/autobuilder/src/main.rs index a2c9df2d9b0..0d9605c4c1d 100644 --- a/ql/autobuilder/src/main.rs +++ b/ql/autobuilder/src/main.rs @@ -23,7 +23,7 @@ fn main() -> std::io::Result<()> { .arg("--include-extension=.jsonl") .arg("--include=**/qlpack.yml") .arg("--include=deprecated.blame") - .arg("--size-limit=5m") + .arg("--size-limit=10m") .arg("--language=ql") .arg("--working-dir=.") .arg(db); diff --git a/ql/extractor/Cargo.toml b/ql/extractor/Cargo.toml index 45bcc5e5d30..1a187625d22 100644 --- a/ql/extractor/Cargo.toml +++ b/ql/extractor/Cargo.toml @@ -14,7 +14,7 @@ tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", re tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} -tree-sitter-json = {git = "https://github.com/tausbn/tree-sitter-json.git", rev = "ea1f655604c32c2f76aad2abed2498a56d81f3a9"} +tree-sitter-json = {git = "https://github.com/tausbn/tree-sitter-json.git", rev = "745663ee997f1576fe1e7187e6347e0db36ec7a9"} clap = "2.33" tracing = "0.1" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } diff --git a/ql/generator/Cargo.toml b/ql/generator/Cargo.toml index 92cee7e1257..4fcc98be310 100644 --- a/ql/generator/Cargo.toml +++ b/ql/generator/Cargo.toml @@ -15,4 +15,4 @@ tree-sitter-ql = { git = "https://github.com/tree-sitter/tree-sitter-ql.git", re tree-sitter-ql-dbscheme = { git = "https://github.com/erik-krogh/tree-sitter-ql-dbscheme.git", rev = "63e1344353f63931e88bfbc2faa2e78e1421b213"} tree-sitter-ql-yaml = {git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "cf704bf3671e1ae148e173464fb65a4d2bbf5f99"} tree-sitter-blame = {path = "../buramu/tree-sitter-blame"} -tree-sitter-json = { git = "https://github.com/tausbn/tree-sitter-json.git", rev = "ea1f655604c32c2f76aad2abed2498a56d81f3a9"} +tree-sitter-json = { git = "https://github.com/tausbn/tree-sitter-json.git", rev = "745663ee997f1576fe1e7187e6347e0db36ec7a9"} From f155f19725bfe9930796f9da24b743afdf111f92 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 22 Feb 2023 14:15:18 +0000 Subject: [PATCH 360/415] QL: Respond to comments. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 3c6e6f895b2..f7e5c5b9184 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -189,7 +189,7 @@ module KindPredicatesLog { string getEvaluationStrategy() { result = evaluationStrategy } - string getRaHash() { result = this.getString("raHash") } + string getRAHash() { result = this.getString("raHash") } string getPredicateName() { result = this.getString("predicateName") } @@ -229,7 +229,7 @@ module KindPredicatesLog { PipeLineRuns getArray() { result = runs } - string getRaReference() { result = this.getString("raReference") } + string getRAReference() { result = this.getString("raReference") } Array getCounts() { result = this.getArray("counts") } From d64d03ec483eb779816bb998f97d98363262a368 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 22 Feb 2023 14:15:47 +0000 Subject: [PATCH 361/415] QL: Fix Code Scanning warning. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index f7e5c5b9184..3370e349c2f 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -223,9 +223,8 @@ module KindPredicatesLog { class PipeLineRun extends Object { PipeLineRuns runs; - int index; - PipeLineRun() { runs.getObject(index) = this } + PipeLineRun() { runs.getObject(_) = this } PipeLineRuns getArray() { result = runs } From 498d0c359e599e9bd42c7d297b431dd6cc3e11e6 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 22 Feb 2023 14:43:03 +0000 Subject: [PATCH 362/415] QL: Convert various int getters to float (to avoid overflow) and correctly handle '-1' padding. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 47 +++++++++++++++++++++----- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 3370e349c2f..0e6674d8fbd 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -13,6 +13,8 @@ class Object extends JSON::Object { int getNumber(string key) { result = this.getValue(key).(JSON::Number).getValue().toInt() } + float getFloat(string key) { result = this.getValue(key).(JSON::Number).getValue().toFloat() } + Array getArray(string key) { result = this.getValue(key) } Object getObject(string key) { result = this.getValue(key) } @@ -31,9 +33,20 @@ class Array extends JSON::Array { int getNumber(int i) { result = this.getChild(i).(JSON::Number).getValue().toInt() } + float getFloat(int i) { result = this.getChild(i).(JSON::Number).getValue().toFloat() } + Array getArray(int i) { result = this.getChild(i) } } +/** + * Gets the i'th non-negative number in `a`. + * + * This is needed because the evaluator log is padded with -1s in some cases. + */ +private float getRanked(Array a, int i) { + result = rank[i + 1](int j, float f | f = a.getFloat(j) and f >= 0 | f order by j) +} + module EvaluatorLog { class Entry extends Object { } @@ -86,13 +99,13 @@ module EvaluatorLog { string getRAReference() { result = this.getString("raReference") } - int getCount(int i) { result = this.getArray("counts").getNumber(i) } + float getCount(int i) { result = getRanked(this.getArray("counts"), i) } - int getDuplicationPercentage(int i) { - result = this.getArray("duplicationPercentages").getNumber(i) + float getDuplicationPercentage(int i) { + result = getRanked(this.getArray("duplicationPercentages"), i) } - int getResultSize() { result = this.getNumber("resultSize") } + float getResultSize() { result = this.getFloat("resultSize") } } class PredicateCompleted extends Entry { @@ -100,7 +113,7 @@ module EvaluatorLog { int getStartEvent() { result = this.getNumber("startEvent") } - int getResultSize() { result = this.getNumber("resultSize") } + float getResultSize() { result = this.getFloat("resultSize") } } class QueryCompleted extends Entry { @@ -118,7 +131,7 @@ module EvaluatorLog { class CacheLookup extends Entry { CacheLookup() { this.getType() = "CACHE_LOOKUP" } - int getRelationSize() { result = this.getNumber("relationSize") } + float getRelationSize() { result = this.getFloat("relationSize") } } class SentinelEmpty extends Entry { @@ -214,7 +227,7 @@ module KindPredicatesLog { ) } - int getResultSize() { result = this.getNumber("resultSize") } + float getResultSize() { result = this.getFloat("resultSize") } } class SentinelEmpty extends SummaryEvent { @@ -230,9 +243,11 @@ module KindPredicatesLog { string getRAReference() { result = this.getString("raReference") } - Array getCounts() { result = this.getArray("counts") } + float getCount(int i) { result = getRanked(this.getArray("counts"), i) } - Array getDuplicationPercentages() { result = this.getArray("duplicationPercentages") } + float getDuplicationPercentage(int i) { + result = getRanked(this.getArray("duplicationPercentages"), i) + } } class PipeLineRuns extends Array { @@ -245,9 +260,23 @@ module KindPredicatesLog { PipeLineRun getRun(int i) { result = this.getObject(i) } } + class Depencencies extends Object { + SummaryEvent event; + + Depencencies() { event.getObject("dependencies") = this } + + SummaryEvent getEvent() { result = event } + + predicate hasEntry(string name, string hash) { this.getString(name) = hash } + + SummaryEvent getADependency() { this.getString(_) = result.getRAHash() } + } + class ComputeSimple extends SummaryEvent { ComputeSimple() { evaluationStrategy = "COMPUTE_SIMPLE" } + Depencencies getDependencies() { result = this.getObject("dependencies") } + PipeLineRun getPipelineRun() { result.getArray() = this.getArray("pipelineRuns") } } From 62f4e4843386157ef8e181b0539f3ec7ebb2d1ef Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 22 Feb 2023 16:46:46 +0100 Subject: [PATCH 363/415] Swift: fix comments in PrintAst library --- swift/ql/lib/codeql/swift/printast/PrintAst.qll | 2 +- swift/ql/lib/codeql/swift/printast/PrintAstNode.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/swift/ql/lib/codeql/swift/printast/PrintAst.qll b/swift/ql/lib/codeql/swift/printast/PrintAst.qll index 267919f951e..4527058adc8 100644 --- a/swift/ql/lib/codeql/swift/printast/PrintAst.qll +++ b/swift/ql/lib/codeql/swift/printast/PrintAst.qll @@ -1,5 +1,5 @@ /** - * Provides queries to pretty-print a Go AST as a graph. + * Provides queries to pretty-print a Swift AST as a graph. */ import PrintAstNode diff --git a/swift/ql/lib/codeql/swift/printast/PrintAstNode.qll b/swift/ql/lib/codeql/swift/printast/PrintAstNode.qll index fd1e217c460..fead27ecf71 100644 --- a/swift/ql/lib/codeql/swift/printast/PrintAstNode.qll +++ b/swift/ql/lib/codeql/swift/printast/PrintAstNode.qll @@ -1,5 +1,5 @@ /** - * Provides classes used to pretty-print a Go AST as a graph. + * Provides classes used to pretty-print a Swift AST as a graph. * This is factored out of `PrintAst.qll` for testing purposes. */ From 9980756ee8b1467f8679b9c6d2e6fd4a25be70e4 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 22 Feb 2023 16:51:16 +0000 Subject: [PATCH 364/415] RA parser first draft --- ql/ql/src/experimental/RA.qll | 109 ++++++++++++++++++++++ ql/ql/test/experimental/raparser.expected | 17 ++++ ql/ql/test/experimental/raparser.ql | 42 +++++++++ 3 files changed, 168 insertions(+) create mode 100644 ql/ql/src/experimental/RA.qll create mode 100644 ql/ql/test/experimental/raparser.expected create mode 100644 ql/ql/test/experimental/raparser.ql diff --git a/ql/ql/src/experimental/RA.qll b/ql/ql/src/experimental/RA.qll new file mode 100644 index 00000000000..bd4822c0167 --- /dev/null +++ b/ql/ql/src/experimental/RA.qll @@ -0,0 +1,109 @@ +/** + * Parses RA expressions. + */ +signature class RAstring extends string; + +signature class RApredicate { + string getLineOfRA(int n); +} + +/** + * Parses strings of RA provided by an RA predicate, + */ +module RAParser { + private string parseRaExpr(Predicate p, int line, int arity, int lhs) { + exists(string str | str = p.getLineOfRA(line).trim() | + arity = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 1).toInt() and + lhs = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 2).toInt() and + result = str.regexpCapture("\\{([0-9]+)\\} r([0-9]+) = (.+)", 3) + ) + } + + bindingset[str] + private int parseReturn(string str) { + result = str.trim().regexpCapture("return r([0-9]+)", 1).toInt() + } + + private newtype TRA = + TReturn(Predicate p, int line, int v) { v = parseReturn(p.getLineOfRA(line)) } or + TUnknown(Predicate p, int line, int lhs, int arity, string rhs) { + rhs = parseRaExpr(p, line, arity, lhs) + } + + /** An RA Expression. */ + abstract class RAExpr extends TRA { + /** Gets the predicate this RA expression belongs to. */ + abstract Predicate getPredicate(); + + /** Gets the line index of this RA expression. */ + abstract int getLine(); + + /** Gets the LHS of the expression of the form `rNN = ...` */ + abstract int getLhs(); + + /** Gets a variable of the form `rNN` in the RHS of the RA expression. */ + abstract int getARhsVariable(); + + /** Gets the given arity of the RA expression. */ + abstract int getArity(); + + /** Gets a predicate name referenced in the RHS of an RA expression. */ + abstract string getARhsPredicate(); + + final string toString() { result = getPredicate().getLineOfRA(getLine()) } + + /** Gets a child of this RA expression - not by index yet. */ + RAExpr getAChild() { + result.getPredicate() = this.getPredicate() and result.getLhs() = this.getARhsVariable() + } + } + + /** + * A generic RA expression - where we haven't precisely parsed the RA expression type. + * For Hackathon purposes, we probably don't need more than this. + */ + class RAUnknownExpr extends RAExpr, TUnknown { + Predicate p; + int line; + string rhs; + int arity; + int lhs; + + RAUnknownExpr() { this = TUnknown(p, line, lhs, arity, rhs) } + + override int getLine() { result = line } + + override Predicate getPredicate() { result = p } + + override int getLhs() { result = lhs } + + override int getARhsVariable() { + result = rhs.splitAt(" ").regexpCapture("r([0-9]+)", 1).toInt() + } + + // This is a dumb regex to find a predicate name - they always contain a `#` (TODO...) + override string getARhsPredicate() { result = rhs.splitAt(" ") and result.indexOf("#") > 0 } + + override int getArity() { result = arity } + } + + class RAReturnExpr extends RAExpr, TReturn { + RAReturnExpr() { this = TReturn(p, line, res) } + + Predicate p; + int line; + int res; + + override Predicate getPredicate() { result = p } + + override int getLine() { result = line } + + override int getLhs() { none() } + + override int getARhsVariable() { result = res } + + override int getArity() { none() } + + override string getARhsPredicate() { none() } + } +} diff --git a/ql/ql/test/experimental/raparser.expected b/ql/ql/test/experimental/raparser.expected new file mode 100644 index 00000000000..af61f56f229 --- /dev/null +++ b/ql/ql/test/experimental/raparser.expected @@ -0,0 +1,17 @@ +children +| return r7 | {4} r7 = r3 UNION r6 | +| {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] | +| {4} r3 = STREAM DEDUP r2 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | +| {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] | +| {4} r5 = STREAM DEDUP r4 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | +| {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | {4} r5 = STREAM DEDUP r4 | +| {4} r7 = r3 UNION r6 | {4} r3 = STREAM DEDUP r2 | +| {4} r7 = r3 UNION r6 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | +#select +| p1 | 1 | {1} r1 = CONSTANT(unique string)["p1"] | 1 | 1 | 0 | 0 | +| p1 | 3 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | 2 | 4 | 1 | 1 | +| p1 | 5 | {4} r3 = STREAM DEDUP r2 | 3 | 4 | 0 | 1 | +| p1 | 6 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | 4 | 4 | 1 | 1 | +| p1 | 7 | {4} r5 = STREAM DEDUP r4 | 5 | 4 | 0 | 1 | +| p1 | 8 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | 6 | 4 | 1 | 1 | +| p1 | 9 | {4} r7 = r3 UNION r6 | 7 | 4 | 0 | 2 | diff --git a/ql/ql/test/experimental/raparser.ql b/ql/ql/test/experimental/raparser.ql new file mode 100644 index 00000000000..29489e2a968 --- /dev/null +++ b/ql/ql/test/experimental/raparser.ql @@ -0,0 +1,42 @@ +import experimental.RA + +class TestPredicate extends string { + TestPredicate() { this = "p1" } + + string getLineOfRA(int line) { + line = 1 and + result = " {1} r1 = CONSTANT(unique string)[\"p1\"]" + or + line = 2 and result = "" + or + line = 3 and + result = + " {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT \"p1\", toString(\"p1\"), 123, \" r1 = SCAN fubar\\n r1\"" + or + line = 4 and result = "" + or + line = 5 and result = " {4} r3 = STREAM DEDUP r2" + or + line = 6 and + result = + " {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT \"p1\", \"(no string representation)\", 123, \" r1 = SCAN fubar\\n r1\"" + or + line = 7 and result = " {4} r5 = STREAM DEDUP r4" + or + line = 8 and result = " {4} r6 = r5 AND NOT project##select#query#ffff#nullary({})" + or + line = 9 and result = " {4} r7 = r3 UNION r6" + or + line = 10 and result = " return r7" + } +} + +query predicate children( + RAParser::RAExpr parent, RAParser::RAExpr child +) { + child = parent.getAChild() +} + +from RAParser::RAExpr expr +select expr.getPredicate(), expr.getLine(), expr, expr.getLhs(), expr.getArity(), + count(expr.getARhsPredicate()), count(expr.getARhsVariable()) From f3e5a8f90fa0a3641993edbcb432bf1ff76f5b87 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 22 Feb 2023 17:01:07 +0000 Subject: [PATCH 365/415] Minor tidy --- ql/ql/src/experimental/RA.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ql/ql/src/experimental/RA.qll b/ql/ql/src/experimental/RA.qll index bd4822c0167..c57517e104a 100644 --- a/ql/ql/src/experimental/RA.qll +++ b/ql/ql/src/experimental/RA.qll @@ -1,14 +1,16 @@ /** * Parses RA expressions. */ -signature class RAstring extends string; +/** + * A predicate that contains RA. + */ signature class RApredicate { string getLineOfRA(int n); } /** - * Parses strings of RA provided by an RA predicate, + * Parses strings of RA provided by an RA predicate, and represented the */ module RAParser { private string parseRaExpr(Predicate p, int line, int arity, int lhs) { From 0fdcf0338a39f9e457ee742488545f5c71ef3184 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 22 Feb 2023 17:02:49 +0000 Subject: [PATCH 366/415] Tidy up warnings --- ql/ql/src/experimental/RA.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/ql/src/experimental/RA.qll b/ql/ql/src/experimental/RA.qll index c57517e104a..4976f9aa5f3 100644 --- a/ql/ql/src/experimental/RA.qll +++ b/ql/ql/src/experimental/RA.qll @@ -52,7 +52,7 @@ module RAParser { /** Gets a predicate name referenced in the RHS of an RA expression. */ abstract string getARhsPredicate(); - final string toString() { result = getPredicate().getLineOfRA(getLine()) } + final string toString() { result = this.getPredicate().getLineOfRA(this.getLine()) } /** Gets a child of this RA expression - not by index yet. */ RAExpr getAChild() { From 40e45d36369a7ce9c9f0f03dd15c9b2f500149ef Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 20 Jan 2023 17:45:38 +0000 Subject: [PATCH 367/415] Add test for missing Java build system --- .../java/diagnostics/no-build-system/Test.java | 1 + .../diagnostics.expected/java-autobuilder.json | 1 + .../java/diagnostics/no-build-system/test.py | 8 ++++++++ 3 files changed, 10 insertions(+) create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/Test.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/Test.java b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/Test.java new file mode 100644 index 00000000000..ef22a69f193 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/Test.java @@ -0,0 +1 @@ +class Test {} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json new file mode 100644 index 00000000000..2fb8c2e0966 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json @@ -0,0 +1 @@ +{"timestamp":1674235729,"source":{"id":"java/autobuilder/no-build-command","name":"No build command found","extractorName":"java"},"markdownMessage":"Could not find a Gradle, Maven or Ant top-level project to build. Please [TODO](supply a manual build command)","severity":"error","visibility":{"statusPage":true,"cliSummaryTable":true,"telemetry":true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py new file mode 100644 index 00000000000..3f61230e320 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py @@ -0,0 +1,8 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") From 7a2c6b564576ad0b6837826d8372a20e2803a4e1 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 24 Jan 2023 17:03:54 +0000 Subject: [PATCH 368/415] Java no-build-system test: switch to single-file diagnostics.expected format --- .../java/diagnostics/no-build-system/diagnostics.expected | 1 + .../no-build-system/diagnostics.expected/java-autobuilder.json | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected delete mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected new file mode 100644 index 00000000000..647c7b64458 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected @@ -0,0 +1 @@ +{"markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [TODO](supply a manual build command)", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/no-build-command", "name": "No build command found"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json deleted file mode 100644 index 2fb8c2e0966..00000000000 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected/java-autobuilder.json +++ /dev/null @@ -1 +0,0 @@ -{"timestamp":1674235729,"source":{"id":"java/autobuilder/no-build-command","name":"No build command found","extractorName":"java"},"markdownMessage":"Could not find a Gradle, Maven or Ant top-level project to build. Please [TODO](supply a manual build command)","severity":"error","visibility":{"statusPage":true,"cliSummaryTable":true,"telemetry":true}} \ No newline at end of file From fd1ce5d12c9b61b7d084b86c82e77633f011d7d6 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 25 Jan 2023 12:51:07 +0000 Subject: [PATCH 369/415] Switch to using language-specific diagnostic environment variable --- .../all-platforms/java/diagnostics/no-build-system/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py index 3f61230e320..d258d1c47d3 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py @@ -3,6 +3,6 @@ from create_database_utils import * from diagnostics_test_utils import * os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") From 57ac951451e30a19cf7729b65ae9acbc62d67fe6 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 30 Jan 2023 12:17:45 +0000 Subject: [PATCH 370/415] Add tests for Java autobuilder errors --- .../.gitattributes | 6 + .../build.gradle | 13 + .../diagnostics.expected | 2 + .../force_sequential_test_execution | 4 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + .../android-gradle-incompatibility/gradlew | 240 ++++++++++++++++++ .../gradlew.bat | 91 +++++++ .../project/build.gradle | 58 +++++ .../project/src/main/AndroidManifest.xml | 12 + .../java/com/github/androidsample/Main.java | 11 + .../settings.gradle | 40 +++ .../android-gradle-incompatibility/test.py | 8 + .../compilation-error/diagnostics.expected | 3 + .../diagnostics/compilation-error/pom.xml | 114 +++++++++ .../src/main/java/com/example/App.java | 30 +++ .../src/main/resources/my-app.properties | 1 + .../src/main/resources/page.xml | 8 + .../src/main/resources/struts.xml | 4 + .../src/test/java/com/example/AppTest.java | 20 ++ .../diagnostics/compilation-error/test.py | 8 + .../dependency-error/diagnostics.expected | 1 + .../java/diagnostics/dependency-error/pom.xml | 114 +++++++++ .../src/main/java/com/example/App.java | 30 +++ .../src/main/resources/my-app.properties | 1 + .../src/main/resources/page.xml | 8 + .../src/main/resources/struts.xml | 4 + .../src/test/java/com/example/AppTest.java | 20 ++ .../java/diagnostics/dependency-error/test.py | 17 ++ .../java-version-too-old/.gitattributes | 6 + .../java-version-too-old/.gitignore | 5 + .../java-version-too-old/build.gradle | 34 +++ .../java-version-too-old/diagnostics.expected | 2 + .../force_sequential_test_execution | 3 + .../gradle/verification-metadata.xml | 7 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + .../diagnostics/java-version-too-old/gradlew | 185 ++++++++++++++ .../java-version-too-old/gradlew.bat | 89 +++++++ .../java-version-too-old/settings.gradle | 19 ++ .../src/main/java/com/example/App.java | 14 + .../src/test/java/com/example/AppTest.java | 14 + .../diagnostics/java-version-too-old/test.py | 14 + .../diagnostics.expected | 4 + .../diagnostics/maven-http-repository/pom.xml | 123 +++++++++ .../src/main/java/com/example/App.java | 30 +++ .../src/main/resources/my-app.properties | 1 + .../src/main/resources/page.xml | 8 + .../src/main/resources/struts.xml | 4 + .../src/test/java/com/example/AppTest.java | 20 ++ .../diagnostics/maven-http-repository/test.py | 8 + .../diagnostics.expected | 2 + .../maven-project-1/pom.xml | 114 +++++++++ .../src/main/java/com/example/App.java | 30 +++ .../src/main/resources/my-app.properties | 1 + .../src/main/resources/page.xml | 8 + .../src/main/resources/struts.xml | 4 + .../src/test/java/com/example/AppTest.java | 20 ++ .../maven-project-2/pom.xml | 114 +++++++++ .../src/main/java/com/example/App.java | 30 +++ .../src/main/resources/my-app.properties | 1 + .../src/main/resources/page.xml | 8 + .../src/main/resources/struts.xml | 4 + .../src/test/java/com/example/AppTest.java | 20 ++ .../multiple-candidate-builds/test.py | 8 + .../no-gradle-test-classes/build.gradle | 3 + .../diagnostics.expected | 2 + .../no-gradle-test-classes/settings.gradle | 1 + .../no-gradle-test-classes/test.py | 8 + .../no-gradle-wrapper/.gitattributes | 6 + .../diagnostics/no-gradle-wrapper/.gitignore | 5 + .../no-gradle-wrapper/build.gradle | 30 +++ .../no-gradle-wrapper/diagnostics.expected | 1 + .../force_sequential_test_execution | 3 + .../no-gradle-wrapper/settings.gradle | 19 ++ .../src/main/java/com/example/App.java | 14 + .../src/test/java/com/example/AppTest.java | 14 + .../diagnostics/no-gradle-wrapper/test.py | 8 + 78 files changed, 1946 insertions(+) create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/build.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/force_sequential_test_execution create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradlew create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradlew.bat create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/build.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/AndroidManifest.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/java/com/github/androidsample/Main.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/settings.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/pom.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/java/com/example/App.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/my-app.properties create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/page.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/struts.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/test/java/com/example/AppTest.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/pom.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/java/com/example/App.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/my-app.properties create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/page.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/struts.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/test/java/com/example/AppTest.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitignore create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/build.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/force_sequential_test_execution create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/verification-metadata.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/wrapper/gradle-wrapper.jar create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/wrapper/gradle-wrapper.properties create mode 100755 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew.bat create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/settings.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/main/java/com/example/App.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/test/java/com/example/AppTest.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/pom.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/java/com/example/App.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/my-app.properties create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/page.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/struts.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/test/java/com/example/AppTest.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/pom.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/java/com/example/App.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/my-app.properties create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/page.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/struts.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/test/java/com/example/AppTest.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/pom.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/java/com/example/App.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/my-app.properties create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/page.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/struts.xml create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/test/java/com/example/AppTest.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/build.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/settings.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitattributes create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitignore create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/build.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/force_sequential_test_execution create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/settings.gradle create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/main/java/com/example/App.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/test/java/com/example/AppTest.java create mode 100644 java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/.gitattributes b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/build.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/build.gradle new file mode 100644 index 00000000000..b2708d1ac3d --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/build.gradle @@ -0,0 +1,13 @@ +plugins { + + /** + * Use `apply false` in the top-level build.gradle file to add a Gradle + * plugin as a build dependency but not apply it to the current (root) + * project. Don't use `apply false` in sub-projects. For more information, + * see Applying external plugins with same version to subprojects. + */ + + id 'com.android.application' version '7.3.1' apply false + id 'com.android.library' version '7.3.1' apply false + id 'org.jetbrains.kotlin.android' version '1.7.20' apply false +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected new file mode 100644 index 00000000000..cb521711a69 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected @@ -0,0 +1,2 @@ +{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /Users/chris/semmle-code-repo/target/codeql-integration-tests/ql/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} +{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /Users/chris/semmle-code-repo/target/codeql-integration-tests/ql/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/force_sequential_test_execution b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/force_sequential_test_execution new file mode 100644 index 00000000000..4947fd6fe51 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/force_sequential_test_execution @@ -0,0 +1,4 @@ +# We currently have a bug where gradle tests become flaky when executed in parallel +# - sometimes, gradle fails to connect to the gradle daemon. +# Therefore, force this test to run sequentially. +# Additionally, Android SDK on-demand downloading can fail when multiple tests try to download the same SDK in parallel. diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradlew.bat b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradlew.bat new file mode 100644 index 00000000000..f127cfd49d4 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/build.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/build.gradle new file mode 100644 index 00000000000..7751b92ae54 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/build.gradle @@ -0,0 +1,58 @@ +/** + * The first line in the build configuration applies the Android Gradle plugin + * to this build and makes the android block available to specify + * Android-specific build options. + */ + +plugins { + id 'com.android.application' +} + +/** + * The android block is where you configure all your Android-specific + * build options. + */ + +android { + + /** + * The app's namespace. Used primarily to access app resources. + */ + + namespace 'com.github.androidsample' + + /** + * compileSdk specifies the Android API level Gradle should use to + * compile your app. This means your app can use the API features included in + * this API level and lower. + */ + + compileSdk 33 + + /** + * The defaultConfig block encapsulates default settings and entries for all + * build variants and can override some attributes in main/AndroidManifest.xml + * dynamically from the build system. You can configure product flavors to override + * these values for different versions of your app. + */ + + defaultConfig { + + // Uniquely identifies the package for publishing. + applicationId 'com.github.androidsample' + + // Defines the minimum API level required to run the app. + minSdk 21 + + // Specifies the API level used to test the app. + targetSdk 33 + + // Defines the version number of your app. + versionCode 1 + + // Defines a user-friendly version name for your app. + versionName "1.0" + } + + variantFilter { variant -> if (variant.buildType.name == "debug") { setIgnore(true) } } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/AndroidManifest.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..1352b0d90fa --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/AndroidManifest.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/java/com/github/androidsample/Main.java b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/java/com/github/androidsample/Main.java new file mode 100644 index 00000000000..000b12d036d --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/project/src/main/java/com/github/androidsample/Main.java @@ -0,0 +1,11 @@ +package com.github.androidsample; + +import android.app.Activity; +import android.os.Bundle; + +public class Main extends Activity +{ + @Override + public void onCreate(Bundle savedInstanceState) { + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/settings.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/settings.gradle new file mode 100644 index 00000000000..1fa19406e1a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/settings.gradle @@ -0,0 +1,40 @@ +pluginManagement { + + /** + * The pluginManagement {repositories {...}} block configures the + * repositories Gradle uses to search or download the Gradle plugins and + * their transitive dependencies. Gradle pre-configures support for remote + * repositories such as JCenter, Maven Central, and Ivy. You can also use + * local repositories or define your own remote repositories. The code below + * defines the Gradle Plugin Portal, Google's Maven repository, + * and the Maven Central Repository as the repositories Gradle should use to look for its + * dependencies. + */ + + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + + /** + * The dependencyResolutionManagement {repositories {...}} + * block is where you configure the repositories and dependencies used by + * all modules in your project, such as libraries that you are using to + * create your application. However, you should configure module-specific + * dependencies in each module-level build.gradle file. For new projects, + * Android Studio includes Google's Maven repository and the Maven Central + * Repository by default, but it does not configure any dependencies (unless + * you select a template that requires some). + */ + + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Android Sample" +include ':project' diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py new file mode 100644 index 00000000000..d258d1c47d3 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py @@ -0,0 +1,8 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected new file mode 100644 index 00000000000..00190b0c630 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected @@ -0,0 +1,3 @@ +{"markdownMessage": "A compilation error was observed while autobuilding your code. Please check that the needed compiler version and other tools are installed in your Code Scanning workflow. Suspicious output line: `[ERROR] COMPILATION ERROR : `", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/compilation-error", "name": "Some of your code may have failed to compile"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} +{"markdownMessage": "A compilation error was observed while autobuilding your code. Please check that the needed compiler version and other tools are installed in your Code Scanning workflow. Suspicious output line: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/compilation-error", "name": "Some of your code may have failed to compile"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} +{"markdownMessage": "A compilation error was observed while autobuilding your code. Please check that the needed compiler version and other tools are installed in your Code Scanning workflow. Suspicious output line: `org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/compilation-error", "name": "Some of your code may have failed to compile"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/pom.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/pom.xml new file mode 100644 index 00000000000..ec4aaf128c1 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/pom.xml @@ -0,0 +1,114 @@ + + + + 4.0.0 + + com.example + maven-sample + 1.0-SNAPSHOT + + maven-sample + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + + + + exec-maven-plugin + org.codehaus.mojo + 1.1.1 + + + check-maven-version + package + + java + + + + + com.example.App + + + + com.diffplug.spotless + spotless-maven-plugin + 2.19.1 + + + + check + + compile + + + + + + /* FAIL ME */ + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/java/com/example/App.java b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/java/com/example/App.java new file mode 100644 index 00000000000..175dc00f5ee --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/java/com/example/App.java @@ -0,0 +1,30 @@ +paaaaaaaaaaaaaaaackage com.example; + +import java.util.regex.Pattern; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + String expectedVersion = System.getenv("EXPECT_MAVEN"); + Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize(); + String observedVersion = mavenHome.getFileName().toString(); + if (expectedVersion != null && !expectedVersion.equals(observedVersion)) { + System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome); + System.exit(1); + } + String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX"); + String command = System.getProperty("sun.java.command"); + if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) { + System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'"); + System.exit(1); + } + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/my-app.properties b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/my-app.properties new file mode 100644 index 00000000000..e566b49a29a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/my-app.properties @@ -0,0 +1 @@ +version=1.0 diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/page.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/page.xml new file mode 100644 index 00000000000..2bab459cb03 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/page.xml @@ -0,0 +1,8 @@ + + +A sample + + +

    Hello world!

    + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/struts.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/struts.xml new file mode 100644 index 00000000000..73fc0c6b9cb --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/main/resources/struts.xml @@ -0,0 +1,4 @@ + + +This is a sample file + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/test/java/com/example/AppTest.java b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/test/java/com/example/AppTest.java new file mode 100644 index 00000000000..22a94ca6f01 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/src/test/java/com/example/AppTest.java @@ -0,0 +1,20 @@ +package com.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py new file mode 100644 index 00000000000..d258d1c47d3 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py @@ -0,0 +1,8 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected new file mode 100644 index 00000000000..aae65c93abc --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected @@ -0,0 +1 @@ +{"markdownMessage": "In the course of building your code, it looks like a dependency failed to download. Check that all dependencies are available, including supplying credentials to access any private dependencies. Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/dependency-download-failure", "name": "Failed to download a dependency"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/pom.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/pom.xml new file mode 100644 index 00000000000..b5e230d9d56 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/pom.xml @@ -0,0 +1,114 @@ + + + + 4.0.0 + + com.example + maven-sample + 1.0-SNAPSHOT + + maven-sample + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit-nonesuch + 4.11 + test + + + + + + + exec-maven-plugin + org.codehaus.mojo + 1.1.1 + + + check-maven-version + package + + java + + + + + com.example.App + + + + com.diffplug.spotless + spotless-maven-plugin + 2.19.1 + + + + check + + compile + + + + + + /* FAIL ME */ + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/java/com/example/App.java b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/java/com/example/App.java new file mode 100644 index 00000000000..c9eec918587 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/java/com/example/App.java @@ -0,0 +1,30 @@ +package com.example; + +import java.util.regex.Pattern; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + String expectedVersion = System.getenv("EXPECT_MAVEN"); + Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize(); + String observedVersion = mavenHome.getFileName().toString(); + if (expectedVersion != null && !expectedVersion.equals(observedVersion)) { + System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome); + System.exit(1); + } + String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX"); + String command = System.getProperty("sun.java.command"); + if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) { + System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'"); + System.exit(1); + } + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/my-app.properties b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/my-app.properties new file mode 100644 index 00000000000..e566b49a29a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/my-app.properties @@ -0,0 +1 @@ +version=1.0 diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/page.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/page.xml new file mode 100644 index 00000000000..2bab459cb03 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/page.xml @@ -0,0 +1,8 @@ + + +A sample + + +

    Hello world!

    + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/struts.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/struts.xml new file mode 100644 index 00000000000..73fc0c6b9cb --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/main/resources/struts.xml @@ -0,0 +1,4 @@ + + +This is a sample file + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/test/java/com/example/AppTest.java b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/test/java/com/example/AppTest.java new file mode 100644 index 00000000000..22a94ca6f01 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/src/test/java/com/example/AppTest.java @@ -0,0 +1,20 @@ +package com.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py new file mode 100644 index 00000000000..72207414a25 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py @@ -0,0 +1,17 @@ +import os +import pathlib +import shutil + +from create_database_utils import * +from diagnostics_test_utils import * + +# Ensure the intended dependency download failure is not cached: +try: + shutil.rmtree(pathlib.Path.home().joinpath(".m2", "repository", "junit", "junit-nonesuch")) +except FileNotFoundError: + pass + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitattributes b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitignore b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitignore new file mode 100644 index 00000000000..1b6985c0094 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/build.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/build.gradle new file mode 100644 index 00000000000..c3b774e3d50 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/build.gradle @@ -0,0 +1,34 @@ +/* + * This build file was auto generated by running the Gradle 'init' task + * by 'arthur' at '28/11/20 22:29' with Gradle 3.0 + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * user guide available at https://docs.gradle.org/3.0/userguide/tutorial_java_projects.html + */ + +// Apply the java plugin to add support for Java +apply plugin: 'java' + +// In this section you declare where to find the dependencies of your project +repositories { + // Use 'jcenter' for resolving your dependencies. + // You can declare any Maven/Ivy/file repository here. + jcenter() +} + +// In this section you declare the dependencies for your production and test code +dependencies { + // The production code uses the SLF4J logging API at compile time + compile 'org.slf4j:slf4j-api:1.7.21' + + // Declare the dependency for your favourite test framework you want to use in your tests. + // TestNG is also supported by the Gradle Test task. Just change the + // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add + // 'test.useTestNG()' to your build script. + testCompile 'junit:junit:4.12' +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected new file mode 100644 index 00000000000..817b56bc942 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected @@ -0,0 +1,2 @@ +{"markdownMessage": "Your project may need a different JDK version. Consider adding an `actions/setup-java` step to the Code Scanning workflow file. Suspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/wrong-jdk-version", "name": "Your project may need a different JDK version"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} +{"markdownMessage": "Your project may need a different JDK version. Consider adding an `actions/setup-java` step to the Code Scanning workflow file. Suspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/wrong-jdk-version", "name": "Your project may need a different JDK version"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/force_sequential_test_execution b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/force_sequential_test_execution new file mode 100644 index 00000000000..b0e2500b259 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/force_sequential_test_execution @@ -0,0 +1,3 @@ +# We currently have a bug where gradle tests become flaky when executed in parallel +# - sometimes, gradle fails to connect to the gradle daemon. +# Therefore, force this test to run sequentially. diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/verification-metadata.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/verification-metadata.xml new file mode 100644 index 00000000000..14a69b8178b --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/verification-metadata.xml @@ -0,0 +1,7 @@ + + + + true + false + + \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/wrapper/gradle-wrapper.jar b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 zcma&O1CT9Y(k9%tZQHhO+qUh#ZQHhO+qmuS+qP|E@9xZO?0h@l{(r>DQ>P;GjjD{w zH}lENr;dU&FbEU?00aa80D$0M0RRB{U*7-#kbjS|qAG&4l5%47zyJ#WrfA#1$1Ctx zf&Z_d{GW=lf^w2#qRJ|CvSJUi(^E3iv~=^Z(zH}F)3Z%V3`@+rNB7gTVU{Bb~90p|f+0(v;nz01EG7yDMX9@S~__vVgv%rS$+?IH+oZ03D5zYrv|^ zC1J)SruYHmCki$jLBlTaE5&dFG9-kq3!^i>^UQL`%gn6)jz54$WDmeYdsBE9;PqZ_ zoGd=P4+|(-u4U1dbAVQrFWoNgNd;0nrghPFbQrJctO>nwDdI`Q^i0XJDUYm|T|RWc zZ3^Qgo_Qk$%Fvjj-G}1NB#ZJqIkh;kX%V{THPqOyiq)d)0+(r9o(qKlSp*hmK#iIY zA^)Vr$-Hz<#SF=0@tL@;dCQsm`V9s1vYNq}K1B)!XSK?=I1)tX+bUV52$YQu*0%fnWEukW>mxkz+%3-S!oguE8u#MGzST8_Dy^#U?fA@S#K$S@9msUiX!gd_ow>08w5)nX{-KxqMOo7d?k2&?Vf z&diGDtZr(0cwPe9z9FAUSD9KC)7(n^lMWuayCfxzy8EZsns%OEblHFSzP=cL6}?J| z0U$H!4S_TVjj<`6dy^2j`V`)mC;cB%* z8{>_%E1^FH!*{>4a7*C1v>~1*@TMcLK{7nEQ!_igZC}ikJ$*<$yHy>7)oy79A~#xE zWavoJOIOC$5b6*q*F_qN1>2#MY)AXVyr$6x4b=$x^*aqF*L?vmj>Mgv+|ITnw_BoW zO?jwHvNy^prH{9$rrik1#fhyU^MpFqF2fYEt(;4`Q&XWOGDH8k6M=%@fics4ajI;st# zCU^r1CK&|jzUhRMv;+W~6N;u<;#DI6cCw-otsc@IsN3MoSD^O`eNflIoR~l4*&-%RBYk@gb^|-JXs&~KuSEmMxB}xSb z@K76cXD=Y|=I&SNC2E+>Zg?R6E%DGCH5J1nU!A|@eX9oS(WPaMm==k2s_ueCqdZw| z&hqHp)47`c{BgwgvY2{xz%OIkY1xDwkw!<0veB#yF4ZKJyabhyyVS`gZepcFIk%e2 zTcrmt2@-8`7i-@5Nz>oQWFuMC_KlroCl(PLSodswHqJ3fn<;gxg9=}~3x_L3P`9Sn zChIf}8vCHvTriz~T2~FamRi?rh?>3bX1j}%bLH+uFX+p&+^aXbOK7clZxdU~6Uxgy z8R=obwO4dL%pmVo*Ktf=lH6hnlz_5k3cG;m8lgaPp~?eD!Yn2kf)tU6PF{kLyn|oI@eQ`F z3IF7~Blqg8-uwUuWZScRKn%c2_}dXB6Dx_&xR*n9M9LXasJhtZdr$vBY!rP{c@=)& z#!?L$2UrkvClwQO>U*fSMs67oSj2mxiJ$t;E|>q%Kh_GzzWWO&3;ufU%2z%ucBU8H z3WIwr$n)cfCXR&>tyB7BcSInK>=ByZA%;cVEJhcg<#6N{aZC4>K41XF>ZgjG`z_u& zGY?;Ad?-sgiOnI`oppF1o1Gurqbi*;#x2>+SSV6|1^G@ooVy@fg?wyf@0Y!UZ4!}nGuLeC^l)6pwkh|oRY`s1Pm$>zZ3u-83T|9 zGaKJIV3_x+u1>cRibsaJpJqhcm%?0-L;2 zitBrdRxNmb0OO2J%Y&Ym(6*`_P3&&5Bw157{o7LFguvxC$4&zTy#U=W*l&(Q2MNO} zfaUwYm{XtILD$3864IA_nn34oVa_g^FRuHL5wdUd)+W-p-iWCKe8m_cMHk+=? zeKX)M?Dt(|{r5t7IenkAXo%&EXIb-i^w+0CX0D=xApC=|Xy(`xy+QG^UyFe z+#J6h_&T5i#sV)hj3D4WN%z;2+jJcZxcI3*CHXGmOF3^)JD5j&wfX)e?-|V0GPuA+ zQFot%aEqGNJJHn$!_}#PaAvQ^{3-Ye7b}rWwrUmX53(|~i0v{}G_sI9uDch_brX&6 zWl5Ndj-AYg(W9CGfQf<6!YmY>Ey)+uYd_JNXH=>|`OH-CDCmcH(0%iD_aLlNHKH z7bcW-^5+QV$jK?R*)wZ>r9t}loM@XN&M-Pw=F#xn(;u3!(3SXXY^@=aoj70;_=QE9 zGghsG3ekq#N||u{4We_25U=y#T*S{4I{++Ku)> zQ!DZW;pVcn>b;&g2;YE#+V`v*Bl&Y-i@X6D*OpNA{G@JAXho&aOk(_j^weW{#3X5Y z%$q_wpb07EYPdmyH(1^09i$ca{O<}7) zRWncXdSPgBE%BM#by!E>tdnc$8RwUJg1*x($6$}ae$e9Knj8gvVZe#bLi!<+&BkFj zg@nOpDneyc+hU9P-;jmOSMN|*H#>^Ez#?;%C3hg_65leSUm;iz)UkW)jX#p)e&S&M z1|a?wDzV5NVnlhRBCd_;F87wp>6c<&nkgvC+!@KGiIqWY4l}=&1w7|r6{oBN8xyzh zG$b#2=RJp_iq6)#t5%yLkKx(0@D=C3w+oiXtSuaQ%I1WIb-eiE$d~!)b@|4XLy!CZ z9p=t=%3ad@Ep+<9003D2KZ5VyP~_n$=;~r&YUg5UZ0KVD&tR1DHy9x)qWtKJp#Kq# zP*8p#W(8JJ_*h_3W}FlvRam?<4Z+-H77^$Lvi+#vmhL9J zJ<1SV45xi;SrO2f=-OB(7#iNA5)x1uNC-yNxUw|!00vcW2PufRm>e~toH;M0Q85MQLWd?3O{i8H+5VkR@l9Dg-ma ze2fZ%>G(u5(k9EHj2L6!;(KZ8%8|*-1V|B#EagbF(rc+5iL_5;Eu)L4Z-V;0HfK4d z*{utLse_rvHZeQ>V5H=f78M3Ntg1BPxFCVD{HbNA6?9*^YIq;B-DJd{Ca2L#)qWP? zvX^NhFmX?CTWw&Ns}lgs;r3i+Bq@y}Ul+U%pzOS0Fcv9~aB(0!>GT0)NO?p=25LjN z2bh>6RhgqD7bQj#k-KOm@JLgMa6>%-ok1WpOe)FS^XOU{c?d5shG(lIn3GiVBxmg`u%-j=)^v&pX1JecJics3&jvPI)mDut52? z3jEA)DM%}BYbxxKrizVYwq?(P&19EXlwD9^-6J+4!}9{ywR9Gk42jjAURAF&EO|~N z)?s>$Da@ikI4|^z0e{r`J8zIs>SpM~Vn^{3fArRu;?+43>lD+^XtUcY1HidJwnR6+ z!;oG2=B6Z_=M%*{z-RaHc(n|1RTKQdNjjV!Pn9lFt^4w|AeN06*j}ZyhqZ^!-=cyGP_ShV1rGxkx8t zB;8`h!S{LD%ot``700d0@Grql(DTt4Awgmi+Yr0@#jbe=2#UkK%rv=OLqF)9D7D1j z!~McAwMYkeaL$~kI~90)5vBhBzWYc3Cj1WI0RS`z000R8-@ET0dA~*r(gSiCJmQMN&4%1D zyVNf0?}sBH8zNbBLn>~(W{d3%@kL_eQ6jEcR{l>C|JK z(R-fA!z|TTRG40|zv}7E@PqCAXP3n`;%|SCQ|ZS%ym$I{`}t3KPL&^l5`3>yah4*6 zifO#{VNz3)?ZL$be;NEaAk9b#{tV?V7 zP|wf5YA*1;s<)9A4~l3BHzG&HH`1xNr#%){4xZ!jq%o=7nN*wMuXlFV{HaiQLJ`5G zBhDi#D(m`Q1pLh@Tq+L;OwuC52RdW7b8}~60WCOK5iYMUad9}7aWBuILb({5=z~YF zt?*Jr5NG+WadM{mDL>GyiByCuR)hd zA=HM?J6l1Xv0Dl+LW@w$OTcEoOda^nFCw*Sy^I@$sSuneMl{4ys)|RY#9&NxW4S)9 zq|%83IpslTLoz~&vTo!Ga@?rj_kw{|k{nv+w&Ku?fyk4Ki4I?);M|5Axm)t+BaE)D zm(`AQ#k^DWrjbuXoJf2{Aj^KT zFb1zMSqxq|vceV+Mf-)$oPflsO$@*A0n0Z!R{&(xh8s}=;t(lIy zv$S8x>m;vQNHuRzoaOo?eiWFe{0;$s`Bc+Osz~}Van${u;g(su`3lJ^TEfo~nERfP z)?aFzpDgnLYiERsKPu|0tq4l2wT)Atr6Qb%m-AUn6HnCue*yWICp7TjW$@sO zm5rm4aTcPQ(rfi7a`xP7cKCFrJD}*&_~xgLyr^-bmsL}y;A5P|al8J3WUoBSjqu%v zxC;mK!g(7r6RRJ852Z~feoC&sD3(6}^5-uLK8o)9{8L_%%rItZK9C){UxB|;G>JbP zsRRtS4-3B*5c+K2kvmgZK8472%l>3cntWUOVHxB|{Ay~aOg5RN;{PJgeVD*H%ac+y!h#wi%o2bF2Ca8IyMyH{>4#{E_8u^@+l-+n=V}Sq?$O z{091@v%Bd*3pk0^2UtiF9Z+(a@wy6 zUdw8J*ze$K#=$48IBi1U%;hmhO>lu!uU;+RS}p&6@rQila7WftH->*A4=5W|Fmtze z)7E}jh@cbmr9iup^i%*(uF%LG&!+Fyl@LFA-}Ca#bxRfDJAiR2dt6644TaYw1Ma79 zt8&DYj31j^5WPNf5P&{)J?WlCe@<3u^78wnd(Ja4^a>{^Tw}W>|Cjt^If|7l^l)^Q zbz|7~CF(k_9~n|h;ysZ+jHzkXf(*O*@5m zLzUmbHp=x!Q|!9NVXyipZ3)^GuIG$k;D)EK!a5=8MFLI_lpf`HPKl=-Ww%z8H_0$j ztJ||IfFG1lE9nmQ0+jPQy zCBdKkjArH@K7jVcMNz);Q(Q^R{d5G?-kk;Uu_IXSyWB)~KGIizZL(^&qF;|1PI7!E zTP`%l)gpX|OFn&)M%txpQ2F!hdA~hX1Cm5)IrdljqzRg!f{mN%G~H1&oqe`5eJCIF zHdD7O;AX-{XEV(a`gBFJ9ews#CVS2y!&>Cm_dm3C8*n3MA*e67(WC?uP@8TXuMroq z{#w$%z@CBIkRM7?}Xib+>hRjy?%G!fiw8! z8(gB+8J~KOU}yO7UGm&1g_MDJ$IXS!`+*b*QW2x)9>K~Y*E&bYMnjl6h!{17_8d!%&9D`a7r&LKZjC<&XOvTRaKJ1 zUY@hl5^R&kZl3lU3njk`3dPzxj$2foOL26r(9zsVF3n_F#v)s5vv3@dgs|lP#eylq62{<-vczqP!RpVBTgI>@O6&sU>W|do17+#OzQ7o5A$ICH z?GqwqnK^n2%LR;$^oZM;)+>$X3s2n}2jZ7CdWIW0lnGK-b#EG01)P@aU`pg}th&J-TrU`tIpb5t((0eu|!u zQz+3ZiOQ^?RxxK4;zs=l8q!-n7X{@jSwK(iqNFiRColuEOg}!7cyZi`iBX4g1pNBj zAPzL?P^Ljhn;1$r8?bc=#n|Ed7wB&oHcw()&*k#SS#h}jO?ZB246EGItsz*;^&tzp zu^YJ0=lwsi`eP_pU8}6JA7MS;9pfD;DsSsLo~ogzMNP70@@;Fm8f0^;>$Z>~}GWRw!W5J3tNX*^2+1f3hz{~rIzJo z6W%J(H!g-eI_J1>0juX$X4Cl6i+3wbc~k146UIX&G22}WE>0ga#WLsn9tY(&29zBvH1$`iWtTe zG2jYl@P!P)eb<5DsR72BdI7-zP&cZNI{7q3e@?N8IKc4DE#UVr->|-ryuJXk^u^>4 z$3wE~=q390;XuOQP~TNoDR?#|NSPJ%sTMInA6*rJ%go|=YjGe!B>z6u$IhgQSwoV* zjy3F2#I>uK{42{&IqP59)Y(1*Z>>#W8rCf4_eVsH)`v!P#^;BgzKDR`ARGEZzkNX+ zJUQu=*-ol=Xqqt5=`=pA@BIn@6a9G8C{c&`i^(i+BxQO9?YZ3iu%$$da&Kb?2kCCo zo7t$UpSFWqmydXf@l3bVJ=%K?SSw)|?srhJ-1ZdFu*5QhL$~-IQS!K1s@XzAtv6*Y zl8@(5BlWYLt1yAWy?rMD&bwze8bC3-GfNH=p zynNFCdxyX?K&G(ZZ)afguQ2|r;XoV^=^(;Cku#qYn4Lus`UeKt6rAlFo_rU`|Rq z&G?~iWMBio<78of-2X(ZYHx~=U0Vz4btyXkctMKdc9UM!vYr~B-(>)(Hc|D zMzkN4!PBg%tZoh+=Gba!0++d193gbMk2&krfDgcbx0jI92cq?FFESVg0D$>F+bil} zY~$)|>1HZsX=5sAZ2WgPB5P=8X#TI+NQ(M~GqyVB53c6IdX=k>Wu@A0Svf5#?uHaF zsYn|koIi3$(%GZ2+G+7Fv^lHTb#5b8sAHSTnL^qWZLM<(1|9|QFw9pnRU{svj}_Al zL)b9>fN{QiA($8peNEJyy`(a{&uh-T4_kdZFIVsKKVM(?05}76EEz?#W za^fiZOAd14IJ4zLX-n7Lq0qlQ^lW8Cvz4UKkV9~P}>sq0?xD3vg+$4vLm~C(+ zM{-3Z#qnZ09bJ>}j?6ry^h+@PfaD7*jZxBEY4)UG&daWb??6)TP+|3#Z&?GL?1i+280CFsE|vIXQbm| zM}Pk!U`U5NsNbyKzkrul-DzwB{X?n3E6?TUHr{M&+R*2%yOiXdW-_2Yd6?38M9Vy^ z*lE%gA{wwoSR~vN0=no}tP2Ul5Gk5M(Xq`$nw#ndFk`tcpd5A=Idue`XZ!FS>Q zG^0w#>P4pPG+*NC9gLP4x2m=cKP}YuS!l^?sHSFftZy{4CoQrb_ z^20(NnG`wAhMI=eq)SsIE~&Gp9Ne0nD4%Xiu|0Fj1UFk?6avDqjdXz{O1nKao*46y zT8~iA%Exu=G#{x=KD;_C&M+Zx4+n`sHT>^>=-1YM;H<72k>$py1?F3#T1*ef9mLZw z5naLQr?n7K;2l+{_uIw*_1nsTn~I|kkCgrn;|G~##hM;9l7Jy$yJfmk+&}W@JeKcF zx@@Woiz8qdi|D%aH3XTx5*wDlbs?dC1_nrFpm^QbG@wM=i2?Zg;$VK!c^Dp8<}BTI zyRhAq@#%2pGV49*Y5_mV4+OICP|%I(dQ7x=6Ob}>EjnB_-_18*xrY?b%-yEDT(wrO z9RY2QT0`_OpGfMObKHV;QLVnrK%mc?$WAdIT`kJQT^n%GuzE7|9@k3ci5fYOh(287 zuIbg!GB3xLg$YN=n)^pHGB0jH+_iIiC=nUcD;G6LuJsjn2VI1cyZx=a?ShCsF==QK z;q~*m&}L<-cb+mDDXzvvrRsybcgQ;Vg21P(uLv5I+eGc7o7tc6`;OA9{soHFOz zT~2?>Ts}gprIX$wRBb4yE>ot<8+*Bv`qbSDv*VtRi|cyWS>)Fjs>fkNOH-+PX&4(~ z&)T8Zam2L6puQl?;5zg9h<}k4#|yH9czHw;1jw-pwBM*O2hUR6yvHATrI%^mvs9q_ z&ccT0>f#eDG<^WG^q@oVqlJrhxH)dcq2cty@l3~|5#UDdExyXUmLQ}f4#;6fI{f^t zDCsgIJ~0`af%YR%Ma5VQq-p21k`vaBu6WE?66+5=XUd%Ay%D$irN>5LhluRWt7 zov-=f>QbMk*G##&DTQyou$s7UqjjW@k6=!I@!k+S{pP8R(2=e@io;N8E`EOB;OGoI zw6Q+{X1_I{OO0HPpBz!X!@`5YQ2)t{+!?M_iH25X(d~-Zx~cXnS9z>u?+If|iNJbx zyFU2d1!ITX64D|lE0Z{dLRqL1Ajj=CCMfC4lD3&mYR_R_VZ>_7_~|<^o*%_&jevU+ zQ4|qzci=0}Jydw|LXLCrOl1_P6Xf@c0$ieK2^7@A9UbF{@V_0p%lqW|L?5k>bVM8|p5v&2g;~r>B8uo<4N+`B zH{J)h;SYiIVx@#jI&p-v3dwL5QNV1oxPr8J%ooezTnLW>i*3Isb49%5i!&ac_dEXv zvXmVUck^QHmyrF8>CGXijC_R-y(Qr{3Zt~EmW)-nC!tiH`wlw5D*W7Pip;T?&j%kX z6DkZX4&}iw>hE(boLyjOoupf6JpvBG8}jIh!!VhnD0>}KSMMo{1#uU6kiFcA04~|7 zVO8eI&x1`g4CZ<2cYUI(n#wz2MtVFHx47yE5eL~8bot~>EHbevSt}LLMQX?odD{Ux zJMnam{d)W4da{l7&y-JrgiU~qY3$~}_F#G7|MxT)e;G{U`In&?`j<5D->}cb{}{T(4DF0BOk-=1195KB-E*o@c?`>y#4=dMtYtSY=&L{!TAjFVcq0y@AH`vH! z$41+u!Ld&}F^COPgL(EE{0X7LY&%D7-(?!kjFF7=qw<;`V{nwWBq<)1QiGJgUc^Vz ztMUlq1bZqKn17|6x6iAHbWc~l1HcmAxr%$Puv!znW)!JiukwIrqQ00|H$Z)OmGG@= zv%A8*4cq}(?qn4rN6o`$Y))(MyXr8R<2S^J+v(wmFmtac!%VOfN?&(8Nr!T@kV`N; z*Q33V3t`^rN&aBiHet)18wy{*wi1=W!B%B-Q6}SCrUl$~Hl{@!95ydml@FK8P=u4s z4e*7gV2s=YxEvskw2Ju!2%{8h01rx-3`NCPc(O zH&J0VH5etNB2KY6k4R@2Wvl^Ck$MoR3=)|SEclT2ccJ!RI9Nuter7u9@;sWf-%um;GfI!=eEIQ2l2p_YWUd{|6EG ze{yO6;lMc>;2tPrsNdi@&1K6(1;|$xe8vLgiouj%QD%gYk`4p{Ktv9|j+!OF-P?@p z;}SV|oIK)iwlBs+`ROXkhd&NK zzo__r!B>tOXpBJMDcv!Mq54P+n4(@dijL^EpO1wdg~q+!DT3lB<>9AANSe!T1XgC=J^)IP0XEZ()_vpu!!3HQyJhwh?r`Ae%Yr~b% zO*NY9t9#qWa@GCPYOF9aron7thfWT`eujS4`t2uG6)~JRTI;f(ZuoRQwjZjp5Pg34 z)rp$)Kr?R+KdJ;IO;pM{$6|2y=k_siqvp%)2||cHTe|b5Ht8&A{wazGNca zX$Ol?H)E_R@SDi~4{d-|8nGFhZPW;Cts1;08TwUvLLv&_2$O6Vt=M)X;g%HUr$&06 zISZb(6)Q3%?;3r~*3~USIg=HcJhFtHhIV(siOwV&QkQe#J%H9&E21!C*d@ln3E@J* zVqRO^<)V^ky-R|%{(9`l-(JXq9J)1r$`uQ8a}$vr9E^nNiI*thK8=&UZ0dsFN_eSl z(q~lnD?EymWLsNa3|1{CRPW60>DSkY9YQ;$4o3W7Ms&@&lv9eH!tk~N&dhqX&>K@} zi1g~GqglxkZ5pEFkllJ)Ta1I^c&Bt6#r(QLQ02yHTaJB~- zCcE=5tmi`UA>@P=1LBfBiqk)HB4t8D?02;9eXj~kVPwv?m{5&!&TFYhu>3=_ zsGmYZ^mo*-j69-42y&Jj0cBLLEulNRZ9vXE)8~mt9C#;tZs;=#M=1*hebkS;7(aGf zcs7zH(I8Eui9UU4L--))yy`&d&$In&VA2?DAEss4LAPCLd>-$i?lpXvn!gu^JJ$(DoUlc6wE98VLZ*z`QGQov5l4Fm_h?V-;mHLYDVOwKz7>e4+%AzeO>P6v}ndPW| zM>m#6Tnp7K?0mbK=>gV}=@k*0Mr_PVAgGMu$j+pWxzq4MAa&jpCDU&-5eH27Iz>m^ zax1?*HhG%pJ((tkR(V(O(L%7v7L%!_X->IjS3H5kuXQT2!ow(;%FDE>16&3r){!ex zhf==oJ!}YU89C9@mfDq!P3S4yx$aGB?rbtVH?sHpg?J5C->!_FHM%Hl3#D4eplxzQ zRA+<@LD%LKSkTk2NyWCg7u=$%F#;SIL44~S_OGR}JqX}X+=bc@swpiClB`Zbz|f!4 z7Ysah7OkR8liXfI`}IIwtEoL}(URrGe;IM8%{>b1SsqXh)~w}P>yiFRaE>}rEnNkT z!HXZUtxUp1NmFm)Dm@-{FI^aRQqpSkz}ZSyKR%Y}YHNzBk)ZIp} zMtS=aMvkgWKm9&oTcU0?S|L~CDqA+sHpOxwnswF-fEG)cXCzUR?ps@tZa$=O)=L+5 zf%m58cq8g_o}3?Bhh+c!w4(7AjxwQ3>WnVi<{{38g7yFboo>q|+7qs<$8CPXUFAN< zG&}BHbbyQ5n|qqSr?U~GY{@GJ{(Jny{bMaOG{|IkUj7tj^9pa9|FB_<+KHLxSxR;@ zHpS$4V)PP+tx}22fWx(Ku9y+}Ap;VZqD0AZW4gCDTPCG=zgJmF{|x;(rvdM|2|9a}cex6xrMkERnkE;}jvU-kmzd%_J50$M`lIPCKf+^*zL=@LW`1SaEc%=m zQ+lT06Gw+wVwvQ9fZ~#qd430v2HndFsBa9WjD0P}K(rZYdAt^5WQIvb%D^Q|pkVE^ zte$&#~zmULFACGfS#g=2OLOnIf2Of-k!(BIHjs77nr!5Q1*I9 z1%?=~#Oss!rV~?-6Gm~BWJiA4mJ5TY&iPm_$)H1_rTltuU1F3I(qTQ^U$S>%$l z)Wx1}R?ij0idp@8w-p!Oz{&*W;v*IA;JFHA9%nUvVDy7Q8woheC#|8QuDZb-L_5@R zOqHwrh|mVL9b=+$nJxM`3eE{O$sCt$UK^2@L$R(r^-_+z?lOo+me-VW=Zw z-Bn>$4ovfWd%SPY`ab-u9{INc*k2h+yH%toDHIyqQ zO68=u`N}RIIs7lsn1D){)~%>ByF<>i@qFb<-axvu(Z+6t7v<^z&gm9McRB~BIaDn$ z#xSGT!rzgad8o>~kyj#h1?7g96tOcCJniQ+*#=b7wPio>|6a1Z?_(TS{)KrPe}(8j z!#&A=k(&Pj^F;r)CI=Z{LVu>uj!_W1q4b`N1}E(i%;BWjbEcnD=mv$FL$l?zS6bW!{$7j1GR5ocn94P2u{ z70tAAcpqtQo<@cXw~@i-@6B23;317|l~S>CB?hR5qJ%J3EFgyBdJd^fHZu7AzHF(BQ!tyAz^L0`X z23S4Fe{2X$W0$zu9gm%rg~A>ijaE#GlYlrF9$ds^QtaszE#4M(OLVP2O-;XdT(XIC zatwzF*)1c+t~c{L=fMG8Z=k5lv>U0;C{caN1NItnuSMp)6G3mbahu>E#sj&oy94KC zpH}8oEw{G@N3pvHhp{^-YaZeH;K+T_1AUv;IKD<=mv^&Ueegrb!yf`4VlRl$M?wsl zZyFol(2|_QM`e_2lYSABpKR{{NlxlDSYQNkS;J66aT#MSiTx~;tUmvs-b*CrR4w=f z8+0;*th6kfZ3|5!Icx3RV11sp=?`0Jy3Fs0N4GZQMN=8HmT6%x9@{Dza)k}UwL6JT zHRDh;%!XwXr6yuuy`4;Xsn0zlR$k%r%9abS1;_v?`HX_hI|+EibVnlyE@3aL5vhQq zlIG?tN^w@0(v9M*&L+{_+RQZw=o|&BRPGB>e5=ys7H`nc8nx)|-g;s7mRc7hg{GJC zAe^vCIJhajmm7C6g! zL&!WAQ~5d_5)00?w_*|*H>3$loHrvFbitw#WvLB!JASO?#5Ig5$Ys10n>e4|3d;tS zELJ0|R4n3Az(Fl3-r^QiV_C;)lQ1_CW{5bKS15U|E9?ZgLec@%kXr84>5jV2a5v=w z?pB1GPdxD$IQL4)G||B_lI+A=08MUFFR4MxfGOu07vfIm+j=z9tp~5i_6jb`tR>qV z$#`=BQ*jpCjm$F0+F)L%xRlnS%#&gro6PiRfu^l!EVan|r3y}AHJQOORGx4~ z&<)3=K-tx518DZyp%|!EqpU!+X3Et7n2AaC5(AtrkW>_57i}$eqs$rupubg0a1+WO zGHZKLN2L0D;ab%{_S1Plm|hx8R?O14*w*f&2&bB050n!R2by zw!@XOQx$SqZ5I<(Qu$V6g>o#A!JVwErWv#(Pjx=KeS0@hxr4?13zj#oWwPS(7Ro|v z>Mp@Kmxo79q|}!5qtX2-O@U&&@6s~!I&)1WQIl?lTnh6UdKT_1R640S4~f=_xoN3- zI+O)$R@RjV$F=>Ti7BlnG1-cFKCC(t|Qjm{SalS~V-tX#+2ekRhwmN zZr`8{QF6y~Z!D|{=1*2D-JUa<(1Z=;!Ei!KiRNH?o{p5o3crFF=_pX9O-YyJchr$~ zRC`+G+8kx~fD2k*ZIiiIGR<8r&M@3H?%JVOfE>)})7ScOd&?OjgAGT@WVNSCZ8N(p zuQG~76GE3%(%h1*vUXg$vH{ua0b`sQ4f0*y=u~lgyb^!#CcPJa2mkSEHGLsnO^kb$ zru5_l#nu=Y{rSMWiYx?nO{8I!gH+?wEj~UM?IrG}E|bRIBUM>UlY<`T1EHpRr36vv zBi&dG8oxS|J$!zoaq{+JpJy+O^W(nt*|#g32bd&K^w-t>!Vu9N!k9eA8r!Xc{utY> zg9aZ(D2E0gL#W0MdjwES-7~Wa8iubPrd?8-$C4BP?*wok&O8+ykOx{P=Izx+G~hM8 z*9?BYz!T8~dzcZr#ux8kS7u7r@A#DogBH8km8Ry4slyie^n|GrTbO|cLhpqgMdsjX zJ_LdmM#I&4LqqsOUIXK8gW;V0B(7^$y#h3h>J0k^WJfAMeYek%Y-Dcb_+0zPJez!GM zAmJ1u;*rK=FNM0Nf}Y!!P9c4)HIkMnq^b;JFd!S3?_Qi2G#LIQ)TF|iHl~WKK6JmK zbv7rPE6VkYr_%_BT}CK8h=?%pk@3cz(UrZ{@h40%XgThP*-Oeo`T0eq9 zA8BnWZKzCy5e&&_GEsU4*;_k}(8l_&al5K-V*BFM=O~;MgRkYsOs%9eOY6s6AtE*<7GQAR2ulC3RAJrG_P1iQK5Z~&B z&f8X<>yJV6)oDGIlS$Y*D^Rj(cszTy5c81a5IwBr`BtnC6_e`ArI8CaTX_%rx7;cn zR-0?J_LFg*?(#n~G8cXut(1nVF0Oka$A$1FGcERU<^ggx;p@CZc?3UB41RY+wLS`LWFNSs~YP zuw1@DNN3lTd|jDL7gjBsd9}wIw}4xT2+8dBQzI00m<@?c2L%>}QLfK5%r!a-iII`p zX@`VEUH)uj^$;7jVUYdADQ2k*!1O3WdfgF?OMtUXNpQ1}QINamBTKDuv19^{$`8A1 zeq%q*O0mi@(%sZU>Xdb0Ru96CFqk9-L3pzLVsMQ`Xpa~N6CR{9Rm2)A|CI21L(%GW zh&)Y$BNHa=FD+=mBw3{qTgw)j0b!Eahs!rZnpu)z!!E$*eXE~##yaXz`KE5(nQM`s zD!$vW9XH)iMxu9R>r$VlLk9oIR%HxpUiW=BK@4U)|1WNQ=mz9a z^!KkO=>GaJ!GBXm{KJj^;kh-MkUlEQ%lza`-G&}C5y1>La1sR6hT=d*NeCnuK%_LV zOXt$}iP6(YJKc9j-Fxq~*ItVUqljQ8?oaysB-EYtFQp9oxZ|5m0^Hq(qV!S+hq#g( z?|i*H2MIr^Kxgz+3vIljQ*Feejy6S4v~jKEPTF~Qhq!(ms5>NGtRgO5vfPPc4Z^AM zTj!`5xEreIN)vaNxa|q6qWdg>+T`Ol0Uz)ckXBXEGvPNEL3R8hB3=C5`@=SYgAju1 z!)UBr{2~=~xa{b8>x2@C7weRAEuatC)3pkRhT#pMPTpSbA|tan%U7NGMvzmF?c!V8 z=pEWxbdXbTAGtWTyI?Fml%lEr-^AE}w#l(<7OIw;ctw}imYax&vR4UYNJZK6P7ZOd zP87XfhnUHxCUHhM@b*NbTi#(-8|wcv%3BGNs#zRCVV(W?1Qj6^PPQa<{yaBwZ`+<`w|;rqUY_C z&AeyKwwf*q#OW-F()lir=T^<^wjK65Lif$puuU5+tk$;e_EJ;Lu+pH>=-8=PDhkBg z8cWt%@$Sc#C6F$Vd+0507;{OOyT7Hs%nKS88q-W!$f~9*WGBpHGgNp}=C*7!RiZ5s zn1L_DbKF@B8kwhDiLKRB@lsXVVLK|ph=w%_`#owlf@s@V(pa`GY$8h%;-#h@TsO|Y8V=n@*!Rog7<7Cid%apR|x zOjhHCyfbIt%+*PCveTEcuiDi%Wx;O;+K=W?OFUV%)%~6;gl?<0%)?snDDqIvkHF{ zyI02)+lI9ov42^hL>ZRrh*HhjF9B$A@=H94iaBESBF=eC_KT$8A@uB^6$~o?3Wm5t1OIaqF^~><2?4e3c&)@wKn9bD? zoeCs;H>b8DL^F&>Xw-xjZEUFFTv>JD^O#1E#)CMBaG4DX9bD(Wtc8Rzq}9soQ8`jf zeSnHOL}<+WVSKp4kkq&?SbETjq6yr@4%SAqOG=9E(3YeLG9dtV+8vmzq+6PFPk{L; z(&d++iu=^F%b+ea$i2UeTC{R*0Isk;vFK!no<;L+(`y`3&H-~VTdKROkdyowo1iqR zbVW(3`+(PQ2>TKY>N!jGmGo7oeoB8O|P_!Ic@ zZ^;3dnuXo;WJ?S+)%P>{Hcg!Jz#2SI(s&dY4QAy_vRlmOh)QHvs_7c&zkJCmJGVvV zX;Mtb>QE+xp`KyciG$Cn*0?AK%-a|=o!+7x&&yzHQOS>8=B*R=niSnta^Pxp1`=md z#;$pS$4WCT?mbiCYU?FcHGZ#)kHVJTTBt^%XE(Q};aaO=Zik0UgLcc0I(tUpt(>|& zcxB_|fxCF7>&~5eJ=Dpn&5Aj{A^cV^^}(7w#p;HG&Q)EaN~~EqrE1qKrMAc&WXIE;>@<&)5;gD2?={Xf@Mvn@OJKw=8Mgn z!JUFMwD+s==JpjhroT&d{$kQAy%+d`a*XxDEVxy3`NHzmITrE`o!;5ClXNPb4t*8P zzAivdr{j_v!=9!^?T3y?gzmqDWX6mkzhIzJ-3S{T5bcCFMr&RPDryMcdwbBuZbsgN zGrp@^i?rcfN7v0NKGzDPGE#4yszxu=I_`MI%Z|10nFjU-UjQXXA?k8Pk|OE<(?ae) zE%vG#eZAlj*E7_3dx#Zz4kMLj>H^;}33UAankJiDy5ZvEhrjr`!9eMD8COp}U*hP+ zF}KIYx@pkccIgyxFm#LNw~G&`;o&5)2`5aogs`1~7cMZQ7zj!%L4E`2yzlQN6REX20&O<9 zKV6fyr)TScJPPzNTC2gL+0x#=u>(({{D7j)c-%tvqls3#Y?Z1m zV5WUE)zdJ{$p>yX;^P!UcXP?UD~YM;IRa#Rs5~l+*$&nO(;Ers`G=0D!twR(0GF@c zHl9E5DQI}Oz74n zfKP>&$q0($T4y$6w(p=ERAFh+>n%iaeRA%!T%<^+pg?M)@ucY<&59$x9M#n+V&>}=nO9wCV{O~lg&v#+jcUj(tQ z`0u1YH)-`U$15a{pBkGyPL0THv1P|4e@pf@3IBZS4dVJPo#H>pWq%Lr0YS-SeWash z8R7=jb28KPMI|_lo#GEO|5B?N_e``H*23{~a!AmUJ+fb4HX-%QI@lSEUxKlGV7z7Q zSKw@-TR>@1RL%w{x}dW#k1NgW+q4yt2Xf1J62Bx*O^WG8OJ|FqI4&@d3_o8Id@*)4 zYrk=>@!wv~mh7YWv*bZhxqSmFh2Xq)o=m;%n$I?GSz49l1$xRpPu_^N(vZ>*>Z<04 z2+rP70oM=NDysd!@fQdM2OcyT?3T^Eb@lIC-UG=Bw{BjQ&P`KCv$AcJ;?`vdZ4){d z&gkoUK{$!$$K`3*O-jyM1~p-7T*qb)Ys>Myt^;#1&a%O@x8A+E>! zY8=eD`ZG)LVagDLBeHg>=atOG?Kr%h4B%E6m@J^C+U|y)XX@f z8oyJDW|9g=<#f<{JRr{y#~euMnv)`7j=%cHWLc}ngjq~7k**6%4u>Px&W%4D94(r* z+akunK}O0DC2A%Xo9jyF;DobX?!1I(7%}@7F>i%&nk*LMO)bMGg2N+1iqtg+r(70q zF5{Msgsm5GS7DT`kBsjMvOrkx&|EU!{{~gL4d2MWrAT=KBQ-^zQCUq{5PD1orxlIL zq;CvlWx#f1NWvh`hg011I%?T_s!e38l*lWVt|~z-PO4~~1g)SrJ|>*tXh=QfXT)%( z+ex+inPvD&O4Ur;JGz>$sUOnWdpSLcm1X%aQDw4{dB!cnj`^muI$CJ2%p&-kULVCE z>$eMR36kN$wCPR+OFDM3-U(VOrp9k3)lI&YVFqd;Kpz~K)@Fa&FRw}L(SoD z9B4a+hQzZT-BnVltst&=kq6Y(f^S4hIGNKYBgMxGJ^;2yrO}P3;r)(-I-CZ)26Y6? z&rzHI_1GCvGkgy-t1E;r^3Le30|%$ebDRu2+gdLG)r=A~Qz`}~&L@aGJ{}vVs_GE* zVUjFnzHiXfKQbpv&bR&}l2bzIjAooB)=-XNcYmrGmBh(&iu@o!^hn0^#}m2yZZUK8 zufVm7Gq0y`Mj;9b>`c?&PZkU0j4>IL=UL&-Lp3j&47B5pAW4JceG{!XCA)kT<%2nqCxj<)uy6XR_uws~>_MEKPOpAQ!H zkn>FKh)<9DwwS*|Y(q?$^N!6(51O0 z^JM~Ax{AI1Oj$fs-S5d4T7Z_i1?{%0SsIuQ&r8#(JA=2iLcTN+?>wOL532%&dMYkT z*T5xepC+V6zxhS@vNbMoi|i)=rpli@R9~P!39tWbSSb904ekv7D#quKbgFEMTb48P zuq(VJ+&L8aWU(_FCD$3^uD!YM%O^K(dvy~Wm2hUuh6bD|#(I39Xt>N1Y{ZqXL`Fg6 zKQ?T2htHN!(Bx;tV2bfTtIj7e)liN-29s1kew>v(D^@)#v;}C4-G=7x#;-dM4yRWm zyY`cS21ulzMK{PoaQ6xChEZ}o_#}X-o}<&0)$1#3we?+QeLt;aVCjeA)hn!}UaKt< zat1fHEx13y-rXNMvpUUmCVzocPmN~-Y4(YJvQ#db)4|%B!rBsgAe+*yor~}FrNH08 z3V!97S}D7d$zbSD{$z;@IYMxM6aHdypIuS*pr_U6;#Y!_?0i|&yU*@16l z*dcMqDQgfNBf}?quiu4e>H)yTVfsp#f+Du0@=Kc41QockXkCkvu>FBd6Q+@FL!(Yx z2`YuX#eMEiLEDhp+9uFqME_E^faV&~9qjBHJkIp~%$x^bN=N)K@kvSVEMdDuzA0sn z88CBG?`RX1@#hQNd`o^V{37)!w|nA)QfiYBE^m=yQKv-fQF+UCMcuEe1d4BH7$?>b zJl-r9@0^Ie=)guO1vOd=i$_4sz>y3x^R7n4ED!5oXL3@5**h(xr%Hv)_gILarO46q+MaDOF%ChaymKoI6JU5Pg;7#2n9-18|S1;AK+ zgsn6;k6-%!QD>D?cFy}8F;r@z8H9xN1jsOBw2vQONVqBVEbkiNUqgw~*!^##ht>w0 zUOykwH=$LwX2j&nLy=@{hr)2O&-wm-NyjW7n~Zs9UlH;P7iP3 zI}S(r0YFVYacnKH(+{*)Tbw)@;6>%=&Th=+Z6NHo_tR|JCI8TJiXv2N7ei7M^Q+RM z?9o`meH$5Yi;@9XaNR#jIK^&{N|DYNNbtdb)XW1Lv2k{E>;?F`#Pq|&_;gm~&~Zc9 zf+6ZE%{x4|{YdtE?a^gKyzr}dA>OxQv+pq|@IXL%WS0CiX!V zm$fCePA%lU{%pTKD7|5NJHeXg=I0jL@$tOF@K*MI$)f?om)D63K*M|r`gb9edD1~Y zc|w7N)Y%do7=0{RC|AziW7#am$)9jciRJ?IWl9PE{G3U+$%FcyKs_0Cgq`=K3@ttV z9g;M!3z~f_?P%y3-ph%vBMeS@p7P&Ea8M@97+%XEj*(1E6vHj==d zjsoviB>j^$_^OI_DEPvFkVo(BGRo%cJeD){6Uckei=~1}>sp299|IRjhXe)%?uP0I zF5+>?0#Ye}T^Y$u_rc4=lPcq4K^D(TZG-w30-YiEM=dcK+4#o*>lJ8&JLi+3UcpZk z!^?95S^C0ja^jwP`|{<+3cBVog$(mRdQmadS+Vh~z zS@|P}=|z3P6uS+&@QsMp0no9Od&27O&14zHXGAOEy zh~OKpymK5C%;LLb467@KgIiVwYbYd6wFxI{0-~MOGfTq$nBTB!{SrWmL9Hs}C&l&l#m?s*{tA?BHS4mVKHAVMqm63H<|c5n0~k)-kbg zXidai&9ZUy0~WFYYKT;oe~rytRk?)r8bptITsWj(@HLI;@=v5|XUnSls7$uaxFRL+ zRVMGuL3w}NbV1`^=Pw*0?>bm8+xfeY(1PikW*PB>>Tq(FR`91N0c2&>lL2sZo5=VD zQY{>7dh_TX98L2)n{2OV=T10~*YzX27i2Q7W86M4$?gZIXZaBq#sA*{PH8){|GUi;oM>e?ua7eF4WFuFYZSG| zze?srg|5Ti8Og{O zeFxuw9!U+zhyk?@w zjsA6(oKD=Ka;A>Ca)oPORxK+kxH#O@zhC!!XS4@=swnuMk>t+JmLmFiE^1aX3f<)D@`%K0FGK^gg1a1j>zi z2KhV>sjU7AX3F$SEqrXSC}fRx64GDoc%!u2Yag68Lw@w9v;xOONf@o)Lc|Uh3<21ctTYu-mFZuHk*+R{GjXHIGq3p)tFtQp%TYqD=j1&y)>@zxoxUJ!G@ zgI0XKmP6MNzw>nRxK$-Gbzs}dyfFzt>#5;f6oR27ql!%+{tr+(`(>%51|k`ML} zY4eE)Lxq|JMas(;JibNQds1bUB&r}ydMQXBY4x(^&fY_&LlQC)3hylc$~8&~|06-D z#T+%66rYbHX%^KuqJED_wuGB+=h`nWA!>1n0)3wZrBG3%`b^Ozv6__dNa@%V14|!D zQ?o$z5u0^8`giv%qE!BzZ!3j;BlDlJDk)h@9{nSQeEk!z9RGW) z${RSF3phEM*ce*>Xdp}585vj$|40=&S{S-GTiE?Op*vY&Lvr9}BO$XWy80IF+6@%n z5*2ueT_g@ofP#u5pxb7n*fv^Xtt7&?SRc{*2Ka-*!BuOpf}neHGCiHy$@Ka1^Dint z;DkmIL$-e)rj4o2WQV%Gy;Xg(_Bh#qeOsTM2f@KEe~4kJ8kNLQ+;(!j^bgJMcNhvklP5Z6I+9Fq@c&D~8Fb-4rmDT!MB5QC{Dsb;BharP*O;SF4& zc$wj-7Oep7#$WZN!1nznc@Vb<_Dn%ga-O#J(l=OGB`dy=Sy&$(5-n3zzu%d7E#^8`T@}V+5B;PP8J14#4cCPw-SQTdGa2gWL0*zKM z#DfSXs_iWOMt)0*+Y>Lkd=LlyoHjublNLefhKBv@JoC>P7N1_#> zv=mLWe96%EY;!ZGSQDbZWb#;tzqAGgx~uk+-$+2_8U`!ypbwXl z^2E-FkM1?lY@yt8=J3%QK+xaZ6ok=-y%=KXCD^0r!5vUneW>95PzCkOPO*t}p$;-> ze5j-BLT_;)cZQzR2CEsm@rU7GZfFtdp*a|g4wDr%8?2QkIGasRfDWT-Dvy*U{?IHT z*}wGnzdlSptl#ZF^sf)KT|BJs&kLG91^A6ls{CzFprZ6-Y!V0Xysh%9p%iMd7HLsS zN+^Un$tDV)T@i!v?3o0Fsx2qI(AX_$dDkBzQ@fRM%n zRXk6hb9Py#JXUs+7)w@eo;g%QQ95Yq!K_d=z{0dGS+pToEI6=Bo8+{k$7&Z zo4>PH(`ce8E-Ps&uv`NQ;U$%t;w~|@E3WVOCi~R4oj5wP?%<*1C%}Jq%a^q~T7u>K zML5AKfQDv6>PuT`{SrKHRAF+^&edg6+5R_#H?Lz3iGoWo#PCEd0DS;)2U({{X#zU^ zw_xv{4x7|t!S)>44J;KfA|DC?;uQ($l+5Vp7oeqf7{GBF9356nx|&B~gs+@N^gSdd zvb*>&W)|u#F{Z_b`f#GVtQ`pYv3#||N{xj1NgB<#=Odt6{eB%#9RLt5v zIi|0u70`#ai}9fJjKv7dE!9ZrOIX!3{$z_K5FBd-Kp-&e4(J$LD-)NMTp^_pB`RT; zftVVlK2g@+1Ahv2$D){@Y#cL#dUj9*&%#6 zd2m9{1NYp>)6=oAvqdCn5#cx{AJ%S8skUgMglu2*IAtd+z1>B&`MuEAS(D(<6X#Lj z?f4CFx$)M&$=7*>9v1ER4b6!SIz-m0e{o0BfkySREchp?WdVPpQCh!q$t>?rL!&Jg zd#heM;&~A}VEm8Dvy&P|J*eAV&w!&Nx6HFV&B8jJFVTmgLaswn!cx$&%JbTsloz!3 zMEz1d`k==`Ueub_JAy_&`!ogbwx27^ZXgFNAbx=g_I~5nO^r)}&myw~+yY*cJl4$I znNJ32M&K=0(2Dj_>@39`3=FX!v3nZHno_@q^!y}%(yw0PqOo=);6Y@&ylVe>nMOZ~ zd>j#QQSBn3oaWd;qy$&5(5H$Ayi)0haAYO6TH>FR?rhqHmNOO+(})NB zLI@B@v0)eq!ug`>G<@htRlp3n!EpU|n+G+AvXFrWSUsLMBfL*ZB`CRsIVHNTR&b?K zxBgsN0BjfB>UVcJ|x%=-zb%OV7lmZc& zxiupadZVF7)6QuhoY;;FK2b*qL0J-Rn-8!X4ZY$-ZSUXV5DFd7`T41c(#lAeLMoeT z4%g655v@7AqT!i@)Edt5JMbN(=Q-6{=L4iG8RA%}w;&pKmtWvI4?G9pVRp|RTw`g0 zD5c12B&A2&P6Ng~8WM2eIW=wxd?r7A*N+&!Be7PX3s|7~z=APxm=A?5 zt>xB4WG|*Td@VX{Rs)PV0|yK`oI3^xn(4c_j&vgxk_Y3o(-`_5o`V zRTghg6%l@(qodXN;dB#+OKJEEvhfcnc#BeO2|E(5df-!fKDZ!%9!^BJ_4)9P+9Dq5 zK1=(v?KmIp34r?z{NEWnLB3Px{XYwy-akun4F7xTRr2^zeYW{gcK9)>aJDdU5;w5@ zak=<+-PLH-|04pelTb%ULpuuuJC7DgyT@D|p{!V!0v3KpDnRjANN12q6SUR3mb9<- z>2r~IApQGhstZ!3*?5V z8#)hJ0TdZg0M-BK#nGFP>$i=qk82DO z7h;Ft!D5E15OgW)&%lej*?^1~2=*Z5$2VX>V{x8SC+{i10BbtUk9@I#Vi&hX)q
    Q!LwySI{Bnv%Sm)yh{^sSVJ8&h_D-BJ_YZe5eCaAWU9b$O2c z$T|{vWVRtOL!xC0DTc(Qbe`ItNtt5hr<)VijD0{U;T#bUEp381_y`%ZIav?kuYG{iyYdEBPW=*xNSc;Rlt6~F4M`5G+VtOjc z*0qGzCb@gME5udTjJA-9O<&TWd~}ysBd(eVT1-H82-doyH9RST)|+Pb{o*;$j9Tjs zhU!IlsPsj8=(x3bAKJTopW3^6AKROHR^7wZ185wJGVhA~hEc|LP;k7NEz-@4p5o}F z`AD6naG3(n=NF9HTH81=F+Q|JOz$7wm9I<+#BSmB@o_cLt2GkW9|?7mM;r!JZp89l zbo!Hp8=n!XH1{GwaDU+k)pGp`C|cXkCU5%vcH)+v@0eK>%7gWxmuMu9YLlChA|_D@ zi#5zovN_!a-0?~pUV-Rj*1P)KwdU-LguR>YM&*Nen+ln8Q$?WFCJg%DY%K}2!!1FE zDv-A%Cbwo^p(lzac&_TZ-l#9kq`mhLcY3h9ZTUVCM(Ad&=EriQY5{jJv<5K&g|*Lk zgV%ILnf1%8V2B0E&;Sp4sYbYOvvMebLwYwzkRQ#F8GpTQq#uv=J`uaSJ34OWITeSGo6+-8Xw znCk*n{kdDEi)Hi&u^)~cs@iyCkFWB2SWZU|Uc%^43ZIZQ-vWNExCCtDWjqHs;;tWf$v{}0{p0Rvxkq``)*>+Akq%|Na zA`@~-Vfe|+(AIlqru+7Ceh4nsVmO9p9jc8}HX^W&ViBDXT+uXbT#R#idPn&L>+#b6 zflC-4C5-X;kUnR~L>PSLh*gvL68}RBsu#2l`s_9KjUWRhiqF`j)`y`2`YU(>3bdBj z?>iyjEhe-~$^I5!nn%B6Wh+I`FvLNvauve~eX<+Ipl&04 zT}};W&1a3%W?dJ2=N#0t?e+aK+%t}5q%jSLvp3jZ%?&F}nOOWr>+{GFIa%wO_2`et z=JzoRR~}iKuuR+azPI8;Gf9)z3kyA4EIOSl!sRR$DlW}0>&?GbgPojmjmnln;cTqCt=ADbE zZ8GAnoM+S1(5$i8^O4t`ue;vO4i}z0wz-QEIVe5_u03;}-!G1NyY8;h^}y;tzY}i5 zqQr#Ur3Fy8sSa$Q0ys+f`!`+>9WbvU_I`Sj;$4{S>O3?#inLHCrtLy~!s#WXV=oVP zeE93*Nc`PBi4q@%Ao$x4lw9vLHM!6mn3-b_cebF|n-2vt-zYVF_&sDE--J-P;2WHo z+@n2areE0o$LjvjlV2X7ZU@j+`{*8zq`JR3gKF#EW|#+{nMyo-a>nFFTg&vhyT=b} zDa8+v0(Dgx0yRL@ZXOYIlVSZ0|MFizy0VPW8;AfA5|pe!#j zX}Py^8fl5SyS4g1WSKKtnyP+_PoOwMMwu`(i@Z)diJp~U54*-miOchy7Z35eL>^M z4p<-aIxH4VUZgS783@H%M7P9hX>t{|RU7$n4T(brCG#h9e9p! z+o`i;EGGq3&pF;~5V~eBD}lC)>if$w%Vf}AFxGqO88|ApfHf&Bvu+xdG)@vuF}Yvk z)o;~k-%+0K0g+L`Wala!$=ZV|z$e%>f0%XoLib%)!R^RoS+{!#X?h-6uu zF&&KxORdZU&EwQFITIRLo(7TA3W}y6X{?Y%y2j0It!ekU#<)$qghZtpcS>L3uh`Uj z7GY;6f$9qKynP#oS3$$a{p^{D+0oJQ71`1?OAn_m8)UGZmj3l*ZI)`V-a>MKGGFG< z&^jg#Ok%(hhm>hSrZ5;Qga4u(?^i>GiW_j9%_7M>j(^|Om$#{k+^*ULnEgzW_1gCICtAD^WpC`A z{9&DXkG#01Xo)U$OC(L5Y$DQ|Q4C6CjUKk1UkPj$nXH##J{c8e#K|&{mA*;b$r0E4 zUNo0jthwA(c&N1l=PEe8Rw_8cEl|-eya9z&H3#n`B$t#+aJ03RFMzrV@gowbe8v(c zIFM60^0&lCFO10NU4w@|61xiZ4CVXeaKjd;d?sv52XM*lS8XiVjgWpRB;&U_C0g+`6B5V&w|O6B*_q zsATxL!M}+$He)1eOWECce#eS@2n^xhlB4<_Nn?yCVEQWDs(r`|@2GqLe<#(|&P0U? z$7V5IgpWf09uIf_RazRwC?qEqRaHyL?iiS05UiGesJy%^>-C{{ypTBI&B0-iUYhk> zIk<5xpsuV@g|z(AZD+C-;A!fTG=df1=<%nxy(a(IS+U{ME4ZbDEBtcD_3V=icT6*_ z)>|J?>&6%nvHhZERBtjK+s4xnut*@>GAmA5m*OTp$!^CHTr}vM4n(X1Q*;{e-Rd2BCF-u@1ZGm z!S8hJ6L=Gl4T_SDa7Xx|-{4mxveJg=ctf`BJ*fy!yF6Dz&?w(Q_6B}WQVtNI!BVBC zKfX<>7vd6C96}XAQmF-Jd?1Q4eTfRB3q7hCh0f!(JkdWT5<{iAE#dKy*Jxq&3a1@~ z8C||Dn2mFNyrUV|<-)C^_y7@8c2Fz+2jrae9deBDu;U}tJ{^xAdxCD248(k;dCJ%o z`y3sADe>U%suxwwv~8A1+R$VB=Q?%U?4joI$um;aH+eCrBqpn- z%79D_7rb;R-;-9RTrwi9dPlg8&@tfWhhZ(Vx&1PQ+6(huX`;M9x~LrW~~#3{j0Bh2kDU$}@!fFQej4VGkJv?M4rU^x!RU zEwhu$!CA_iDjFjrJa`aocySDX16?~;+wgav;}Zut6Mg%C4>}8FL?8)Kgwc(Qlj{@#2Pt0?G`$h7P#M+qoXtlV@d}%c&OzO+QYKK`kyXaK{U(O^2DyIXCZlNQjt0^8~8JzNGrIxhj}}M z&~QZlbx%t;MJ(Vux;2tgNKGlAqphLq%pd}JG9uoVHUo?|hN{pLQ6Em%r*+7t^<);X zm~6=qChlNAVXNN*Sow->*4;}T;l;D1I-5T{Bif@4_}=>l`tK;qqDdt5zvisCKhMAH z#r}`)7VW?LZqfdmXQ%zo5bJ00{Xb9^YKrk0Nf|oIW*K@(=`o2Vndz}ZDyk{!u}PVx zzd--+_WC*U{~DH3{?GI64IB+@On&@9X>EUAo&L+G{L^dozaI4C3G#2wr~hseW@K&g zKWs{uHu-9Je!3;4pE>eBltKUXb^*hG8I&413)$J&{D4N%7PcloU6bn%jPxJyQL?g* z9g+YFFEDiE`8rW^laCNzQmi7CTnPfwyg3VDHRAl>h=In6jeaVOP@!-CP60j3+#vpL zEYmh_oP0{-gTe7Or`L6x)6w?77QVi~jD8lWN@3RHcm80iV%M1A!+Y6iHM)05iC64tb$X2lV_%Txk@0l^hZqi^%Z?#- zE;LE0uFx)R08_S-#(wC=dS&}vj6P4>5ZWjhthP=*Hht&TdLtKDR;rXEX4*z0h74FA zMCINqrh3Vq;s%3MC1YL`{WjIAPkVL#3rj^9Pj9Ss7>7duy!9H0vYF%>1jh)EPqvlr6h%R%CxDsk| z!BACz7E%j?bm=pH6Eaw{+suniuY7C9Ut~1cWfOX9KW9=H><&kQlinPV3h9R>3nJvK z4L9(DRM=x;R&d#a@oFY7mB|m8h4692U5eYfcw|QKwqRsshN(q^v$4$)HgPpAJDJ`I zkqjq(8Cd!K!+wCd=d@w%~e$=gdUgD&wj$LQ1r>-E=O@c ze+Z$x{>6(JA-fNVr)X;*)40Eym1TtUZI1Pwwx1hUi+G1Jlk~vCYeXMNYtr)1?qwyg zsX_e*$h?380O00ou?0R@7-Fc59o$UvyVs4cUbujHUA>sH!}L54>`e` zHUx#Q+Hn&Og#YVOuo*niy*GU3rH;%f``nk#NN5-xrZ34NeH$l`4@t);4(+0|Z#I>Y z)~Kzs#exIAaf--65L0UHT_SvV8O2WYeD>Mq^Y6L!Xu8%vnpofG@w!}R7M28?i1*T&zp3X4^OMCY6(Dg<-! zXmcGQrRgHXGYre7GfTJ)rhl|rs%abKT_Nt24_Q``XH{88NVPW+`x4ZdrMuO0iZ0g` z%p}y};~T5gbb9SeL8BSc`SO#ixC$@QhXxZ=B}L`tP}&k?1oSPS=4%{UOHe0<_XWln zwbl5cn(j-qK`)vGHY5B5C|QZd5)W7c@{bNVXqJ!!n$^ufc?N9C-BF2QK1(kv++h!>$QbAjq)_b$$PcJdV+F7hz0Hu@ zqj+}m0qn{t^tD3DfBb~0B36|Q`bs*xs|$i^G4uNUEBl4g;op-;Wl~iThgga?+dL7s zUP(8lMO?g{GcYpDS{NM!UA8Hco?#}eNEioRBHy4`mq!Pd-9@-97|k$hpEX>xoX+dY zDr$wfm^P&}Wu{!%?)U_(%Mn79$(ywvu*kJ9r4u|MyYLI_67U7%6Gd_vb##Nerf@>& z8W11z$$~xEZt$dPG}+*IZky+os5Ju2eRi;1=rUEeIn>t-AzC_IGM-IXWK3^6QNU+2pe=MBn4I*R@A%-iLDCOHTE-O^wo$sL_h{dcPl=^muAQb`_BRm};=cy{qSkui;`WSsj9%c^+bIDQ z0`_?KX0<-=o!t{u(Ln)v>%VGL z0pC=GB7*AQ?N7N{ut*a%MH-tdtNmNC+Yf$|KS)BW(gQJ*z$d{+{j?(e&hgTy^2|AR9vx1Xre2fagGv0YXWqtNkg*v%40v?BJBt|f9wX5 z{QTlCM}b-0{mV?IG>TW_BdviUKhtosrBqdfq&Frdz>cF~yK{P@(w{Vr7z2qKFwLhc zQuogKO@~YwyS9%+d-zD7mJG~@?EFJLSn!a&mhE5$_4xBl&6QHMzL?CdzEnC~C3$X@ zvY!{_GR06ep5;<#cKCSJ%srxX=+pn?ywDwtJ2{TV;0DKBO2t++B(tIO4)Wh`rD13P z4fE$#%zkd=UzOB74gi=-*CuID&Z3zI^-`4U^S?dHxK8fP*;fE|a(KYMgMUo`THIS1f!*6dOI2 zFjC3O=-AL`6=9pp;`CYPTdVX z8(*?V&%QoipuH0>WKlL8A*zTKckD!paN@~hh zmXzm~qZhMGVdQGd=AG8&20HW0RGV8X{$9LldFZYm zE?}`Q3i?xJRz43S?VFMmqRyvWaS#(~Lempg9nTM$EFDP(Gzx#$r)W&lpFKqcAoJh-AxEw$-bjW>`_+gEi z2w`99#UbFZGiQjS8kj~@PGqpsPX`T{YOj`CaEqTFag;$jY z8_{Wzz>HXx&G*Dx<5skhpETxIdhKH?DtY@b9l8$l?UkM#J-Snmts7bd7xayKTFJ(u zyAT&@6cAYcs{PBfpqZa%sxhJ5nSZBPji?Zlf&}#L?t)vC4X5VLp%~fz2Sx<*oN<7` z?ge=k<=X7r<~F7Tvp9#HB{!mA!QWBOf%EiSJ6KIF8QZNjg&x~-%e*tflL(ji_S^sO ztmib1rp09uon}RcsFi#k)oLs@$?vs(i>5k3YN%$T(5Or(TZ5JW9mA6mIMD08=749$ z!d+l*iu{Il7^Yu}H;lgw=En1sJpCKPSqTCHy4(f&NPelr31^*l%KHq^QE>z>Ks_bH zjbD?({~8Din7IvZeJ>8Ey=e;I?thpzD=zE5UHeO|neioJwG;IyLk?xOz(yO&0DTU~ z^#)xcs|s>Flgmp;SmYJ4g(|HMu3v7#;c*Aa8iF#UZo7CvDq4>8#qLJ|YdZ!AsH%^_7N1IQjCro

    K7UpUK$>l@ zw`1S}(D?mUXu_C{wupRS-jiX~w=Uqqhf|Vb3Cm9L=T+w91Cu^ z*&Ty%sN?x*h~mJc4g~k{xD4ZmF%FXZNC;oVDwLZ_WvrnzY|{v8hc1nmx4^}Z;yriXsAf+Lp+OFLbR!&Ox?xABwl zu8w&|5pCxmu#$?Cv2_-Vghl2LZ6m7}VLEfR5o2Ou$x02uA-%QB2$c(c1rH3R9hesc zfpn#oqpbKuVsdfV#cv@5pV4^f_!WS+F>SV6N0JQ9E!T90EX((_{bSSFv9ld%I0&}9 zH&Jd4MEX1e0iqDtq~h?DBrxQX1iI0lIs<|kB$Yrh&cpeK0-^K%=FBsCBT46@h#yi!AyDq1V(#V}^;{{V*@T4WJ&U-NTq43w=|K>z8%pr_nC>%C(Wa_l78Ufib$r8Od)IIN=u>417 z`Hl{9A$mI5A(;+-Q&$F&h-@;NR>Z<2U;Y21>>Z;s@0V@SbkMQQj%_;~+qTuQ?c|AV zcWm3XZQHhP&R%QWarS%mJ!9R^&!_)*s(v+VR@I#QrAT}`17Y+l<`b-nvmDNW`De%y zrwTZ9EJrj1AFA>B`1jYDow}~*dfPs}IZMO3=a{Fy#IOILc8F0;JS4x(k-NSpbN@qM z`@aE_e}5{!$v3+qVs7u?sOV(y@1Os*Fgu`fCW9=G@F_#VQ%xf$hj0~wnnP0$hFI+@ zkQj~v#V>xn)u??YutKsX>pxKCl^p!C-o?+9;!Nug^ z{rP!|+KsP5%uF;ZCa5F;O^9TGac=M|=V z_H(PfkV1rz4jl?gJ(ArXMyWT4y(86d3`$iI4^l9`vLdZkzpznSd5Ikfrs8qcSy&>z zTIZgWZGXw0n9ibQxYWE@gI0(3#KA-dAdPcsL_|hg2@~C!VZDM}5;v_Nykfq!*@*Zf zE_wVgx82GMDryKO{U{D>vSzSc%B~|cjDQrt5BN=Ugpsf8H8f1lR4SGo#hCuXPL;QQ z#~b?C4MoepT3X`qdW2dNn& zo8)K}%Lpu>0tQei+{>*VGErz|qjbK#9 zvtd8rcHplw%YyQCKR{kyo6fgg!)6tHUYT(L>B7er5)41iG`j$qe*kSh$fY!PehLcD zWeKZHn<492B34*JUQh=CY1R~jT9Jt=k=jCU2=SL&&y5QI2uAG2?L8qd2U(^AW#{(x zThSy=C#>k+QMo^7caQcpU?Qn}j-`s?1vXuzG#j8(A+RUAY})F@=r&F(8nI&HspAy4 z4>(M>hI9c7?DCW8rw6|23?qQMSq?*Vx?v30U%luBo)B-k2mkL)Ljk5xUha3pK>EEj z@(;tH|M@xkuN?gsz;*bygizwYR!6=(Xgcg^>WlGtRYCozY<rFX2E>kaZo)O<^J7a`MX8Pf`gBd4vrtD|qKn&B)C&wp0O-x*@-|m*0egT=-t@%dD zgP2D+#WPptnc;_ugD6%zN}Z+X4=c61XNLb7L1gWd8;NHrBXwJ7s0ce#lWnnFUMTR& z1_R9Fin4!d17d4jpKcfh?MKRxxQk$@)*hradH2$3)nyXep5Z;B z?yX+-Bd=TqO2!11?MDtG0n(*T^!CIiF@ZQymqq1wPM_X$Iu9-P=^}v7npvvPBu!d$ z7K?@CsA8H38+zjA@{;{kG)#AHME>Ix<711_iQ@WWMObXyVO)a&^qE1GqpP47Q|_AG zP`(AD&r!V^MXQ^e+*n5~Lp9!B+#y3#f8J^5!iC@3Y@P`;FoUH{G*pj*q7MVV)29+j z>BC`a|1@U_v%%o9VH_HsSnM`jZ-&CDvbiqDg)tQEnV>b%Ptm)T|1?TrpIl)Y$LnG_ zzKi5j2Fx^K^PG1=*?GhK;$(UCF-tM~^=Z*+Wp{FSuy7iHt9#4n(sUuHK??@v+6*|10Csdnyg9hAsC5_OrSL;jVkLlf zHXIPukLqbhs~-*oa^gqgvtpgTk_7GypwH><53riYYL*M=Q@F-yEPLqQ&1Sc zZB%w}T~RO|#jFjMWcKMZccxm-SL)s_ig?OC?y_~gLFj{n8D$J_Kw%{r0oB8?@dWzn zB528d-wUBQzrrSSLq?fR!K%59Zv9J4yCQhhDGwhptpA5O5U?Hjqt>8nOD zi{)0CI|&Gu%zunGI*XFZh(ix)q${jT8wnnzbBMPYVJc4HX*9d^mz|21$=R$J$(y7V zo0dxdbX3N#=F$zjstTf*t8vL)2*{XH!+<2IJ1VVFa67|{?LP&P41h$2i2;?N~RA30LV`BsUcj zfO9#Pg1$t}7zpv#&)8`mis3~o+P(DxOMgz-V*(?wWaxi?R=NhtW}<#^Z?(BhSwyar zG|A#Q7wh4OfK<|DAcl9THc-W4*>J4nTevsD%dkj`U~wSUCh15?_N@uMdF^Kw+{agk zJ`im^wDqj`Ev)W3k3stasP`88-M0ZBs7;B6{-tSm3>I@_e-QfT?7|n0D~0RRqDb^G zyHb=is;IwuQ&ITzL4KsP@Z`b$d%B0Wuhioo1CWttW8yhsER1ZUZzA{F*K=wmi-sb#Ju+j z-l@In^IKnb{bQG}Ps>+Vu_W#grNKNGto+yjA)?>0?~X`4I3T@5G1)RqGUZuP^NJCq&^HykuYtMDD8qq+l8RcZNJsvN(10{ zQ1$XcGt}QH-U^WU!-wRR1d--{B$%vY{JLWIV%P4-KQuxxDeJaF#{eu&&r!3Qu{w}0f--8^H|KwE>)ORrcR+2Qf zb})DRcH>k0zWK8@{RX}NYvTF;E~phK{+F;MkIP$)T$93Ba2R2TvKc>`D??#mv9wg$ zd~|-`Qx5LwwsZ2hb*Rt4S9dsF%Cny5<1fscy~)d;0m2r$f=83<->c~!GNyb!U)PA; zq^!`@@)UaG)Ew(9V?5ZBq#c%dCWZrplmuM`o~TyHjAIMh0*#1{B>K4po-dx$Tk-Cq z=WZDkP5x2W&Os`N8KiYHRH#UY*n|nvd(U>yO=MFI-2BEp?x@=N<~CbLJBf6P)}vLS?xJXYJ2^<3KJUdrwKnJnTp{ zjIi|R=L7rn9b*D#Xxr4*R<3T5AuOS+#U8hNlfo&^9JO{VbH!v9^JbK=TCGR-5EWR@ zN8T-_I|&@A}(hKeL4_*eb!1G8p~&_Im8|wc>Cdir+gg90n1dw?QaXcx6Op_W1r=axRw>4;rM*UOpT#Eb9xU1IiWo@h?|5uP zka>-XW0Ikp@dIe;MN8B01a7+5V@h3WN{J=HJ*pe0uwQ3S&MyWFni47X32Q7SyCTNQ z+sR!_9IZa5!>f&V$`q!%H8ci!a|RMx5}5MA_kr+bhtQy{-^)(hCVa@I!^TV4RBi zAFa!Nsi3y37I5EK;0cqu|9MRj<^r&h1lF}u0KpKQD^5Y+LvFEwM zLU@@v4_Na#Axy6tn3P%sD^5P#<7F;sd$f4a7LBMk zGU^RZHBcxSA%kCx*eH&wgA?Qwazm8>9SCSz_!;MqY-QX<1@p$*T8lc?@`ikEqJ>#w zcG``^CoFMAhdEXT9qt47g0IZkaU)4R7wkGs^Ax}usqJ5HfDYAV$!=6?>J6+Ha1I<5 z|6=9soU4>E))tW$<#>F ziZ$6>KJf0bPfbx_)7-}tMINlc=}|H+$uX)mhC6-Hz+XZxsKd^b?RFB6et}O#+>Wmw9Ec9) z{q}XFWp{3@qmyK*Jvzpyqv57LIR;hPXKsrh{G?&dRjF%Zt5&m20Ll?OyfUYC3WRn{cgQ?^V~UAv+5 z&_m#&nIwffgX1*Z2#5^Kl4DbE#NrD&Hi4|7SPqZ}(>_+JMz=s|k77aEL}<=0Zfb)a z%F(*L3zCA<=xO)2U3B|pcTqDbBoFp>QyAEU(jMu8(jLA61-H!ucI804+B!$E^cQQa z)_ERrW3g!B9iLb3nn3dlkvD7KsY?sRvls3QC0qPi>o<)GHx%4Xb$5a3GBTJ(k@`e@ z$RUa^%S15^1oLEmA=sayrP5;9qtf!Z1*?e$ORVPsXpL{jL<6E)0sj&swP3}NPmR%FM?O>SQgN5XfHE< zo(4#Cv11(%Nnw_{_Ro}r6=gKd{k?NebJ~<~Kv0r(r0qe4n3LFx$5%x(BKvrz$m?LG zjLIc;hbj0FMdb9aH9Lpsof#yG$(0sG2%RL;d(n>;#jb!R_+dad+K;Ccw!|RY?uS(a zj~?=&M!4C(5LnlH6k%aYvz@7?xRa^2gml%vn&eKl$R_lJ+e|xsNfXzr#xuh(>`}9g zLHSyiFwK^-p!;p$yt7$F|3*IfO3Mlu9e>Dpx8O`37?fA`cj`C0B-m9uRhJjs^mRp# zWB;Aj6|G^1V6`jg7#7V9UFvnB4((nIwG?k%c7h`?0tS8J3Bn0t#pb#SA}N-|45$-j z$R>%7cc2ebAClXc(&0UtHX<>pd)akR3Kx_cK+n<}FhzmTx!8e9^u2e4%x{>T6pQ`6 zO182bh$-W5A3^wos0SV_TgPmF4WUP-+D25KjbC{y_6W_9I2_vNKwU(^qSdn&>^=*t z&uvp*@c8#2*paD!ZMCi3;K{Na;I4Q35zw$YrW5U@Kk~)&rw;G?d7Q&c9|x<Hg|CNMsxovmfth*|E*GHezPTWa^Hd^F4!B3sF;)? z(NaPyAhocu1jUe(!5Cy|dh|W2=!@fNmuNOzxi^tE_jAtzNJ0JR-avc_H|ve#KO}#S z#a(8secu|^Tx553d4r@3#6^MHbH)vmiBpn0X^29xEv!Vuh1n(Sr5I0V&`jA2;WS|Y zbf0e}X|)wA-Pf5gBZ>r4YX3Mav1kKY(ulAJ0Q*jB)YhviHK)w!TJsi3^dMa$L@^{` z_De`fF4;M87vM3Ph9SzCoCi$#Fsd38u!^0#*sPful^p5oI(xGU?yeYjn;Hq1!wzFk zG&2w}W3`AX4bxoVm03y>ts{KaDf!}b&7$(P4KAMP=vK5?1In^-YYNtx1f#}+2QK@h zeSeAI@E6Z8a?)>sZ`fbq9_snl6LCu6g>o)rO;ijp3|$vig+4t} zylEo7$SEW<_U+qgVcaVhk+4k+C9THI5V10qV*dOV6pPtAI$)QN{!JRBKh-D zk2^{j@bZ}yqW?<#VVuI_27*cI-V~sJiqQv&m07+10XF+#ZnIJdr8t`9s_EE;T2V;B z4UnQUH9EdX%zwh-5&wflY#ve!IWt0UE-My3?L#^Bh%kcgP1q{&26eXLn zTkjJ*w+(|_>Pq0v8{%nX$QZbf)tbJaLY$03;MO=Ic-uqYUmUCuXD>J>o6BCRF=xa% z3R4SK9#t1!K4I_d>tZgE>&+kZ?Q}1qo4&h%U$GfY058s%*=!kac{0Z+4Hwm!)pFLR zJ+5*OpgWUrm0FPI2ib4NPJ+Sk07j(`diti^i#kh&f}i>P4~|d?RFb#!JN)~D@)beox}bw?4VCf^y*`2{4`-@%SFTry2h z>9VBc9#JxEs1+0i2^LR@B1J`B9Ac=#FW=(?2;5;#U$0E0UNag_!jY$&2diQk_n)bT zl5Me_SUvqUjwCqmVcyb`igygB_4YUB*m$h5oeKv3uIF0sk}~es!{D>4r%PC*F~FN3owq5e0|YeUTSG#Vq%&Gk7uwW z0lDo#_wvflqHeRm*}l?}o;EILszBt|EW*zNPmq#?4A+&i0xx^?9obLyY4xx=Y9&^G;xYXYPxG)DOpPg!i_Ccl#3L}6xAAZzNhPK1XaC_~ z!A|mlo?Be*8Nn=a+FhgpOj@G7yYs(Qk(8&|h@_>w8Y^r&5nCqe0V60rRz?b5%J;GYeBqSAjo|K692GxD4` zRZyM2FdI+-jK2}WAZTZ()w_)V{n5tEb@>+JYluDozCb$fA4H)$bzg(Ux{*hXurjO^ zwAxc+UXu=&JV*E59}h3kzQPG4M)X8E*}#_&}w*KEgtX)cU{vm9b$atHa;s>| z+L6&cn8xUL*OSjx4YGjf6{Eq+Q3{!ZyhrL&^6Vz@jGbI%cAM9GkmFlamTbcQGvOlL zmJ?(FI)c86=JEs|*;?h~o)88>12nXlpMR4@yh%qdwFNpct;vMlc=;{FSo*apJ;p}! zAX~t;3tb~VuP|ZW;z$=IHf->F@Ml)&-&Bnb{iQyE#;GZ@C$PzEf6~q}4D>9jic@mTO5x76ulDz@+XAcm35!VSu zT*Gs>;f0b2TNpjU_BjHZ&S6Sqk6V1370+!eppV2H+FY!q*n=GHQ!9Rn6MjY!Jc77A zG7Y!lFp8?TIHN!LXO?gCnsYM-gQxsm=Ek**VmZu7vnuufD7K~GIxfxbsQ@qv2T zPa`tvHB$fFCyZl>3oYg?_wW)C>^_iDOc^B7klnTOoytQH18WkOk)L2BSD0r%xgRSW zQS9elF^?O=_@|58zKLK;(f77l-Zzu}4{fXed2saq!5k#UZAoDBqYQS{sn@j@Vtp|$ zG%gnZ$U|9@u#w1@11Sjl8ze^Co=)7yS(}=;68a3~g;NDe_X^}yJj;~s8xq9ahQ5_r zxAlTMnep*)w1e(TG%tWsjo3RR;yVGPEO4V{Zp?=a_0R#=V^ioQu4YL=BO4r0$$XTX zZfnw#_$V}sDAIDrezGQ+h?q24St0QNug_?{s-pI(^jg`#JRxM1YBV;a@@JQvH8*>> zIJvku74E0NlXkYe_624>znU0J@L<-c=G#F3k4A_)*;ky!C(^uZfj%WB3-*{*B$?9+ zDm$WFp=0(xnt6`vDQV3Jl5f&R(Mp};;q8d3I%Kn>Kx=^;uSVCw0L=gw53%Bp==8Sw zxtx=cs!^-_+i{2OK`Q;913+AXc_&Z5$@z3<)So0CU3;JAv=H?@Zpi~riQ{z-zLtVL z!oF<}@IgJp)Iyz1zVJ42!SPHSkjYNS4%ulVVIXdRuiZ@5Mx8LJS}J#qD^Zi_xQ@>DKDr-_e#>5h3dtje*NcwH_h;i{Sx7}dkdpuW z(yUCjckQsagv*QGMSi9u1`Z|V^}Wjf7B@q%j2DQXyd0nOyqg%m{CK_lAoKlJ7#8M} z%IvR?Vh$6aDWK2W!=i?*<77q&B8O&3?zP(Cs@kapc)&p7En?J;t-TX9abGT#H?TW? ztO5(lPKRuC7fs}zwcUKbRh=7E8wzTsa#Z{a`WR}?UZ%!HohN}d&xJ=JQhpO1PI#>X zHkb>pW04pU%Bj_mf~U}1F1=wxdBZu1790>3Dm44bQ#F=T4V3&HlOLsGH)+AK$cHk6 zia$=$kog?)07HCL*PI6}DRhpM^*%I*kHM<#1Se+AQ!!xyhcy6j7`iDX7Z-2i73_n# zas*?7LkxS-XSqv;YBa zW_n*32D(HTYQ0$feV_Fru1ZxW0g&iwqixPX3=9t4o)o|kOo79V$?$uh?#8Q8e>4e)V6;_(x&ViUVxma+i25qea;d-oK7ouuDsB^ab{ zu1qjQ%`n56VtxBE#0qAzb7lph`Eb-}TYpXB!H-}3Ykqyp`otprp7{VEuW*^IR2n$Fb99*nAtqT&oOFIf z@w*6>YvOGw@Ja?Pp1=whZqydzx@9X4n^2!n83C5{C?G@|E?&$?p*g68)kNvUTJ)I6 z1Q|(#UuP6pj78GUxq11m-GSszc+)X{C2eo-?8ud9sB=3(D47v?`JAa{V(IF zPZQ_0AY*9M97>Jf<o%#O_%Wq}8>YM=q0|tGY+hlXcpE=Z4Od z`NT7Hu2hnvRoqOw@g1f=bv`+nba{GwA$Ak0INlqI1k<9!x_!sL()h?hEWoWrdU3w` zZ%%)VR+Bc@_v!C#koM1p-3v_^L6)_Ktj4HE>aUh%2XZE@JFMOn)J~c`_7VWNb9c-N z2b|SZMR4Z@E7j&q&9(6H3yjEu6HV7{2!1t0lgizD;mZ9$r(r7W5G$ky@w(T_dFnOD z*p#+z$@pKE+>o@%eT(2-p_C}wbQ5s(%Sn_{$HDN@MB+Ev?t@3dPy`%TZ!z}AThZSu zN<1i$siJhXFdjV zP*y|V<`V8t=h#XTRUR~5`c`Z9^-`*BZf?WAehGdg)E2Je)hqFa!k{V(u+(hTf^Yq& zoruUh2(^3pe)2{bvt4&4Y9CY3js)PUHtd4rVG57}uFJL)D(JfSIo^{P=7liFXG zq5yqgof0V8paQcP!gy+;^pp-DA5pj=gbMN0eW=-eY+N8~y+G>t+x}oa!5r>tW$xhI zPQSv=pi;~653Gvf6~*JcQ%t1xOrH2l3Zy@8AoJ+wz@daW@m7?%LXkr!bw9GY@ns3e zSfuWF_gkWnesv?s3I`@}NgE2xwgs&rj?kH-FEy82=O8`+szN ziHch`vvS`zNfap14!&#i9H@wF7}yIPm=UB%(o(}F{wsZ(wA0nJ2aD^@B41>>o-_U6 zUqD~vdo48S8~FTb^+%#zcbQiiYoDKYcj&$#^;Smmb+Ljp(L=1Kt_J!;0s%1|JK}Wi z;={~oL!foo5n8=}rs6MmUW~R&;SIJO3TL4Ky?kh+b2rT9B1Jl4>#Uh-Bec z`Hsp<==#UEW6pGPhNk8H!!DUQR~#F9jEMI6T*OWfN^Ze&X(4nV$wa8QUJ>oTkruH# zm~O<`J7Wxseo@FqaZMl#Y(mrFW9AHM9Kb|XBMqaZ2a)DvJgYipkDD_VUF_PKd~dT7 z#02}bBfPn9a!X!O#83=lbJSK#E}K&yx-HI#T6ua)6o0{|={*HFusCkHzs|Fn&|C3H zBck1cmfcWVUN&i>X$YU^Sn6k2H;r3zuXbJFz)r5~3$d$tUj(l1?o={MM){kjgqXRO zc5R*#{;V7AQh|G|)jLM@wGAK&rm2~@{Pewv#06pHbKn#wL0P6F1!^qw9g&cW3Z=9} zj)POhOlwsh@eF=>z?#sIs*C-Nl(yU!#DaiaxhEs#iJqQ8w%(?+6lU02MYSeDkr!B- zPjMv+on6OLXgGnAtl(ao>|X2Y8*Hb}GRW5}-IzXnoo-d0!m4Vy$GS!XOLy>3_+UGs z2D|YcQx@M#M|}TDOetGi{9lGo9m-=0-^+nKE^*?$^uHkxZh}I{#UTQd;X!L+W@jm( zDg@N4+lUqI92o_rNk{3P>1gxAL=&O;x)ZT=q1mk0kLlE$WeWuY_$0`0jY-Kkt zP*|m3AF}Ubd=`<>(Xg0har*_@x2YH}bn0Wk*OZz3*e5;Zc;2uBdnl8?&XjupbkOeNZsNh6pvsq_ydmJI+*z**{I{0K)-;p1~k8cpJXL$^t!-`E}=*4G^-E8>H!LjTPxSx zcF+cS`ommfKMhNSbas^@YbTpH1*RFrBuATUR zt{oFWSk^$xU&kbFQ;MCX22RAN5F6eq9UfR$ut`Jw--p2YX)A*J69m^!oYfj2y7NYcH6&r+0~_sH^c^nzeN1AU4Ga7=FlR{S|Mm~MpzY0$Z+p2W(a={b-pR9EO1Rs zB%KY|@wLcAA@)KXi!d2_BxrkhDn`DT1=Dec}V!okd{$+wK z4E{n8R*xKyci1(CnNdhf$Dp2(Jpof0-0%-38X=Dd9PQgT+w%Lshx9+loPS~MOm%ZT zt%2B2iL_KU_ita%N>xjB!#71_3=3c}o zgeW~^U_ZTJQ2!PqXulQd=3b=XOQhwATK$y(9$#1jOQ4}4?~l#&nek)H(04f(Sr=s| zWv7Lu1=%WGk4FSw^;;!8&YPM)pQDCY9DhU`hMty1@sq1=Tj7bFsOOBZOFlpR`W>-J$-(kezWJj;`?x-v>ev{*8V z8p|KXJPV$HyQr1A(9LVrM47u-XpcrIyO`yWvx1pVYc&?154aneRpLqgx)EMvRaa#|9?Wwqs2+W8n5~79G z(}iCiLk;?enn}ew`HzhG+tu+Ru@T+K5juvZN)wY;x6HjvqD!&!)$$;1VAh~7fg0K| zEha#aN=Yv|3^~YFH}cc38ovVb%L|g@9W6fo(JtT6$fa?zf@Ct88e}m?i)b*Jgc{fl zExfdvw-BYDmH6>(4QMt#p0;FUIQqkhD}aH?a7)_%JtA~soqj{ppP_82yi9kaxuK>~ ze_)Zt>1?q=ZH*kF{1iq9sr*tVuy=u>Zev}!gEZx@O6-fjyu9X00gpIl-fS_pzjpqJ z1yqBmf9NF!jaF<+YxgH6oXBdK)sH(>VZ)1siyA$P<#KDt;8NT*l_0{xit~5j1P)FN zI8hhYKhQ)i z37^aP13B~u65?sg+_@2Kr^iWHN=U;EDSZ@2W2!5ALhGNWXnFBY%7W?1 z=HI9JzQ-pLKZDYTv<0-lt|6c-RwhxZ)mU2Os{bsX_i^@*fKUj8*aDO5pks=qn3Dv6 zwggpKLuyRCTVPwmw1r}B#AS}?X7b837UlXwp~E2|PJw2SGVueL7){Y&z!jL!XN=0i zU^Eig`S2`{+gU$68aRdWx?BZ{sU_f=8sn~>s~M?GU~`fH5kCc; z8ICp+INM3(3{#k32RZdv6b9MQYdZXNuk7ed8;G?S2nT+NZBG=Tar^KFl2SvhW$bGW#kdWL-I)s_IqVnCDDM9fm8g;P;8 z7t4yZn3^*NQfx7SwmkzP$=fwdC}bafQSEF@pd&P8@H#`swGy_rz;Z?Ty5mkS%>m#% zp_!m9e<()sfKiY(nF<1zBz&&`ZlJf6QLvLhl`_``%RW&{+O>Xhp;lwSsyRqGf=RWd zpftiR`={2(siiPAS|p}@q=NhVc0ELprt%=fMXO3B)4ryC2LT(o=sLM7hJC!}T1@)E zA3^J$3&1*M6Xq>03FX`R&w*NkrZE?FwU+Muut;>qNhj@bX17ZJxnOlPSZ=Zeiz~T_ zOu#yc3t6ONHB;?|r4w+pI)~KGN;HOGC)txxiUN8#mexj+W(cz%9a4sx|IRG=}ia zuEBuba3AHsV2feqw-3MvuL`I+2|`Ud4~7ZkN=JZ;L20|Oxna5vx1qbIh#k2O4$RQF zo`tL()zxaqibg^GbB+BS5#U{@K;WWQj~GcB1zb}zJkPwH|5hZ9iH2308!>_;%msji zJHSL~s)YHBR=Koa1mLEOHos*`gp=s8KA-C zu0aE+W!#iJ*0xqKm3A`fUGy#O+X+5W36myS>Uh2!R*s$aCU^`K&KKLCCDkejX2p=5 z%o7-fl03x`gaSNyr?3_JLv?2RLS3F*8ub>Jd@^Cc17)v8vYEK4aqo?OS@W9mt%ITJ z9=S2%R8M){CugT@k~~0x`}Vl!svYqX=E)c_oU6o}#Hb^%G1l3BudxA{F*tbjG;W_>=xV73pKY53v%>I)@D36I_@&p$h|Aw zonQS`07z_F#@T-%@-Tb|)7;;anoD_WH>9ewFy(ZcEOM$#Y)8>qi7rCnsH9GO-_7zF zu*C87{Df1P4TEOsnzZ@H%&lvV(3V@;Q!%+OYRp`g05PjY^gL$^$-t0Y>H*CDDs?FZly*oZ&dxvsxaUWF!{em4{A>n@vpXg$dwvt@_rgmHF z-MER`ABa8R-t_H*kv>}CzOpz;!>p^^9ztHMsHL|SRnS<-y5Z*r(_}c4=fXF`l^-i}>e7v!qs_jv zqvWhX^F=2sDNWA9c@P0?lUlr6ecrTKM%pNQ^?*Lq?p-0~?_j50xV%^(+H>sMul#Tw zeciF*1=?a7cI(}352%>LO96pD+?9!fNyl^9v3^v&Y4L)mNGK0FN43&Xf8jUlxW1Bw zyiu2;qW-aGNhs=zbuoxnxiwZ3{PFZM#Kw)9H@(hgX23h(`Wm~m4&TvoZoYp{plb^> z_#?vXcxd>r7K+1HKJvhed>gtK`TAbJUazUWQY6T~t2af%#<+Veyr%7-#*A#@&*;@g58{i|E%6yC_InGXCOd{L0;$)z#?n7M`re zh!kO{6=>7I?*}czyF7_frt#)s1CFJ_XE&VrDA?Dp3XbvF{qsEJgb&OLSNz_5g?HpK z9)8rsr4JN!Af3G9!#Qn(6zaUDqLN(g2g8*M)Djap?WMK9NKlkC)E2|-g|#-rp%!Gz zAHd%`iq|81efi93m3yTBw3g0j#;Yb2X{mhRAI?&KDmbGqou(2xiRNb^sV}%%Wu0?< z?($L>(#BO*)^)rSgyNRni$i`R4v;GhlCZ8$@e^ROX(p=2_v6Y!%^As zu022)fHdv_-~Yu_H6WVPLpHQx!W%^6j)cBhS`O3QBW#x(eX54d&I22op(N59b*&$v zFiSRY6rOc^(dgSV1>a7-5C;(5S5MvKcM2Jm-LD9TGqDpP097%52V+0>Xqq!! zq4e3vj53SE6i8J`XcQB|MZPP8j;PAOnpGnllH6#Ku~vS42xP*Nz@~y%db7Xi8s09P z1)e%8ys6&M8D=Dt6&t`iKG_4X=!kgRQoh%Z`dc&mlOUqXk-k`jKv9@(a^2-Upw>?< zt5*^DV~6Zedbec4NVl($2T{&b)zA@b#dUyd>`2JC0=xa_fIm8{5um zr-!ApXZhC8@=vC2WyxO|!@0Km)h8ep*`^he92$@YwP>VcdoS5OC^s38e#7RPsg4j+ zbVGG}WRSET&ZfrcR(x~k8n1rTP%CnfUNKUonD$P?FtNFF#cn!wEIab-;jU=B1dHK@ z(;(yAQJ`O$sMn>h;pf^8{JISW%d+@v6@CnXh9n5TXGC}?FI9i-D0OMaIg&mAg=0Kn zNJ7oz5*ReJukD55fUsMuaP+H4tDN&V9zfqF@ zr=#ecUk9wu{0;!+gl;3Bw=Vn^)z$ahVhhw)io!na&9}LmWurLb0zubxK=UEnU*{5P z+SP}&*(iBKSO4{alBHaY^)5Q=mZ+2OwIooJ7*Q5XJ+2|q`9#f?6myq!&oz?klihLq z4C)$XP!BNS0G_Z1&TM>?Jk{S~{F3n83ioli=IO6f%wkvCl(RFFw~j0tb{GvXTx>*sB0McY0s&SNvj4+^h`9nJ_wM>F!Uc>X}9PifQekn0sKI2SAJP!a4h z5cyGTuCj3ZBM^&{dRelIlT^9zcfaAuL5Y~bl!ppSf`wZbK$z#6U~rdclk``e+!qhe z6Qspo*%<)eu6?C;Bp<^VuW6JI|Ncvyn+LlSl;Mp22Bl7ARQ0Xc24%29(ZrdsIPw&-=yHQ7_Vle|5h>AST0 zUGX2Zk34vp?U~IHT|;$U86T+UUHl_NE4m|}>E~6q``7hccCaT^#y+?wD##Q%HwPd8 zV3x4L4|qqu`B$4(LXqDJngNy-{&@aFBvVsywt@X^}iH7P%>bR?ciC$I^U-4Foa`YKI^qDyGK7k%E%c_P=yzAi`YnxGA%DeNd++j3*h^ z=rn>oBd0|~lZ<6YvmkKY*ZJlJ;Im0tqgWu&E92eqt;+NYdxx`eS(4Hw_Jb5|yVvBg z*tbdY^!AN;luEyN4VRhS@-_DC{({ziH{&Z}iGElSV~qvT>L-8G%+yEL zX#MFOhj{InyKG=mvW-<1B@c-}x$vA(nU?>S>0*eN#!SLzQ)Ex7fvQ)S4D<8|I#N$3 zT5Ei`Z?cxBODHX8(Xp73v`IsAYC@9b;t}z0wxVuQSY1J^GRwDPN@qbM-ZF48T$GZ< z8WU+;Pqo?{ghI-KZ-i*ydXu`Ep0Xw^McH_KE9J0S7G;x8Fe`DVG?j3Pv=0YzJ}yZR z%2=oqHiUjvuk0~Ca>Kol4CFi0_xQT~;_F?=u+!kIDl-9g`#ZNZ9HCy17Ga1v^Jv9# z{T4Kb1-AzUxq*MutfOWWZgD*HnFfyYg0&e9f(5tZ>krPF6{VikNeHoc{linPPt#Si z&*g>(c54V8rT_AX!J&bNm-!umPvOR}vDai#`CX___J#=zeB*{4<&2WpaDncZsOkp* zsg<%@@rbrMkR_ux9?LsQxzoBa1s%$BBn6vk#{&&zUwcfzeCBJUwFYSF$08qDsB;gWQN*g!p8pxjofWbqNSZOEKOaTx@+* zwdt5*Q47@EOZ~EZL9s?1o?A%9TJT=Ob_13yyugvPg*e&ZU(r6^k4=2+D-@n=Hv5vu zSXG|hM(>h9^zn=eQ=$6`JO&70&2|%V5Lsx>)(%#;pcOfu>*nk_3HB_BNaH$`jM<^S zcSftDU1?nL;jy)+sfonQN}(}gUW?d_ikr*3=^{G)=tjBtEPe>TO|0ddVB zTklrSHiW+!#26frPXQQ(YN8DG$PZo?(po(QUCCf_OJC`pw*uey00%gmH!`WJkrKXj2!#6?`T25mTu9OJp2L8z3! z=arrL$ZqxuE{%yV)14Kd>k}j7pxZ6#$Dz8$@WV5p8kTqN<-7W)Q7Gt2{KoOPK_tZ| zf2WG~O5@{qPI+W<4f_;reuFVdO^5`ADC1!JQE|N`s3cq@(0WB!n0uh@*c{=LAd;~} zyGK@hbF-Oo+!nN)@i*O(`@FA#u?o=~e{`4O#5}z&=UkU*50fOrzi11D^&FOqe>wii z?*k+2|EcUs;Gx{!@KBT~>PAwLrIDT7Th=Utu?~?np@t^gFs?zgX=D${RwOY^WGh-+ z+#4$066ISh8eYW#FXWp~S`<*%O^ZuItL1Tyqt8#tZ zY120E;^VG`!lZn&3sPd$RkdHpU#|w+bYV)pJC|SH9g%|5IkxVTQcBA4CL0}$&}ef@ zW^Vtj%M;;_1xxP9x#ex17&4N*{ksO*_4O}xYu(p*JkL#yr}@7b)t5X?%CY<+s5_MJ zuiqt+N_;A(_)%lumoyRFixWa-M7qK_9s6<1X?JDa9fP!+_6u~~M$5L=ipB=7(j#f< zZ34J%=bs549%~_mA(|={uZNs_0?o7;-LBP(ZRnkd{-^|2|=4vUTmtByHL8 zEph`(LSEzQj68a+`d$V<45J7cyv^#|^|%fD#si1Nx!4NW*`l*{->HEWNh6-|g>-=r zXmQ|-i}Ku$ndUeHQ^&ieT!Lf}vf6GaqW9$DJ2NWrqwPY%%4nip$@vK$nRp*_C-v<| zuKz~ZyN&<%!NS26&x?jhy+@awJipMQ-8(X4#Ae5??U<1QMt1l9R=w9fAnEF}NYu$2 z>6}Vkc zIb*A?G*z8^IvibmBKn_u^5&T_1oey0gZS2~obf(#xk=erZGTEdQnt3DMGM+0oPwss zj5zXD;(oWhB_T@~Ig#9@v)AKtXu3>Inmgf@A|-lD-1U>cNyl3h?ADD9)GG4}zUGPk zZzaXe!~Kf?<~@$G?Uql3t8jy9{2!doq4=J}j9ktTxss{p6!9UdjyDERlA*xZ!=Q)KDs5O)phz>Vq3BNGoM(H|=1*Q4$^2fTZw z(%nq1P|5Rt81}SYJpEEzMPl5VJsV5&4e)ZWKDyoZ>1EwpkHx-AQVQc8%JMz;{H~p{=FXV>jIxvm4X*qv52e?Y-f%DJ zxEA165GikEASQ^fH6K#d!Tpu2HP{sFs%E=e$gYd$aj$+xue6N+Wc(rAz~wUsk2`(b z8Kvmyz%bKQxpP}~baG-rwYcYCvkHOi zlkR<=>ZBTU*8RF_d#Bl@zZsRIhx<%~Z@Z=ik z>adw3!DK(8R|q$vy{FTxw%#xliD~6qXmY^7_9kthVPTF~Xy1CfBqbU~?1QmxmU=+k z(ggxvEuA;0e&+ci-zQR{-f7aO{O(Pz_OsEjLh_K>MbvoZ4nxtk5u{g@nPv)cgW_R} z9}EA4K4@z0?7ue}Z(o~R(X&FjejUI2g~08PH1E4w>9o{)S(?1>Z0XMvTb|;&EuyOE zGvWNpYX)Nv<8|a^;1>bh#&znEcl-r!T#pn= z4$?Yudha6F%4b>*8@=BdtXXY4N+`U4Dmx$}>HeVJk-QdTG@t!tVT#0(LeV0gvqyyw z2sEp^9eY0N`u10Tm4n8No&A=)IeEC|gnmEXoNSzu!1<4R<%-9kY_8~5Ej?zRegMn78wuMs#;i&eUA0Zk_RXQ3b&TT} z;SCI=7-FUB@*&;8|n>(_g^HGf3@QODE3LpmX~ELnymQm{Sx9xrKS zK29p~?v@R$0=v6Dr5aW>-!{+h@?Q58|Kz8{{W`%J+lDAdb&M5VHrX_mDY;1-JLnf)ezmPau$)1;=`-FU=-r-83tX=C`S#}GZufju zQ>sXNT0Ny=k@nc%cFnvA_i4SC)?_ORXHq8B4D%el1uPX`c~uG#S1M7C+*MMqLw78E zhY2dI8@+N^qrMI1+;TUda(vGqGSRyU{Fnm`aqrr7bz42c5xsOO-~oZpkzorD1g}Y<6rk&3>PsSGy}W?MtqFky@A(X# zIuNZK0cK?^=;PUAu>j0#HtjbHCV*6?jzA&OoE$*Jlga*}LF`SF?WLhv1O|zqC<>*> zYB;#lsYKx0&kH@BFpW8n*yDcc6?;_zaJs<-jPSkCsSX-!aV=P5kUgF@Nu<{a%#K*F z134Q{9|YX7X(v$62_cY3^G%t~rD>Q0z@)1|zs)vjJ6Jq9;7#Ki`w+eS**En?7;n&7 zu==V3T&eFboN3ZiMx3D8qYc;VjFUk_H-WWCau(VFXSQf~viH0L$gwD$UfFHqNcgN`x}M+YQ6RnN<+@t>JUp#)9YOkqst-Ga?{FsDpEeX0(5v{0J~SEbWiL zXC2}M4?UH@u&|;%0y`eb33ldo4~z-x8zY!oVmV=c+f$m?RfDC35mdQ2E>Pze7KWP- z>!Bh<&57I+O_^s}9Tg^k)h7{xx@0a0IA~GAOt2yy!X%Q$1rt~LbTB6@Du!_0%HV>N zlf)QI1&gvERKwso23mJ!Ou6ZS#zCS5W`gxE5T>C#E|{i<1D35C222I33?Njaz`On7 zi<+VWFP6D{e-{yiN#M|Jgk<44u1TiMI78S5W`Sdb5f+{zu34s{CfWN7a3Cf^@L%!& zN$?|!!9j2c)j$~+R6n#891w-z8(!oBpL2K=+%a$r2|~8-(vQj5_XT`<0Ksf;oP+tz z9CObS!0m)Tgg`K#xBM8B(|Z)Wb&DYL{WTYv`;A=q6~Nnx2+!lTIXtj8J7dZE!P_{z z#f8w6F}^!?^KE#+ZDv+xd5O&3EmomZzsv?>E-~ygGum45fk!SBN&|eo1rKw^?aZJ4 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/wrapper/gradle-wrapper.properties b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..12d38de6a48 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew new file mode 100755 index 00000000000..4f906e0c811 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew.bat b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/settings.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/settings.gradle new file mode 100644 index 00000000000..233410459f6 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/settings.gradle @@ -0,0 +1,19 @@ +/* + * This settings file was auto generated by the Gradle buildInit task + * by 'arthur' at '28/11/20 22:29' with Gradle 3.0 + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/3.0/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'gradle-sample' diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/main/java/com/example/App.java b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/main/java/com/example/App.java new file mode 100644 index 00000000000..1c13f7d885e --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/main/java/com/example/App.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.example; + +public class App { + public String getGreeting() { + return "Hello world."; + } + + public static void main(String[] args) { + System.out.println(new App().getGreeting()); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/test/java/com/example/AppTest.java b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/test/java/com/example/AppTest.java new file mode 100644 index 00000000000..813bc5e1a2a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/src/test/java/com/example/AppTest.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.example; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class AppTest { + @Test public void testAppHasAGreeting() { + App classUnderTest = new App(); + assertNotNull("app should have a greeting", classUnderTest.getGreeting()); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py new file mode 100644 index 00000000000..9ed756e545d --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py @@ -0,0 +1,14 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +# Ensure we're using an old Java version that won't work with Gradle +if "JAVA_HOME_8_X64" in os.environ: + os.environ["JAVA_HOME"] = os.environ["JAVA_HOME_8_X64"] + sep = ";" if platform.system() == "Windows" else ":" + os.environ["PATH"] = "".join([os.path.join(os.environ["JAVA_HOME"], "bin"), sep, os.environ["PATH"]]) + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected new file mode 100644 index 00000000000..dd7ba09a7f1 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected @@ -0,0 +1,4 @@ +{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} +{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} +{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} +{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/pom.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/pom.xml new file mode 100644 index 00000000000..a1ae8eda7e6 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/pom.xml @@ -0,0 +1,123 @@ + + + + 4.0.0 + + com.example + maven-sample + 1.0-SNAPSHOT + + maven-sample + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + insecure + Insecure HTTP Repository + http://repo.maven.apache.org/maven2/ + default + + + + + + junit-nonesuch + junit-nonesuch + 4.11 + test + + + + + + + exec-maven-plugin + org.codehaus.mojo + 1.1.1 + + + check-maven-version + package + + java + + + + + com.example.App + + + + com.diffplug.spotless + spotless-maven-plugin + 2.19.1 + + + + check + + compile + + + + + + /* FAIL ME */ + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/java/com/example/App.java b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/java/com/example/App.java new file mode 100644 index 00000000000..c9eec918587 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/java/com/example/App.java @@ -0,0 +1,30 @@ +package com.example; + +import java.util.regex.Pattern; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + String expectedVersion = System.getenv("EXPECT_MAVEN"); + Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize(); + String observedVersion = mavenHome.getFileName().toString(); + if (expectedVersion != null && !expectedVersion.equals(observedVersion)) { + System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome); + System.exit(1); + } + String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX"); + String command = System.getProperty("sun.java.command"); + if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) { + System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'"); + System.exit(1); + } + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/my-app.properties b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/my-app.properties new file mode 100644 index 00000000000..e566b49a29a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/my-app.properties @@ -0,0 +1 @@ +version=1.0 diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/page.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/page.xml new file mode 100644 index 00000000000..2bab459cb03 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/page.xml @@ -0,0 +1,8 @@ + + +A sample + + +

    Hello world!

    + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/struts.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/struts.xml new file mode 100644 index 00000000000..73fc0c6b9cb --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/main/resources/struts.xml @@ -0,0 +1,4 @@ + + +This is a sample file + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/test/java/com/example/AppTest.java b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/test/java/com/example/AppTest.java new file mode 100644 index 00000000000..22a94ca6f01 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/src/test/java/com/example/AppTest.java @@ -0,0 +1,20 @@ +package com.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py new file mode 100644 index 00000000000..d258d1c47d3 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py @@ -0,0 +1,8 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected new file mode 100644 index 00000000000..59f036ad289 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected @@ -0,0 +1,2 @@ +{"markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [TODO](manually supply a build command)", "severity": "warning", "source": {"extractorName": "java", "id": "java/autobuilder/multiple-candidate-build-directories", "name": "Multiple candidate Maven build directories"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} +{"markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [TODO](supply a manual a build command)", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/multiple-candidate-build-directories-fatal", "name": "No build system could identify a unique top-level project"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/pom.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/pom.xml new file mode 100644 index 00000000000..ec4aaf128c1 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/pom.xml @@ -0,0 +1,114 @@ + + + + 4.0.0 + + com.example + maven-sample + 1.0-SNAPSHOT + + maven-sample + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + + + + exec-maven-plugin + org.codehaus.mojo + 1.1.1 + + + check-maven-version + package + + java + + + + + com.example.App + + + + com.diffplug.spotless + spotless-maven-plugin + 2.19.1 + + + + check + + compile + + + + + + /* FAIL ME */ + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/java/com/example/App.java b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/java/com/example/App.java new file mode 100644 index 00000000000..c9eec918587 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/java/com/example/App.java @@ -0,0 +1,30 @@ +package com.example; + +import java.util.regex.Pattern; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + String expectedVersion = System.getenv("EXPECT_MAVEN"); + Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize(); + String observedVersion = mavenHome.getFileName().toString(); + if (expectedVersion != null && !expectedVersion.equals(observedVersion)) { + System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome); + System.exit(1); + } + String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX"); + String command = System.getProperty("sun.java.command"); + if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) { + System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'"); + System.exit(1); + } + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/my-app.properties b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/my-app.properties new file mode 100644 index 00000000000..e566b49a29a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/my-app.properties @@ -0,0 +1 @@ +version=1.0 diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/page.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/page.xml new file mode 100644 index 00000000000..2bab459cb03 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/page.xml @@ -0,0 +1,8 @@ + + +A sample + + +

    Hello world!

    + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/struts.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/struts.xml new file mode 100644 index 00000000000..73fc0c6b9cb --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/main/resources/struts.xml @@ -0,0 +1,4 @@ + + +This is a sample file + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/test/java/com/example/AppTest.java b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/test/java/com/example/AppTest.java new file mode 100644 index 00000000000..22a94ca6f01 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-1/src/test/java/com/example/AppTest.java @@ -0,0 +1,20 @@ +package com.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/pom.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/pom.xml new file mode 100644 index 00000000000..ec4aaf128c1 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/pom.xml @@ -0,0 +1,114 @@ + + + + 4.0.0 + + com.example + maven-sample + 1.0-SNAPSHOT + + maven-sample + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + + + + exec-maven-plugin + org.codehaus.mojo + 1.1.1 + + + check-maven-version + package + + java + + + + + com.example.App + + + + com.diffplug.spotless + spotless-maven-plugin + 2.19.1 + + + + check + + compile + + + + + + /* FAIL ME */ + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/java/com/example/App.java b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/java/com/example/App.java new file mode 100644 index 00000000000..c9eec918587 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/java/com/example/App.java @@ -0,0 +1,30 @@ +package com.example; + +import java.util.regex.Pattern; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Hello world! + * + */ +public class App +{ + public static void main( String[] args ) + { + System.out.println( "Hello World!" ); + String expectedVersion = System.getenv("EXPECT_MAVEN"); + Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize(); + String observedVersion = mavenHome.getFileName().toString(); + if (expectedVersion != null && !expectedVersion.equals(observedVersion)) { + System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome); + System.exit(1); + } + String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX"); + String command = System.getProperty("sun.java.command"); + if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) { + System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'"); + System.exit(1); + } + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/my-app.properties b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/my-app.properties new file mode 100644 index 00000000000..e566b49a29a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/my-app.properties @@ -0,0 +1 @@ +version=1.0 diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/page.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/page.xml new file mode 100644 index 00000000000..2bab459cb03 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/page.xml @@ -0,0 +1,8 @@ + + +A sample + + +

    Hello world!

    + + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/struts.xml b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/struts.xml new file mode 100644 index 00000000000..73fc0c6b9cb --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/main/resources/struts.xml @@ -0,0 +1,4 @@ + + +This is a sample file + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/test/java/com/example/AppTest.java b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/test/java/com/example/AppTest.java new file mode 100644 index 00000000000..22a94ca6f01 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/maven-project-2/src/test/java/com/example/AppTest.java @@ -0,0 +1,20 @@ +package com.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py new file mode 100644 index 00000000000..d258d1c47d3 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py @@ -0,0 +1,8 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/build.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/build.gradle new file mode 100644 index 00000000000..8591a5fdd8d --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/build.gradle @@ -0,0 +1,3 @@ +task clean { + println 'Clean task executed' +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected new file mode 100644 index 00000000000..c2bab48f038 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected @@ -0,0 +1,2 @@ +{"markdownMessage": "Autobuilding found a Gradle project without the Gradle wrapper present. Trying to use the most recent version, which may not be appropriate. Consider adding the Gradle wrapper to the repository", "severity": "warning", "source": {"extractorName": "java", "id": "java/autobuilder/guessed-gradle-version", "name": "Required Gradle version not specified"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} +{"markdownMessage": "We tried to build a Gradle project that does not define a `testClasses` goal. Consider supplying a manual build command instead. Suspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/test-classes-gradle-target", "name": "Gradle target 'testClasses' not found"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/settings.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/settings.gradle new file mode 100644 index 00000000000..a6635527945 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/settings.gradle @@ -0,0 +1 @@ +// Empty project, which doesn't have a testClasses goal. diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py new file mode 100644 index 00000000000..d258d1c47d3 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py @@ -0,0 +1,8 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitattributes b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitattributes new file mode 100644 index 00000000000..00a51aff5e5 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitignore b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitignore new file mode 100644 index 00000000000..1b6985c0094 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/build.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/build.gradle new file mode 100644 index 00000000000..071a12b7691 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/build.gradle @@ -0,0 +1,30 @@ +/* + * This build file was auto generated by running the Gradle 'init' task + * by 'arthur' at '28/11/20 22:29' with Gradle 3.0 + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * user guide available at https://docs.gradle.org/3.0/userguide/tutorial_java_projects.html + */ + +// Apply the java plugin to add support for Java +apply plugin: 'java' + +// In this section you declare where to find the dependencies of your project +repositories { + // Use 'jcenter' for resolving your dependencies. + // You can declare any Maven/Ivy/file repository here. + jcenter() +} + +// In this section you declare the dependencies for your production and test code +dependencies { + // The production code uses the SLF4J logging API at compile time + compile 'org.slf4j:slf4j-api:1.7.21' + + // Declare the dependency for your favourite test framework you want to use in your tests. + // TestNG is also supported by the Gradle Test task. Just change the + // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add + // 'test.useTestNG()' to your build script. + testCompile 'junit:junit:4.12' +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected new file mode 100644 index 00000000000..227bd3040a6 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected @@ -0,0 +1 @@ +{"markdownMessage": "Autobuilding found a Gradle project without the Gradle wrapper present. Trying to use the most recent version, which may not be appropriate. Consider adding the Gradle wrapper to the repository", "severity": "warning", "source": {"extractorName": "java", "id": "java/autobuilder/guessed-gradle-version", "name": "Required Gradle version not specified"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/force_sequential_test_execution b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/force_sequential_test_execution new file mode 100644 index 00000000000..b0e2500b259 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/force_sequential_test_execution @@ -0,0 +1,3 @@ +# We currently have a bug where gradle tests become flaky when executed in parallel +# - sometimes, gradle fails to connect to the gradle daemon. +# Therefore, force this test to run sequentially. diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/settings.gradle b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/settings.gradle new file mode 100644 index 00000000000..233410459f6 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/settings.gradle @@ -0,0 +1,19 @@ +/* + * This settings file was auto generated by the Gradle buildInit task + * by 'arthur' at '28/11/20 22:29' with Gradle 3.0 + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/3.0/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'gradle-sample' diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/main/java/com/example/App.java b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/main/java/com/example/App.java new file mode 100644 index 00000000000..1c13f7d885e --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/main/java/com/example/App.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.example; + +public class App { + public String getGreeting() { + return "Hello world."; + } + + public static void main(String[] args) { + System.out.println(new App().getGreeting()); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/test/java/com/example/AppTest.java b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/test/java/com/example/AppTest.java new file mode 100644 index 00000000000..813bc5e1a2a --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/src/test/java/com/example/AppTest.java @@ -0,0 +1,14 @@ +/* + * This Java source file was generated by the Gradle 'init' task. + */ +package com.example; + +import org.junit.Test; +import static org.junit.Assert.*; + +public class AppTest { + @Test public void testAppHasAGreeting() { + App classUnderTest = new App(); + assertNotNull("app should have a greeting", classUnderTest.getGreeting()); + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py new file mode 100644 index 00000000000..d258d1c47d3 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py @@ -0,0 +1,8 @@ +import os +from create_database_utils import * +from diagnostics_test_utils import * + +os.mkdir("diagnostics") +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) + +check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") From 53ac1e0133c688adc54f26d900a5232a764b5dfe Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 7 Feb 2023 10:44:22 +0000 Subject: [PATCH 371/415] Replace test absolute directory --- .../android-gradle-incompatibility/diagnostics.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected index cb521711a69..6d56972acd6 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected @@ -1,2 +1,2 @@ -{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /Users/chris/semmle-code-repo/target/codeql-integration-tests/ql/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} -{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /Users/chris/semmle-code-repo/target/codeql-integration-tests/ql/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file +{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} +{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file From 2c216793a491f48ffba3c1a48c393a1a49445751 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 7 Feb 2023 16:37:35 +0000 Subject: [PATCH 372/415] Diagnostics tests: don't create own diagnostics directory The CLI does this now. Also omit default arguments to the integration test script. --- .../java/diagnostics/android-gradle-incompatibility/test.py | 5 ++--- .../all-platforms/java/diagnostics/compilation-error/test.py | 5 ++--- .../all-platforms/java/diagnostics/dependency-error/test.py | 5 ++--- .../java/diagnostics/java-version-too-old/test.py | 5 ++--- .../java/diagnostics/maven-http-repository/test.py | 5 ++--- .../java/diagnostics/multiple-candidate-builds/test.py | 5 ++--- .../all-platforms/java/diagnostics/no-build-system/test.py | 5 ++--- .../java/diagnostics/no-gradle-test-classes/test.py | 5 ++--- .../all-platforms/java/diagnostics/no-gradle-wrapper/test.py | 5 ++--- 9 files changed, 18 insertions(+), 27 deletions(-) diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py index d258d1c47d3..23fe1d32fd8 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/test.py @@ -2,7 +2,6 @@ import os from create_database_utils import * from diagnostics_test_utils import * -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py index d258d1c47d3..23fe1d32fd8 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/test.py @@ -2,7 +2,6 @@ import os from create_database_utils import * from diagnostics_test_utils import * -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py index 72207414a25..ee07cd14bdf 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/test.py @@ -11,7 +11,6 @@ try: except FileNotFoundError: pass -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py index 9ed756e545d..9def03947b3 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/test.py @@ -8,7 +8,6 @@ if "JAVA_HOME_8_X64" in os.environ: sep = ";" if platform.system() == "Windows" else ":" os.environ["PATH"] = "".join([os.path.join(os.environ["JAVA_HOME"], "bin"), sep, os.environ["PATH"]]) -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py index d258d1c47d3..23fe1d32fd8 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/test.py @@ -2,7 +2,6 @@ import os from create_database_utils import * from diagnostics_test_utils import * -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py index d258d1c47d3..23fe1d32fd8 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/test.py @@ -2,7 +2,6 @@ import os from create_database_utils import * from diagnostics_test_utils import * -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py index d258d1c47d3..23fe1d32fd8 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/test.py @@ -2,7 +2,6 @@ import os from create_database_utils import * from diagnostics_test_utils import * -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py index d258d1c47d3..23fe1d32fd8 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/test.py @@ -2,7 +2,6 @@ import os from create_database_utils import * from diagnostics_test_utils import * -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py index d258d1c47d3..23fe1d32fd8 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/test.py @@ -2,7 +2,6 @@ import os from create_database_utils import * from diagnostics_test_utils import * -os.mkdir("diagnostics") -run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None, extra_env = {"CODEQL_EXTRACTOR_JAVA_DIAGNOSTIC_DIR": "diagnostics"}) +run_codeql_database_create([], lang="java", runFunction = runUnsuccessfully, db = None) -check_diagnostics(test_dir = ".", diagnostics_dir = "diagnostics") +check_diagnostics() From 73e4480cc6cae8675502eeb259433a479340b8d0 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 16 Feb 2023 11:03:03 +0000 Subject: [PATCH 373/415] Update test expectations --- .../diagnostics.expected | 30 +++++++++- .../compilation-error/diagnostics.expected | 45 +++++++++++++- .../dependency-error/diagnostics.expected | 15 ++++- .../java-version-too-old/diagnostics.expected | 30 +++++++++- .../diagnostics.expected | 60 +++++++++++++++++-- .../diagnostics.expected | 30 +++++++++- .../no-build-system/diagnostics.expected | 15 ++++- .../diagnostics.expected | 30 +++++++++- .../no-gradle-wrapper/diagnostics.expected | 15 ++++- 9 files changed, 252 insertions(+), 18 deletions(-) diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected index 6d56972acd6..f95aa9fe9aa 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected @@ -1,2 +1,28 @@ -{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} -{"markdownMessage": "It looks like an Android build may have failed. Ensure the Code Scanning workflow installs any dependencies such as the NDK or React Native, and that the Gradle and Android SDK versions being used are compatible. Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/android-build-failure", "name": "Android build failure"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [https://developer.android.com/studio/releases/gradle-plugin#updating-gradle](Gradle and Android SDK versions are compatible). Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/android-build-failure", + "name": "Android build failure" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} +{ + "markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [https://developer.android.com/studio/releases/gradle-plugin#updating-gradle](Gradle and Android SDK versions are compatible). Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/android-build-failure", + "name": "Android build failure" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected index 00190b0c630..81b15627115 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/compilation-error/diagnostics.expected @@ -1,3 +1,42 @@ -{"markdownMessage": "A compilation error was observed while autobuilding your code. Please check that the needed compiler version and other tools are installed in your Code Scanning workflow. Suspicious output line: `[ERROR] COMPILATION ERROR : `", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/compilation-error", "name": "Some of your code may have failed to compile"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} -{"markdownMessage": "A compilation error was observed while autobuilding your code. Please check that the needed compiler version and other tools are installed in your Code Scanning workflow. Suspicious output line: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/compilation-error", "name": "Some of your code may have failed to compile"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} -{"markdownMessage": "A compilation error was observed while autobuilding your code. Please check that the needed compiler version and other tools are installed in your Code Scanning workflow. Suspicious output line: `org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/compilation-error", "name": "Some of your code may have failed to compile"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `[ERROR] COMPILATION ERROR : `", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/compilation-error", + "name": "Some of your code may have failed to compile" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} +{ + "markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/compilation-error", + "name": "Some of your code may have failed to compile" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} +{ + "markdownMessage": "A compilation error was observed while autobuilding your code. Check that your Code Scanning workflow installs the needed compiler version and dependencies. Suspicious output line: `org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project maven-sample: Compilation failure`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/compilation-error", + "name": "Some of your code may have failed to compile" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected index aae65c93abc..29a15f21d72 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected @@ -1 +1,14 @@ -{"markdownMessage": "In the course of building your code, it looks like a dependency failed to download. Check that all dependencies are available, including supplying credentials to access any private dependencies. Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/dependency-download-failure", "name": "Failed to download a dependency"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows](supply credentials for any private dependencies). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/dependency-download-failure", + "name": "Failed to download a dependency" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected index 817b56bc942..6f11e4f0a90 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected @@ -1,2 +1,28 @@ -{"markdownMessage": "Your project may need a different JDK version. Consider adding an `actions/setup-java` step to the Code Scanning workflow file. Suspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/wrong-jdk-version", "name": "Your project may need a different JDK version"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} -{"markdownMessage": "Your project may need a different JDK version. Consider adding an `actions/setup-java` step to the Code Scanning workflow file. Suspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/wrong-jdk-version", "name": "Your project may need a different JDK version"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [https://github.com/actions/setup-java#eclipse-temurin](an appropriate `setup-java` step). Suspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/wrong-jdk-version", + "name": "Your project may need a different JDK version" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} +{ + "markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [https://github.com/actions/setup-java#eclipse-temurin](an appropriate `setup-java` step). Suspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/wrong-jdk-version", + "name": "Your project may need a different JDK version" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected index dd7ba09a7f1..383b9253fb4 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected @@ -1,4 +1,56 @@ -{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} -{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} -{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": false, "statusPage": false, "telemetry": true}} -{"markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Edit your code scanning workflow to override the default block on insecure repositories, or update your code to use HTTPS to access dependencies. Suspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/non-https-repository", "name": "A non-https Maven repository access failed"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/non-https-repository", + "name": "A non-https Maven repository access failed" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} +{ + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/non-https-repository", + "name": "A non-https Maven repository access failed" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} +{ + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/non-https-repository", + "name": "A non-https Maven repository access failed" + }, + "visibility": { + "cliSummaryTable": false, + "statusPage": false, + "telemetry": true + } +} +{ + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/non-https-repository", + "name": "A non-https Maven repository access failed" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected index 59f036ad289..e1c40aaca8d 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected @@ -1,2 +1,28 @@ -{"markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [TODO](manually supply a build command)", "severity": "warning", "source": {"extractorName": "java", "id": "java/autobuilder/multiple-candidate-build-directories", "name": "Multiple candidate Maven build directories"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} -{"markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [TODO](supply a manual a build command)", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/multiple-candidate-build-directories-fatal", "name": "No build system could identify a unique top-level project"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [TODO](manually supply a build command)", + "severity": "warning", + "source": { + "extractorName": "java", + "id": "java/autobuilder/multiple-candidate-build-directories", + "name": "Multiple candidate Maven build directories" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} +{ + "markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language](supply a manual a build command)", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/multiple-candidate-build-directories-fatal", + "name": "No build system could identify a unique top-level project" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected index 647c7b64458..81ac8b32a14 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected @@ -1 +1,14 @@ -{"markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [TODO](supply a manual build command)", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/no-build-command", "name": "No build command found"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language](supply a manual build command)", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/no-build-command", + "name": "No build command found" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected index c2bab48f038..ed6825a92a4 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected @@ -1,2 +1,28 @@ -{"markdownMessage": "Autobuilding found a Gradle project without the Gradle wrapper present. Trying to use the most recent version, which may not be appropriate. Consider adding the Gradle wrapper to the repository", "severity": "warning", "source": {"extractorName": "java", "id": "java/autobuilder/guessed-gradle-version", "name": "Required Gradle version not specified"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} -{"markdownMessage": "We tried to build a Gradle project that does not define a `testClasses` goal. Consider supplying a manual build command instead. Suspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`", "severity": "error", "source": {"extractorName": "java", "id": "java/autobuilder/test-classes-gradle-target", "name": "Gradle target 'testClasses' not found"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "Built a Gradle project without the [https://docs.gradle.org/current/userguide/gradle_wrapper.html](Gradle wrapper). This may use an incompatible version of Gradle", + "severity": "warning", + "source": { + "extractorName": "java", + "id": "java/autobuilder/guessed-gradle-version", + "name": "Required Gradle version not specified" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} +{ + "markdownMessage": "Gradle project does not define a `testClasses` goal. [https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language](Supply a manual build command) that builds the code that should be analyzed. Suspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/autobuilder/test-classes-gradle-target", + "name": "Gradle target 'testClasses' not found" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected index 227bd3040a6..fea988d84f3 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected @@ -1 +1,14 @@ -{"markdownMessage": "Autobuilding found a Gradle project without the Gradle wrapper present. Trying to use the most recent version, which may not be appropriate. Consider adding the Gradle wrapper to the repository", "severity": "warning", "source": {"extractorName": "java", "id": "java/autobuilder/guessed-gradle-version", "name": "Required Gradle version not specified"}, "visibility": {"cliSummaryTable": true, "statusPage": true, "telemetry": true}} \ No newline at end of file +{ + "markdownMessage": "Built a Gradle project without the [https://docs.gradle.org/current/userguide/gradle_wrapper.html](Gradle wrapper). This may use an incompatible version of Gradle", + "severity": "warning", + "source": { + "extractorName": "java", + "id": "java/autobuilder/guessed-gradle-version", + "name": "Required Gradle version not specified" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} From c4640a6a9af9203b36f46e699498ed563230f4ae Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 22 Feb 2023 14:56:07 +0000 Subject: [PATCH 374/415] Fix diagnostic markdown links --- .../android-gradle-incompatibility/diagnostics.expected | 4 ++-- .../diagnostics/dependency-error/diagnostics.expected | 2 +- .../diagnostics/java-version-too-old/diagnostics.expected | 4 ++-- .../maven-http-repository/diagnostics.expected | 8 ++++---- .../multiple-candidate-builds/diagnostics.expected | 2 +- .../java/diagnostics/no-build-system/diagnostics.expected | 2 +- .../no-gradle-test-classes/diagnostics.expected | 4 ++-- .../diagnostics/no-gradle-wrapper/diagnostics.expected | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected index f95aa9fe9aa..29e2215412e 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/android-gradle-incompatibility/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [https://developer.android.com/studio/releases/gradle-plugin#updating-gradle](Gradle and Android SDK versions are compatible). Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", + "markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle). Suspicious output line: ` > Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": { "extractorName": "java", @@ -13,7 +13,7 @@ } } { - "markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [https://developer.android.com/studio/releases/gradle-plugin#updating-gradle](Gradle and Android SDK versions are compatible). Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", + "markdownMessage": "An Android build may have failed. Ensure the Code Scanning workflow installs required dependencies, and that the [Gradle and Android SDK versions are compatible](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle). Suspicious output line: `Caused by: java.lang.RuntimeException: Minimum supported Gradle version is 7.4. Current version is 7.3. If using the gradle wrapper, try editing the distributionUrl in /gradle/wrapper/gradle-wrapper.properties to gradle-7.4-all.zip`", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected index 29a15f21d72..21fa19216be 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/dependency-error/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows](supply credentials for any private dependencies). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`", + "markdownMessage": "A dependency failed to download. Check that all dependencies are available, and [supply credentials for any private dependencies](https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#set-up-secrets-in-github-action-workflows). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact junit:junit-nonesuch:jar:4.11 in central (https://repo.maven.apache.org/maven2)`", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected index 6f11e4f0a90..a48a1e1dd07 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/java-version-too-old/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [https://github.com/actions/setup-java#eclipse-temurin](an appropriate `setup-java` step). Suspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", + "markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin). Suspicious output line: `> Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", "severity": "error", "source": { "extractorName": "java", @@ -13,7 +13,7 @@ } } { - "markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [https://github.com/actions/setup-java#eclipse-temurin](an appropriate `setup-java` step). Suspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", + "markdownMessage": "Your project may need a different JDK version. Ensure your Code Scanning workflow file has [an appropriate `setup-java` step](https://github.com/actions/setup-java#eclipse-temurin). Suspicious output line: `Caused by: java.lang.IllegalArgumentException: Could not target platform: 'Java SE 11' using tool chain: 'JDK 8 (1.8)'.`", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected index 383b9253fb4..56c315303c1 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/maven-http-repository/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": { "extractorName": "java", @@ -13,7 +13,7 @@ } } { - "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.transfer.ArtifactTransferException: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": { "extractorName": "java", @@ -27,7 +27,7 @@ } } { - "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `Caused by: org.eclipse.aether.transfer.NoRepositoryConnectorException: Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)]`", "severity": "error", "source": { "extractorName": "java", @@ -41,7 +41,7 @@ } } { - "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked](update your build to use HTTPS). Suspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`", + "markdownMessage": "Building your code triggered an access to an insecure HTTP Maven repository. Allow access to insecure repositories, or [update your build to use HTTPS](https://maven.apache.org/docs/3.8.1/release-notes.html#how-to-fix-when-i-get-a-http-repository-blocked). Suspicious output line: `[ERROR] Failed to execute goal on project maven-sample: Could not resolve dependencies for project com.example:maven-sample:jar:1.0-SNAPSHOT: Failed to collect dependencies at junit-nonesuch:junit-nonesuch:jar:4.11: Failed to read artifact descriptor for junit-nonesuch:junit-nonesuch:jar:4.11: Could not transfer artifact junit-nonesuch:junit-nonesuch:pom:4.11 from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories: [insecure (http://repo.maven.apache.org/maven2/, default, releases+snapshots)] -> [Help 1]`", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected index e1c40aaca8d..75512cbaa23 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected @@ -13,7 +13,7 @@ } } { - "markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language](supply a manual a build command)", + "markdownMessage": "If you want to use one of the candidate build systems and directories (see previous warnings), please [supply a manual a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected index 81ac8b32a14..e7a8e2ed10d 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-build-system/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language](supply a manual build command)", + "markdownMessage": "Could not find a Gradle, Maven or Ant top-level project to build. Please [supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected index ed6825a92a4..c5d896da5be 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-test-classes/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "Built a Gradle project without the [https://docs.gradle.org/current/userguide/gradle_wrapper.html](Gradle wrapper). This may use an incompatible version of Gradle", + "markdownMessage": "Built a Gradle project without the [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html). This may use an incompatible version of Gradle", "severity": "warning", "source": { "extractorName": "java", @@ -13,7 +13,7 @@ } } { - "markdownMessage": "Gradle project does not define a `testClasses` goal. [https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language](Supply a manual build command) that builds the code that should be analyzed. Suspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`", + "markdownMessage": "Gradle project does not define a `testClasses` goal. [Supply a manual build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language) that builds the code that should be analyzed. Suspicious output line: `org.gradle.execution.TaskSelectionException: Task 'testClasses' not found in root project 'no-gradle-test-classes'.`", "severity": "error", "source": { "extractorName": "java", diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected index fea988d84f3..ad5c5bdb7c6 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/no-gradle-wrapper/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "Built a Gradle project without the [https://docs.gradle.org/current/userguide/gradle_wrapper.html](Gradle wrapper). This may use an incompatible version of Gradle", + "markdownMessage": "Built a Gradle project without the [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html). This may use an incompatible version of Gradle", "severity": "warning", "source": { "extractorName": "java", From 560a341e873e9d75de12e7d1d40f0b9380c9e914 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 22 Feb 2023 17:42:21 +0000 Subject: [PATCH 375/415] Fix multiple-candidate-builds message --- .../diagnostics/multiple-candidate-builds/diagnostics.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected index 75512cbaa23..07c5d942baa 100644 --- a/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected +++ b/java/ql/integration-tests/all-platforms/java/diagnostics/multiple-candidate-builds/diagnostics.expected @@ -1,5 +1,5 @@ { - "markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [TODO](manually supply a build command)", + "markdownMessage": "Building using Maven was skipped because there were multiple sibling build directories containing build files: [./maven-project-1,./maven-project-2]. If you want to use one of these, please [manually supply a build command](https://docs.github.com/en/github-ae@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language)", "severity": "warning", "source": { "extractorName": "java", From 6a32a3ae585a9296bf7cbc4691dbb4b50128e9cd Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 22 Feb 2023 22:47:51 +0000 Subject: [PATCH 376/415] QL: Add predicates for timestamps and locations --- ql/ql/src/codeql_ql/StructuredLogs.qll | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 0e6674d8fbd..67716c60b1d 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -1,6 +1,35 @@ private import ql private import codeql_ql.ast.internal.TreeSitter +/** Gets a timestamp corresponding to the number of seconds since the date Semmle was founded. */ +bindingset[d, h, m, s, ms] +private float getTimestamp(date d, int h, int m, int s, int ms) { + result = (("2006-12-28".toDate().daysTo(d) * 24 + h) * 60 + m) * 60 + s + ms / 1000.0 +} + +bindingset[str] +private float stringToTimestamp(string str) { + exists(string r, date d, int h, int m, int s, int ms | + r = "(\\d{4}-\\d{2}-\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{3})Z" + | + d = str.regexpCapture(r, 1).toDate() and + h = str.regexpCapture(r, 2).toInt() and + m = str.regexpCapture(r, 3).toInt() and + s = str.regexpCapture(r, 4).toInt() and + ms = str.regexpCapture(r, 5).toInt() and + result = getTimestamp(d, h, m, s, ms) + ) +} + +bindingset[s] +private Predicate getPredicateFromPosition(string s) { + exists(string r, string filepath, int startline | r = "(.*):(\\d+),(\\d+)-(\\d+),(\\d+)" | + filepath = s.regexpCapture(r, 1) and + startline = s.regexpCapture(r, 2).toInt() and + result.hasLocationInfo(filepath, startline, _, _, _) + ) +} + class Object extends JSON::Object { JSON::Value getValue(string key) { exists(JSON::Pair p | p = this.getChild(_) | @@ -24,6 +53,8 @@ class Object extends JSON::Object { int getEventId() { result = this.getNumber("event_id") } string getTime() { result = this.getString("time") } + + float getTimestamp() { result = stringToTimestamp(this.getTime()) } } class Array extends JSON::Array { @@ -227,6 +258,8 @@ module KindPredicatesLog { ) } + float getCompletionTime() { result = stringToTimestamp(this.getCompletionTimeString()) } + float getResultSize() { result = this.getFloat("resultSize") } } @@ -278,6 +311,10 @@ module KindPredicatesLog { Depencencies getDependencies() { result = this.getObject("dependencies") } PipeLineRun getPipelineRun() { result.getArray() = this.getArray("pipelineRuns") } + + string getPosition() { result = this.getString("position") } + + Predicate getPredicate() { result = getPredicateFromPosition(this.getPosition()) } } class ComputeRecursive extends SummaryEvent { From bd5ae88a9a47bb799e983def9bdafe4a4688ab1c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 23 Feb 2023 10:00:40 +0100 Subject: [PATCH 377/415] Ruby: Move `FileSystem.qll` implementation into shared `util` pack --- ruby/ql/lib/codeql/files/FileSystem.qll | 174 ++----------------- shared/util/codeql/util/FileSystem.qll | 212 ++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 157 deletions(-) create mode 100644 shared/util/codeql/util/FileSystem.qll diff --git a/ruby/ql/lib/codeql/files/FileSystem.qll b/ruby/ql/lib/codeql/files/FileSystem.qll index 552b85a4673..f6a5f959287 100644 --- a/ruby/ql/lib/codeql/files/FileSystem.qll +++ b/ruby/ql/lib/codeql/files/FileSystem.qll @@ -1,177 +1,37 @@ /** Provides classes for working with files and folders. */ private import codeql.Locations +private import codeql.util.FileSystem -/** A file or folder. */ -abstract class Container extends @container { - /** Gets a file or sub-folder in this container. */ - Container getAChildContainer() { this = result.getParentContainer() } +private module Input implements InputSig { + abstract class ContainerBase extends @container { + abstract string getAbsolutePath(); - /** Gets a file in this container. */ - File getAFile() { result = this.getAChildContainer() } + ContainerBase getParentContainer() { containerparent(result, this) } - /** Gets a sub-folder in this container. */ - Folder getAFolder() { result = this.getAChildContainer() } - - /** - * Gets the absolute, canonical path of this container, using forward slashes - * as path separator. - * - * The path starts with a _root prefix_ followed by zero or more _path - * segments_ separated by forward slashes. - * - * The root prefix is of one of the following forms: - * - * 1. A single forward slash `/` (Unix-style) - * 2. An upper-case drive letter followed by a colon and a forward slash, - * such as `C:/` (Windows-style) - * 3. Two forward slashes, a computer name, and then another forward slash, - * such as `//FileServer/` (UNC-style) - * - * Path segments are never empty (that is, absolute paths never contain two - * contiguous slashes, except as part of a UNC-style root prefix). Also, path - * segments never contain forward slashes, and no path segment is of the - * form `.` (one dot) or `..` (two dots). - * - * Note that an absolute path never ends with a forward slash, except if it is - * a bare root prefix, that is, the path has no path segments. A container - * whose absolute path has no segments is always a `Folder`, not a `File`. - */ - abstract string getAbsolutePath(); - - /** - * Gets the base name of this container including extension, that is, the last - * segment of its absolute path, or the empty string if it has no segments. - * - * Here are some examples of absolute paths and the corresponding base names - * (surrounded with quotes to avoid ambiguity): - * - *
    - * - * - * - * - * - * - * - *
    Absolute pathBase name
    "/tmp/tst.go""tst.go"
    "C:/Program Files (x86)""Program Files (x86)"
    "/"""
    "C:/"""
    "D:/"""
    "//FileServer/"""
    - */ - string getBaseName() { - result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + string toString() { result = this.getAbsolutePath() } } - /** - * Gets the extension of this container, that is, the suffix of its base name - * after the last dot character, if any. - * - * In particular, - * - * - if the name does not include a dot, there is no extension, so this - * predicate has no result; - * - if the name ends in a dot, the extension is the empty string; - * - if the name contains multiple dots, the extension follows the last dot. - * - * Here are some examples of absolute paths and the corresponding extensions - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - *
    Absolute pathExtension
    "/tmp/tst.go""go"
    "/tmp/.classpath""classpath"
    "/bin/bash"not defined
    "/tmp/tst2."""
    "/tmp/x.tar.gz""gz"
    - */ - string getExtension() { - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) + class FolderBase extends ContainerBase, @folder { + override string getAbsolutePath() { folders(this, result) } } - /** Gets the file in this container that has the given `baseName`, if any. */ - File getFile(string baseName) { - result = this.getAFile() and - result.getBaseName() = baseName + class FileBase extends ContainerBase, @file { + override string getAbsolutePath() { files(this, result) } } - /** Gets the sub-folder in this container that has the given `baseName`, if any. */ - Folder getFolder(string baseName) { - result = this.getAFolder() and - result.getBaseName() = baseName - } - - /** Gets the parent container of this file or folder, if any. */ - Container getParentContainer() { containerparent(result, this) } - - /** - * Gets the relative path of this file or folder from the root folder of the - * analyzed source location. The relative path of the root folder itself is - * the empty string. - * - * This has no result if the container is outside the source root, that is, - * if the root folder is not a reflexive, transitive parent of this container. - */ - string getRelativePath() { - exists(string absPath, string pref | - absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) - | - absPath = pref and result = "" - or - absPath = pref.regexpReplaceAll("/$", "") + "/" + result and - not result.matches("/%") - ) - } - - /** - * Gets the stem of this container, that is, the prefix of its base name up to - * (but not including) the last dot character if there is one, or the entire - * base name if there is not. - * - * Here are some examples of absolute paths and the corresponding stems - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - *
    Absolute pathStem
    "/tmp/tst.go""tst"
    "/tmp/.classpath"""
    "/bin/bash""bash"
    "/tmp/tst2.""tst2"
    "/tmp/x.tar.gz""x.tar"
    - */ - string getStem() { - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) - } - - /** - * Gets a URL representing the location of this container. - * - * For more information see https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls. - */ - abstract string getURL(); - - /** - * Gets a textual representation of the path of this container. - * - * This is the absolute path of the container. - */ - string toString() { result = this.getAbsolutePath() } + predicate hasSourceLocationPrefix = sourceLocationPrefix/1; } +private module Impl = Make; + +class Container = Impl::Container; + /** A folder. */ -class Folder extends Container, @folder { - override string getAbsolutePath() { folders(this, result) } - - /** Gets the URL of this folder. */ - override string getURL() { result = "folder://" + this.getAbsolutePath() } -} +class Folder extends Container, Impl::Folder { } /** A file. */ -class File extends Container, @file { - override string getAbsolutePath() { files(this, result) } - - /** Gets the URL of this file. */ - override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } - +class File extends Container, Impl::File { /** Holds if this file was extracted from ordinary source code. */ predicate fromSource() { any() } } diff --git a/shared/util/codeql/util/FileSystem.qll b/shared/util/codeql/util/FileSystem.qll new file mode 100644 index 00000000000..f685cf9c3e3 --- /dev/null +++ b/shared/util/codeql/util/FileSystem.qll @@ -0,0 +1,212 @@ +/** Provides classes for working with files and folders. */ + +/** Provides the input specification of the files and folders implementation. */ +signature module InputSig { + /** + * A base class for files and folders. + * + * Typically `@container`. + */ + class ContainerBase { + /** + * Gets the absolute path of this container. + * + * Typically `containerparent(result, this)`. + */ + string getAbsolutePath(); + + /** Gets the parent container of this container, if any. */ + ContainerBase getParentContainer(); + } + + /** + * A base class for files. + * + * Typically `@file`. + */ + class FileBase extends ContainerBase; + + /** + * A base class for folders. + * + * Typically `@folder`. + */ + class FolderBase extends ContainerBase; + + /** + * Holds if `s` is the source location prefix. + * + * Typically `sourceLocationPrefix(s)`. + */ + predicate hasSourceLocationPrefix(string s); +} + +/** Provides a class hierarchy for working with files and folders. */ +module Make { + /** A file or folder. */ + class Container instanceof Input::ContainerBase { + /** Gets a file or sub-folder in this container. */ + Container getAChildContainer() { this = result.getParentContainer() } + + /** Gets a file in this container. */ + File getAFile() { result = this.getAChildContainer() } + + /** Gets a sub-folder in this container. */ + Folder getAFolder() { result = this.getAChildContainer() } + + /** + * Gets the absolute, canonical path of this container, using forward slashes + * as path separator. + * + * The path starts with a _root prefix_ followed by zero or more _path + * segments_ separated by forward slashes. + * + * The root prefix is of one of the following forms: + * + * 1. A single forward slash `/` (Unix-style) + * 2. An upper-case drive letter followed by a colon and a forward slash, + * such as `C:/` (Windows-style) + * 3. Two forward slashes, a computer name, and then another forward slash, + * such as `//FileServer/` (UNC-style) + * + * Path segments are never empty (that is, absolute paths never contain two + * contiguous slashes, except as part of a UNC-style root prefix). Also, path + * segments never contain forward slashes, and no path segment is of the + * form `.` (one dot) or `..` (two dots). + * + * Note that an absolute path never ends with a forward slash, except if it is + * a bare root prefix, that is, the path has no path segments. A container + * whose absolute path has no segments is always a `Folder`, not a `File`. + */ + string getAbsolutePath() { result = super.getAbsolutePath() } + + /** + * Gets the base name of this container including extension, that is, the last + * segment of its absolute path, or the empty string if it has no segments. + * + * Here are some examples of absolute paths and the corresponding base names + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + * + *
    Absolute pathBase name
    "/tmp/tst.txt""tst.txt"
    "C:/Program Files (x86)""Program Files (x86)"
    "/"""
    "C:/"""
    "D:/"""
    "//FileServer/"""
    + */ + string getBaseName() { + result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + } + + /** + * Gets the extension of this container, that is, the suffix of its base name + * after the last dot character, if any. + * + * In particular, + * + * - if the name does not include a dot, there is no extension, so this + * predicate has no result; + * - if the name ends in a dot, the extension is the empty string; + * - if the name contains multiple dots, the extension follows the last dot. + * + * Here are some examples of absolute paths and the corresponding extensions + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + *
    Absolute pathExtension
    "/tmp/tst.txt""txt"
    "/tmp/.classpath""classpath"
    "/bin/bash"not defined
    "/tmp/tst2."""
    "/tmp/x.tar.gz""gz"
    + */ + string getExtension() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) + } + + /** Gets the file in this container that has the given `baseName`, if any. */ + File getFile(string baseName) { + result = this.getAFile() and + result.getBaseName() = baseName + } + + /** Gets the sub-folder in this container that has the given `baseName`, if any. */ + Folder getFolder(string baseName) { + result = this.getAFolder() and + result.getBaseName() = baseName + } + + /** Gets the parent container of this file or folder, if any. */ + Container getParentContainer() { result = super.getParentContainer() } + + /** + * Gets the relative path of this file or folder from the root folder of the + * analyzed source location. The relative path of the root folder itself is + * the empty string. + * + * This has no result if the container is outside the source root, that is, + * if the root folder is not a reflexive, transitive parent of this container. + */ + string getRelativePath() { + exists(string absPath, string pref | + absPath = this.getAbsolutePath() and Input::hasSourceLocationPrefix(pref) + | + absPath = pref and result = "" + or + absPath = pref.regexpReplaceAll("/$", "") + "/" + result and + not result.matches("/%") + ) + } + + /** + * Gets the stem of this container, that is, the prefix of its base name up to + * (but not including) the last dot character if there is one, or the entire + * base name if there is not. + * + * Here are some examples of absolute paths and the corresponding stems + * (surrounded with quotes to avoid ambiguity): + * + * + * + * + * + * + * + * + *
    Absolute pathStem
    "/tmp/tst.txt""tst"
    "/tmp/.classpath"""
    "/bin/bash""bash"
    "/tmp/tst2.""tst2"
    "/tmp/x.tar.gz""x.tar"
    + */ + string getStem() { + result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) + } + + /** + * Gets a URL representing the location of this container. + * + * For more information see https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls. + */ + string getURL() { none() } + + /** + * Gets a textual representation of the path of this container. + * + * This is the absolute path of the container. + */ + string toString() { result = this.getAbsolutePath() } + } + + /** A folder. */ + class Folder extends Container instanceof Input::FolderBase { + /** Gets the URL of this folder. */ + override string getURL() { result = "folder://" + this.getAbsolutePath() } + } + + /** A file. */ + class File extends Container instanceof Input::FileBase { + /** Gets the URL of this file. */ + override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } + } +} From ad37523b07995c55b0dd715e56bdfc5566d65d57 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 23 Feb 2023 10:07:13 +0100 Subject: [PATCH 378/415] C#: Adopt shared file system implementation --- csharp/ql/lib/qlpack.yml | 1 + csharp/ql/lib/semmle/code/csharp/File.qll | 186 ++-------------------- 2 files changed, 18 insertions(+), 169 deletions(-) diff --git a/csharp/ql/lib/qlpack.yml b/csharp/ql/lib/qlpack.yml index 3e0b633019a..3f118d8115f 100644 --- a/csharp/ql/lib/qlpack.yml +++ b/csharp/ql/lib/qlpack.yml @@ -8,6 +8,7 @@ upgrades: upgrades dependencies: codeql/ssa: ${workspace} codeql/tutorial: ${workspace} + codeql/util: ${workspace} dataExtensions: - ext/*.model.yml - ext/generated/*.model.yml diff --git a/csharp/ql/lib/semmle/code/csharp/File.qll b/csharp/ql/lib/semmle/code/csharp/File.qll index e4e0d3c6c26..79406aec2f6 100644 --- a/csharp/ql/lib/semmle/code/csharp/File.qll +++ b/csharp/ql/lib/semmle/code/csharp/File.qll @@ -3,184 +3,34 @@ */ private import Comments +private import codeql.util.FileSystem -/** A file or folder. */ -class Container extends @container { - /** - * Gets the absolute, canonical path of this container, using forward slashes - * as path separator. - * - * The path starts with a _root prefix_ followed by zero or more _path - * segments_ separated by forward slashes. - * - * The root prefix is of one of the following forms: - * - * 1. A single forward slash `/` (Unix-style) - * 2. An upper-case drive letter followed by a colon and a forward slash, - * such as `C:/` (Windows-style) - * 3. Two forward slashes, a computer name, and then another forward slash, - * such as `//FileServer/` (UNC-style) - * - * Path segments are never empty (that is, absolute paths never contain two - * contiguous slashes, except as part of a UNC-style root prefix). Also, path - * segments never contain forward slashes, and no path segment is of the - * form `.` (one dot) or `..` (two dots). - * - * Note that an absolute path never ends with a forward slash, except if it is - * a bare root prefix, that is, the path has no path segments. A container - * whose absolute path has no segments is always a `Folder`, not a `File`. - */ - string getAbsolutePath() { none() } +private module Input implements InputSig { + abstract class ContainerBase extends @container { + abstract string getAbsolutePath(); - /** - * Gets a URL representing the location of this container. - * - * For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls). - */ - string getURL() { none() } + ContainerBase getParentContainer() { containerparent(result, this) } - /** - * Gets the relative path of this file or folder from the root folder of the - * analyzed source location. The relative path of the root folder itself is - * the empty string. - * - * This has no result if the container is outside the source root, that is, - * if the root folder is not a reflexive, transitive parent of this container. - */ - string getRelativePath() { - exists(string absPath, string pref | - absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) - | - absPath = pref and result = "" - or - absPath = pref.regexpReplaceAll("/$", "") + "/" + result and - not result.matches("/%") - ) + string toString() { result = this.getAbsolutePath() } } - /** - * Gets the base name of this container including extension, that is, the last - * segment of its absolute path, or the empty string if it has no segments. - * - * Here are some examples of absolute paths and the corresponding base names - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - * - *
    Absolute pathBase name
    "/tmp/tst.cs""tst.cs"
    "C:/Program Files (x86)""Program Files (x86)"
    "/"""
    "C:/"""
    "D:/"""
    "//FileServer/"""
    - */ - string getBaseName() { - result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) + class FolderBase extends ContainerBase, @folder { + override string getAbsolutePath() { folders(this, result) } } - /** - * Gets the extension of this container, that is, the suffix of its base name - * after the last dot character, if any. - * - * In particular, - * - * - if the name does not include a dot, there is no extension, so this - * predicate has no result; - * - if the name ends in a dot, the extension is the empty string; - * - if the name contains multiple dots, the extension follows the last dot. - * - * Here are some examples of absolute paths and the corresponding extensions - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - *
    Absolute pathExtension
    "/tmp/tst.cs""cs"
    "/tmp/.classpath""classpath"
    "/bin/bash"not defined
    "/tmp/tst2."""
    "/tmp/x.tar.gz""gz"
    - */ - string getExtension() { - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) + class FileBase extends ContainerBase, @file { + override string getAbsolutePath() { files(this, result) } } - /** - * Gets the stem of this container, that is, the prefix of its base name up to - * (but not including) the last dot character if there is one, or the entire - * base name if there is not. - * - * Here are some examples of absolute paths and the corresponding stems - * (surrounded with quotes to avoid ambiguity): - * - * - * - * - * - * - * - * - *
    Absolute pathStem
    "/tmp/tst.cs""tst"
    "/tmp/.classpath"""
    "/bin/bash""bash"
    "/tmp/tst2.""tst2"
    "/tmp/x.tar.gz""x.tar"
    - */ - string getStem() { - result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) - } - - /** Gets the parent container of this file or folder, if any. */ - Container getParentContainer() { containerparent(result, this) } - - /** Gets a file or sub-folder in this container. */ - Container getAChildContainer() { this = result.getParentContainer() } - - /** Gets a file in this container. */ - File getAFile() { result = this.getAChildContainer() } - - /** Gets the file in this container that has the given `baseName`, if any. */ - File getFile(string baseName) { - result = this.getAFile() and - result.getBaseName() = baseName - } - - /** Gets a sub-folder in this container. */ - Folder getAFolder() { result = this.getAChildContainer() } - - /** Gets the sub-folder in this container that has the given `baseName`, if any. */ - Folder getFolder(string baseName) { - result = this.getAFolder() and - result.getBaseName() = baseName - } - - /** Gets the file or sub-folder in this container that has the given `name`, if any. */ - Container getChildContainer(string name) { - result = this.getAChildContainer() and - result.getBaseName() = name - } - - /** Gets the file in this container that has the given `stem` and `extension`, if any. */ - File getFile(string stem, string extension) { - result = this.getAChildContainer() and - result.getStem() = stem and - result.getExtension() = extension - } - - /** Gets a sub-folder contained in this container. */ - Folder getASubFolder() { result = this.getAChildContainer() } - - /** - * Gets a textual representation of the path of this container. - * - * This is the absolute path of the container. - */ - string toString() { result = this.getAbsolutePath() } + predicate hasSourceLocationPrefix = sourceLocationPrefix/1; } +private module Impl = Make; + +class Container = Impl::Container; + /** A folder. */ -class Folder extends Container, @folder { - override string getAbsolutePath() { folders(this, result) } - - override string getURL() { result = "folder://" + this.getAbsolutePath() } -} +class Folder extends Container, Impl::Folder { } bindingset[flag] private predicate fileHasExtractionFlag(File f, int flag) { @@ -191,9 +41,7 @@ private predicate fileHasExtractionFlag(File f, int flag) { } /** A file. */ -class File extends Container, @file { - override string getAbsolutePath() { files(this, result) } - +class File extends Container, Impl::File { /** Gets the number of lines in this file. */ int getNumberOfLines() { numlines(this, result, _, _) } From 58563744d6a49b00b49168350a9abb9892dd4110 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 09:50:09 +0000 Subject: [PATCH 379/415] A simple query --- ql/ql/src/codeql_ql/StructuredLogs.qll | 8 ++++++++ ql/ql/src/experimental/queries/SlowPredicates.ql | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 ql/ql/src/experimental/queries/SlowPredicates.ql diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 0e6674d8fbd..ab440e4f230 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -210,6 +210,8 @@ module KindPredicatesLog { AppearsAs getAppearsAs() { result = this.getObject("appearsAs") } + int getMillis() { result = this.getNumber("millis") } + predicate hasCompletionTime( int year, string month, int day, int hours, int minute, int second, int millisecond ) { @@ -228,6 +230,12 @@ module KindPredicatesLog { } float getResultSize() { result = this.getFloat("resultSize") } + + override string toString() { + if exists(this.getPredicateName()) + then result = getPredicateName() + else result = "" + } } class SentinelEmpty extends SummaryEvent { diff --git a/ql/ql/src/experimental/queries/SlowPredicates.ql b/ql/ql/src/experimental/queries/SlowPredicates.ql new file mode 100644 index 00000000000..f92b521c983 --- /dev/null +++ b/ql/ql/src/experimental/queries/SlowPredicates.ql @@ -0,0 +1,15 @@ +/** + * Shows a list of the "slow" predicates by wallclock time. + */ + +import ql +import codeql_ql.StructuredLogs + +int predicateRank(KindPredicatesLog::SummaryEvent evt) { + evt = + rank[result](KindPredicatesLog::ComputeSimple y, int m | m = y.getMillis() | y order by m desc) +} + +from KindPredicatesLog::SummaryEvent evt +where predicateRank(evt) < 50 +select evt, evt.getMillis() as time order by time desc From eb553266aed0ee83709c8d1df7559bdf8086e742 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 09:51:29 +0000 Subject: [PATCH 380/415] Add this. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index ab440e4f230..5608387550e 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -233,7 +233,7 @@ module KindPredicatesLog { override string toString() { if exists(this.getPredicateName()) - then result = getPredicateName() + then result = this.getPredicateName() else result = "" } } From 564d7c0d531a2b2e63e78c1e6cccc3e24e494656 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 10:22:18 +0000 Subject: [PATCH 381/415] Fix bug --- ql/ql/src/experimental/queries/SlowPredicates.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/ql/src/experimental/queries/SlowPredicates.ql b/ql/ql/src/experimental/queries/SlowPredicates.ql index f92b521c983..e716e94852f 100644 --- a/ql/ql/src/experimental/queries/SlowPredicates.ql +++ b/ql/ql/src/experimental/queries/SlowPredicates.ql @@ -7,7 +7,7 @@ import codeql_ql.StructuredLogs int predicateRank(KindPredicatesLog::SummaryEvent evt) { evt = - rank[result](KindPredicatesLog::ComputeSimple y, int m | m = y.getMillis() | y order by m desc) + rank[result](KindPredicatesLog::SummaryEvent y, int m | m = y.getMillis() | y order by m desc) } from KindPredicatesLog::SummaryEvent evt From 6cf575df78f035617d283adc0242aebb8f9a359e Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 12:19:25 +0000 Subject: [PATCH 382/415] Query and tests for sum without domain --- ql/ql/src/codeql_ql/ast/Ast.qll | 2 +- ql/ql/src/queries/bugs/SumWithoutDomain.ql | 16 ++++++++++++++++ .../bugs/SumWithoutDomain/SumWithoutDomain.qlref | 1 + .../test/queries/bugs/SumWithoutDomain/Test.qll | 7 +++++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 ql/ql/src/queries/bugs/SumWithoutDomain.ql create mode 100644 ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref create mode 100644 ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll diff --git a/ql/ql/src/codeql_ql/ast/Ast.qll b/ql/ql/src/codeql_ql/ast/Ast.qll index 6b3cf3a8d7b..4264cdf24db 100644 --- a/ql/ql/src/codeql_ql/ast/Ast.qll +++ b/ql/ql/src/codeql_ql/ast/Ast.qll @@ -1808,7 +1808,7 @@ class FullAggregate extends TFullAggregate, Aggregate { /** * Gets the kind of aggregate. - * E.g. for `min(int i | foo(i))` the result is "foo". + * E.g. for `min(int i | foo(i))` the result is "min". */ override string getKind() { result = kind } diff --git a/ql/ql/src/queries/bugs/SumWithoutDomain.ql b/ql/ql/src/queries/bugs/SumWithoutDomain.ql new file mode 100644 index 00000000000..150f075504e --- /dev/null +++ b/ql/ql/src/queries/bugs/SumWithoutDomain.ql @@ -0,0 +1,16 @@ +/** + * @name Sum is missing a domain + * @description An aggregate like 'sum' should work over a domain, otherwise duplicate values will not be counted. + * @kind problem + * @problem.severity error + * @id ql/sum-missing-domain + * @tags correctness + * @precision medium + */ + +import ql + +from ExprAggregate agg +where agg.getKind() = ["sum", "strictsum"] +select agg, + "This " + agg.getKind() + " does not have a domain argument, so may produce surprising results." diff --git a/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref b/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref new file mode 100644 index 00000000000..dc782dfbd0a --- /dev/null +++ b/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.qlref @@ -0,0 +1 @@ +queries/bugs/SumWithoutDomain.ql \ No newline at end of file diff --git a/ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll b/ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll new file mode 100644 index 00000000000..8190aed8101 --- /dev/null +++ b/ql/ql/test/queries/bugs/SumWithoutDomain/Test.qll @@ -0,0 +1,7 @@ +// Result is 3 and not 4 +int foo() { + result = sum([1, 1, 2]) // <- Alert here +} + +// Ok - false negative +predicate bar() { sum(int x | x = [1, 1, 2] | x) = 3 } From fccf2d705efce1ea7b7c48d0e0bd2e96a0e342a6 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 12:25:29 +0000 Subject: [PATCH 383/415] Add the expected file --- .../test/queries/bugs/SumWithoutDomain/SumWithoutDomain.expected | 1 + 1 file changed, 1 insertion(+) create mode 100644 ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.expected diff --git a/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.expected b/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.expected new file mode 100644 index 00000000000..d34316073ed --- /dev/null +++ b/ql/ql/test/queries/bugs/SumWithoutDomain/SumWithoutDomain.expected @@ -0,0 +1 @@ +| Test.qll:3:12:3:25 | ExprAggregate[sum] | This sum does not have a domain argument, so may produce surprising results. | From d7d9bea5e8f1bd67109dfa2859d42d73057d006f Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 14:27:39 +0000 Subject: [PATCH 384/415] QL: Add a query for computing the join order metric for non-recursive predicates. --- .../src/queries/performance/LargeJoinOrder.ql | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 ql/ql/src/queries/performance/LargeJoinOrder.ql diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql new file mode 100644 index 00000000000..3d51affd20f --- /dev/null +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -0,0 +1,29 @@ +/** + * Shows a list of the non-recursive predicates with the worst join order as determined + * by the join order metric. + */ + +import ql +import codeql_ql.StructuredLogs +import KindPredicatesLog + +/** + * Gets the badness of a non-recursive predicate evaluation. + * + * The badness is the maximum number of tuples in the pipeline divided by the + * maximum of two numbers: the size of the result and the size of the largest dependency. + */ +float getBadness(ComputeSimple simple) { + exists(float maxTupleCount, float resultSize, float largestDependency, float denom | + resultSize = simple.getResultSize() and + maxTupleCount = max(simple.getPipelineRun().getCount(_)) and + largestDependency = max(simple.getDependencies().getADependency().getResultSize()) and + denom = resultSize.maximum(largestDependency) and + denom > 0 and // avoid division by zero (which would create a NaN result). + result = maxTupleCount / denom + ) +} + +from ComputeSimple evt, float f +where f = getBadness(evt) and f > 1.5 +select evt, f order by f desc From eb8a0c1129aea40bde5df3e1c9d1dbb01db870dc Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 22 Feb 2023 14:28:42 +0000 Subject: [PATCH 385/415] Add test for a too-new Kotlin version --- .../diagnostics.expected | 14 +++++++++++++ .../com/intellij/mock/MockProject.java | 3 +++ .../com/intellij/openapi/Disposable.java | 3 +++ .../fake-kotlinc-source/driver/Main.java | 20 +++++++++++++++++++ .../kotlin/KotlinVersion.java | 7 +++++++ .../jetbrains/kotlin/cli/common/ExitCode.java | 3 +++ .../common/arguments/CommonToolArguments.java | 3 +++ .../arguments/K2JVMCompilerArguments.java | 3 +++ .../ParseCommandLineArgumentsKt.java | 7 +++++++ .../kotlin/cli/jvm/K2JVMCompiler.java | 9 +++++++++ .../kotlin/config/CompilerConfiguration.java | 3 +++ .../jetbrains/kotlin/utils/KotlinPaths.java | 3 +++ .../kotlin-version-too-new/test.py | 11 ++++++++++ 13 files changed, 89 insertions(+) create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/diagnostics.expected create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/mock/MockProject.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/openapi/Disposable.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/driver/Main.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/kotlin/KotlinVersion.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/ExitCode.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/ParseCommandLineArgumentsKt.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/config/CompilerConfiguration.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/utils/KotlinPaths.java create mode 100644 java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/test.py diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/diagnostics.expected b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/diagnostics.expected new file mode 100644 index 00000000000..3494b6a6f7d --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/diagnostics.expected @@ -0,0 +1,14 @@ +{ + "markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 1.8.30", + "severity": "error", + "source": { + "extractorName": "java", + "id": "java/extractor-agent/kotlin-version-too-new", + "name": "Android build failure" + }, + "visibility": { + "cliSummaryTable": true, + "statusPage": true, + "telemetry": true + } +} diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/mock/MockProject.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/mock/MockProject.java new file mode 100644 index 00000000000..75eaf862803 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/mock/MockProject.java @@ -0,0 +1,3 @@ +package com.intellij.mock; + +public class MockProject { } diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/openapi/Disposable.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/openapi/Disposable.java new file mode 100644 index 00000000000..c4c7538d732 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/com/intellij/openapi/Disposable.java @@ -0,0 +1,3 @@ +package com.intellij.openapi; + +public class Disposable { } diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/driver/Main.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/driver/Main.java new file mode 100644 index 00000000000..8a2c7b74ed7 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/driver/Main.java @@ -0,0 +1,20 @@ +package driver; + +import java.util.ArrayList; +import java.util.List; +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments; +import org.jetbrains.kotlin.cli.common.arguments.ParseCommandLineArgumentsKt; +import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler; + +public class Main { + + public static void main(String[] args) { + + List compilerArgs = new ArrayList(); + K2JVMCompilerArguments parsedArgs = new K2JVMCompilerArguments(); + (new ParseCommandLineArgumentsKt()).parseCommandLineArguments(compilerArgs, parsedArgs); + (new K2JVMCompiler()).doExecute(parsedArgs, null, null, null); + + } + +} diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/kotlin/KotlinVersion.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/kotlin/KotlinVersion.java new file mode 100644 index 00000000000..e4bd4ecb7e1 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/kotlin/KotlinVersion.java @@ -0,0 +1,7 @@ +package kotlin; + +public class KotlinVersion { + + public static String CURRENT = "999.999.999"; + +} diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/ExitCode.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/ExitCode.java new file mode 100644 index 00000000000..017c62b8d12 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/ExitCode.java @@ -0,0 +1,3 @@ +package org.jetbrains.kotlin.cli.common; + +public class ExitCode { } diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.java new file mode 100644 index 00000000000..fda9bc15320 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/CommonToolArguments.java @@ -0,0 +1,3 @@ +package org.jetbrains.kotlin.cli.common.arguments; + +class CommonToolArguments { } diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java new file mode 100644 index 00000000000..68a08768490 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java @@ -0,0 +1,3 @@ +package org.jetbrains.kotlin.cli.common.arguments; + +public class K2JVMCompilerArguments extends CommonToolArguments { } diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/ParseCommandLineArgumentsKt.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/ParseCommandLineArgumentsKt.java new file mode 100644 index 00000000000..3aa2a64dcee --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/common/arguments/ParseCommandLineArgumentsKt.java @@ -0,0 +1,7 @@ +package org.jetbrains.kotlin.cli.common.arguments; + +public class ParseCommandLineArgumentsKt { + + public void parseCommandLineArguments(java.util.List p0, org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments p1) { } + +} diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java new file mode 100644 index 00000000000..4ac8813e1d6 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.java @@ -0,0 +1,9 @@ +package org.jetbrains.kotlin.cli.jvm; + +public class K2JVMCompiler { + + public org.jetbrains.kotlin.cli.common.ExitCode doExecute(org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments p0, org.jetbrains.kotlin.config.CompilerConfiguration p1, com.intellij.openapi.Disposable p2, org.jetbrains.kotlin.utils.KotlinPaths p3) { + return null; + } + +} diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/config/CompilerConfiguration.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/config/CompilerConfiguration.java new file mode 100644 index 00000000000..36bbae2044d --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/config/CompilerConfiguration.java @@ -0,0 +1,3 @@ +package org.jetbrains.kotlin.config; + +public class CompilerConfiguration { } diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/utils/KotlinPaths.java b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/utils/KotlinPaths.java new file mode 100644 index 00000000000..82babe67d77 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/fake-kotlinc-source/org/jetbrains/kotlin/utils/KotlinPaths.java @@ -0,0 +1,3 @@ +package org.jetbrains.kotlin.utils; + +public class KotlinPaths { } diff --git a/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/test.py b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/test.py new file mode 100644 index 00000000000..484ea6c0486 --- /dev/null +++ b/java/ql/integration-tests/all-platforms/kotlin/diagnostics/kotlin-version-too-new/test.py @@ -0,0 +1,11 @@ +from create_database_utils import * +from diagnostics_test_utils import * + +import glob +import os.path + +os.mkdir('fake-kotlinc-classes') +runSuccessfully(["javac"] + [os.path.relpath(x, "fake-kotlinc-source") for x in glob.glob("fake-kotlinc-source/**/*.java", recursive = True)] + ["-d", "../fake-kotlinc-classes"], cwd = "fake-kotlinc-source") +run_codeql_database_create(["java -cp fake-kotlinc-classes driver.Main"], lang = "java", runFunction = runUnsuccessfully, db = None) + +check_diagnostics() From 38ca4a8d3d025e7f6797533a1b50e208743c8741 Mon Sep 17 00:00:00 2001 From: Taus Date: Thu, 23 Feb 2023 15:25:38 +0000 Subject: [PATCH 386/415] QL: Remove unused predicates --- ql/ql/src/codeql_ql/StructuredLogs.qll | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 67716c60b1d..e763e5bbc85 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -333,15 +333,3 @@ module KindPredicatesLog { Extensional() { evaluationStrategy = "EXTENSIONAL" } } } - -// Stuff to test whether we've covered all event types -private File logFile() { result = any(EvaluatorLog::LogHeader h).getLocation().getFile() } - -private Object missing() { - result = - any(Object o | - o.getLocation().getFile() = logFile() and - not o instanceof EvaluatorLog::Entry and - not exists(o.getParent().getParent()) // don't count nested objects - ) -} From 7595c1c306704e3bf07ef226bfb04bc2d494cc03 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 12:59:58 +0000 Subject: [PATCH 387/415] QL: Add a visitor for traversing recursive evaluations. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 154 ++++++++++++++++++ .../src/codeql_ql/ast/internal/TreeSitter.qll | 6 + 2 files changed, 160 insertions(+) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index e763e5bbc85..1637b07c301 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -261,6 +261,10 @@ module KindPredicatesLog { float getCompletionTime() { result = stringToTimestamp(this.getCompletionTimeString()) } float getResultSize() { result = this.getFloat("resultSize") } + + Array getRA(string ordering) { result = this.getObject("ra").getArray(ordering) } + + string getAnOrdering() { exists(this.getRA(result)) } } class SentinelEmpty extends SummaryEvent { @@ -317,12 +321,162 @@ module KindPredicatesLog { Predicate getPredicate() { result = getPredicateFromPosition(this.getPosition()) } } + /** Gets the `index`'th event that's evaluated by `recursive`. */ + private InLayer layerEventRank(ComputeRecursive recursive, int index) { + result = + rank[index + 1](InLayer cand, int startline, string filepath | + cand.getComputeRecursiveEvent() = recursive and + cand.hasLocationInfo(filepath, startline, _, _, _) + | + cand order by filepath, startline + ) + } + + /** + * Gets the first predicate that's evaluated in an iteration + * of the SCC computation rooted at `recursive`. + */ + private InLayer firstPredicate(ComputeRecursive recursive) { + result = layerEventRank(recursive, 0) + } + + /** + * Gets the last predicate that's evaluated in an iteration + * of the SCC computation rooted at `recursive`. + */ + private InLayer lastPredicate(ComputeRecursive recursive) { + exists(int n | + result = layerEventRank(recursive, n) and + not exists(layerEventRank(recursive, n + 1)) + ) + } + + /** + * Holds if the predicate represented by `next` was evaluated after the + * predicate represented by `prev` in the SCC computation rooted at `recursive`. + */ + predicate successor(ComputeRecursive recursive, InLayer prev, InLayer next) { + exists(int index | + layerEventRank(recursive, index) = prev and + layerEventRank(recursive, index + 1) = next + ) + } + + /** + * Holds if the predicate represented by `inLayer` was run in the `iteration`'iteration + * of the SCC computation rooted at `recursive`. + */ + private predicate ran(ComputeRecursive recursive, int iteration, InLayer inLayer) { + exists(int index | + inLayer = layerEventRank(recursive, index) and + inLayer.getPredicateIterationMillis().getNumber(iteration) >= 0 + ) + } + + /** + * Gets the next iteration in which the predicate `pred` in the `iteration`'th iteration + * of a recursive SCC rooted at `recursive` should be evaluated. + */ + int nextPipeline(ComputeRecursive recursive, int iteration, InLayer inLayer) { + iteration = 0 and + if ran(recursive, iteration, inLayer) then result = 1 else result = 0 + or + iteration > 1 and + exists(int n | n = nextPipeline(recursive, iteration - 1, inLayer) | + if ran(recursive, iteration, inLayer) then result = n + 1 else result = n + ) + } + + bindingset[this] + signature class ResultSig; + + /** + * A signature for generically traversing a SCC computation. + */ + signature module Fold { + /** + * Gets the base case for the fold. That is, the initial value that + * is produced from the first evaluation of the first IN_LAYER event + * in the recursive evaluation. + */ + bindingset[run] + R base(PipeLineRun run); + + /** + * Gets the recursive case for the fold. That is, `r` is the accumulation + * of the previous evaluations, and `run` is the pipeline of the next IN_LAYER + * event that is evaluated. + */ + bindingset[run, r] + R fold(PipeLineRun run, R r); + } + + module Iterate F> { + private R iterate(ComputeRecursive recursive, int iteration, InLayer pred) { + // Case: The first iteration + iteration = 0 and + ( + // Subcase: The first predicate in the first iteration + pred = firstPredicate(recursive) and + result = F::base(pred.getPipelineRuns().getRun(0)) + or + // Subcase: The predicate has a predecessor + exists(InLayer pred0, R r | + successor(recursive, pred0, pred) and + r = iterate(recursive, 0, pred0) and + result = F::fold(pred.getPipelineRuns().getRun(0), r) + ) + ) + or + // Case: Not the first iteration + iteration > 0 and + ( + // Subcase: The first predicate in the iteration + pred = firstPredicate(recursive) and + exists(InLayer last, R r | + last = lastPredicate(recursive) and + r = iterate(recursive, iteration - 1, last) and + result = F::fold(pred.getPipelineRuns().getRun(iteration), r) + ) + or + // Subcase: The predicate has a predecessor in the same iteration + exists(InLayer pred0, R r | + successor(recursive, pred0, pred) and + r = iterate(recursive, iteration, pred0) and + result = F::fold(pred.getPipelineRuns().getRun(iteration), r) + ) + ) + } + + R iterate(ComputeRecursive recursive) { + exists(int iteration, InLayer pred | + pred = lastPredicate(recursive) and + result = iterate(recursive, iteration, pred) and + not exists(iterate(recursive, iteration + 1, pred)) + ) + } + } + class ComputeRecursive extends SummaryEvent { ComputeRecursive() { evaluationStrategy = "COMPUTE_RECURSIVE" } } class InLayer extends SummaryEvent { InLayer() { evaluationStrategy = "IN_LAYER" } + + string getMainHash() { result = this.getString("mainHash") } + + ComputeRecursive getComputeRecursiveEvent() { result.getRAHash() = this.getMainHash() } + + Array getPredicateIterationMillis() { result = this.getArray("predicateIterationMillis") } + + float getPredicateIterationMillis(int i) { + result = getRanked(this.getArray("predicateIterationMillis"), i) + } + + PipeLineRuns getPipelineRuns() { result = this.getArray("pipelineRuns") } + + float getDeltaSize(int i) { result = getRanked(this.getArray("deltaSizes"), i) } } class ComputedExtensional extends SummaryEvent { diff --git a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll index d15da37b4f2..1e7bfa71352 100644 --- a/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll +++ b/ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll @@ -1866,6 +1866,12 @@ module JSON { /** Gets the location of this element. */ final L::Location getLocation() { json_ast_node_info(this, _, _, result) } + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + /** Gets the parent of this element. */ final AstNode getParent() { json_ast_node_info(this, result, _, _) } From 23b9abcbbfce60b70d50847176a3a51069a22a0d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 13:00:22 +0000 Subject: [PATCH 388/415] QL: Add a query for finding the predicates with the highest tuple sums. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 25 ----------------- .../src/queries/performance/LargeTupleSum.ql | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 25 deletions(-) create mode 100644 ql/ql/src/queries/performance/LargeTupleSum.ql diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 1637b07c301..26925241ce5 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -362,31 +362,6 @@ module KindPredicatesLog { ) } - /** - * Holds if the predicate represented by `inLayer` was run in the `iteration`'iteration - * of the SCC computation rooted at `recursive`. - */ - private predicate ran(ComputeRecursive recursive, int iteration, InLayer inLayer) { - exists(int index | - inLayer = layerEventRank(recursive, index) and - inLayer.getPredicateIterationMillis().getNumber(iteration) >= 0 - ) - } - - /** - * Gets the next iteration in which the predicate `pred` in the `iteration`'th iteration - * of a recursive SCC rooted at `recursive` should be evaluated. - */ - int nextPipeline(ComputeRecursive recursive, int iteration, InLayer inLayer) { - iteration = 0 and - if ran(recursive, iteration, inLayer) then result = 1 else result = 0 - or - iteration > 1 and - exists(int n | n = nextPipeline(recursive, iteration - 1, inLayer) | - if ran(recursive, iteration, inLayer) then result = n + 1 else result = n - ) - } - bindingset[this] signature class ResultSig; diff --git a/ql/ql/src/queries/performance/LargeTupleSum.ql b/ql/ql/src/queries/performance/LargeTupleSum.ql new file mode 100644 index 00000000000..e5bbed79bbd --- /dev/null +++ b/ql/ql/src/queries/performance/LargeTupleSum.ql @@ -0,0 +1,28 @@ +/** + * Shows a list of the "slow" predicates by tuple sum. + */ + +import ql +import codeql_ql.StructuredLogs +import KindPredicatesLog + +module SumCounts implements Fold { + int base(PipeLineRun run) { result = sum(int i | | run.getCount(i)) } + + bindingset[s] + int fold(PipeLineRun run, int s) { result = sum(int i | | run.getCount(i)) + s } +} + +int sumTuples(SummaryEvent event) { + result = strictsum(int i | | event.(ComputeSimple).getPipelineRun().getCount(i)) + or + result = Iterate::iterate(event) +} + +int predicateRank(SummaryEvent evt) { + evt = rank[result](SummaryEvent y, int s | s = sumTuples(y) | y order by s desc) +} + +from SummaryEvent evt, int s +where predicateRank(evt) < 50 and s = sumTuples(evt) +select evt, s order by s desc From e02368f6fa064a206b5af30c61f98f29f9e64436 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 16:04:39 +0000 Subject: [PATCH 389/415] 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 2206055674c..a0fd5078807 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.7 +version: 0.4.8 extractor: javascript library: true groups: diff --git a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml index d89868c33af..6391cd89371 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.7 +version: 0.4.8 suites: codeql-suites defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls groups: From 7e2b286f03cf3043dbf50946f7791af68647389b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 16:12:23 +0000 Subject: [PATCH 390/415] JS: Bump version of ML-powered library and query packs to 0.4.9 --- .../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 a0fd5078807..36cbd0ff6bc 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.8 +version: 0.4.9 extractor: javascript library: true groups: diff --git a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml index 6391cd89371..3ad20587684 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.8 +version: 0.4.9 suites: codeql-suites defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls groups: From 9c8b8dff88798de2663aefd2f985dba1d6919f07 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 17:00:43 +0000 Subject: [PATCH 391/415] QL: Output more rows in the join order query. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 12 ++++++++ .../src/queries/performance/LargeJoinOrder.ql | 30 ++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index f2ac0086492..6aa181dfed2 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -269,6 +269,8 @@ module KindPredicatesLog { then result = this.getPredicateName() else result = "" } + + Array getRa(string ordering) { result = this.getObject("ra").getArray(ordering) } } class SentinelEmpty extends SummaryEvent { @@ -284,8 +286,12 @@ module KindPredicatesLog { string getRAReference() { result = this.getString("raReference") } + Array getCounts() { result = this.getArray("counts") } + float getCount(int i) { result = getRanked(this.getArray("counts"), i) } + Array getDuplicationPercentage() { result = this.getArray("duplicationPercentages") } + float getDuplicationPercentage(int i) { result = getRanked(this.getArray("duplicationPercentages"), i) } @@ -323,6 +329,12 @@ module KindPredicatesLog { string getPosition() { result = this.getString("position") } Predicate getPredicate() { result = getPredicateFromPosition(this.getPosition()) } + + /** + * Gets the RA for this event. Unlike recursive predicates, a COMPUTE_SIMPLE + * event only has one pipeline ordering (and it's named "pipeline"). + */ + Array getRa() { result = this.getObject("ra").getArray("pipeline") } } class ComputeRecursive extends SummaryEvent { diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index 3d51affd20f..5080783c49b 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -16,7 +16,7 @@ import KindPredicatesLog float getBadness(ComputeSimple simple) { exists(float maxTupleCount, float resultSize, float largestDependency, float denom | resultSize = simple.getResultSize() and - maxTupleCount = max(simple.getPipelineRun().getCount(_)) and + extractInformation(simple, maxTupleCount, _, _, _, _) and largestDependency = max(simple.getDependencies().getADependency().getResultSize()) and denom = resultSize.maximum(largestDependency) and denom > 0 and // avoid division by zero (which would create a NaN result). @@ -24,6 +24,28 @@ float getBadness(ComputeSimple simple) { ) } -from ComputeSimple evt, float f -where f = getBadness(evt) and f > 1.5 -select evt, f order by f desc +pragma[nomagic] +predicate hasPipelineRun(ComputeSimple simple, PipeLineRun run) { run = simple.getPipelineRun() } + +predicate extractInformation( + ComputeSimple simple, float maxTupleCount, int pipelineIndex, Array tuples, + Array duplicationPercentages, Array ra +) { + exists(PipeLineRun run | + hasPipelineRun(simple, run) and + maxTupleCount = max(run.getCount(_)) and + pragma[only_bind_out](tuples.getFloat(pipelineIndex)) = maxTupleCount and + tuples = run.getCounts() and + duplicationPercentages = run.getDuplicationPercentage() and + ra = simple.getRa() + ) +} + +from + ComputeSimple evt, float f, float maxTupleCount, int pipelineIndex, Array tuples, + Array duplicationPercentages, Array ra +where + f = getBadness(evt) and + f > 1.5 and + extractInformation(evt, maxTupleCount, pipelineIndex, tuples, duplicationPercentages, ra) +select evt, f, pipelineIndex, tuples, duplicationPercentages, ra order by f desc From 229e291e1b081eab513d0f8042f846f2ad95ed4c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 17:34:07 +0000 Subject: [PATCH 392/415] QL: Fix naming. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 4 ++-- ql/ql/src/queries/performance/LargeJoinOrder.ql | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 6aa181dfed2..797f8c36f18 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -270,7 +270,7 @@ module KindPredicatesLog { else result = "" } - Array getRa(string ordering) { result = this.getObject("ra").getArray(ordering) } + Array getRA(string ordering) { result = this.getObject("ra").getArray(ordering) } } class SentinelEmpty extends SummaryEvent { @@ -334,7 +334,7 @@ module KindPredicatesLog { * Gets the RA for this event. Unlike recursive predicates, a COMPUTE_SIMPLE * event only has one pipeline ordering (and it's named "pipeline"). */ - Array getRa() { result = this.getObject("ra").getArray("pipeline") } + Array getRA() { result = this.getObject("ra").getArray("pipeline") } } class ComputeRecursive extends SummaryEvent { diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index 5080783c49b..44ed35c15b6 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -37,7 +37,7 @@ predicate extractInformation( pragma[only_bind_out](tuples.getFloat(pipelineIndex)) = maxTupleCount and tuples = run.getCounts() and duplicationPercentages = run.getDuplicationPercentage() and - ra = simple.getRa() + ra = simple.getRA() ) } From e368b8f72ac2c8051ccb1f569de177c06a5839f9 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 17:48:21 +0000 Subject: [PATCH 393/415] Add classes and predicates to StructuredLogs --- ql/ql/src/codeql_ql/StructuredLogs.qll | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index f2ac0086492..98575f175bd 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -269,6 +269,31 @@ module KindPredicatesLog { then result = this.getPredicateName() else result = "" } + + RA getRA() { result = this.getObject("ra") } + } + + class PipeLine extends Array { + RA ra; + string raReference; + + RA getRA() { result = ra } + + string getRAReference() { result = raReference } + + PipeLine() { this = ra.getArray(raReference) } + + string getLineOfRA(int n) { result = this.getString(n) } + } + + class RA extends Object { + SummaryEvent evt; + + SummaryEvent getEvent() { result = evt } + + RA() { evt.getObject("ra") = this } + + PipeLine getPipeLine(string name) { result = this.getArray(name) } } class SentinelEmpty extends SummaryEvent { @@ -284,6 +309,17 @@ module KindPredicatesLog { string getRAReference() { result = this.getString("raReference") } + PipeLine getPipeLine() { + exists(SummaryEvent evt | runs.getEvent() = evt | + result = evt.getRA().getPipeLine(pragma[only_bind_into](this.getRAReference())) + ) + } + + float getCount(int i, string raLine) { + result = this.getCount(i) and + raLine = this.getPipeLine().getLineOfRA(pragma[only_bind_into](i)) + } + float getCount(int i) { result = getRanked(this.getArray("counts"), i) } float getDuplicationPercentage(int i) { From 77871e287d13297401b206f6bbdb24fb896df303 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 18:35:24 +0000 Subject: [PATCH 394/415] Use RAExpr --- ql/ql/src/codeql_ql/StructuredLogs.qll | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 98575f175bd..9d7de6ac39e 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -1,5 +1,6 @@ private import ql private import codeql_ql.ast.internal.TreeSitter +private import experimental.RA /** Gets a timestamp corresponding to the number of seconds since the date Semmle was founded. */ bindingset[d, h, m, s, ms] @@ -78,6 +79,10 @@ private float getRanked(Array a, int i) { result = rank[i + 1](int j, float f | f = a.getFloat(j) and f >= 0 | f order by j) } +private string getRankedLine(Array a, int i) { + result = rank[i + 1](int j, string s | s = a.getString(j) and s != "" | s order by j) +} + module EvaluatorLog { class Entry extends Object { } @@ -283,7 +288,9 @@ module KindPredicatesLog { PipeLine() { this = ra.getArray(raReference) } - string getLineOfRA(int n) { result = this.getString(n) } + string getLineOfRA(int n) { result = getRankedLine(this, n) } + + RAExpr getExpr(int n) { result.getPredicate() = this and result.getLine() = n } } class RA extends Object { @@ -320,6 +327,12 @@ module KindPredicatesLog { raLine = this.getPipeLine().getLineOfRA(pragma[only_bind_into](i)) } + float getCountAndExpr(int i, RAExpr raExpr) { + result = this.getCount(i) and + raExpr.getPredicate() = this.getPipeLine() and + raExpr.getLine() = i + } + float getCount(int i) { result = getRanked(this.getArray("counts"), i) } float getDuplicationPercentage(int i) { @@ -376,4 +389,6 @@ module KindPredicatesLog { class Extensional extends SummaryEvent { Extensional() { evaluationStrategy = "EXTENSIONAL" } } + + class RAExpr = RAParser::RAExpr; } From 196dbd3a337f2bfe34da1ac1cc86fd9f18ec20cf Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 19:01:52 +0000 Subject: [PATCH 395/415] Exploratory query to test the API --- .../experimental/queries/PredicateSummaries.ql | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 ql/ql/src/experimental/queries/PredicateSummaries.ql diff --git a/ql/ql/src/experimental/queries/PredicateSummaries.ql b/ql/ql/src/experimental/queries/PredicateSummaries.ql new file mode 100644 index 00000000000..d3f9d91e706 --- /dev/null +++ b/ql/ql/src/experimental/queries/PredicateSummaries.ql @@ -0,0 +1,18 @@ +/** + * Finds evaluations with very large tuple counts somewhere + */ + +import ql +import codeql_ql.StructuredLogs + +float maxTupleCount(KindPredicatesLog::SummaryEvent evt) { + result = max(KindPredicatesLog::PipeLineRuns r | r.getEvent() = evt | r.getRun(_).getCount(_)) +} + +int maxPipeLineLength(KindPredicatesLog::SummaryEvent evt) { + result = max(evt.getRA().getPipeLine(_).getLength()) +} + +from KindPredicatesLog::SummaryEvent evt +select evt, evt.getResultSize(), evt.getMillis() as ms, maxTupleCount(evt) as mc, evt.getMillis(), + maxPipeLineLength(evt) as len order by mc desc From dde18de2d1368454e798d4bc3facb75099dec47c Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 19:03:05 +0000 Subject: [PATCH 396/415] Fixes --- ql/ql/src/codeql_ql/StructuredLogs.qll | 2 ++ ql/ql/src/experimental/queries/PredicateSummaries.ql | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index 9d7de6ac39e..f039825489e 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -68,6 +68,8 @@ class Array extends JSON::Array { float getFloat(int i) { result = this.getChild(i).(JSON::Number).getValue().toFloat() } Array getArray(int i) { result = this.getChild(i) } + + int getLength() { result = count(this.getChild(_)) } } /** diff --git a/ql/ql/src/experimental/queries/PredicateSummaries.ql b/ql/ql/src/experimental/queries/PredicateSummaries.ql index d3f9d91e706..da71cb9617e 100644 --- a/ql/ql/src/experimental/queries/PredicateSummaries.ql +++ b/ql/ql/src/experimental/queries/PredicateSummaries.ql @@ -14,5 +14,5 @@ int maxPipeLineLength(KindPredicatesLog::SummaryEvent evt) { } from KindPredicatesLog::SummaryEvent evt -select evt, evt.getResultSize(), evt.getMillis() as ms, maxTupleCount(evt) as mc, evt.getMillis(), +select evt, evt.getResultSize(), evt.getMillis() as ms, maxTupleCount(evt) as mc, maxPipeLineLength(evt) as len order by mc desc From 9ee078d1f27ae7fbb5dcdf6fd0f745e2d3ee6b34 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 19:11:09 +0000 Subject: [PATCH 397/415] QL: More column information. --- .../src/queries/performance/LargeJoinOrder.ql | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index 44ed35c15b6..88a36f8c57b 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -16,7 +16,7 @@ import KindPredicatesLog float getBadness(ComputeSimple simple) { exists(float maxTupleCount, float resultSize, float largestDependency, float denom | resultSize = simple.getResultSize() and - extractInformation(simple, maxTupleCount, _, _, _, _) and + extractInformation(simple, maxTupleCount, _, _, _) and largestDependency = max(simple.getDependencies().getADependency().getResultSize()) and denom = resultSize.maximum(largestDependency) and denom > 0 and // avoid division by zero (which would create a NaN result). @@ -28,13 +28,11 @@ pragma[nomagic] predicate hasPipelineRun(ComputeSimple simple, PipeLineRun run) { run = simple.getPipelineRun() } predicate extractInformation( - ComputeSimple simple, float maxTupleCount, int pipelineIndex, Array tuples, - Array duplicationPercentages, Array ra + ComputeSimple simple, float maxTupleCount, Array tuples, Array duplicationPercentages, Array ra ) { exists(PipeLineRun run | hasPipelineRun(simple, run) and maxTupleCount = max(run.getCount(_)) and - pragma[only_bind_out](tuples.getFloat(pipelineIndex)) = maxTupleCount and tuples = run.getCounts() and duplicationPercentages = run.getDuplicationPercentage() and ra = simple.getRA() @@ -42,10 +40,13 @@ predicate extractInformation( } from - ComputeSimple evt, float f, float maxTupleCount, int pipelineIndex, Array tuples, - Array duplicationPercentages, Array ra + ComputeSimple evt, float badness, float maxTupleCount, Array tuples, Array duplicationPercentages, + Array ra, int index where - f = getBadness(evt) and - f > 1.5 and - extractInformation(evt, maxTupleCount, pipelineIndex, tuples, duplicationPercentages, ra) -select evt, f, pipelineIndex, tuples, duplicationPercentages, ra order by f desc + badness = getBadness(evt) and + badness > 1.5 and + extractInformation(evt, maxTupleCount, tuples, duplicationPercentages, ra) +select evt.getPredicateName() as predicate_name, badness, index, + tuples.getFloat(index) as tuple_count, + duplicationPercentages.getFloat(index) as duplication_percentage, ra.getString(index) order by + badness desc From 41d88a45d954e13914dab1bcc63053f6a06bdadd Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Thu, 23 Feb 2023 21:02:43 +0000 Subject: [PATCH 398/415] Fix merge --- ql/ql/src/queries/performance/LargeJoinOrder.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index 88a36f8c57b..790def7ead1 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -35,7 +35,7 @@ predicate extractInformation( maxTupleCount = max(run.getCount(_)) and tuples = run.getCounts() and duplicationPercentages = run.getDuplicationPercentage() and - ra = simple.getRA() + ra = simple.getPipeLine() ) } From b0e391cff04958f37e890451422c310b06c6d554 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 22:12:23 +0000 Subject: [PATCH 399/415] QL: Extend the join order metric to cover recursive predicates. --- ql/ql/src/codeql_ql/StructuredLogs.qll | 48 ++-- ql/ql/src/experimental/RA.qll | 178 +++++++++++- .../src/queries/performance/LargeJoinOrder.ql | 259 ++++++++++++++++-- 3 files changed, 441 insertions(+), 44 deletions(-) diff --git a/ql/ql/src/codeql_ql/StructuredLogs.qll b/ql/ql/src/codeql_ql/StructuredLogs.qll index e349af4ddb4..f2e6939f7e6 100644 --- a/ql/ql/src/codeql_ql/StructuredLogs.qll +++ b/ql/ql/src/codeql_ql/StructuredLogs.qll @@ -77,7 +77,8 @@ class Array extends JSON::Array { * * This is needed because the evaluator log is padded with -1s in some cases. */ -private float getRanked(Array a, int i) { +pragma[nomagic] +private float getRankedFloat(Array a, int i) { result = rank[i + 1](int j, float f | f = a.getFloat(j) and f >= 0 | f order by j) } @@ -137,10 +138,10 @@ module EvaluatorLog { string getRAReference() { result = this.getString("raReference") } - float getCount(int i) { result = getRanked(this.getArray("counts"), i) } + float getCount(int i) { result = getRankedFloat(this.getArray("counts"), i) } float getDuplicationPercentage(int i) { - result = getRanked(this.getArray("duplicationPercentages"), i) + result = getRankedFloat(this.getArray("duplicationPercentages"), i) } float getResultSize() { result = this.getFloat("resultSize") } @@ -250,6 +251,11 @@ module KindPredicatesLog { int getMillis() { result = this.getNumber("millis") } + PipeLineRuns getPipelineRuns() { result = this.getArray("pipelineRuns") } + + pragma[nomagic] + float getDeltaSize(int i) { result = getRankedFloat(this.getArray("deltaSizes"), i) } + predicate hasCompletionTime( int year, string month, int day, int hours, int minute, int second, int millisecond ) { @@ -271,9 +277,7 @@ module KindPredicatesLog { float getResultSize() { result = this.getFloat("resultSize") } - Array getRA(string ordering) { result = this.getObject("ra").getArray(ordering) } - - string getAnOrdering() { exists(this.getRA(result)) } + string getAnOrdering() { exists(this.getRA().getPipeLine(result)) } override string toString() { if exists(this.getPredicateName()) @@ -307,6 +311,8 @@ module KindPredicatesLog { RA() { evt.getObject("ra") = this } PipeLine getPipeLine(string name) { result = this.getArray(name) } + + PipeLine getPipeLine() { result = this.getPipeLine("pipeline") } } class SentinelEmpty extends SummaryEvent { @@ -341,12 +347,12 @@ module KindPredicatesLog { Array getCounts() { result = this.getArray("counts") } - float getCount(int i) { result = getRanked(this.getArray("counts"), i) } + float getCount(int i) { result = getRankedFloat(this.getArray("counts"), i) } Array getDuplicationPercentage() { result = this.getArray("duplicationPercentages") } float getDuplicationPercentage(int i) { - result = getRanked(this.getArray("duplicationPercentages"), i) + result = getRankedFloat(this.getArray("duplicationPercentages"), i) } } @@ -391,10 +397,14 @@ module KindPredicatesLog { } /** Gets the `index`'th event that's evaluated by `recursive`. */ - private InLayer layerEventRank(ComputeRecursive recursive, int index) { + private SummaryEvent layerEventRank(ComputeRecursive recursive, int index) { result = - rank[index + 1](InLayer cand, int startline, string filepath | - cand.getComputeRecursiveEvent() = recursive and + rank[index + 1](SummaryEvent cand, int startline, string filepath | + ( + cand = recursive + or + cand.(InLayer).getComputeRecursiveEvent() = recursive + ) and cand.hasLocationInfo(filepath, startline, _, _, _) | cand order by filepath, startline @@ -405,15 +415,13 @@ module KindPredicatesLog { * Gets the first predicate that's evaluated in an iteration * of the SCC computation rooted at `recursive`. */ - private InLayer firstPredicate(ComputeRecursive recursive) { - result = layerEventRank(recursive, 0) - } + SummaryEvent firstPredicate(ComputeRecursive recursive) { result = layerEventRank(recursive, 0) } /** * Gets the last predicate that's evaluated in an iteration * of the SCC computation rooted at `recursive`. */ - private InLayer lastPredicate(ComputeRecursive recursive) { + SummaryEvent lastPredicate(ComputeRecursive recursive) { exists(int n | result = layerEventRank(recursive, n) and not exists(layerEventRank(recursive, n + 1)) @@ -424,7 +432,7 @@ module KindPredicatesLog { * Holds if the predicate represented by `next` was evaluated after the * predicate represented by `prev` in the SCC computation rooted at `recursive`. */ - predicate successor(ComputeRecursive recursive, InLayer prev, InLayer next) { + predicate successor(ComputeRecursive recursive, SummaryEvent prev, InLayer next) { exists(int index | layerEventRank(recursive, index) = prev and layerEventRank(recursive, index + 1) = next @@ -503,6 +511,8 @@ module KindPredicatesLog { class ComputeRecursive extends SummaryEvent { ComputeRecursive() { evaluationStrategy = "COMPUTE_RECURSIVE" } + + Depencencies getDependencies() { result = this.getObject("dependencies") } } class InLayer extends SummaryEvent { @@ -515,12 +525,8 @@ module KindPredicatesLog { Array getPredicateIterationMillis() { result = this.getArray("predicateIterationMillis") } float getPredicateIterationMillis(int i) { - result = getRanked(this.getArray("predicateIterationMillis"), i) + result = getRankedFloat(this.getArray("predicateIterationMillis"), i) } - - PipeLineRuns getPipelineRuns() { result = this.getArray("pipelineRuns") } - - float getDeltaSize(int i) { result = getRanked(this.getArray("deltaSizes"), i) } } class ComputedExtensional extends SummaryEvent { diff --git a/ql/ql/src/experimental/RA.qll b/ql/ql/src/experimental/RA.qll index 4976f9aa5f3..7187ebfc8c7 100644 --- a/ql/ql/src/experimental/RA.qll +++ b/ql/ql/src/experimental/RA.qll @@ -26,8 +26,71 @@ module RAParser { result = str.trim().regexpCapture("return r([0-9]+)", 1).toInt() } + bindingset[str] + private predicate parseScan(string str, int arity, int lhs, string rhs) { + exists(string r, string trimmed | + r = "\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+SCAN\\s+([0-9a-zA-Z:#_]+)\\s.*" and + trimmed = str.trim() + | + arity = trimmed.regexpCapture(r, 1).toInt() and + lhs = trimmed.regexpCapture(r, 2).toInt() and + rhs = trimmed.regexpCapture(r, 3) + ) + } + + bindingset[str] + private predicate parseJoin(string str, int arity, int lhs, string left, string right) { + exists(string r, string trimmed | + r = + "\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+JOIN\\s+([0-9a-zA-Z:#_]+)\\s+WITH\\s+([0-9a-zA-Z:#_]+)\\s.*" and + trimmed = str.trim() + | + arity = trimmed.regexpCapture(r, 1).toInt() and + lhs = trimmed.regexpCapture(r, 2).toInt() and + left = trimmed.regexpCapture(r, 3) and + right = trimmed.regexpCapture(r, 4) + ) + } + + bindingset[str] + private predicate parseSelect(string str, int arity, int lhs, string rhs) { + exists(string r, string trimmed | + r = "\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+SELECT\\s+([0-9a-zA-Z:#_]+).*" and + trimmed = str.trim() + | + arity = trimmed.regexpCapture(r, 1).toInt() and + lhs = trimmed.regexpCapture(r, 2).toInt() and + rhs = trimmed.regexpCapture(r, 3) + ) + } + + bindingset[str] + private predicate parseAntiJoin(string str, int arity, int lhs, string left, string right) { + exists(string r, string trimmed | + r = "\\{(\\d+)\\}\\s+r(\\d+)\\s+=\\s+([0-9a-zA-Z:#_]+)\\s+AND\\s+NOT\\s+([0-9a-zA-Z:#_]+).*" and + trimmed = str.trim() + | + arity = trimmed.regexpCapture(r, 1).toInt() and + lhs = trimmed.regexpCapture(r, 2).toInt() and + left = trimmed.regexpCapture(r, 3) and + right = trimmed.regexpCapture(r, 4) + ) + } + private newtype TRA = TReturn(Predicate p, int line, int v) { v = parseReturn(p.getLineOfRA(line)) } or + TScan(Predicate p, int line, int arity, int lhs, string rhs) { + parseScan(p.getLineOfRA(line), arity, lhs, rhs) + } or + TJoin(Predicate p, int line, int arity, int lhs, string left, string right) { + parseJoin(p.getLineOfRA(line), arity, lhs, left, right) + } or + TSelect(Predicate p, int line, int arity, int lhs, string rhs) { + parseSelect(p.getLineOfRA(line), arity, lhs, rhs) + } or + TAntiJoin(Predicate p, int line, int arity, int lhs, string left, string right) { + parseAntiJoin(p.getLineOfRA(line), arity, lhs, left, right) + } or TUnknown(Predicate p, int line, int lhs, int arity, string rhs) { rhs = parseRaExpr(p, line, arity, lhs) } @@ -90,12 +153,12 @@ module RAParser { } class RAReturnExpr extends RAExpr, TReturn { - RAReturnExpr() { this = TReturn(p, line, res) } - Predicate p; int line; int res; + RAReturnExpr() { this = TReturn(p, line, res) } + override Predicate getPredicate() { result = p } override int getLine() { result = line } @@ -108,4 +171,115 @@ module RAParser { override string getARhsPredicate() { none() } } + + class RAScanExpr extends RAExpr, TScan { + Predicate p; + int line; + int arity; + int lhs; + string rhs; + + RAScanExpr() { this = TScan(p, line, arity, lhs, rhs) } + + override Predicate getPredicate() { result = p } + + override int getLine() { result = line } + + override int getLhs() { result = lhs } + + override int getArity() { result = arity } + + override int getARhsVariable() { isVariable(rhs, result) } + + override string getARhsPredicate() { + result = rhs and + not isVariable(result, _) + } + } + + bindingset[s] + private predicate isVariable(string s, int n) { n = s.regexpCapture("r(\\d+)", 1).toInt() } + + class RAJoinExpr extends RAExpr, TJoin { + Predicate p; + int line; + int arity; + int lhs; + string left; + string right; + + RAJoinExpr() { this = TJoin(p, line, arity, lhs, left, right) } + + override Predicate getPredicate() { result = p } + + override int getLine() { result = line } + + override int getLhs() { result = lhs } + + override int getArity() { result = arity } + + // Note: We could return reasonable values here sometimes. + override int getARhsVariable() { isVariable([left, right], result) } + + // Note: We could return reasonable values here sometimes. + override string getARhsPredicate() { + result = [left, right] and + not isVariable(result, _) + } + } + + class RaSelectExpr extends RAExpr, TSelect { + Predicate p; + int line; + int arity; + int lhs; + string rhs; + + RaSelectExpr() { this = TSelect(p, line, arity, lhs, rhs) } + + override Predicate getPredicate() { result = p } + + override int getLine() { result = line } + + override int getLhs() { result = lhs } + + override int getArity() { result = arity } + + // Note: We could return reasonable values here sometimes. + override int getARhsVariable() { isVariable(rhs, result) } + + // Note: We could return reasonable values here sometimes. + override string getARhsPredicate() { + result = rhs and + not isVariable(result, _) + } + } + + class RaAntiJoinExpr extends RAExpr, TAntiJoin { + Predicate p; + int line; + int arity; + int lhs; + string left; + string right; + + RaAntiJoinExpr() { this = TAntiJoin(p, line, arity, lhs, left, right) } + + override Predicate getPredicate() { result = p } + + override int getLine() { result = line } + + override int getLhs() { result = lhs } + + override int getArity() { result = arity } + + // Note: We could return reasonable values here sometimes. + override int getARhsVariable() { isVariable([left, right], result) } + + // Note: We could return reasonable values here sometimes. + override string getARhsPredicate() { + result = [left, right] and + not isVariable(result, _) + } + } } diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index 790def7ead1..4338d06ae36 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -6,6 +6,7 @@ import ql import codeql_ql.StructuredLogs import KindPredicatesLog +import experimental.RA /** * Gets the badness of a non-recursive predicate evaluation. @@ -13,10 +14,10 @@ import KindPredicatesLog * The badness is the maximum number of tuples in the pipeline divided by the * maximum of two numbers: the size of the result and the size of the largest dependency. */ -float getBadness(ComputeSimple simple) { +float getNonRecursiveBadness(ComputeSimple simple) { exists(float maxTupleCount, float resultSize, float largestDependency, float denom | resultSize = simple.getResultSize() and - extractInformation(simple, maxTupleCount, _, _, _) and + maxTupleCount = max(simple.getPipelineRun().getCount(_)) and largestDependency = max(simple.getDependencies().getADependency().getResultSize()) and denom = resultSize.maximum(largestDependency) and denom > 0 and // avoid division by zero (which would create a NaN result). @@ -24,29 +25,245 @@ float getBadness(ComputeSimple simple) { ) } -pragma[nomagic] -predicate hasPipelineRun(ComputeSimple simple, PipeLineRun run) { run = simple.getPipelineRun() } - -predicate extractInformation( - ComputeSimple simple, float maxTupleCount, Array tuples, Array duplicationPercentages, Array ra +predicate hasTupleCount( + ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, int i, + float tupleCount ) { - exists(PipeLineRun run | - hasPipelineRun(simple, run) and - maxTupleCount = max(run.getCount(_)) and - tuples = run.getCounts() and - duplicationPercentages = run.getDuplicationPercentage() and - ra = simple.getPipeLine() + inLayer = firstPredicate(recursive) and + exists(PipeLineRun run | run = inLayer.getPipelineRuns().getRun(iteration) | + ordering = run.getRAReference() and + tupleCount = run.getCount(i) + ) + or + exists(SummaryEvent inLayer0, float tupleCount0, PipeLineRun run | + run = inLayer.getPipelineRuns().getRun(pragma[only_bind_into](iteration)) and + successor(recursive, inLayer0, inLayer) and + hasTupleCount(recursive, ordering, inLayer0, pragma[only_bind_into](iteration), i, tupleCount0) and + tupleCount = run.getCount(i) + tupleCount0 ) } +predicate hasTupleCount(ComputeRecursive recursive, string ordering, int i, float tupleCount) { + tupleCount = + strictsum(SummaryEvent inLayer, int iteration, int tc | + inLayer = getInLayerOrRecursive(recursive) and + hasTupleCount(recursive, ordering, inLayer, iteration, i, tc) + | + tc + ) +} + +pragma[nomagic] +predicate hasDuplication( + ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, int i, + float duplication +) { + inLayer = firstPredicate(recursive) and + exists(PipeLineRun run | run = inLayer.getPipelineRuns().getRun(iteration) | + ordering = run.getRAReference() and + duplication = run.getDuplicationPercentage(i) + ) + or + exists(SummaryEvent inLayer0, float duplication0, PipeLineRun run | + run = inLayer.getPipelineRuns().getRun(pragma[only_bind_into](iteration)) and + successor(recursive, inLayer0, inLayer) and + hasDuplication(recursive, ordering, inLayer0, pragma[only_bind_into](iteration), i, duplication0) and + duplication = run.getDuplicationPercentage(i).maximum(duplication0) + ) +} + +predicate hasDuplication(ComputeRecursive recursive, string ordering, int i, float duplication) { + duplication = + max(SummaryEvent inLayer, int iteration, int dup | + inLayer = getInLayerOrRecursive(recursive) and + hasDuplication(recursive, ordering, inLayer, iteration, i, dup) + | + dup + ) +} + +// ----- +/** + * Holds if the bucket `bucket` has `resultSize` resultSize in the `iteration`'th iteration. + * + * For example, the "base" bucket in iteration 0 has size 42. + */ +private predicate hasResultSize( + ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, float resultSize +) { + inLayer = firstPredicate(recursive) and + ordering = inLayer.getPipelineRuns().getRun(iteration).getRAReference() and + resultSize = inLayer.getDeltaSize(iteration) + or + exists(SummaryEvent inLayer0, int resultSize0 | + successor(recursive, inLayer0, inLayer) and + hasResultSize(recursive, ordering, inLayer0, iteration, resultSize0) and + resultSize = inLayer.getDeltaSize(iteration) + resultSize0 + ) +} + +predicate hasResultSize(ComputeRecursive recursive, string ordering, float resultSize) { + resultSize = + strictsum(InLayer inLayer, int iteration, float r | + inLayer.getComputeRecursiveEvent() = recursive and + hasResultSize(recursive, ordering, inLayer, iteration, r) + | + r + ) +} + +RAParser::RAExpr getAnRaOperation(SummaryEvent inLayer, string ordering) { + inLayer.getRA().getPipeLine(ordering) = result.getPredicate() +} + +SummaryEvent getInLayerEventWithName(ComputeRecursive recursive, string predicateName) { + result = getInLayerOrRecursive(recursive) and + result.getPredicateName() = predicateName +} + +bindingset[predicateName, iteration] +int getSize(ComputeRecursive recursive, string predicateName, int iteration, TDeltaKind kind) { + exists(int i | + kind = TPrevious() and + i = iteration - 1 + or + kind = TCurrent() and + i = iteration + | + result = getInLayerEventWithName(recursive, predicateName).getDeltaSize(iteration - 1) + or + not exists(getInLayerEventWithName(recursive, predicateName).getDeltaSize(iteration - 1)) and + result = 0 + ) +} + +SummaryEvent getDependencyWithName(Depencencies dependency, string predicateName) { + result.getPredicateName() = predicateName and + dependency.getADependency() = result +} + +newtype TDeltaKind = + TCurrent() or + TPrevious() + +bindingset[predicateName] +private predicate isDelta(string predicateName, TDeltaKind kind, string withoutSuffix) { + kind = TPrevious() and + withoutSuffix = predicateName.regexpCapture("(.+)#prev_delta", 1) + or + kind = TCurrent() and + withoutSuffix = predicateName.regexpCapture("(.+)#cur_delta", 1) +} + +predicate hasDependentPredicateSizeInBucket( + ComputeRecursive recursive, string bucket, SummaryEvent inLayer, int iteration, + string predicateName, float size +) { + exists( | + inLayer = firstPredicate(recursive) and + bucket = inLayer.getPipelineRuns().getRun(iteration).getRAReference() + | + // We treat iteration 0 as a non-recursive case + if bucket = "base" + then size = getDependencyWithName(recursive.getDependencies(), predicateName).getResultSize() + else + exists(TDeltaKind kind | + size = getSize(recursive, predicateName, iteration, kind) and + isDelta(getAnRaOperation(inLayer, bucket).getARhsPredicate(), kind, predicateName) + ) + ) + or + exists(SummaryEvent inLayer0, float size0 | + successor(recursive, inLayer0, inLayer) and + hasDependentPredicateSizeInBucket(recursive, bucket, inLayer0, iteration, predicateName, size0) + | + // We treat iteration 0 as a non-recursive case + if bucket = "base" + then size = getDependencyWithName(recursive.getDependencies(), predicateName).getResultSize() + else + exists(TDeltaKind kind | + size = getSize(recursive, predicateName, iteration, kind) + size0 and + isDelta(getAnRaOperation(inLayer, bucket).getARhsPredicate(), kind, predicateName) + ) + ) +} + +SummaryEvent getInLayerOrRecursive(ComputeRecursive recursive) { + result = recursive or result.(InLayer).getComputeRecursiveEvent() = recursive +} + +predicate hasDependentPredicateSizeInBucket( + ComputeRecursive recursive, string bucket, string predicateName, float size +) { + size = + strictsum(SummaryEvent inLayer, int iteration, int s | + inLayer = getInLayerOrRecursive(recursive) and + hasDependentPredicateSizeInBucket(recursive, bucket, inLayer, iteration, predicateName, s) + | + s + ) +} + +/** + * Gets the badness of a recursive predicate evaluation. + * + * The badness is the maximum number of tuples in the pipeline divided by the + * maximum of two numbers: the size of the result and the size of the largest dependency. + * + * A dependency of a recursive predicate is defined as follows: + * - For a "base" ordering, it is identical to the definition of a dependency for a + * non-recursive predicate + * - For a non-"base" ordering, it's defined as any `#prev_delta` or `#cur_delta` predicates + * that appear in the pipeline. + */ +float getRecursiveBadness(ComputeRecursive recursive, string bucket) { + exists(float maxTupleCount, float resultSize, float maxDependentPredicateSize | + maxTupleCount = max(float tc | hasTupleCount(recursive, bucket, _, tc) | tc) and + hasResultSize(recursive, bucket, resultSize) and + maxDependentPredicateSize = + max(float size | hasDependentPredicateSizeInBucket(recursive, bucket, _, size) | size) and + resultSize.maximum(maxDependentPredicateSize) > 0 and + result = maxTupleCount / resultSize.maximum(maxDependentPredicateSize) + ) +} + +predicate extractSimpleInformation( + ComputeSimple simple, string predicateName, int index, float tupleCount, + float duplicationPercentage, string operation +) { + exists(PipeLineRun run | + run = simple.getPipelineRun() and + tupleCount = run.getCounts().getFloat(pragma[only_bind_into](index)) and + duplicationPercentage = run.getDuplicationPercentage().getFloat(pragma[only_bind_into](index)) and + operation = simple.getRA().getPipeLine().getLineOfRA(pragma[only_bind_into](index)) and + predicateName = simple.getPredicateName() + ) +} + +predicate extractRecursiveInformation( + ComputeRecursive recursive, string predicateName, string ordering, int index, float tupleCount, + float duplicationPercentage, string operation +) { + hasTupleCount(recursive, ordering, index, tupleCount) and + hasDuplication(recursive, ordering, index, duplicationPercentage) and + operation = recursive.getRA().getPipeLine(ordering).getLineOfRA(index) and + predicateName = recursive.getPredicateName() + " (" + ordering + ")" +} + from - ComputeSimple evt, float badness, float maxTupleCount, Array tuples, Array duplicationPercentages, - Array ra, int index + SummaryEvent evt, float badness, float tupleCount, float duplicationPercentage, string operation, + int index, string predicateName where - badness = getBadness(evt) and badness > 1.5 and - extractInformation(evt, maxTupleCount, tuples, duplicationPercentages, ra) -select evt.getPredicateName() as predicate_name, badness, index, - tuples.getFloat(index) as tuple_count, - duplicationPercentages.getFloat(index) as duplication_percentage, ra.getString(index) order by - badness desc + ( + badness = getNonRecursiveBadness(evt) and + extractSimpleInformation(evt, predicateName, index, tupleCount, duplicationPercentage, operation) + or + exists(string bucket | + badness = getRecursiveBadness(evt, bucket) and + extractRecursiveInformation(evt, predicateName, bucket, index, tupleCount, + duplicationPercentage, operation) + ) + ) +select predicateName as predicate_name, badness, index, tupleCount as tuple_count, + duplicationPercentage as duplication_percentage, operation order by badness desc From f0fe6fba88995b5353bc064e954a8c5f4e32a2b4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 22:25:04 +0000 Subject: [PATCH 400/415] QL: Accept test changes. --- ql/ql/test/experimental/raparser.expected | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ql/ql/test/experimental/raparser.expected b/ql/ql/test/experimental/raparser.expected index af61f56f229..46e9058c8ce 100644 --- a/ql/ql/test/experimental/raparser.expected +++ b/ql/ql/test/experimental/raparser.expected @@ -1,17 +1,26 @@ children | return r7 | {4} r7 = r3 UNION r6 | | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] | +| {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] | +| {4} r3 = STREAM DEDUP r2 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | | {4} r3 = STREAM DEDUP r2 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] | +| {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | {1} r1 = CONSTANT(unique string)["p1"] | +| {4} r5 = STREAM DEDUP r4 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | | {4} r5 = STREAM DEDUP r4 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | {4} r5 = STREAM DEDUP r4 | +| {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | {4} r5 = STREAM DEDUP r4 | | {4} r7 = r3 UNION r6 | {4} r3 = STREAM DEDUP r2 | | {4} r7 = r3 UNION r6 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | +| {4} r7 = r3 UNION r6 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | #select | p1 | 1 | {1} r1 = CONSTANT(unique string)["p1"] | 1 | 1 | 0 | 0 | | p1 | 3 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | 2 | 4 | 1 | 1 | +| p1 | 3 | {4} r2 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", toString("p1"), 123, " r1 = SCAN fubar\\n r1" | 2 | 4 | 1 | 1 | | p1 | 5 | {4} r3 = STREAM DEDUP r2 | 3 | 4 | 0 | 1 | | p1 | 6 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | 4 | 4 | 1 | 1 | +| p1 | 6 | {4} r4 = JOIN r1 WITH raparser#d14bb8db::TestPredicate#b ON FIRST 1 OUTPUT "p1", "(no string representation)", 123, " r1 = SCAN fubar\\n r1" | 4 | 4 | 1 | 1 | | p1 | 7 | {4} r5 = STREAM DEDUP r4 | 5 | 4 | 0 | 1 | | p1 | 8 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | 6 | 4 | 1 | 1 | +| p1 | 8 | {4} r6 = r5 AND NOT project##select#query#ffff#nullary({}) | 6 | 4 | 1 | 1 | | p1 | 9 | {4} r7 = r3 UNION r6 | 7 | 4 | 0 | 2 | From 1f40518c78b6911a1c9d3cb16cc99f48c99e0b08 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 23 Feb 2023 22:39:20 +0000 Subject: [PATCH 401/415] QL: Fixup the join-order query. --- .../src/queries/performance/LargeJoinOrder.ql | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index 4338d06ae36..c0cc6b4a0c9 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -82,11 +82,10 @@ predicate hasDuplication(ComputeRecursive recursive, string ordering, int i, flo ) } -// ----- /** - * Holds if the bucket `bucket` has `resultSize` resultSize in the `iteration`'th iteration. + * Holds if the ordering `ordering` has `resultSize` resultSize in the `iteration`'th iteration. * - * For example, the "base" bucket in iteration 0 has size 42. + * For example, the "base" ordering in iteration 0 has size 42. */ private predicate hasResultSize( ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, float resultSize @@ -130,9 +129,9 @@ int getSize(ComputeRecursive recursive, string predicateName, int iteration, TDe kind = TCurrent() and i = iteration | - result = getInLayerEventWithName(recursive, predicateName).getDeltaSize(iteration - 1) + result = getInLayerEventWithName(recursive, predicateName).getDeltaSize(i) or - not exists(getInLayerEventWithName(recursive, predicateName).getDeltaSize(iteration - 1)) and + not exists(getInLayerEventWithName(recursive, predicateName).getDeltaSize(i)) and result = 0 ) } @@ -155,35 +154,35 @@ private predicate isDelta(string predicateName, TDeltaKind kind, string withoutS withoutSuffix = predicateName.regexpCapture("(.+)#cur_delta", 1) } -predicate hasDependentPredicateSizeInBucket( - ComputeRecursive recursive, string bucket, SummaryEvent inLayer, int iteration, +predicate hasDependentPredicateSize( + ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, string predicateName, float size ) { exists( | inLayer = firstPredicate(recursive) and - bucket = inLayer.getPipelineRuns().getRun(iteration).getRAReference() + ordering = inLayer.getPipelineRuns().getRun(iteration).getRAReference() | // We treat iteration 0 as a non-recursive case - if bucket = "base" + if ordering = "base" then size = getDependencyWithName(recursive.getDependencies(), predicateName).getResultSize() else exists(TDeltaKind kind | size = getSize(recursive, predicateName, iteration, kind) and - isDelta(getAnRaOperation(inLayer, bucket).getARhsPredicate(), kind, predicateName) + isDelta(getAnRaOperation(inLayer, ordering).getARhsPredicate(), kind, predicateName) ) ) or exists(SummaryEvent inLayer0, float size0 | successor(recursive, inLayer0, inLayer) and - hasDependentPredicateSizeInBucket(recursive, bucket, inLayer0, iteration, predicateName, size0) + hasDependentPredicateSize(recursive, ordering, inLayer0, iteration, predicateName, size0) | // We treat iteration 0 as a non-recursive case - if bucket = "base" + if ordering = "base" then size = getDependencyWithName(recursive.getDependencies(), predicateName).getResultSize() else exists(TDeltaKind kind | size = getSize(recursive, predicateName, iteration, kind) + size0 and - isDelta(getAnRaOperation(inLayer, bucket).getARhsPredicate(), kind, predicateName) + isDelta(getAnRaOperation(inLayer, ordering).getARhsPredicate(), kind, predicateName) ) ) } @@ -192,13 +191,13 @@ SummaryEvent getInLayerOrRecursive(ComputeRecursive recursive) { result = recursive or result.(InLayer).getComputeRecursiveEvent() = recursive } -predicate hasDependentPredicateSizeInBucket( - ComputeRecursive recursive, string bucket, string predicateName, float size +predicate hasDependentPredicateSize( + ComputeRecursive recursive, string ordering, string predicateName, float size ) { size = strictsum(SummaryEvent inLayer, int iteration, int s | inLayer = getInLayerOrRecursive(recursive) and - hasDependentPredicateSizeInBucket(recursive, bucket, inLayer, iteration, predicateName, s) + hasDependentPredicateSize(recursive, ordering, inLayer, iteration, predicateName, s) | s ) @@ -216,12 +215,12 @@ predicate hasDependentPredicateSizeInBucket( * - For a non-"base" ordering, it's defined as any `#prev_delta` or `#cur_delta` predicates * that appear in the pipeline. */ -float getRecursiveBadness(ComputeRecursive recursive, string bucket) { +float getRecursiveBadness(ComputeRecursive recursive, string ordering) { exists(float maxTupleCount, float resultSize, float maxDependentPredicateSize | - maxTupleCount = max(float tc | hasTupleCount(recursive, bucket, _, tc) | tc) and - hasResultSize(recursive, bucket, resultSize) and + maxTupleCount = max(float tc | hasTupleCount(recursive, ordering, _, tc) | tc) and + hasResultSize(recursive, ordering, resultSize) and maxDependentPredicateSize = - max(float size | hasDependentPredicateSizeInBucket(recursive, bucket, _, size) | size) and + max(float size | hasDependentPredicateSize(recursive, ordering, _, size) | size) and resultSize.maximum(maxDependentPredicateSize) > 0 and result = maxTupleCount / resultSize.maximum(maxDependentPredicateSize) ) @@ -259,9 +258,9 @@ where badness = getNonRecursiveBadness(evt) and extractSimpleInformation(evt, predicateName, index, tupleCount, duplicationPercentage, operation) or - exists(string bucket | - badness = getRecursiveBadness(evt, bucket) and - extractRecursiveInformation(evt, predicateName, bucket, index, tupleCount, + exists(string ordering | + badness = getRecursiveBadness(evt, ordering) and + extractRecursiveInformation(evt, predicateName, ordering, index, tupleCount, duplicationPercentage, operation) ) ) From 10aad99e21602fa4f1a263f5b50411d0872e585a Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Fri, 24 Feb 2023 11:02:07 +0000 Subject: [PATCH 402/415] Add avg case --- ql/ql/src/queries/bugs/SumWithoutDomain.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/ql/src/queries/bugs/SumWithoutDomain.ql b/ql/ql/src/queries/bugs/SumWithoutDomain.ql index 150f075504e..841f2ab3cb0 100644 --- a/ql/ql/src/queries/bugs/SumWithoutDomain.ql +++ b/ql/ql/src/queries/bugs/SumWithoutDomain.ql @@ -11,6 +11,6 @@ import ql from ExprAggregate agg -where agg.getKind() = ["sum", "strictsum"] +where agg.getKind() = ["sum", "strictsum", "avg"] select agg, "This " + agg.getKind() + " does not have a domain argument, so may produce surprising results." From 375de59a148516b6e8180f14070367ea531e5064 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 24 Feb 2023 12:07:15 +0000 Subject: [PATCH 403/415] QL: More fixes to the join-order query. --- .../src/queries/performance/LargeJoinOrder.ql | 140 +++++++++++------- 1 file changed, 83 insertions(+), 57 deletions(-) diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index c0cc6b4a0c9..f07fd76474f 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -30,16 +30,16 @@ predicate hasTupleCount( float tupleCount ) { inLayer = firstPredicate(recursive) and - exists(PipeLineRun run | run = inLayer.getPipelineRuns().getRun(iteration) | - ordering = run.getRAReference() and + exists(PipeLineRun run | + run = inLayer.getPipelineRuns().getRun(iteration) and ordering = run.getRAReference() + | tupleCount = run.getCount(i) - ) - or - exists(SummaryEvent inLayer0, float tupleCount0, PipeLineRun run | - run = inLayer.getPipelineRuns().getRun(pragma[only_bind_into](iteration)) and - successor(recursive, inLayer0, inLayer) and - hasTupleCount(recursive, ordering, inLayer0, pragma[only_bind_into](iteration), i, tupleCount0) and - tupleCount = run.getCount(i) + tupleCount0 + or + exists(SummaryEvent inLayer0, float tupleCount0 | + successor(recursive, inLayer0, inLayer) and + hasTupleCount(recursive, ordering, inLayer0, pragma[only_bind_into](iteration), i, tupleCount0) and + tupleCount = run.getCount(i) + tupleCount0 + ) ) } @@ -58,17 +58,19 @@ predicate hasDuplication( ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, int i, float duplication ) { - inLayer = firstPredicate(recursive) and - exists(PipeLineRun run | run = inLayer.getPipelineRuns().getRun(iteration) | - ordering = run.getRAReference() and + exists(PipeLineRun run | + run = inLayer.getPipelineRuns().getRun(iteration) and + ordering = run.getRAReference() + | + inLayer = firstPredicate(recursive) and duplication = run.getDuplicationPercentage(i) - ) - or - exists(SummaryEvent inLayer0, float duplication0, PipeLineRun run | - run = inLayer.getPipelineRuns().getRun(pragma[only_bind_into](iteration)) and - successor(recursive, inLayer0, inLayer) and - hasDuplication(recursive, ordering, inLayer0, pragma[only_bind_into](iteration), i, duplication0) and - duplication = run.getDuplicationPercentage(i).maximum(duplication0) + or + exists(SummaryEvent inLayer0, float duplication0 | + successor(recursive, inLayer0, inLayer) and + hasDuplication(recursive, ordering, inLayer0, pragma[only_bind_into](iteration), i, + duplication0) and + duplication = run.getDuplicationPercentage(i).maximum(duplication0) + ) ) } @@ -90,14 +92,18 @@ predicate hasDuplication(ComputeRecursive recursive, string ordering, int i, flo private predicate hasResultSize( ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, float resultSize ) { - inLayer = firstPredicate(recursive) and - ordering = inLayer.getPipelineRuns().getRun(iteration).getRAReference() and - resultSize = inLayer.getDeltaSize(iteration) - or - exists(SummaryEvent inLayer0, int resultSize0 | - successor(recursive, inLayer0, inLayer) and - hasResultSize(recursive, ordering, inLayer0, iteration, resultSize0) and - resultSize = inLayer.getDeltaSize(iteration) + resultSize0 + exists(PipeLineRun run | + run = inLayer.getPipelineRuns().getRun(iteration) and + ordering = run.getRAReference() + | + inLayer = firstPredicate(recursive) and + resultSize = inLayer.getDeltaSize(iteration) + or + exists(SummaryEvent inLayer0, int resultSize0 | + successor(recursive, inLayer0, inLayer) and + hasResultSize(recursive, ordering, inLayer0, iteration, resultSize0) and + resultSize = inLayer.getDeltaSize(iteration) + resultSize0 + ) ) } @@ -122,17 +128,20 @@ SummaryEvent getInLayerEventWithName(ComputeRecursive recursive, string predicat bindingset[predicateName, iteration] int getSize(ComputeRecursive recursive, string predicateName, int iteration, TDeltaKind kind) { - exists(int i | + exists(int i, SummaryEvent event | kind = TPrevious() and i = iteration - 1 or kind = TCurrent() and i = iteration | - result = getInLayerEventWithName(recursive, predicateName).getDeltaSize(i) - or - not exists(getInLayerEventWithName(recursive, predicateName).getDeltaSize(i)) and - result = 0 + event = getInLayerEventWithName(recursive, predicateName) and + ( + result = event.getDeltaSize(i) + or + not exists(event.getDeltaSize(i)) and + result = 0 + ) ) } @@ -154,36 +163,53 @@ private predicate isDelta(string predicateName, TDeltaKind kind, string withoutS withoutSuffix = predicateName.regexpCapture("(.+)#cur_delta", 1) } +bindingset[iteration] +float getRecursiveDependencySize( + ComputeRecursive recursive, string predicateName, int iteration, SummaryEvent inLayer, + string ordering, TDeltaKind kind +) { + result = getSize(recursive, predicateName, iteration, kind) and + isDelta(getAnRaOperation(inLayer, ordering).getARhsPredicate(), kind, predicateName) +} + +bindingset[ordering, iteration] +predicate hasDependentPredicateSizeImpl( + ComputeRecursive recursive, string ordering, float size, string predicateName, int iteration, + SummaryEvent inLayer +) { + // We treat the base case as a non-recursive case + if ordering = "base" + then + size = + [ + getDependencyWithName(recursive.getDependencies(), predicateName).getResultSize(), + getRecursiveDependencySize(recursive, predicateName, iteration, inLayer, ordering, + TCurrent()) + ] + else + size = + getRecursiveDependencySize(recursive, predicateName, iteration, inLayer, ordering, TPrevious()) +} + +pragma[nomagic] predicate hasDependentPredicateSize( ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, string predicateName, float size ) { - exists( | + exists(PipeLineRun run | + run = inLayer.getPipelineRuns().getRun(pragma[only_bind_into](iteration)) and + ordering = run.getRAReference() + | inLayer = firstPredicate(recursive) and - ordering = inLayer.getPipelineRuns().getRun(iteration).getRAReference() - | - // We treat iteration 0 as a non-recursive case - if ordering = "base" - then size = getDependencyWithName(recursive.getDependencies(), predicateName).getResultSize() - else - exists(TDeltaKind kind | - size = getSize(recursive, predicateName, iteration, kind) and - isDelta(getAnRaOperation(inLayer, ordering).getARhsPredicate(), kind, predicateName) - ) - ) - or - exists(SummaryEvent inLayer0, float size0 | - successor(recursive, inLayer0, inLayer) and - hasDependentPredicateSize(recursive, ordering, inLayer0, iteration, predicateName, size0) - | - // We treat iteration 0 as a non-recursive case - if ordering = "base" - then size = getDependencyWithName(recursive.getDependencies(), predicateName).getResultSize() - else - exists(TDeltaKind kind | - size = getSize(recursive, predicateName, iteration, kind) + size0 and - isDelta(getAnRaOperation(inLayer, ordering).getARhsPredicate(), kind, predicateName) - ) + hasDependentPredicateSizeImpl(recursive, ordering, size, predicateName, iteration, inLayer) + or + exists(SummaryEvent inLayer0, float size0, float size1 | + successor(recursive, inLayer0, inLayer) and + hasDependentPredicateSize(recursive, ordering, inLayer0, pragma[only_bind_into](iteration), + predicateName, size0) and + hasDependentPredicateSizeImpl(recursive, ordering, size1, predicateName, iteration, inLayer) and + size = size0 + size1 + ) ) } From c9f8ebd62064ef7f0ea04366ecc2698615dbbf18 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 24 Feb 2023 13:19:52 +0000 Subject: [PATCH 404/415] QL: Remove redundant conjunct in aggregates. --- .../src/queries/performance/LargeJoinOrder.ql | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/ql/ql/src/queries/performance/LargeJoinOrder.ql b/ql/ql/src/queries/performance/LargeJoinOrder.ql index f07fd76474f..35bbdd4eb9c 100644 --- a/ql/ql/src/queries/performance/LargeJoinOrder.ql +++ b/ql/ql/src/queries/performance/LargeJoinOrder.ql @@ -76,18 +76,11 @@ predicate hasDuplication( predicate hasDuplication(ComputeRecursive recursive, string ordering, int i, float duplication) { duplication = - max(SummaryEvent inLayer, int iteration, int dup | - inLayer = getInLayerOrRecursive(recursive) and - hasDuplication(recursive, ordering, inLayer, iteration, i, dup) - | - dup - ) + max(int iteration, int dup | hasDuplication(recursive, ordering, _, iteration, i, dup) | dup) } /** * Holds if the ordering `ordering` has `resultSize` resultSize in the `iteration`'th iteration. - * - * For example, the "base" ordering in iteration 0 has size 42. */ private predicate hasResultSize( ComputeRecursive recursive, string ordering, SummaryEvent inLayer, int iteration, float resultSize @@ -109,12 +102,7 @@ private predicate hasResultSize( predicate hasResultSize(ComputeRecursive recursive, string ordering, float resultSize) { resultSize = - strictsum(InLayer inLayer, int iteration, float r | - inLayer.getComputeRecursiveEvent() = recursive and - hasResultSize(recursive, ordering, inLayer, iteration, r) - | - r - ) + strictsum(int iteration, float r | hasResultSize(recursive, ordering, _, iteration, r) | r) } RAParser::RAExpr getAnRaOperation(SummaryEvent inLayer, string ordering) { @@ -221,9 +209,8 @@ predicate hasDependentPredicateSize( ComputeRecursive recursive, string ordering, string predicateName, float size ) { size = - strictsum(SummaryEvent inLayer, int iteration, int s | - inLayer = getInLayerOrRecursive(recursive) and - hasDependentPredicateSize(recursive, ordering, inLayer, iteration, predicateName, s) + strictsum(int iteration, float s | + hasDependentPredicateSize(recursive, ordering, _, iteration, predicateName, s) | s ) From f1d765aa275d9dcd812ba3e2d380ece4d5074ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 24 Feb 2023 18:45:52 +0100 Subject: [PATCH 405/415] Missing taintstep for java.net.URL.toURI() --- java/ql/lib/ext/java.net.model.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/lib/ext/java.net.model.yml b/java/ql/lib/ext/java.net.model.yml index 2c153b37a05..591a1eac708 100644 --- a/java/ql/lib/ext/java.net.model.yml +++ b/java/ql/lib/ext/java.net.model.yml @@ -27,4 +27,5 @@ extensions: - ["java.net", "URI", False, "toString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URI", False, "toURL", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URL", False, "URL", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] + - ["java.net", "URL", False, "toURI", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URLDecoder", False, "decode", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] From f393a3c549be0115e43698947ac3b28e04ff45bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 24 Feb 2023 18:50:31 +0100 Subject: [PATCH 406/415] Add toExternalForm --- java/ql/lib/ext/java.net.model.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/lib/ext/java.net.model.yml b/java/ql/lib/ext/java.net.model.yml index 591a1eac708..906c6d7aa3d 100644 --- a/java/ql/lib/ext/java.net.model.yml +++ b/java/ql/lib/ext/java.net.model.yml @@ -27,5 +27,6 @@ extensions: - ["java.net", "URI", False, "toString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URI", False, "toURL", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URL", False, "URL", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] - - ["java.net", "URL", False, "toURI", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"] + - ["java.net", "URL", False, "toURI", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] + - ["java.net", "URL", False, "toExternalForm", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URLDecoder", False, "decode", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] From 4a9f63ea1a6103bd4dbf1937e8c642e9f664ed67 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 27 Feb 2023 09:32:42 +0100 Subject: [PATCH 407/415] Fix toASCIIString casing --- java/ql/lib/ext/java.net.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/lib/ext/java.net.model.yml b/java/ql/lib/ext/java.net.model.yml index 906c6d7aa3d..1ee1c96347f 100644 --- a/java/ql/lib/ext/java.net.model.yml +++ b/java/ql/lib/ext/java.net.model.yml @@ -23,7 +23,7 @@ extensions: data: - ["java.net", "URI", False, "URI", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] - ["java.net", "URI", False, "create", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["java.net", "URI", False, "toAsciiString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] + - ["java.net", "URI", False, "toASCIIString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URI", False, "toString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URI", False, "toURL", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] - ["java.net", "URL", False, "URL", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"] From c027e10ef7c67aa34bb5d52dc88f18b428503add Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 27 Feb 2023 09:33:16 +0100 Subject: [PATCH 408/415] Add java.net tests --- .../frameworks/jdk/java.net/Test.java | 99 +++++++++++++++++++ .../frameworks/jdk/java.net/test.expected | 0 .../frameworks/jdk/java.net/test.ql | 2 + 3 files changed, 101 insertions(+) create mode 100644 java/ql/test/library-tests/frameworks/jdk/java.net/Test.java create mode 100644 java/ql/test/library-tests/frameworks/jdk/java.net/test.expected create mode 100644 java/ql/test/library-tests/frameworks/jdk/java.net/test.ql diff --git a/java/ql/test/library-tests/frameworks/jdk/java.net/Test.java b/java/ql/test/library-tests/frameworks/jdk/java.net/Test.java new file mode 100644 index 00000000000..866a6bd77d3 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/jdk/java.net/Test.java @@ -0,0 +1,99 @@ +package generatedtest; + +import java.net.URI; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.Charset; + +// Test case generated by GenerateFlowTestCase.ql +public class Test { + + Object source() { + return null; + } + + void sink(Object o) {} + + public void test() throws Exception { + + { + // "java.net;URI;false;URI;(String);;Argument[0];Argument[-1];taint;manual" + URI out = null; + String in = (String) source(); + out = new URI(in); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URI;false;create;;;Argument[0];ReturnValue;taint;manual" + URI out = null; + String in = (String) source(); + out = URI.create(in); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URI;false;toASCIIString;;;Argument[-1];ReturnValue;taint;manual" + String out = null; + URI in = (URI) source(); + out = in.toASCIIString(); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URI;false;toString;;;Argument[-1];ReturnValue;taint;manual" + String out = null; + URI in = (URI) source(); + out = in.toString(); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URI;false;toURL;;;Argument[-1];ReturnValue;taint;manual" + URL out = null; + URI in = (URI) source(); + out = in.toURL(); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URL;false;URL;(String);;Argument[0];Argument[-1];taint;manual" + URL out = null; + String in = (String) source(); + out = new URL(in); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URL;false;toExternalForm;;;Argument[-1];ReturnValue;taint;manual" + String out = null; + URL in = (URL) source(); + out = in.toExternalForm(); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URL;false;toURI;;;Argument[-1];ReturnValue;taint;manual" + URI out = null; + URL in = (URL) source(); + out = in.toURI(); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URLDecoder;false;decode;;;Argument[0];ReturnValue;taint;manual" + String out = null; + String in = (String) source(); + out = URLDecoder.decode(in); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URLDecoder;false;decode;;;Argument[0];ReturnValue;taint;manual" + String out = null; + String in = (String) source(); + out = URLDecoder.decode(in, (Charset) null); + sink(out); // $ hasTaintFlow + } + { + // "java.net;URLDecoder;false;decode;;;Argument[0];ReturnValue;taint;manual" + String out = null; + String in = (String) source(); + out = URLDecoder.decode(in, (String) null); + sink(out); // $ hasTaintFlow + } + + } + +} diff --git a/java/ql/test/library-tests/frameworks/jdk/java.net/test.expected b/java/ql/test/library-tests/frameworks/jdk/java.net/test.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/library-tests/frameworks/jdk/java.net/test.ql b/java/ql/test/library-tests/frameworks/jdk/java.net/test.ql new file mode 100644 index 00000000000..5d91e4e8e26 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/jdk/java.net/test.ql @@ -0,0 +1,2 @@ +import java +import TestUtilities.InlineFlowTest From e4627cb702bfd88e410dcd50dccae3a2c3015774 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Tue, 21 Feb 2023 14:25:59 +0100 Subject: [PATCH 409/415] Swift: make `codegen` a bit more language-agnostic --- swift/codegen/codegen.py | 55 ++++++++------ swift/codegen/generators/dbschemegen.py | 8 +-- swift/codegen/generators/qlgen.py | 10 +-- swift/codegen/lib/paths.py | 10 +-- swift/codegen/lib/render.py | 19 ++--- swift/codegen/test/test_qlgen.py | 10 +-- swift/codegen/test/test_render.py | 96 ++++++++++++------------- swift/codegen/test/utils.py | 4 +- 8 files changed, 114 insertions(+), 98 deletions(-) diff --git a/swift/codegen/codegen.py b/swift/codegen/codegen.py index f9c85ce6049..24f1646544f 100755 --- a/swift/codegen/codegen.py +++ b/swift/codegen/codegen.py @@ -24,31 +24,44 @@ def _parse_args() -> argparse.Namespace: "and cpp") p.add_argument("--verbose", "-v", action="store_true", help="print more information") p.add_argument("--quiet", "-q", action="store_true", help="only print errors") - p.add_argument("--swift-dir", type=_abspath, default=paths.swift_dir, - help="the directory that should be regarded as the root of the swift codebase. Used to compute QL " - "imports and in some comments (default %(default)s)") - p.add_argument("--schema", type=_abspath, default=paths.swift_dir / "schema.py", - help="input schema file (default %(default)s)") - p.add_argument("--dbscheme", type=_abspath, default=paths.swift_dir / "ql/lib/swift.dbscheme", - help="output file for dbscheme generation, input file for trap generation (default %(default)s)") - p.add_argument("--ql-output", type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/generated", - help="output directory for generated QL files (default %(default)s)") - p.add_argument("--ql-stub-output", type=_abspath, default=paths.swift_dir / "ql/lib/codeql/swift/elements", - help="output directory for QL stub/customization files (default %(default)s). Defines also the " - "generated qll file importing every class file") - p.add_argument("--ql-test-output", type=_abspath, default=paths.swift_dir / "ql/test/extractor-tests/generated", - help="output directory for QL generated extractor test files (default %(default)s)") + p.add_argument("--root-dir", type=_abspath, default=paths.root_dir, + help="the directory that should be regarded as the root of the language pack codebase. Used to" + "compute QL imports and in some comments and as root for relative paths provided as options " + "(default %(default)s)") + p.add_argument("--language", default=paths.root_dir.name, + help="string that should replace {language} in other provided options") + path_arguments = [ + p.add_argument("--schema", default="schema.py", + help="input schema file (default %(default)s)"), + p.add_argument("--dbscheme", default="ql/lib/{language}.dbscheme", + help="output file for dbscheme generation, input file for trap generation (default " + "%(default)s)"), + p.add_argument("--ql-output", default="ql/lib/codeql/{language}/generated", + help="output directory for generated QL files (default %(default)s)"), + p.add_argument("--ql-stub-output", default="ql/lib/codeql/{language}/elements", + help="output directory for QL stub/customization files (default %(default)s). Defines also the " + "generated qll file importing every class file"), + p.add_argument("--ql-test-output", default="ql/test/extractor-tests/generated", + help="output directory for QL generated extractor test files (default %(default)s)"), + p.add_argument("--cpp-output", + help="output directory for generated C++ files, required if trap or cpp is provided to " + "--generate"), + p.add_argument("--generated-registry", default="ql/.generated.list", + help="registry file containing information about checked-in generated code"), + ] p.add_argument("--ql-format", action="store_true", default=True, help="use codeql to autoformat QL files (which is the default)") p.add_argument("--no-ql-format", action="store_false", dest="ql_format", help="do not format QL files") p.add_argument("--codeql-binary", default="codeql", help="command to use for QL formatting (default %(default)s)") - p.add_argument("--cpp-output", type=_abspath, - help="output directory for generated C++ files, required if trap or cpp is provided to --generate") - p.add_argument("--generated-registry", type=_abspath, default=paths.swift_dir / "ql/.generated.list", - help="registry file containing information about checked-in generated code") p.add_argument("--force", "-f", action="store_true", - help="generate all files without skipping unchanged files and overwriting modified ones") - return p.parse_args() + help="generate all files without skipping unchanged files and overwriting modified ones"), + opts = p.parse_args() + # absolutize all paths relative to --root-dir + for arg in path_arguments: + path = getattr(opts, arg.dest) + if path is not None: + setattr(opts, arg.dest, opts.root_dir / path.format(language=opts.language)) + return opts def _abspath(x: str) -> typing.Optional[pathlib.Path]: @@ -65,7 +78,7 @@ def run(): log_level = logging.INFO logging.basicConfig(format="{levelname} {message}", style='{', level=log_level) for target in opts.generate: - generate(target, opts, render.Renderer(opts.swift_dir)) + generate(target, opts, render.Renderer(opts.root_dir)) if __name__ == "__main__": diff --git a/swift/codegen/generators/dbschemegen.py b/swift/codegen/generators/dbschemegen.py index fe7681b3b47..23591a41606 100755 --- a/swift/codegen/generators/dbschemegen.py +++ b/swift/codegen/generators/dbschemegen.py @@ -110,12 +110,12 @@ def get_declarations(data: schema.Schema): return declarations -def get_includes(data: schema.Schema, include_dir: pathlib.Path, swift_dir: pathlib.Path): +def get_includes(data: schema.Schema, include_dir: pathlib.Path, root_dir: pathlib.Path): includes = [] for inc in data.includes: inc = include_dir / inc with open(inc) as inclusion: - includes.append(SchemeInclude(src=inc.relative_to(swift_dir), data=inclusion.read())) + includes.append(SchemeInclude(src=inc.relative_to(root_dir), data=inclusion.read())) return includes @@ -125,8 +125,8 @@ def generate(opts, renderer): data = schemaloader.load_file(input) - dbscheme = Scheme(src=input.relative_to(opts.swift_dir), - includes=get_includes(data, include_dir=input.parent, swift_dir=opts.swift_dir), + dbscheme = Scheme(src=input.relative_to(opts.root_dir), + includes=get_includes(data, include_dir=input.parent, root_dir=opts.root_dir), declarations=get_declarations(data)) renderer.render(dbscheme, out) diff --git a/swift/codegen/generators/qlgen.py b/swift/codegen/generators/qlgen.py index c6d285148fd..e7730938d7f 100755 --- a/swift/codegen/generators/qlgen.py +++ b/swift/codegen/generators/qlgen.py @@ -198,8 +198,8 @@ def get_ql_ipa_class(cls: schema.Class): return get_ql_ipa_class_db(cls.name) -def get_import(file: pathlib.Path, swift_dir: pathlib.Path): - stem = file.relative_to(swift_dir / "ql/lib").with_suffix("") +def get_import(file: pathlib.Path, root_dir: pathlib.Path): + stem = file.relative_to(root_dir / "ql/lib").with_suffix("") return str(stem).replace("/", ".") @@ -344,7 +344,7 @@ def generate(opts, renderer): classes_by_dir_and_name = sorted(classes.values(), key=lambda cls: (cls.dir, cls.name)) for c in classes_by_dir_and_name: - imports[c.name] = get_import(stub_out / c.path, opts.swift_dir) + imports[c.name] = get_import(stub_out / c.path, opts.root_dir) for c in classes.values(): qll = out / c.path.with_suffix(".qll") @@ -355,7 +355,7 @@ def generate(opts, renderer): path = _get_path(c) stub_file = stub_out / path if not renderer.is_customized_stub(stub_file): - base_import = get_import(out / path, opts.swift_dir) + base_import = get_import(out / path, opts.root_dir) renderer.render(_get_stub(c, base_import), stub_file) # for example path/to/elements -> path/to/elements.qll @@ -404,7 +404,7 @@ def generate(opts, renderer): if not renderer.is_customized_stub(stub_file): # stub rendering must be postponed as we might not have yet all subtracted ipa types in `ipa_type` stubs[stub_file] = ql.Synth.ConstructorStub(ipa_type) - constructor_import = get_import(stub_file, opts.swift_dir) + constructor_import = get_import(stub_file, opts.root_dir) constructor_imports.append(constructor_import) if ipa_type.is_ipa: ipa_constructor_imports.append(constructor_import) diff --git a/swift/codegen/lib/paths.py b/swift/codegen/lib/paths.py index 2ad1284b17b..eae5192c0d9 100644 --- a/swift/codegen/lib/paths.py +++ b/swift/codegen/lib/paths.py @@ -6,13 +6,13 @@ import os try: workspace_dir = pathlib.Path(os.environ['BUILD_WORKSPACE_DIRECTORY']).resolve() # <- means we are using bazel run - swift_dir = workspace_dir / 'swift' + root_dir = workspace_dir / 'swift' except KeyError: _this_file = pathlib.Path(__file__).resolve() - swift_dir = _this_file.parents[2] - workspace_dir = swift_dir.parent + root_dir = _this_file.parents[2] + workspace_dir = root_dir.parent -lib_dir = swift_dir / 'codegen' / 'lib' -templates_dir = swift_dir / 'codegen' / 'templates' +lib_dir = root_dir / 'codegen' / 'lib' +templates_dir = root_dir / 'codegen' / 'templates' exe_file = pathlib.Path(sys.argv[0]).resolve() diff --git a/swift/codegen/lib/render.py b/swift/codegen/lib/render.py index 06f62d54263..5f710837151 100644 --- a/swift/codegen/lib/render.py +++ b/swift/codegen/lib/render.py @@ -25,13 +25,16 @@ class Error(Exception): class Renderer: """ Template renderer using mustache templates in the `templates` directory """ - def __init__(self, swift_dir: pathlib.Path): + def __init__(self, root_dir: pathlib.Path): self._r = pystache.Renderer(search_dirs=str(paths.templates_dir), escape=lambda u: u) - self._swift_dir = swift_dir - self._generator = self._get_path(paths.exe_file) + self._root_dir = root_dir + try: + self._generator = self._get_path(paths.exe_file) + except ValueError: + self._generator = paths.exe_file.name def _get_path(self, file: pathlib.Path): - return file.relative_to(self._swift_dir) + return file.relative_to(self._root_dir) def render(self, data: object, output: pathlib.Path): """ Render `data` to `output`. @@ -60,7 +63,7 @@ class Renderer: def manage(self, generated: typing.Iterable[pathlib.Path], stubs: typing.Iterable[pathlib.Path], registry: pathlib.Path, force: bool = False) -> "RenderManager": - return RenderManager(self._swift_dir, generated, stubs, registry, force) + return RenderManager(self._root_dir, generated, stubs, registry, force) class RenderManager(Renderer): @@ -85,10 +88,10 @@ class RenderManager(Renderer): pre: str post: typing.Optional[str] = None - def __init__(self, swift_dir: pathlib.Path, generated: typing.Iterable[pathlib.Path], + def __init__(self, root_dir: pathlib.Path, generated: typing.Iterable[pathlib.Path], stubs: typing.Iterable[pathlib.Path], registry: pathlib.Path, force: bool = False): - super().__init__(swift_dir) + super().__init__(root_dir) self._registry_path = registry self._force = force self._hashes = {} @@ -117,7 +120,7 @@ class RenderManager(Renderer): self._hashes.pop(self._get_path(f), None) # clean up the registry from files that do not exist any more for f in list(self._hashes): - if not (self._swift_dir / f).exists(): + if not (self._root_dir / f).exists(): self._hashes.pop(f) self._dump_registry() diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index 02c9247509a..c0bbc9a9f73 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -17,16 +17,16 @@ def run_mock(): # these are lambdas so that they will use patched paths when called -def stub_path(): return paths.swift_dir / "ql/lib/stub/path" +def stub_path(): return paths.root_dir / "ql/lib/stub/path" -def ql_output_path(): return paths.swift_dir / "ql/lib/other/path" +def ql_output_path(): return paths.root_dir / "ql/lib/other/path" -def ql_test_output_path(): return paths.swift_dir / "ql/test/path" +def ql_test_output_path(): return paths.root_dir / "ql/test/path" -def generated_registry_path(): return paths.swift_dir / "registry.list" +def generated_registry_path(): return paths.root_dir / "registry.list" def import_file(): return stub_path().with_suffix(".qll") @@ -47,7 +47,7 @@ def qlgen_opts(opts): opts.ql_test_output = ql_test_output_path() opts.generated_registry = generated_registry_path() opts.ql_format = True - opts.swift_dir = paths.swift_dir + opts.root_dir = paths.root_dir opts.force = False return opts diff --git a/swift/codegen/test/test_render.py b/swift/codegen/test/test_render.py index 64a3c6eb831..2e569c258b7 100644 --- a/swift/codegen/test/test_render.py +++ b/swift/codegen/test/test_render.py @@ -22,7 +22,7 @@ def pystache_renderer(pystache_renderer_cls): @pytest.fixture def sut(pystache_renderer): - return render.Renderer(paths.swift_dir) + return render.Renderer(paths.root_dir) def assert_file(file, text): @@ -48,12 +48,12 @@ def test_render(pystache_renderer, sut): data = mock.Mock(spec=("template",)) text = "some text" pystache_renderer.render_name.side_effect = (text,) - output = paths.swift_dir / "some/output.txt" + output = paths.root_dir / "some/output.txt" sut.render(data, output) assert_file(output, text) assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] @@ -61,8 +61,8 @@ def test_managed_render(pystache_renderer, sut): data = mock.Mock(spec=("template",)) text = "some text" pystache_renderer.render_name.side_effect = (text,) - output = paths.swift_dir / "some/output.txt" - registry = paths.swift_dir / "a/registry.list" + output = paths.root_dir / "some/output.txt" + registry = paths.root_dir / "a/registry.list" write(registry) with sut.manage(generated=(), stubs=(), registry=registry) as renderer: @@ -72,7 +72,7 @@ def test_managed_render(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(text)} {hash(text)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] @@ -80,8 +80,8 @@ def test_managed_render_with_no_registry(pystache_renderer, sut): data = mock.Mock(spec=("template",)) text = "some text" pystache_renderer.render_name.side_effect = (text,) - output = paths.swift_dir / "some/output.txt" - registry = paths.swift_dir / "a/registry.list" + output = paths.root_dir / "some/output.txt" + registry = paths.root_dir / "a/registry.list" with sut.manage(generated=(), stubs=(), registry=registry) as renderer: renderer.render(data, output) @@ -90,7 +90,7 @@ def test_managed_render_with_no_registry(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(text)} {hash(text)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] @@ -99,8 +99,8 @@ def test_managed_render_with_post_processing(pystache_renderer, sut): text = "some text" postprocessed_text = "some other text" pystache_renderer.render_name.side_effect = (text,) - output = paths.swift_dir / "some/output.txt" - registry = paths.swift_dir / "a/registry.list" + output = paths.root_dir / "some/output.txt" + registry = paths.root_dir / "a/registry.list" write(registry) with sut.manage(generated=(), stubs=(), registry=registry) as renderer: @@ -111,14 +111,14 @@ def test_managed_render_with_post_processing(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(text)} {hash(postprocessed_text)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] def test_managed_render_with_erasing(pystache_renderer, sut): - output = paths.swift_dir / "some/output.txt" - stub = paths.swift_dir / "some/stub.txt" - registry = paths.swift_dir / "a/registry.list" + output = paths.root_dir / "some/output.txt" + stub = paths.root_dir / "some/stub.txt" + registry = paths.root_dir / "a/registry.list" write(output) write(stub, "// generated bla bla") write(registry) @@ -134,9 +134,9 @@ def test_managed_render_with_erasing(pystache_renderer, sut): def test_managed_render_with_skipping_of_generated_file(pystache_renderer, sut): data = mock.Mock(spec=("template",)) - output = paths.swift_dir / "some/output.txt" + output = paths.root_dir / "some/output.txt" some_output = "some output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(output, some_output) write(registry, f"some/output.txt {hash(some_output)} {hash(some_output)}\n") @@ -149,16 +149,16 @@ def test_managed_render_with_skipping_of_generated_file(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(some_output)} {hash(some_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] def test_managed_render_with_skipping_of_stub_file(pystache_renderer, sut): data = mock.Mock(spec=("template",)) - stub = paths.swift_dir / "some/stub.txt" + stub = paths.root_dir / "some/stub.txt" some_output = "// generated some output" some_processed_output = "// generated some processed output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(stub, some_processed_output) write(registry, f"some/stub.txt {hash(some_output)} {hash(some_processed_output)}\n") @@ -171,14 +171,14 @@ def test_managed_render_with_skipping_of_stub_file(pystache_renderer, sut): assert_file(registry, f"some/stub.txt {hash(some_output)} {hash(some_processed_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] def test_managed_render_with_modified_generated_file(pystache_renderer, sut): - output = paths.swift_dir / "some/output.txt" + output = paths.root_dir / "some/output.txt" some_processed_output = "// some processed output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(output, "// something else") write(registry, f"some/output.txt whatever {hash(some_processed_output)}\n") @@ -187,9 +187,9 @@ def test_managed_render_with_modified_generated_file(pystache_renderer, sut): def test_managed_render_with_modified_stub_file_still_marked_as_generated(pystache_renderer, sut): - stub = paths.swift_dir / "some/stub.txt" + stub = paths.root_dir / "some/stub.txt" some_processed_output = "// generated some processed output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(stub, "// generated something else") write(registry, f"some/stub.txt whatever {hash(some_processed_output)}\n") @@ -198,9 +198,9 @@ def test_managed_render_with_modified_stub_file_still_marked_as_generated(pystac def test_managed_render_with_modified_stub_file_not_marked_as_generated(pystache_renderer, sut): - stub = paths.swift_dir / "some/stub.txt" + stub = paths.root_dir / "some/stub.txt" some_processed_output = "// generated some processed output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(stub, "// no more generated") write(registry, f"some/stub.txt whatever {hash(some_processed_output)}\n") @@ -218,11 +218,11 @@ def test_managed_render_exception_drops_written_and_inexsistent_from_registry(py data = mock.Mock(spec=("template",)) text = "some text" pystache_renderer.render_name.side_effect = (text,) - output = paths.swift_dir / "some/output.txt" - registry = paths.swift_dir / "x/registry.list" + output = paths.root_dir / "some/output.txt" + registry = paths.root_dir / "x/registry.list" write(output, text) - write(paths.swift_dir / "a") - write(paths.swift_dir / "c") + write(paths.root_dir / "a") + write(paths.root_dir / "c") write(registry, "a a a\n" f"some/output.txt whatever {hash(text)}\n" "b b b\n" @@ -237,9 +237,9 @@ def test_managed_render_exception_drops_written_and_inexsistent_from_registry(py def test_managed_render_drops_inexsistent_from_registry(pystache_renderer, sut): - registry = paths.swift_dir / "x/registry.list" - write(paths.swift_dir / "a") - write(paths.swift_dir / "c") + registry = paths.root_dir / "x/registry.list" + write(paths.root_dir / "a") + write(paths.root_dir / "c") write(registry, f"a {hash('')} {hash('')}\n" "b b b\n" f"c {hash('')} {hash('')}") @@ -251,9 +251,9 @@ def test_managed_render_drops_inexsistent_from_registry(pystache_renderer, sut): def test_managed_render_exception_does_not_erase(pystache_renderer, sut): - output = paths.swift_dir / "some/output.txt" - stub = paths.swift_dir / "some/stub.txt" - registry = paths.swift_dir / "a/registry.list" + output = paths.root_dir / "some/output.txt" + stub = paths.root_dir / "some/stub.txt" + registry = paths.root_dir / "a/registry.list" write(output) write(stub, "// generated bla bla") write(registry) @@ -277,7 +277,7 @@ def test_render_with_extensions(pystache_renderer, sut): sut.render(data, output) expected_templates = ["test_template_foo", "test_template_bar", "test_template_baz"] assert pystache_renderer.mock_calls == [ - mock.call.render_name(t, data, generator=paths.exe_file.relative_to(paths.swift_dir)) + mock.call.render_name(t, data, generator=paths.exe_file.relative_to(paths.root_dir)) for t in expected_templates ] for expected_output, expected_contents in zip(expected_outputs, rendered): @@ -286,9 +286,9 @@ def test_render_with_extensions(pystache_renderer, sut): def test_managed_render_with_force_not_skipping_generated_file(pystache_renderer, sut): data = mock.Mock(spec=("template",)) - output = paths.swift_dir / "some/output.txt" + output = paths.root_dir / "some/output.txt" some_output = "some output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(output, some_output) write(registry, f"some/output.txt {hash(some_output)} {hash(some_output)}\n") @@ -301,16 +301,16 @@ def test_managed_render_with_force_not_skipping_generated_file(pystache_renderer assert_file(registry, f"some/output.txt {hash(some_output)} {hash(some_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] def test_managed_render_with_force_not_skipping_stub_file(pystache_renderer, sut): data = mock.Mock(spec=("template",)) - stub = paths.swift_dir / "some/stub.txt" + stub = paths.root_dir / "some/stub.txt" some_output = "// generated some output" some_processed_output = "// generated some processed output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(stub, some_processed_output) write(registry, f"some/stub.txt {hash(some_output)} {hash(some_processed_output)}\n") @@ -323,14 +323,14 @@ def test_managed_render_with_force_not_skipping_stub_file(pystache_renderer, sut assert_file(registry, f"some/stub.txt {hash(some_output)} {hash(some_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.swift_dir)), + mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), ] def test_managed_render_with_force_ignores_modified_generated_file(sut): - output = paths.swift_dir / "some/output.txt" + output = paths.root_dir / "some/output.txt" some_processed_output = "// some processed output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(output, "// something else") write(registry, f"some/output.txt whatever {hash(some_processed_output)}\n") @@ -339,9 +339,9 @@ def test_managed_render_with_force_ignores_modified_generated_file(sut): def test_managed_render_with_force_ignores_modified_stub_file_still_marked_as_generated(sut): - stub = paths.swift_dir / "some/stub.txt" + stub = paths.root_dir / "some/stub.txt" some_processed_output = "// generated some processed output" - registry = paths.swift_dir / "a/registry.list" + registry = paths.root_dir / "a/registry.list" write(stub, "// generated something else") write(registry, f"some/stub.txt whatever {hash(some_processed_output)}\n") diff --git a/swift/codegen/test/utils.py b/swift/codegen/test/utils.py index cf686bbf599..70db539f3f2 100644 --- a/swift/codegen/test/utils.py +++ b/swift/codegen/test/utils.py @@ -33,13 +33,13 @@ def render_manager(renderer): @pytest.fixture def opts(): ret = mock.MagicMock() - ret.swift_dir = paths.swift_dir + ret.root_dir = paths.root_dir return ret @pytest.fixture(autouse=True) def override_paths(tmp_path): - with mock.patch("swift.codegen.lib.paths.swift_dir", tmp_path), \ + with mock.patch("swift.codegen.lib.paths.root_dir", tmp_path), \ mock.patch("swift.codegen.lib.paths.exe_file", tmp_path / "exe"): yield From aca18f5da88dc851365b69545b818855bd6d5f7c Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 23 Feb 2023 09:26:23 +0100 Subject: [PATCH 410/415] Swift: make codegen use a config file --- swift/BUILD.bazel | 6 ++-- swift/codegen.conf | 7 +++++ swift/codegen/BUILD.bazel | 5 +++- swift/codegen/codegen.py | 60 +++++++++++++++++++++++++++------------ 4 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 swift/codegen.conf diff --git a/swift/BUILD.bazel b/swift/BUILD.bazel index bafbe01f712..b403c09e86e 100644 --- a/swift/BUILD.bazel +++ b/swift/BUILD.bazel @@ -5,13 +5,13 @@ load("//misc/bazel:pkg_runfiles.bzl", "pkg_runfiles") filegroup( name = "schema", - srcs = ["schema.py"], + srcs = ["schema.py"] + glob(["*.dbscheme"]), visibility = ["//swift:__subpackages__"], ) filegroup( - name = "schema_includes", - srcs = glob(["*.dbscheme"]), + name = "codegen_conf", + srcs = ["codegen.conf"], visibility = ["//swift:__subpackages__"], ) diff --git a/swift/codegen.conf b/swift/codegen.conf new file mode 100644 index 00000000000..8f5965bef5c --- /dev/null +++ b/swift/codegen.conf @@ -0,0 +1,7 @@ +# configuration file for Swift code generation default options +--generate=dbscheme,ql +--dbscheme=ql/lib/swift.dbscheme +--ql-output=ql/lib/codeql/swift/generated +--ql-stub-output=ql/lib/codeql/swift/elements +--ql-test-output=ql/test/extractor-tests/generated +--generated-registry=ql/.generated.list diff --git a/swift/codegen/BUILD.bazel b/swift/codegen/BUILD.bazel index 2e9d2ab835a..fcf72c0c2ae 100644 --- a/swift/codegen/BUILD.bazel +++ b/swift/codegen/BUILD.bazel @@ -5,10 +5,13 @@ py_binary( srcs = ["codegen.py"], data = [ "//swift:schema", - "//swift:schema_includes", + "//swift:codegen_conf", "//swift/codegen/templates:cpp", "//swift/codegen/templates:trap", ], + args = [ + "--configuration-file=$(location //swift:codegen_conf)", + ], visibility = ["//swift:__subpackages__"], deps = [ "//swift/codegen/generators", diff --git a/swift/codegen/codegen.py b/swift/codegen/codegen.py index 24f1646544f..5e9f4e9ac50 100755 --- a/swift/codegen/codegen.py +++ b/swift/codegen/codegen.py @@ -7,6 +7,7 @@ import os import sys import pathlib import typing +import shlex if 'BUILD_WORKSPACE_DIRECTORY' not in os.environ: # we are not running with `bazel run`, set up module search path @@ -18,35 +19,45 @@ from swift.codegen.generators import generate def _parse_args() -> argparse.Namespace: + dirs = [pathlib.Path().resolve()] + dirs.extend(dirs[0].parents) + for dir in dirs: + conf = dir / "codegen.conf" + if conf.exists(): + break + else: + conf = None + p = argparse.ArgumentParser(description="Code generation suite") - p.add_argument("--generate", type=lambda x: x.split(","), default=["dbscheme", "ql"], + p.add_argument("--generate", type=lambda x: x.split(","), help="specify what targets to generate as a comma separated list, choosing among dbscheme, ql, trap " "and cpp") p.add_argument("--verbose", "-v", action="store_true", help="print more information") p.add_argument("--quiet", "-q", action="store_true", help="only print errors") - p.add_argument("--root-dir", type=_abspath, default=paths.root_dir, - help="the directory that should be regarded as the root of the language pack codebase. Used to" - "compute QL imports and in some comments and as root for relative paths provided as options " - "(default %(default)s)") - p.add_argument("--language", default=paths.root_dir.name, - help="string that should replace {language} in other provided options") + p.add_argument("--configuration-file", "-c", type=_abspath, default=conf, + help="A configuration file to load options from. By default, the first codegen.conf file found by " + "going up directories from the current location. If present all paths provided in options are " + "considered relative to its directory") + p.add_argument("--root-dir", type=_abspath, + help="the directory that should be regarded as the root of the language pack codebase. Used to " + "compute QL imports and in some comments and as root for relative paths provided as options. " + "If not provided it defaults to the directory of the configuration file, if any") path_arguments = [ p.add_argument("--schema", default="schema.py", help="input schema file (default %(default)s)"), - p.add_argument("--dbscheme", default="ql/lib/{language}.dbscheme", - help="output file for dbscheme generation, input file for trap generation (default " - "%(default)s)"), - p.add_argument("--ql-output", default="ql/lib/codeql/{language}/generated", - help="output directory for generated QL files (default %(default)s)"), - p.add_argument("--ql-stub-output", default="ql/lib/codeql/{language}/elements", - help="output directory for QL stub/customization files (default %(default)s). Defines also the " + p.add_argument("--dbscheme", + help="output file for dbscheme generation, input file for trap generation"), + p.add_argument("--ql-output", + help="output directory for generated QL files"), + p.add_argument("--ql-stub-output", + help="output directory for QL stub/customization files. Defines also the " "generated qll file importing every class file"), - p.add_argument("--ql-test-output", default="ql/test/extractor-tests/generated", - help="output directory for QL generated extractor test files (default %(default)s)"), + p.add_argument("--ql-test-output", + help="output directory for QL generated extractor test files"), p.add_argument("--cpp-output", help="output directory for generated C++ files, required if trap or cpp is provided to " "--generate"), - p.add_argument("--generated-registry", default="ql/.generated.list", + p.add_argument("--generated-registry", help="registry file containing information about checked-in generated code"), ] p.add_argument("--ql-format", action="store_true", default=True, @@ -56,11 +67,24 @@ def _parse_args() -> argparse.Namespace: p.add_argument("--force", "-f", action="store_true", help="generate all files without skipping unchanged files and overwriting modified ones"), opts = p.parse_args() + if opts.configuration_file is not None: + with open(opts.configuration_file) as config: + defaults = p.parse_args(shlex.split(config.read(), comments=True)) + for flag, value in opts._get_kwargs(): + if value is None: + setattr(opts, flag, getattr(defaults, flag)) + if opts.root_dir is None: + opts.root_dir = opts.configuration_file.parent + if opts.root_dir is None: + p.error("Either --configuration-file or --root-dir must be provided, or a codegen.conf file must be in a " + "containing directory") + if not opts.generate: + p.error("Nothing to do, specify --generate") # absolutize all paths relative to --root-dir for arg in path_arguments: path = getattr(opts, arg.dest) if path is not None: - setattr(opts, arg.dest, opts.root_dir / path.format(language=opts.language)) + setattr(opts, arg.dest, opts.root_dir / path) return opts From feb4e60c4b8fe4622fd643243ab967121c7af762 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 23 Feb 2023 11:28:10 +0100 Subject: [PATCH 411/415] Swift: make all ql generation language agnostic --- swift/codegen/generators/qlgen.py | 23 +- swift/codegen/lib/ql.py | 18 +- swift/codegen/templates/ql_class.mustache | 4 +- .../ql_ipa_constructor_stub.mustache | 4 +- swift/codegen/templates/ql_ipa_types.mustache | 4 +- swift/codegen/templates/ql_parent.mustache | 5 +- swift/codegen/templates/ql_stub.mustache | 4 +- .../codegen/templates/ql_test_class.mustache | 2 +- .../templates/ql_test_missing.mustache | 2 +- .../templates/ql_test_property.mustache | 2 +- swift/codegen/test/test_qlgen.py | 471 +++++++++--------- swift/ql/.generated.list | 246 ++++----- .../generated/Comment/MISSING_SOURCE.txt | 2 +- .../OtherAvailabilitySpec/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../decl/ConstructorDecl/MISSING_SOURCE.txt | 2 +- .../decl/DestructorDecl/MISSING_SOURCE.txt | 2 +- .../decl/EnumCaseDecl/MISSING_SOURCE.txt | 2 +- .../decl/EnumElementDecl/MISSING_SOURCE.txt | 2 +- .../GenericTypeParamDecl/MISSING_SOURCE.txt | 2 +- .../decl/InfixOperatorDecl/MISSING_SOURCE.txt | 2 +- .../PatternBindingDecl/MISSING_SOURCE.txt | 2 +- .../PostfixOperatorDecl/MISSING_SOURCE.txt | 2 +- .../PrecedenceGroupDecl/MISSING_SOURCE.txt | 2 +- .../PrefixOperatorDecl/MISSING_SOURCE.txt | 2 +- .../decl/ProtocolDecl/MISSING_SOURCE.txt | 2 +- .../decl/StructDecl/MISSING_SOURCE.txt | 2 +- .../decl/SubscriptDecl/MISSING_SOURCE.txt | 2 +- .../decl/TopLevelCodeDecl/MISSING_SOURCE.txt | 2 +- .../decl/TypeAliasDecl/MISSING_SOURCE.txt | 2 +- .../expr/Argument/MISSING_SOURCE.txt | 2 +- .../expr/ArrayExpr/MISSING_SOURCE.txt | 2 +- .../expr/AssignExpr/MISSING_SOURCE.txt | 2 +- .../expr/AutoClosureExpr/MISSING_SOURCE.txt | 2 +- .../expr/BinaryExpr/MISSING_SOURCE.txt | 2 +- .../expr/BindOptionalExpr/MISSING_SOURCE.txt | 2 +- .../BooleanLiteralExpr/MISSING_SOURCE.txt | 2 +- .../expr/CallExpr/MISSING_SOURCE.txt | 2 +- .../expr/CaptureListExpr/MISSING_SOURCE.txt | 2 +- .../expr/ClosureExpr/MISSING_SOURCE.txt | 2 +- .../expr/CoerceExpr/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../expr/DeclRefExpr/MISSING_SOURCE.txt | 2 +- .../DefaultArgumentExpr/MISSING_SOURCE.txt | 2 +- .../expr/DictionaryExpr/MISSING_SOURCE.txt | 2 +- .../DiscardAssignmentExpr/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../expr/DynamicTypeExpr/MISSING_SOURCE.txt | 2 +- .../expr/FloatLiteralExpr/MISSING_SOURCE.txt | 2 +- .../expr/ForceTryExpr/MISSING_SOURCE.txt | 2 +- .../expr/ForceValueExpr/MISSING_SOURCE.txt | 2 +- .../ForcedCheckedCastExpr/MISSING_SOURCE.txt | 2 +- .../generated/expr/IfExpr/MISSING_SOURCE.txt | 2 +- .../expr/InOutExpr/MISSING_SOURCE.txt | 2 +- .../IntegerLiteralExpr/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../generated/expr/IsExpr/MISSING_SOURCE.txt | 2 +- .../KeyPathApplicationExpr/MISSING_SOURCE.txt | 2 +- .../expr/KeyPathDotExpr/MISSING_SOURCE.txt | 2 +- .../expr/KeyPathExpr/MISSING_SOURCE.txt | 2 +- .../LazyInitializerExpr/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../expr/MemberRefExpr/MISSING_SOURCE.txt | 2 +- .../expr/NilLiteralExpr/MISSING_SOURCE.txt | 2 +- .../expr/OneWayExpr/MISSING_SOURCE.txt | 2 +- .../expr/OpaqueValueExpr/MISSING_SOURCE.txt | 2 +- .../OpenExistentialExpr/MISSING_SOURCE.txt | 2 +- .../OptionalEvaluationExpr/MISSING_SOURCE.txt | 2 +- .../expr/OptionalTryExpr/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../expr/PrefixUnaryExpr/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../expr/RegexLiteralExpr/MISSING_SOURCE.txt | 2 +- .../expr/StringLiteralExpr/MISSING_SOURCE.txt | 2 +- .../expr/SubscriptExpr/MISSING_SOURCE.txt | 2 +- .../expr/SuperRefExpr/MISSING_SOURCE.txt | 2 +- .../generated/expr/TapExpr/MISSING_SOURCE.txt | 2 +- .../generated/expr/TryExpr/MISSING_SOURCE.txt | 2 +- .../expr/TupleElementExpr/MISSING_SOURCE.txt | 2 +- .../expr/TupleExpr/MISSING_SOURCE.txt | 2 +- .../expr/TypeExpr/MISSING_SOURCE.txt | 2 +- .../VarargExpansionExpr/MISSING_SOURCE.txt | 2 +- .../pattern/AnyPattern/MISSING_SOURCE.txt | 2 +- .../pattern/BindingPattern/MISSING_SOURCE.txt | 2 +- .../pattern/BoolPattern/MISSING_SOURCE.txt | 2 +- .../EnumElementPattern/MISSING_SOURCE.txt | 2 +- .../pattern/ExprPattern/MISSING_SOURCE.txt | 2 +- .../pattern/IsPattern/MISSING_SOURCE.txt | 2 +- .../pattern/NamedPattern/MISSING_SOURCE.txt | 2 +- .../OptionalSomePattern/MISSING_SOURCE.txt | 2 +- .../pattern/ParenPattern/MISSING_SOURCE.txt | 2 +- .../pattern/TuplePattern/MISSING_SOURCE.txt | 2 +- .../pattern/TypedPattern/MISSING_SOURCE.txt | 2 +- .../stmt/BraceStmt/MISSING_SOURCE.txt | 2 +- .../stmt/BreakStmt/MISSING_SOURCE.txt | 2 +- .../stmt/CaseLabelItem/MISSING_SOURCE.txt | 2 +- .../stmt/CaseStmt/MISSING_SOURCE.txt | 2 +- .../stmt/ConditionElement/MISSING_SOURCE.txt | 2 +- .../stmt/ContinueStmt/MISSING_SOURCE.txt | 2 +- .../stmt/DeferStmt/MISSING_SOURCE.txt | 2 +- .../stmt/DoCatchStmt/MISSING_SOURCE.txt | 2 +- .../generated/stmt/DoStmt/MISSING_SOURCE.txt | 2 +- .../stmt/FallthroughStmt/MISSING_SOURCE.txt | 2 +- .../stmt/ForEachStmt/MISSING_SOURCE.txt | 2 +- .../stmt/GuardStmt/MISSING_SOURCE.txt | 2 +- .../generated/stmt/IfStmt/MISSING_SOURCE.txt | 2 +- .../stmt/RepeatWhileStmt/MISSING_SOURCE.txt | 2 +- .../stmt/ReturnStmt/MISSING_SOURCE.txt | 2 +- .../stmt/StmtCondition/MISSING_SOURCE.txt | 2 +- .../stmt/SwitchStmt/MISSING_SOURCE.txt | 2 +- .../stmt/ThrowStmt/MISSING_SOURCE.txt | 2 +- .../stmt/WhileStmt/MISSING_SOURCE.txt | 2 +- .../stmt/YieldStmt/MISSING_SOURCE.txt | 2 +- .../type/ArraySliceType/MISSING_SOURCE.txt | 2 +- .../BoundGenericClassType/MISSING_SOURCE.txt | 2 +- .../BoundGenericEnumType/MISSING_SOURCE.txt | 2 +- .../BoundGenericStructType/MISSING_SOURCE.txt | 2 +- .../type/ClassType/MISSING_SOURCE.txt | 2 +- .../DependentMemberType/MISSING_SOURCE.txt | 2 +- .../type/DictionaryType/MISSING_SOURCE.txt | 2 +- .../type/EnumType/MISSING_SOURCE.txt | 2 +- .../MISSING_SOURCE.txt | 2 +- .../type/FunctionType/MISSING_SOURCE.txt | 2 +- .../GenericFunctionType/MISSING_SOURCE.txt | 2 +- .../GenericTypeParamType/MISSING_SOURCE.txt | 2 +- .../type/LValueType/MISSING_SOURCE.txt | 2 +- .../type/MetatypeType/MISSING_SOURCE.txt | 2 +- .../type/OptionalType/MISSING_SOURCE.txt | 2 +- .../type/ParenType/MISSING_SOURCE.txt | 2 +- .../type/ProtocolType/MISSING_SOURCE.txt | 2 +- .../type/StructType/MISSING_SOURCE.txt | 2 +- .../type/TypeAliasType/MISSING_SOURCE.txt | 2 +- .../type/TypeRepr/MISSING_SOURCE.txt | 2 +- .../UnboundGenericType/MISSING_SOURCE.txt | 2 +- 135 files changed, 533 insertions(+), 498 deletions(-) diff --git a/swift/codegen/generators/qlgen.py b/swift/codegen/generators/qlgen.py index e7730938d7f..bb140ab4f82 100755 --- a/swift/codegen/generators/qlgen.py +++ b/swift/codegen/generators/qlgen.py @@ -14,7 +14,7 @@ QL code generation corresponding to raw types) Moreover in the test directory for each in it will generate beneath the extractor-tests/generated// directory either - * a `MISSING_SOURCE.txt` explanation file if no `swift` source is present, or + * a `MISSING_SOURCE.txt` explanation file if no source is present, or * one `.ql` test query for all single properties and on `_.ql` test query for each optional or repeated property """ @@ -287,7 +287,7 @@ def _should_skip_qltest(cls: schema.Class, lookup: typing.Dict[str, schema.Class cls, lookup) -def _get_stub(cls: schema.Class, base_import: str) -> ql.Stub: +def _get_stub(cls: schema.Class, base_import: str, generated_import_prefix: str) -> ql.Stub: if isinstance(cls.ipa, schema.IpaInfo): if cls.ipa.from_class is not None: accessors = [ @@ -307,7 +307,7 @@ def _get_stub(cls: schema.Class, base_import: str) -> ql.Stub: ] else: accessors = [] - return ql.Stub(name=cls.name, base_import=base_import, ipa_accessors=accessors) + return ql.Stub(name=cls.name, base_import=base_import, import_prefix=generated_import_prefix, ipa_accessors=accessors) def generate(opts, renderer): @@ -335,6 +335,7 @@ def generate(opts, renderer): raise RootElementHasChildren(root) imports = {} + generated_import_prefix = get_import(out, opts.root_dir) with renderer.manage(generated=generated, stubs=stubs, registry=opts.generated_registry, force=opts.force) as renderer: @@ -349,6 +350,7 @@ def generate(opts, renderer): for c in classes.values(): qll = out / c.path.with_suffix(".qll") c.imports = [imports[t] for t in get_classes_used_by(c)] + c.import_prefix = generated_import_prefix renderer.render(c, qll) for c in data.classes.values(): @@ -356,16 +358,18 @@ def generate(opts, renderer): stub_file = stub_out / path if not renderer.is_customized_stub(stub_file): base_import = get_import(out / path, opts.root_dir) - renderer.render(_get_stub(c, base_import), stub_file) + renderer.render(_get_stub(c, base_import, generated_import_prefix), stub_file) # for example path/to/elements -> path/to/elements.qll renderer.render(ql.ImportList([i for name, i in imports.items() if not classes[name].ql_internal]), include_file) + elements_module = get_import(include_file, opts.root_dir) + renderer.render( ql.GetParentImplementation( classes=list(classes.values()), - additional_imports=[i for name, i in imports.items() if classes[name].ql_internal], + imports=[elements_module] + [i for name, i in imports.items() if classes[name].ql_internal], ), out / 'ParentChild.qll') @@ -374,7 +378,7 @@ def generate(opts, renderer): continue test_dir = test_out / c.group / c.name test_dir.mkdir(parents=True, exist_ok=True) - if not any(test_dir.glob("*.swift")): + if all(f.suffix in (".txt", ".ql", ".actual", ".expected") for f in test_dir.glob("*.*")): log.warning(f"no test source in {test_dir.relative_to(test_out)}") renderer.render(ql.MissingTestInstructions(), test_dir / missing_test_source_filename) @@ -383,11 +387,13 @@ def generate(opts, renderer): lambda p: p.is_total) renderer.render(ql.ClassTester(class_name=c.name, properties=total_props, + elements_module=elements_module, # in case of collapsed hierarchies we want to see the actual QL class in results show_ql_class="qltest_collapse_hierarchy" in c.pragmas), test_dir / f"{c.name}.ql") for p in partial_props: renderer.render(ql.PropertyTester(class_name=c.name, + elements_module=elements_module, property=p), test_dir / f"{c.name}_{p.getter}.ql") final_ipa_types = [] @@ -403,7 +409,7 @@ def generate(opts, renderer): stub_file = stub_out / cls.group / f"{cls.name}Constructor.qll" if not renderer.is_customized_stub(stub_file): # stub rendering must be postponed as we might not have yet all subtracted ipa types in `ipa_type` - stubs[stub_file] = ql.Synth.ConstructorStub(ipa_type) + stubs[stub_file] = ql.Synth.ConstructorStub(ipa_type, import_prefix=generated_import_prefix) constructor_import = get_import(stub_file, opts.root_dir) constructor_imports.append(constructor_import) if ipa_type.is_ipa: @@ -413,7 +419,8 @@ def generate(opts, renderer): for stub_file, data in stubs.items(): renderer.render(data, stub_file) - renderer.render(ql.Synth.Types(root.name, final_ipa_types, non_final_ipa_types), out / "Synth.qll") + renderer.render(ql.Synth.Types(root.name, generated_import_prefix, + final_ipa_types, non_final_ipa_types), out / "Synth.qll") renderer.render(ql.ImportList(constructor_imports), out / "SynthConstructors.qll") renderer.render(ql.ImportList(ipa_constructor_imports), out / "PureSynthConstructors.qll") if opts.ql_format: diff --git a/swift/codegen/lib/ql.py b/swift/codegen/lib/ql.py index fd1b0154d7d..ace39a61e0e 100644 --- a/swift/codegen/lib/ql.py +++ b/swift/codegen/lib/ql.py @@ -97,6 +97,7 @@ class Class: properties: List[Property] = field(default_factory=list) dir: pathlib.Path = pathlib.Path() imports: List[str] = field(default_factory=list) + import_prefix: Optional[str] = None qltest_skip: bool = False qltest_collapse_hierarchy: bool = False qltest_uncollapse_hierarchy: bool = False @@ -152,6 +153,7 @@ class Stub: name: str base_import: str + import_prefix: str ipa_accessors: List[IpaUnderlyingAccessor] = field(default_factory=list) @property @@ -178,7 +180,7 @@ class GetParentImplementation: template: ClassVar = 'ql_parent' classes: List[Class] = field(default_factory=list) - additional_imports: List[str] = field(default_factory=list) + imports: List[str] = field(default_factory=list) @dataclass @@ -190,19 +192,23 @@ class PropertyForTest: @dataclass -class ClassTester: +class TesterBase: + class_name: str + elements_module: str + + +@dataclass +class ClassTester(TesterBase): template: ClassVar = 'ql_test_class' - class_name: str properties: List[PropertyForTest] = field(default_factory=list) show_ql_class: bool = False @dataclass -class PropertyTester: +class PropertyTester(TesterBase): template: ClassVar = 'ql_test_property' - class_name: str property: PropertyForTest @@ -290,6 +296,7 @@ class Synth: template: ClassVar = "ql_ipa_types" root: str + import_prefix: str final_classes: List["Synth.FinalClass"] = field(default_factory=list) non_final_classes: List["Synth.NonFinalClass"] = field(default_factory=list) @@ -302,3 +309,4 @@ class Synth: template: ClassVar = "ql_ipa_constructor_stub" cls: "Synth.FinalClass" + import_prefix: str diff --git a/swift/codegen/templates/ql_class.mustache b/swift/codegen/templates/ql_class.mustache index cd0b3ac2355..173df3a75b9 100644 --- a/swift/codegen/templates/ql_class.mustache +++ b/swift/codegen/templates/ql_class.mustache @@ -1,6 +1,6 @@ // generated by {{generator}} -private import codeql.swift.generated.Synth -private import codeql.swift.generated.Raw +private import {{import_prefix}}.Synth +private import {{import_prefix}}.Raw {{#imports}} import {{.}} {{/imports}} diff --git a/swift/codegen/templates/ql_ipa_constructor_stub.mustache b/swift/codegen/templates/ql_ipa_constructor_stub.mustache index f207db66d21..e5e525417d3 100644 --- a/swift/codegen/templates/ql_ipa_constructor_stub.mustache +++ b/swift/codegen/templates/ql_ipa_constructor_stub.mustache @@ -1,9 +1,9 @@ // generated by {{generator}}, remove this comment if you wish to edit this file -private import codeql.swift.generated.Raw +private import {{import_prefix}}.Raw {{#cls}} {{#is_db}} {{#has_subtracted_ipa_types}} -private import codeql.swift.generated.PureSynthConstructors +private import {{import_prefix}}.PureSynthConstructors {{/has_subtracted_ipa_types}} {{/is_db}} diff --git a/swift/codegen/templates/ql_ipa_types.mustache b/swift/codegen/templates/ql_ipa_types.mustache index 9a4eef5e6b5..430361f6776 100644 --- a/swift/codegen/templates/ql_ipa_types.mustache +++ b/swift/codegen/templates/ql_ipa_types.mustache @@ -1,5 +1,5 @@ -private import codeql.swift.generated.SynthConstructors -private import codeql.swift.generated.Raw +private import {{import_prefix}}.SynthConstructors +private import {{import_prefix}}.Raw cached module Synth { cached newtype T{{root}} = diff --git a/swift/codegen/templates/ql_parent.mustache b/swift/codegen/templates/ql_parent.mustache index 53f80712aac..6777d366ddf 100644 --- a/swift/codegen/templates/ql_parent.mustache +++ b/swift/codegen/templates/ql_parent.mustache @@ -1,9 +1,8 @@ // generated by {{generator}} -import codeql.swift.elements -{{#additional_imports}} +{{#imports}} import {{.}} -{{/additional_imports}} +{{/imports}} private module Impl { {{#classes}} diff --git a/swift/codegen/templates/ql_stub.mustache b/swift/codegen/templates/ql_stub.mustache index 99e133fd7c9..7e17efc6d46 100644 --- a/swift/codegen/templates/ql_stub.mustache +++ b/swift/codegen/templates/ql_stub.mustache @@ -1,8 +1,8 @@ // generated by {{generator}}, remove this comment if you wish to edit this file private import {{base_import}} {{#has_ipa_accessors}} -private import codeql.swift.generated.Raw -private import codeql.swift.generated.Synth +private import {{import_prefix}}.Raw +private import {{import_prefix}}.Synth {{/has_ipa_accessors}} {{#ql_internal}} diff --git a/swift/codegen/templates/ql_test_class.mustache b/swift/codegen/templates/ql_test_class.mustache index adaf80de867..d689753cfd3 100644 --- a/swift/codegen/templates/ql_test_class.mustache +++ b/swift/codegen/templates/ql_test_class.mustache @@ -1,6 +1,6 @@ // generated by {{generator}} -import codeql.swift.elements +import {{elements_module}} import TestUtils from {{class_name}} x{{#properties}}, {{#type}}{{.}}{{/type}}{{^type}}string{{/type}} {{getter}}{{/properties}} diff --git a/swift/codegen/templates/ql_test_missing.mustache b/swift/codegen/templates/ql_test_missing.mustache index 0343d40c2aa..5a714744ef2 100644 --- a/swift/codegen/templates/ql_test_missing.mustache +++ b/swift/codegen/templates/ql_test_missing.mustache @@ -1,4 +1,4 @@ // generated by {{generator}} -After a swift source file is added in this directory and {{generator}} is run again, test queries +After a source file is added in this directory and {{generator}} is run again, test queries will appear and this file will be deleted diff --git a/swift/codegen/templates/ql_test_property.mustache b/swift/codegen/templates/ql_test_property.mustache index 46887384159..5e81298089d 100644 --- a/swift/codegen/templates/ql_test_property.mustache +++ b/swift/codegen/templates/ql_test_property.mustache @@ -1,6 +1,6 @@ // generated by {{generator}} -import codeql.swift.elements +import {{elements_module}} import TestUtils {{#property}} diff --git a/swift/codegen/test/test_qlgen.py b/swift/codegen/test/test_qlgen.py index c0bbc9a9f73..e543bd9c1a9 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/swift/codegen/test/test_qlgen.py @@ -35,9 +35,11 @@ def import_file(): return stub_path().with_suffix(".qll") def children_file(): return ql_output_path() / "ParentChild.qll" -stub_import_prefix = "stub.path." +stub_import = "stub.path" +stub_import_prefix = stub_import + "." root_import = stub_import_prefix + "Element" -gen_import_prefix = "other.path." +gen_import = "other.path" +gen_import_prefix = gen_import + "." @pytest.fixture @@ -133,12 +135,20 @@ def generate_tests(generate): return func +def a_ql_class(**kwargs): + return ql.Class(**kwargs, import_prefix=gen_import) + + +def a_ql_stub(**kwargs): + return ql.Stub(**kwargs, import_prefix=gen_import) + + def test_one_empty_class(generate_classes): assert generate_classes([ schema.Class("A") ]) == { - "A.qll": (ql.Stub(name="A", base_import=gen_import_prefix + "A"), - ql.Class(name="A", final=True)), + "A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "A"), + a_ql_class(name="A", final=True)), } @@ -149,15 +159,15 @@ def test_hierarchy(generate_classes): schema.Class("B", bases=["A"], derived={"D"}), schema.Class("A", derived={"B", "C"}), ]) == { - "A.qll": (ql.Stub(name="A", base_import=gen_import_prefix + "A"), - ql.Class(name="A")), - "B.qll": (ql.Stub(name="B", base_import=gen_import_prefix + "B"), - ql.Class(name="B", bases=["A"], imports=[stub_import_prefix + "A"])), - "C.qll": (ql.Stub(name="C", base_import=gen_import_prefix + "C"), - ql.Class(name="C", bases=["A"], imports=[stub_import_prefix + "A"])), - "D.qll": (ql.Stub(name="D", base_import=gen_import_prefix + "D"), - ql.Class(name="D", final=True, bases=["B", "C"], - imports=[stub_import_prefix + cls for cls in "BC"])), + "A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "A"), + a_ql_class(name="A")), + "B.qll": (a_ql_stub(name="B", base_import=gen_import_prefix + "B"), + a_ql_class(name="B", bases=["A"], imports=[stub_import_prefix + "A"])), + "C.qll": (a_ql_stub(name="C", base_import=gen_import_prefix + "C"), + a_ql_class(name="C", bases=["A"], imports=[stub_import_prefix + "A"])), + "D.qll": (a_ql_stub(name="D", base_import=gen_import_prefix + "D"), + a_ql_class(name="D", final=True, bases=["B", "C"], + imports=[stub_import_prefix + cls for cls in "BC"])), } @@ -186,15 +196,15 @@ def test_hierarchy_children(generate_children_implementations): schema.Class("C", bases=["A"], derived={"D"}, pragmas=["ql_internal"]), schema.Class("D", bases=["B", "C"]), ]) == ql.GetParentImplementation( - classes=[ql.Class(name="A", ql_internal=True), - ql.Class(name="B", bases=["A"], imports=[ + classes=[a_ql_class(name="A", ql_internal=True), + a_ql_class(name="B", bases=["A"], imports=[ stub_import_prefix + "A"]), - ql.Class(name="C", bases=["A"], imports=[ + a_ql_class(name="C", bases=["A"], imports=[ stub_import_prefix + "A"], ql_internal=True), - ql.Class(name="D", final=True, bases=["B", "C"], - imports=[stub_import_prefix + cls for cls in "BC"]), + a_ql_class(name="D", final=True, bases=["B", "C"], + imports=[stub_import_prefix + cls for cls in "BC"]), ], - additional_imports=[stub_import_prefix + cls for cls in "AC"], + imports=[stub_import] + [stub_import_prefix + cls for cls in "AC"], ) @@ -203,12 +213,12 @@ def test_single_property(generate_classes): schema.Class("MyObject", properties=[ schema.SingleProperty("foo", "bar")]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="Foo", type="bar", tablename="my_objects", - tableparams=["this", "result"], doc="foo of this my object"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", + tableparams=["this", "result"], doc="foo of this my object"), + ])), } @@ -226,42 +236,45 @@ def test_children(generate_classes): schema.RepeatedOptionalProperty("child_4", "int", is_child=True), ]), ]) == { - "FakeRoot.qll": (ql.Stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), - ql.Class(name="FakeRoot", final=True)), - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="A", type="int", tablename="my_objects", - tableparams=["this", "result", "_"], - doc="a of this my object"), - ql.Property(singular="Child1", type="int", tablename="my_objects", - tableparams=["this", "_", "result"], prev_child="", - doc="child 1 of this my object"), - ql.Property(singular="B", plural="Bs", type="int", - tablename="my_object_bs", - tableparams=["this", "index", "result"], - doc="b of this my object", doc_plural="bs of this my object"), - ql.Property(singular="Child", plural="Children", type="int", - tablename="my_object_children", - tableparams=["this", "index", "result"], prev_child="Child1", - doc="child of this my object", - doc_plural="children of this my object"), - ql.Property(singular="C", type="int", tablename="my_object_cs", - tableparams=["this", "result"], is_optional=True, - doc="c of this my object"), - ql.Property(singular="Child3", type="int", tablename="my_object_child_3s", - tableparams=["this", "result"], is_optional=True, - prev_child="Child", doc="child 3 of this my object"), - ql.Property(singular="D", plural="Ds", type="int", - tablename="my_object_ds", - tableparams=["this", "index", "result"], is_optional=True, - doc="d of this my object", doc_plural="ds of this my object"), - ql.Property(singular="Child4", plural="Child4s", type="int", - tablename="my_object_child_4s", - tableparams=["this", "index", "result"], is_optional=True, - prev_child="Child3", doc="child 4 of this my object", - doc_plural="child 4s of this my object"), - ])), + "FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), + a_ql_class(name="FakeRoot", final=True)), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="A", type="int", tablename="my_objects", + tableparams=["this", "result", "_"], + doc="a of this my object"), + ql.Property(singular="Child1", type="int", tablename="my_objects", + tableparams=["this", "_", "result"], prev_child="", + doc="child 1 of this my object"), + ql.Property(singular="B", plural="Bs", type="int", + tablename="my_object_bs", + tableparams=["this", "index", "result"], + doc="b of this my object", + doc_plural="bs of this my object"), + ql.Property(singular="Child", plural="Children", type="int", + tablename="my_object_children", + tableparams=["this", "index", "result"], prev_child="Child1", + doc="child of this my object", + doc_plural="children of this my object"), + ql.Property(singular="C", type="int", tablename="my_object_cs", + tableparams=["this", "result"], is_optional=True, + doc="c of this my object"), + ql.Property(singular="Child3", type="int", + tablename="my_object_child_3s", + tableparams=["this", "result"], is_optional=True, + prev_child="Child", doc="child 3 of this my object"), + ql.Property(singular="D", plural="Ds", type="int", + tablename="my_object_ds", + tableparams=["this", "index", "result"], is_optional=True, + doc="d of this my object", + doc_plural="ds of this my object"), + ql.Property(singular="Child4", plural="Child4s", type="int", + tablename="my_object_child_4s", + tableparams=["this", "index", "result"], is_optional=True, + prev_child="Child3", doc="child 4 of this my object", + doc_plural="child 4s of this my object"), + ])), } @@ -273,19 +286,19 @@ def test_single_properties(generate_classes): schema.SingleProperty("three", "z"), ]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="One", type="x", tablename="my_objects", - tableparams=["this", "result", "_", "_"], - doc="one of this my object"), - ql.Property(singular="Two", type="y", tablename="my_objects", - tableparams=["this", "_", "result", "_"], - doc="two of this my object"), - ql.Property(singular="Three", type="z", tablename="my_objects", - tableparams=["this", "_", "_", "result"], - doc="three of this my object"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="One", type="x", tablename="my_objects", + tableparams=["this", "result", "_", "_"], + doc="one of this my object"), + ql.Property(singular="Two", type="y", tablename="my_objects", + tableparams=["this", "_", "result", "_"], + doc="two of this my object"), + ql.Property(singular="Three", type="z", tablename="my_objects", + tableparams=["this", "_", "_", "result"], + doc="three of this my object"), + ])), } @@ -296,14 +309,14 @@ def test_optional_property(generate_classes, is_child, prev_child): schema.Class("MyObject", properties=[ schema.OptionalProperty("foo", "bar", is_child=is_child)]), ]) == { - "FakeRoot.qll": (ql.Stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), - ql.Class(name="FakeRoot", final=True)), - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, properties=[ - ql.Property(singular="Foo", type="bar", tablename="my_object_foos", - tableparams=["this", "result"], - is_optional=True, prev_child=prev_child, doc="foo of this my object"), - ])), + "FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), + a_ql_class(name="FakeRoot", final=True)), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_object_foos", + tableparams=["this", "result"], + is_optional=True, prev_child=prev_child, doc="foo of this my object"), + ])), } @@ -314,14 +327,14 @@ def test_repeated_property(generate_classes, is_child, prev_child): schema.Class("MyObject", properties=[ schema.RepeatedProperty("foo", "bar", is_child=is_child)]), ]) == { - "FakeRoot.qll": (ql.Stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), - ql.Class(name="FakeRoot", final=True)), - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, properties=[ - ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", - tableparams=["this", "index", "result"], prev_child=prev_child, - doc="foo of this my object", doc_plural="foos of this my object"), - ])), + "FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), + a_ql_class(name="FakeRoot", final=True)), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, properties=[ + ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", + tableparams=["this", "index", "result"], prev_child=prev_child, + doc="foo of this my object", doc_plural="foos of this my object"), + ])), } @@ -333,15 +346,15 @@ def test_repeated_optional_property(generate_classes, is_child, prev_child): schema.RepeatedOptionalProperty("foo", "bar", is_child=is_child)]), ]) == { - "FakeRoot.qll": (ql.Stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), - ql.Class(name="FakeRoot", final=True)), - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, properties=[ - ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", - tableparams=["this", "index", "result"], is_optional=True, - prev_child=prev_child, doc="foo of this my object", - doc_plural="foos of this my object"), - ])), + "FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"), + a_ql_class(name="FakeRoot", final=True)), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, properties=[ + ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", + tableparams=["this", "index", "result"], is_optional=True, + prev_child=prev_child, doc="foo of this my object", + doc_plural="foos of this my object"), + ])), } @@ -350,11 +363,11 @@ def test_predicate_property(generate_classes): schema.Class("MyObject", properties=[ schema.PredicateProperty("is_foo")]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, properties=[ - ql.Property(singular="isFoo", type="predicate", tablename="my_object_is_foo", - tableparams=["this"], is_predicate=True, doc="this my object is foo"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, properties=[ + ql.Property(singular="isFoo", type="predicate", tablename="my_object_is_foo", + tableparams=["this"], is_predicate=True, doc="this my object is foo"), + ])), } @@ -365,8 +378,8 @@ def test_single_class_property(generate_classes, is_child, prev_child): schema.Class("MyObject", properties=[ schema.SingleProperty("foo", "Bar", is_child=is_child)]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class( + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class( name="MyObject", final=True, imports=[stub_import_prefix + "Bar"], properties=[ ql.Property(singular="Foo", type="Bar", tablename="my_objects", tableparams=[ @@ -374,8 +387,8 @@ def test_single_class_property(generate_classes, is_child, prev_child): prev_child=prev_child, doc="foo of this my object"), ], )), - "Bar.qll": (ql.Stub(name="Bar", base_import=gen_import_prefix + "Bar"), - ql.Class(name="Bar", final=True)), + "Bar.qll": (a_ql_stub(name="Bar", base_import=gen_import_prefix + "Bar"), + a_ql_class(name="Bar", final=True)), } @@ -384,8 +397,8 @@ def test_class_with_doc(generate_classes): assert generate_classes([ schema.Class("A", doc=doc), ]) == { - "A.qll": (ql.Stub(name="A", base_import=gen_import_prefix + "A"), - ql.Class(name="A", final=True, doc=doc)), + "A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "A"), + a_ql_class(name="A", final=True, doc=doc)), } @@ -395,11 +408,11 @@ def test_class_dir(generate_classes): schema.Class("A", derived={"B"}, group=dir), schema.Class("B", bases=["A"]), ]) == { - f"{dir}/A.qll": (ql.Stub(name="A", base_import=gen_import_prefix + "another.rel.path.A"), - ql.Class(name="A", dir=pathlib.Path(dir))), - "B.qll": (ql.Stub(name="B", base_import=gen_import_prefix + "B"), - ql.Class(name="B", final=True, bases=["A"], - imports=[stub_import_prefix + "another.rel.path.A"])), + f"{dir}/A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "another.rel.path.A"), + a_ql_class(name="A", dir=pathlib.Path(dir))), + "B.qll": (a_ql_stub(name="B", base_import=gen_import_prefix + "B"), + a_ql_class(name="B", final=True, bases=["A"], + imports=[stub_import_prefix + "another.rel.path.A"])), } @@ -487,12 +500,20 @@ def test_test_missing_source(generate_tests): } +def a_ql_class_tester(**kwargs): + return ql.ClassTester(**kwargs, elements_module=stub_import) + + +def a_ql_property_tester(**kwargs): + return ql.PropertyTester(**kwargs, elements_module=stub_import) + + def test_test_source_present(opts, generate_tests): write(opts.ql_test_output / "A" / "test.swift") assert generate_tests([ schema.Class("A"), ]) == { - "A/A.ql": ql.ClassTester(class_name="A"), + "A/A.ql": a_ql_class_tester(class_name="A"), } @@ -501,7 +522,7 @@ def test_test_source_present_with_dir(opts, generate_tests): assert generate_tests([ schema.Class("A", group="foo"), ]) == { - "foo/A/A.ql": ql.ClassTester(class_name="A"), + "foo/A/A.ql": a_ql_class_tester(class_name="A"), } @@ -515,7 +536,7 @@ def test_test_total_properties(opts, generate_tests): schema.PredicateProperty("y", "int"), ]), ]) == { - "B/B.ql": ql.ClassTester(class_name="B", properties=[ + "B/B.ql": a_ql_class_tester(class_name="B", properties=[ ql.PropertyForTest(getter="getX", type="string"), ql.PropertyForTest(getter="y"), ]) @@ -533,21 +554,21 @@ def test_test_partial_properties(opts, generate_tests): schema.RepeatedOptionalProperty("z", "int"), ]), ]) == { - "B/B.ql": ql.ClassTester(class_name="B", properties=[ + "B/B.ql": a_ql_class_tester(class_name="B", properties=[ ql.PropertyForTest(getter="hasX"), ql.PropertyForTest(getter="getNumberOfYs", type="int"), ]), - "B/B_getX.ql": ql.PropertyTester(class_name="B", - property=ql.PropertyForTest(getter="getX", is_total=False, - type="string")), - "B/B_getY.ql": ql.PropertyTester(class_name="B", - property=ql.PropertyForTest(getter="getY", is_total=False, - is_repeated=True, - type="bool")), - "B/B_getZ.ql": ql.PropertyTester(class_name="B", - property=ql.PropertyForTest(getter="getZ", is_total=False, - is_repeated=True, - type="int")), + "B/B_getX.ql": a_ql_property_tester(class_name="B", + property=ql.PropertyForTest(getter="getX", is_total=False, + type="string")), + "B/B_getY.ql": a_ql_property_tester(class_name="B", + property=ql.PropertyForTest(getter="getY", is_total=False, + is_repeated=True, + type="bool")), + "B/B_getZ.ql": a_ql_property_tester(class_name="B", + property=ql.PropertyForTest(getter="getZ", is_total=False, + is_repeated=True, + type="int")), } @@ -562,14 +583,14 @@ def test_test_properties_deduplicated(opts, generate_tests): schema.Class("B", bases=["Base"], derived={"Final"}), schema.Class("Final", bases=["A", "B"]), ]) == { - "Final/Final.ql": ql.ClassTester(class_name="Final", properties=[ + "Final/Final.ql": a_ql_class_tester(class_name="Final", properties=[ ql.PropertyForTest(getter="getX", type="string"), ql.PropertyForTest(getter="getNumberOfYs", type="int"), ]), - "Final/Final_getY.ql": ql.PropertyTester(class_name="Final", - property=ql.PropertyForTest(getter="getY", is_total=False, - is_repeated=True, - type="bool")), + "Final/Final_getY.ql": a_ql_property_tester(class_name="Final", + property=ql.PropertyForTest(getter="getY", is_total=False, + is_repeated=True, + type="bool")), } @@ -586,7 +607,7 @@ def test_test_properties_skipped(opts, generate_tests): "b", "int", pragmas=["bar", "qltest_skip", "baz"]), ]), ]) == { - "Derived/Derived.ql": ql.ClassTester(class_name="Derived"), + "Derived/Derived.ql": a_ql_class_tester(class_name="Derived"), } @@ -599,7 +620,7 @@ def test_test_base_class_skipped(opts, generate_tests): ]), schema.Class("Derived", bases=["Base"]), ]) == { - "Derived/Derived.ql": ql.ClassTester(class_name="Derived"), + "Derived/Derived.ql": a_ql_class_tester(class_name="Derived"), } @@ -622,7 +643,7 @@ def test_test_class_hierarchy_collapse(opts, generate_tests): schema.Class("D2", bases=["Base"], derived={"D3"}, properties=[schema.SingleProperty("y", "string")]), schema.Class("D3", bases=["D2"], properties=[schema.SingleProperty("z", "string")]), ]) == { - "Base/Base.ql": ql.ClassTester(class_name="Base", show_ql_class=True), + "Base/Base.ql": a_ql_class_tester(class_name="Base", show_ql_class=True), } @@ -636,9 +657,9 @@ def test_test_class_hierarchy_uncollapse(opts, generate_tests): schema.Class("D3", bases=["D2"]), schema.Class("D4", bases=["D2"]), ]) == { - "Base/Base.ql": ql.ClassTester(class_name="Base", show_ql_class=True), - "D3/D3.ql": ql.ClassTester(class_name="D3"), - "D4/D4.ql": ql.ClassTester(class_name="D4"), + "Base/Base.ql": a_ql_class_tester(class_name="Base", show_ql_class=True), + "D3/D3.ql": a_ql_class_tester(class_name="D3"), + "D4/D4.ql": a_ql_class_tester(class_name="D4"), } @@ -651,8 +672,8 @@ def test_test_class_hierarchy_uncollapse_at_final(opts, generate_tests): schema.Class("D2", bases=["Base"], derived={"D3"}), schema.Class("D3", bases=["D2"], pragmas=["qltest_uncollapse_hierarchy", "bar"]), ]) == { - "Base/Base.ql": ql.ClassTester(class_name="Base", show_ql_class=True), - "D3/D3.ql": ql.ClassTester(class_name="D3"), + "Base/Base.ql": a_ql_class_tester(class_name="Base", show_ql_class=True), + "D3/D3.ql": a_ql_class_tester(class_name="D3"), } @@ -663,14 +684,14 @@ def test_property_description(generate_classes): schema.SingleProperty("foo", "bar", description=description), ]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="Foo", type="bar", tablename="my_objects", - tableparams=["this", "result"], - doc="foo of this my object", - description=description), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", + tableparams=["this", "result"], + doc="foo of this my object", + description=description), + ])), } @@ -679,12 +700,12 @@ def test_property_doc_override(generate_classes): schema.Class("MyObject", properties=[ schema.SingleProperty("foo", "bar", doc="baz")]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="Foo", type="bar", tablename="my_objects", - tableparams=["this", "result"], doc="baz"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", + tableparams=["this", "result"], doc="baz"), + ])), } @@ -694,18 +715,18 @@ def test_repeated_property_doc_override(generate_classes): schema.RepeatedProperty("x", "int", doc="children of this"), schema.RepeatedOptionalProperty("y", "int", doc="child of this")]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="X", plural="Xes", type="int", - tablename="my_object_xes", - tableparams=["this", "index", "result"], - doc="child of this", doc_plural="children of this"), - ql.Property(singular="Y", plural="Ys", type="int", - tablename="my_object_ies", is_optional=True, - tableparams=["this", "index", "result"], - doc="child of this", doc_plural="children of this"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="X", plural="Xes", type="int", + tablename="my_object_xes", + tableparams=["this", "index", "result"], + doc="child of this", doc_plural="children of this"), + ql.Property(singular="Y", plural="Ys", type="int", + tablename="my_object_ies", is_optional=True, + tableparams=["this", "index", "result"], + doc="child of this", doc_plural="children of this"), + ])), } @@ -716,13 +737,13 @@ def test_property_doc_abbreviations(generate_classes, abbr, expected): schema.Class("Object", properties=[ schema.SingleProperty(f"foo_{abbr}_bar", "baz")]), ]) == { - "Object.qll": (ql.Stub(name="Object", base_import=gen_import_prefix + "Object"), - ql.Class(name="Object", final=True, - properties=[ - ql.Property(singular=f"Foo{abbr.capitalize()}Bar", type="baz", - tablename="objects", - tableparams=["this", "result"], doc=expected_doc), - ])), + "Object.qll": (a_ql_stub(name="Object", base_import=gen_import_prefix + "Object"), + a_ql_class(name="Object", final=True, + properties=[ + ql.Property(singular=f"Foo{abbr.capitalize()}Bar", type="baz", + tablename="objects", + tableparams=["this", "result"], doc=expected_doc), + ])), } @@ -733,13 +754,13 @@ def test_property_doc_abbreviations_ignored_if_within_word(generate_classes, abb schema.Class("Object", properties=[ schema.SingleProperty(f"foo_{abbr}acadabra_bar", "baz")]), ]) == { - "Object.qll": (ql.Stub(name="Object", base_import=gen_import_prefix + "Object"), - ql.Class(name="Object", final=True, - properties=[ - ql.Property(singular=f"Foo{abbr.capitalize()}acadabraBar", type="baz", - tablename="objects", - tableparams=["this", "result"], doc=expected_doc), - ])), + "Object.qll": (a_ql_stub(name="Object", base_import=gen_import_prefix + "Object"), + a_ql_class(name="Object", final=True, + properties=[ + ql.Property(singular=f"Foo{abbr.capitalize()}acadabraBar", type="baz", + tablename="objects", + tableparams=["this", "result"], doc=expected_doc), + ])), } @@ -749,20 +770,20 @@ def test_repeated_property_doc_override_with_format(generate_classes): schema.RepeatedProperty("x", "int", doc="special {children} of this"), schema.RepeatedOptionalProperty("y", "int", doc="special {child} of this")]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="X", plural="Xes", type="int", - tablename="my_object_xes", - tableparams=["this", "index", "result"], - doc="special child of this", - doc_plural="special children of this"), - ql.Property(singular="Y", plural="Ys", type="int", - tablename="my_object_ies", is_optional=True, - tableparams=["this", "index", "result"], - doc="special child of this", - doc_plural="special children of this"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="X", plural="Xes", type="int", + tablename="my_object_xes", + tableparams=["this", "index", "result"], + doc="special child of this", + doc_plural="special children of this"), + ql.Property(singular="Y", plural="Ys", type="int", + tablename="my_object_ies", is_optional=True, + tableparams=["this", "index", "result"], + doc="special child of this", + doc_plural="special children of this"), + ])), } @@ -772,18 +793,18 @@ def test_repeated_property_doc_override_with_multiple_formats(generate_classes): schema.RepeatedProperty("x", "int", doc="{cat} or {dog}"), schema.RepeatedOptionalProperty("y", "int", doc="{cats} or {dogs}")]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="X", plural="Xes", type="int", - tablename="my_object_xes", - tableparams=["this", "index", "result"], - doc="cat or dog", doc_plural="cats or dogs"), - ql.Property(singular="Y", plural="Ys", type="int", - tablename="my_object_ies", is_optional=True, - tableparams=["this", "index", "result"], - doc="cat or dog", doc_plural="cats or dogs"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="X", plural="Xes", type="int", + tablename="my_object_xes", + tableparams=["this", "index", "result"], + doc="cat or dog", doc_plural="cats or dogs"), + ql.Property(singular="Y", plural="Ys", type="int", + tablename="my_object_ies", is_optional=True, + tableparams=["this", "index", "result"], + doc="cat or dog", doc_plural="cats or dogs"), + ])), } @@ -792,12 +813,12 @@ def test_property_doc_override_with_format(generate_classes): schema.Class("MyObject", properties=[ schema.SingleProperty("foo", "bar", doc="special {baz} of this")]), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="Foo", type="bar", tablename="my_objects", - tableparams=["this", "result"], doc="special baz of this"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", + tableparams=["this", "result"], doc="special baz of this"), + ])), } @@ -807,12 +828,12 @@ def test_property_on_class_with_default_doc_name(generate_classes): schema.SingleProperty("foo", "bar")], default_doc_name="baz"), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), - ql.Class(name="MyObject", final=True, - properties=[ - ql.Property(singular="Foo", type="bar", tablename="my_objects", - tableparams=["this", "result"], doc="foo of this baz"), - ])), + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), + a_ql_class(name="MyObject", final=True, + properties=[ + ql.Property(singular="Foo", type="bar", tablename="my_objects", + tableparams=["this", "result"], doc="foo of this baz"), + ])), } @@ -820,10 +841,10 @@ def test_stub_on_class_with_ipa_from_class(generate_classes): assert generate_classes([ schema.Class("MyObject", ipa=schema.IpaInfo(from_class="A")), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ ql.IpaUnderlyingAccessor(argument="Entity", type="Raw::A", constructorparams=["result"]), ]), - ql.Class(name="MyObject", final=True, ipa=True)), + a_ql_class(name="MyObject", final=True, ipa=True)), } @@ -831,12 +852,12 @@ def test_stub_on_class_with_ipa_on_arguments(generate_classes): assert generate_classes([ schema.Class("MyObject", ipa=schema.IpaInfo(on_arguments={"base": "A", "index": "int", "label": "string"})), ]) == { - "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ + "MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[ ql.IpaUnderlyingAccessor(argument="Base", type="Raw::A", constructorparams=["result", "_", "_"]), ql.IpaUnderlyingAccessor(argument="Index", type="int", constructorparams=["_", "result", "_"]), ql.IpaUnderlyingAccessor(argument="Label", type="string", constructorparams=["_", "_", "result"]), ]), - ql.Class(name="MyObject", final=True, ipa=True)), + a_ql_class(name="MyObject", final=True, ipa=True)), } diff --git a/swift/ql/.generated.list b/swift/ql/.generated.list index 5f8e2a27011..5f97a0e829c 100644 --- a/swift/ql/.generated.list +++ b/swift/ql/.generated.list @@ -660,11 +660,11 @@ ql/lib/codeql/swift/generated/type/VariadicSequenceType.qll 796537097d8e32eda38b ql/lib/codeql/swift/generated/type/WeakStorageType.qll dda4397a49f537ec44117a86dc09705a07d281e31bf4643738b15219053ed380 dda4397a49f537ec44117a86dc09705a07d281e31bf4643738b15219053ed380 ql/test/extractor-tests/generated/AvailabilityInfo/AvailabilityInfo.ql 6e06e222636d5e3451afdce4d5e1b801206a0abf060cc5714350d25e784f8eda 3274ca1b3d85142037d0f12ecf9e15f77c3eeb285621adc9312a6691806d08c8 ql/test/extractor-tests/generated/AvailabilityInfo/AvailabilityInfo_getSpec.ql 44ccccad28d8648aa3349d9290bd1478bb021797c26bc2f8c1e3de14a42be3bd aefab61b6fa1c06c5c79d337cffb61335dca74ef9906deba12f7eaea42f9ac14 -ql/test/extractor-tests/generated/Comment/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/Comment/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/Diagnostics/Diagnostics.ql 6a4a9480cc929381e0337b181e5ac519a7abc6d597ebe24fb6701acf79ced86f 199c5bf8bd38e161d989e0e4db1ea1d3ddcb4d7cf571afd9112ce3ed8d9b8d2a ql/test/extractor-tests/generated/File/File.ql ab0968ae31b749da2b66462bd04e4dfb30604dba405a84594b575abfc4fa4c35 bcc0ff648b28c5ecd567e196e700272883756bbcc65296bbb880a979e3162628 -ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/decl/AccessorDecl/AccessorDecl.ql 5c017af7e6b16ee68990eec12affe81eb114338bac4d445f4b231fe0f110eccc db86c828a892b0acd150a780914e7e48c280cad473d3680a453bdee03aee1e9d ql/test/extractor-tests/generated/decl/AccessorDecl/AccessorDecl_getBody.ql 1d42eb1a5b832cfaf1949b61a01a6a11448a6d4369a44f2511bb31d1d7fc10a8 b326a6743121353f8a66410d3d9151ca969939abcbbe5c411872ca290da45123 ql/test/extractor-tests/generated/decl/AccessorDecl/AccessorDecl_getCapture.ql 17f9903978c9a8fc607d970532270090cea030ff57c2f6699c37672707ce5c70 cdd7ce47691a84aa5402a8946d4027f7b9dbce930057dfd62c14b470a5710cb0 @@ -700,19 +700,19 @@ ql/test/extractor-tests/generated/decl/ConcreteVarDecl/ConcreteVarDecl_getProper ql/test/extractor-tests/generated/decl/ConcreteVarDecl/ConcreteVarDecl_getPropertyWrapperBackingVarBinding.ql addbf4e32d383fc35b7505a33c5a675feeedd708c4b94ce8fc89c5bc88c36f1f 549c8ec9cf2c1dc6881e848af8be9900d54604a747ded1f04bd5cadf93e5ede3 ql/test/extractor-tests/generated/decl/ConcreteVarDecl/ConcreteVarDecl_getPropertyWrapperProjectionVar.ql 502a76b34c78d3cf8f38969671840dc9e28d478ba7afe671963145ba4dc9460d 6125a91820b6b8d139392c32478383e52e40e572e0f92a32f0e513409d2c4e11 ql/test/extractor-tests/generated/decl/ConcreteVarDecl/ConcreteVarDecl_getPropertyWrapperProjectionVarBinding.ql 40274aac8b67cb6a285bf91ccdc725ae1556b13ebcc6854a43e759b029733687 44e569aac32148bcce4cd5e8ebb33d7418580b7f5f03dfbd18635db9965b28d9 -ql/test/extractor-tests/generated/decl/ConstructorDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/DestructorDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/EnumCaseDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/decl/ConstructorDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/DestructorDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/EnumCaseDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/decl/EnumDecl/EnumDecl.ql e1906b751a4b72081a61b175e016f5182fdd0e27518f16017d17e14c65dd4268 8a1dd50e951ed2c25f18823ff8b9ab36dc2dc49703801dd48da443bc384bd9b4 ql/test/extractor-tests/generated/decl/EnumDecl/EnumDecl_getBaseType.ql 4ace6176a57dd4c759356ddbefc28b25481c80bdeddfeb396d91b07db55af22a d0d1337ccbba45a648fe68fefc51006e14506d4fb7211fb2bde45f7761c4dbf1 ql/test/extractor-tests/generated/decl/EnumDecl/EnumDecl_getGenericTypeParam.ql 3a0927f87a21d69bfc309f5f7faedb3d0cc2956c071b16c38b2b4acd36f24ea9 aafed56a1744579f05b3817adef6a5fd011d1b5cb7da2db230a43b6f55a04649 ql/test/extractor-tests/generated/decl/EnumDecl/EnumDecl_getMember.ql 621870b7dbeaeefa93cbbfc102e97810b15d39b49db685019c9e3cbf2423ffef e110630f0ba8f588e7f8ebc56a1a31c2ca2f22f2cc763baa76854beb3b3a4ece -ql/test/extractor-tests/generated/decl/EnumElementDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/decl/EnumElementDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/decl/ExtensionDecl/ExtensionDecl.ql 71523b034d2abc6225f433f140841a35a466e82c04cbf07bdb3a9e384024fedb 919c66eeff004324b48249fd746c38891f6f8723f1281ad60126cf4b3c1febe0 ql/test/extractor-tests/generated/decl/ExtensionDecl/ExtensionDecl_getGenericTypeParam.ql e8c9815756cd3d82abfb421b1e38d6381e48938a21f798fd9abd93686acc070b 2574ead6e511f41ba416e831e176ecdaac27dde410157a4ee472a680f922dd20 ql/test/extractor-tests/generated/decl/ExtensionDecl/ExtensionDecl_getMember.ql 8d1c6a2b7cb381a81d11775f0d1cfb13ee04dd27dc742e00a72d676f21481dde 430e5b9ed7eccd90383e362ffa5e512704883304c711b13c9110a57ae282bb40 ql/test/extractor-tests/generated/decl/ExtensionDecl/ExtensionDecl_getProtocol.ql 11fc53f70f6e7f29546337a9f06157baaecd9c7d1d392910e94d18b71a0a9ae2 3591d4ff4108bd3399cecdf444161d770c01af20c14f23afac167beead564998 -ql/test/extractor-tests/generated/decl/GenericTypeParamDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/decl/GenericTypeParamDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/decl/IfConfigDecl/IfConfigDecl.ql 5322f06ce9efe44baa798f31039c2955b31a8c1272580a0db7182ff1a3082509 3b6f34bc90b337b08eb159142bd5c8cbededd5e97d160e1f7342a7eb6e72e0a1 ql/test/extractor-tests/generated/decl/IfConfigDecl/IfConfigDecl_getActiveElement.ql 914165306a2eb5c8039750e1e03bda156a684946abc8709d786b4144d9c9eb3b 5e87dfd99858ae257506415369bff937a731b6309dac2242b03ea79ead045fc1 ql/test/extractor-tests/generated/decl/IfConfigDecl/IfConfigDecl_getMember.ql 2a2f4e89cb045c0f67c18d6c25e7f8cdcee5ce416304783c25ba2efb2afb45d4 4930c38baf0295399478733e24102a99307fe398986060d29e437bd65720f62d @@ -720,7 +720,7 @@ ql/test/extractor-tests/generated/decl/ImportDecl/ImportDecl.ql 65c03a28d5f5638b ql/test/extractor-tests/generated/decl/ImportDecl/ImportDecl_getDeclaration.ql a76c6360ed7b423229ec64dc4d03f586204fbf5107408b7d07c06ef43b30526e bc8569ecf097f0e6176da4f42379158137f70dcfb9b6d60f4c16f643b68f9d91 ql/test/extractor-tests/generated/decl/ImportDecl/ImportDecl_getImportedModule.ql 0339867ca4f414cceba85df20d12eca64a3eea9847bb02829dc28fa95701e987 8c292768f56cecbdfeb92985212e6b39ecada819891921c3ba1532d88d84c43e ql/test/extractor-tests/generated/decl/ImportDecl/ImportDecl_getMember.ql 6d48d3a93bc96dba3bda71ec9d9d6282615c2228a58da6167c169fafaedb3e17 8560b23d0f52b845c81727ce09c0b2f9647965c83d7de165e8cd3d91be5bdd42 -ql/test/extractor-tests/generated/decl/InfixOperatorDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/decl/InfixOperatorDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl.ql f9216e83077ebc0cb5a5bf2d7368af86167a1bfd378f9cd5592fd484a1bbc5dd 1c2de61cb064474340db10de4399c49f15eb0a5669e6dc9587d8b4f656b0134f ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl_getBaseType.ql 54a4bd2cfa666271ae9092285bb7217b082c88483d614066cfb599fc8ab84305 8b24ab8e93efe3922cb192eb5de5f517763058782e83e8732153421adddd68e1 ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl_getExportedModule.ql cfca012f0951c86560d892ea5eae182d5eda661c9484a0df71ef9c905123e8f6 dfebda4fcad0e2f2a2c944782a7355b3caeac569e5a45621c582bc1bb243b2cc @@ -743,152 +743,152 @@ ql/test/extractor-tests/generated/decl/ParamDecl/ParamDecl_getPropertyWrapperLoc ql/test/extractor-tests/generated/decl/ParamDecl/ParamDecl_getPropertyWrapperLocalWrappedVarBinding.ql 14f50b706a2dba7123888868d93fa72a4871e6e04949cc87a7df52e27b7197d1 680242c73f78a64a1687cf59b0a80f715c98b994b32ec90044bcedd2c258f786 ql/test/extractor-tests/generated/decl/ParamDecl/ParamDecl_getPropertyWrapperProjectionVar.ql 406436f415d5a6895be712471e7ab2d8b945539ac01b845ce191c4186e1cd275 4fdd0bc67207fd5cbe30743df46fdc61eeb5e58d877ef4aef5c7d7f0f684ef05 ql/test/extractor-tests/generated/decl/ParamDecl/ParamDecl_getPropertyWrapperProjectionVarBinding.ql c79a13e49d3375edac8e51b27a58318afee959a8df639f7b0d7d77de1e2d60bc 8c3b9dae1079e674854d15f4bd43f1f507b7fac6900f0831d92f2140aae268b4 -ql/test/extractor-tests/generated/decl/PatternBindingDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/PostfixOperatorDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/decl/PatternBindingDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/PostfixOperatorDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/decl/PoundDiagnosticDecl/PoundDiagnosticDecl.ql 17ac00f962db0e003c5845660b0dbad4ba59ce6e1def6384084ec937158544a5 df27465bc073fc4c031f75fa6b53263df2b902a8168f5d5c08851cc24bf0a647 ql/test/extractor-tests/generated/decl/PoundDiagnosticDecl/PoundDiagnosticDecl_getMember.ql d670ff4ea33ea15aa5f0299fd5bb6cc637e8a16faebe19433d250627732f4903 9a2482a469797248aaeed33caa226c92c97392cad3aa9608554d8ad16cc5cb38 -ql/test/extractor-tests/generated/decl/PrecedenceGroupDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/PrefixOperatorDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/ProtocolDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/StructDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/SubscriptDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/TopLevelCodeDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/decl/TypeAliasDecl/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/decl/PrecedenceGroupDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/PrefixOperatorDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/ProtocolDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/StructDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/SubscriptDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/TopLevelCodeDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/decl/TypeAliasDecl/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/AppliedPropertyWrapperExpr/AppliedPropertyWrapperExpr.ql 88d7539565c64d29ffd99e8201a0b47954d13c6ca7df6141fab6311fc37588f0 2ebaaaa97b492762273516355004a6cbc88d75250d856ed5e21660294e150ca0 ql/test/extractor-tests/generated/expr/AppliedPropertyWrapperExpr/AppliedPropertyWrapperExpr_getType.ql 1caa0b9c70afc6f63fb1cb05b30499a615a997849d5128006f9c7147b7f1d4a4 64474604bf6d9028bdcbbb8dd2a607c65cb74038e2d6e88e86908f82590ba7a7 -ql/test/extractor-tests/generated/expr/Argument/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/ArrayExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/AssignExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/AutoClosureExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/BinaryExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/BindOptionalExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/BooleanLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/CallExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/CaptureListExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/ClosureExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/CoerceExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/ConditionalCheckedCastExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/Argument/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/ArrayExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/AssignExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/AutoClosureExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/BinaryExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/BindOptionalExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/BooleanLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/CallExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/CaptureListExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/ClosureExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/CoerceExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/ConditionalCheckedCastExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/ConstructorRefCallExpr/ConstructorRefCallExpr.ql 0214077b52ed4c152c70bbd0347c7340d42e584954fba5242f1380e357ec79a0 f8ce48428247f8616c15d39198bf8b3857f1acca12a800bcc912c34720f5f039 ql/test/extractor-tests/generated/expr/ConstructorRefCallExpr/ConstructorRefCallExpr_getArgument.ql a3a01f99aa8df3aafed50cc7828829e567e01fed7874854e7a620904f1641fc9 962669b36b9adbc3d75bae79a9a754692c20d6e14ee2b47aca8f3f93b27895da ql/test/extractor-tests/generated/expr/ConstructorRefCallExpr/ConstructorRefCallExpr_getType.ql c3504dda8c41ebc386a9011deb06b0f5312538306b5ca10f7c4ff2e0f2c277dd aa6785ac86fe4954ef679fdfa6cd91f964d9281ab0162240b6e4b9eb67b0eda3 -ql/test/extractor-tests/generated/expr/DeclRefExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/DefaultArgumentExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/DictionaryExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/DiscardAssignmentExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/DotSyntaxBaseIgnoredExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/DeclRefExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/DefaultArgumentExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/DictionaryExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/DiscardAssignmentExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/DotSyntaxBaseIgnoredExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/DotSyntaxCallExpr/DotSyntaxCallExpr.ql b161e81b9eee4c3ab66776542559457c02f30da68e59efb98d6388425e66d2e3 d7571dbca05dd36185c0eb2ad4ad9e821433362c10045875fb433fae5264346a ql/test/extractor-tests/generated/expr/DotSyntaxCallExpr/DotSyntaxCallExpr_getArgument.ql ab0023396a31a9fad384ac6ab2819fa3b45726d651fee6ee5d84ea4fbdb55992 410afe1ae14ca17bc245c9fa88f84ba1d02e20a7803910746316ddcacc062ace ql/test/extractor-tests/generated/expr/DotSyntaxCallExpr/DotSyntaxCallExpr_getType.ql ea3d25737d4c02d6ecd405d23471a587945362dee1160f6346484fffa166835d 3edcaae4cd47839dc716640ac9c098a9c65f365a69fb5442d15eb1955c06dcaa ql/test/extractor-tests/generated/expr/DynamicLookupExpr/DynamicLookupExpr.ql 3c08d6e00606b76499ba1a04547cba9918f3be5b3baa4b3fc287bd288c467c8d 6685c8133d7c34346a85653589b3ae9cf2dbedaaff5e87f4dd9e94719a31b715 ql/test/extractor-tests/generated/expr/DynamicLookupExpr/DynamicLookupExpr_getMember.ql ab1669430da9e60e3b5187bd4f45e7a9b501348cd0c66e4d8570c6facc3a82a3 a2e5e9781c9af9c52fe9d5735f146dc4a2e077096f2baee8db75f2a2f82b0037 ql/test/extractor-tests/generated/expr/DynamicLookupExpr/DynamicLookupExpr_getType.ql 216b9caa3388b85959b19db012c6a7af40981ef92e4749b9cc644caee830041c 32691b624baed5c89fbef438214ecb893f9c1d1a575194133b56d79877e3feec -ql/test/extractor-tests/generated/expr/DynamicTypeExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/DynamicTypeExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/EnumIsCaseExpr/EnumIsCaseExpr.ql 9a4505f330e014769509be594299bcaa046d0a2c9a8ce4ac3a1d6d6b050af317 92c8392ded3fb26af7434b8aae34b1649b4c808acafc3adbd8ecb60ada5f6e72 ql/test/extractor-tests/generated/expr/EnumIsCaseExpr/EnumIsCaseExpr_getType.ql edc2e175c971465f5667c4586bc4c77e5c245d267f80009a049b8f657238a5f4 5df26b5bdf975ba910a7c3446705c3ac82a67d05565d860fe58464ee82bafdde -ql/test/extractor-tests/generated/expr/FloatLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/ForceTryExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/ForceValueExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/ForcedCheckedCastExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/FloatLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/ForceTryExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/ForceValueExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/ForcedCheckedCastExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/IdentityExpr/IdentityExpr.ql f87db45ad56628ce62200e1034d1cfd2ff1c799be5a24681fe939bf80108937a e8484eaab79f3be6b53ecb258eb9a3cd8cdcba8534c0ee7d275b8b67b3d2f538 ql/test/extractor-tests/generated/expr/IdentityExpr/IdentityExpr_getType.ql 7a8520abbf50642f886a3cdea37530b0577d509f31d76224467ad5d435bb0e39 a6fd63a7964cf778cc4b23ce5112138d7d5a5db96956e9514741ef9789bd1f19 -ql/test/extractor-tests/generated/expr/IfExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/IfExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/ImplicitConversionExpr/ImplicitConversionExpr.ql 7ffb80368c4d80adccaa0267cc76b42b76304d5d485286f82e22ae51776812f3 51b38032cb3d392be56fa8bdf53379a174cf3de39d4bf6b730c611ae3ab7cec8 ql/test/extractor-tests/generated/expr/ImplicitConversionExpr/ImplicitConversionExpr_getType.ql 184ff1dec5d65024c8a0c2b316706ac58c68c62c715c266211e947168750c89a 486fc8d65c0db86bdada2d540f665278caab43454a69ccc8c2e702729397fef0 -ql/test/extractor-tests/generated/expr/InOutExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/IntegerLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/MakeTemporarilyEscapableExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/MemberRefExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/InOutExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/IntegerLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/MakeTemporarilyEscapableExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/MemberRefExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/MethodLookupExpr/MethodLookupExpr.ql c0c60154b070a8a7ad333544a30f216adf063ae26cac466d60d46b26154eccde 360c9a3ddd9d02a82d0c9de81b8742137d76dba74942f09c9172459565cae19d ql/test/extractor-tests/generated/expr/MethodLookupExpr/MethodLookupExpr_getMember.ql 859ce0b1f54980e6383ff87d7970eb8a7886d9e1fbe12a8a0a35d216850c6775 24faafdb4a88b0019073c06a1cda8e037154b232a364aa47ae151e95df8a868a ql/test/extractor-tests/generated/expr/MethodLookupExpr/MethodLookupExpr_getType.ql 3e749535dbf7ae2cd671b3e35b43ca4f6a5bc68c92f89a09a0a9193cd3200b9a 176102d8d9d5a7bf14ac654d98556048996f2311be0bfe67d16229fd22362ba7 -ql/test/extractor-tests/generated/expr/NilLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/NilLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/ObjectLiteralExpr/ObjectLiteralExpr.ql 6c6b146537773b4b4bdb0e530bd581f4d9ffee93e784a8fdfcabe35309bdd09e 47b2a275af169a031faee39e73c67a70ec47969b731f1cc80a8f76e68d934402 ql/test/extractor-tests/generated/expr/ObjectLiteralExpr/ObjectLiteralExpr_getArgument.ql ab308c1fa027136070a6ee9ebe5149c69b34bb9ae910f201f37cecd8b6341ff8 deef69f4a1a94386a32ec964e696972a2c6a91c34d7e99c7e4a3811980f5ecc4 ql/test/extractor-tests/generated/expr/ObjectLiteralExpr/ObjectLiteralExpr_getType.ql 07d59d9962f3705f8f32302c0d730c179ca980172dd000b724a72e768fbf39db cd146e19249590316bb83efec19dd41234723513025cf9df45313f78f2b364dd -ql/test/extractor-tests/generated/expr/OneWayExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/OpaqueValueExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/OpenExistentialExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/OptionalEvaluationExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/OptionalTryExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/OtherConstructorDeclRefExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/OneWayExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/OpaqueValueExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/OpenExistentialExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/OptionalEvaluationExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/OptionalTryExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/OtherConstructorDeclRefExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/PostfixUnaryExpr/PostfixUnaryExpr.ql 7687a79d05efbbae7ce68780cb946cb500ed79c5e03aa0f3c132d0b98b6efe80 f23082710afb2bc247acab84b669540664461f0ec04a946125f17586640dfba8 ql/test/extractor-tests/generated/expr/PostfixUnaryExpr/PostfixUnaryExpr_getArgument.ql 3b0e6f81599e5565bb78aff753932776c933fefdc8dc49e57db9f5b4164017f6 43031a3d0baa58f69b89a8a5d69f1a40ffeeaddc8a630d241e107de63ea54532 ql/test/extractor-tests/generated/expr/PostfixUnaryExpr/PostfixUnaryExpr_getType.ql fa909883140fe89084c289c18ebc681402c38d0f37159d01f043f62de80521fc 4cd748e201e9374e589eaa0e3cc10310a1378bba15272a327d5cf54dbd526e8f -ql/test/extractor-tests/generated/expr/PrefixUnaryExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/PrefixUnaryExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/expr/PropertyWrapperValuePlaceholderExpr/PropertyWrapperValuePlaceholderExpr.ql 9ac73f157d11e4ee1c47dceaadd2f686893da6557e4e600c62edad90db2eb92d bf353009ee1b6127350d976f2e869b615d54b998e59664bdb25ea8d6ab5b132d ql/test/extractor-tests/generated/expr/PropertyWrapperValuePlaceholderExpr/PropertyWrapperValuePlaceholderExpr_getType.ql 0972415a8ac29f460d480990f85c3976ad947e26510da447bbf74ee61d9b3f4e 463b8ce871911b99c495ea84669b4e6f8eafc645df483f6a99413e930bc0275e ql/test/extractor-tests/generated/expr/PropertyWrapperValuePlaceholderExpr/PropertyWrapperValuePlaceholderExpr_getWrappedValue.ql 208153f062b04bec13a860b64ea51c1d531597140d81a6d4598294dc9f8649a2 dfaea19e1075c02dfc0366fac8fd2edfae8dde06308730eb462c54be5b571129 -ql/test/extractor-tests/generated/expr/RebindSelfInConstructorExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/RegexLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/StringLiteralExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/SubscriptExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/SuperRefExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/TapExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/TryExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/TupleElementExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/TupleExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/TypeExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/expr/VarargExpansionExpr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/AnyPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/BindingPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/BoolPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/EnumElementPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/ExprPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/IsPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/NamedPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/OptionalSomePattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/ParenPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/TuplePattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/pattern/TypedPattern/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/BraceStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/BreakStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/CaseLabelItem/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/CaseStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/ConditionElement/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/ContinueStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/DeferStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/DoCatchStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/DoStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/expr/RebindSelfInConstructorExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/RegexLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/StringLiteralExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/SubscriptExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/SuperRefExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/TapExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/TryExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/TupleElementExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/TupleExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/TypeExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/expr/VarargExpansionExpr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/AnyPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/BindingPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/BoolPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/EnumElementPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/ExprPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/IsPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/NamedPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/OptionalSomePattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/ParenPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/TuplePattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/pattern/TypedPattern/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/BraceStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/BreakStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/CaseLabelItem/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/CaseStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/ConditionElement/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/ContinueStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/DeferStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/DoCatchStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/DoStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/stmt/FailStmt/FailStmt.ql 75bf8a697d3a610caf25cb0d25748f2d1620c20fdd84c278c3e2f2502bc3f418 6e2377b8d2a63deaadbf8661dc7da70e8523637020e7d5fd601ca6893f10a573 -ql/test/extractor-tests/generated/stmt/FallthroughStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/ForEachStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/GuardStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/IfStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/stmt/FallthroughStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/ForEachStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/GuardStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/IfStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/stmt/PoundAssertStmt/PoundAssertStmt.ql dc72e3a7ff4c5dc39530322c343931cdfe63565eb76b29deef64bb311bfe302a 18eb3dab5ae8cfada5d42f1e70be9cb464a61ab5ce91897ce5a44a34387915e7 -ql/test/extractor-tests/generated/stmt/RepeatWhileStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/ReturnStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/StmtCondition/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/SwitchStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/ThrowStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/WhileStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/stmt/YieldStmt/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/ArraySliceType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/BoundGenericClassType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/BoundGenericEnumType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/BoundGenericStructType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/stmt/RepeatWhileStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/ReturnStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/StmtCondition/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/SwitchStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/ThrowStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/WhileStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/stmt/YieldStmt/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/ArraySliceType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/BoundGenericClassType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/BoundGenericEnumType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/BoundGenericStructType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/BuiltinIntegerType/BuiltinIntegerType.ql f85efff665246a0fb345def44cb60ae2415f82c6ef82b9689a61e08e7f1754ae 4c1c50193bfad688a708b4bc0dd08979e561ff764e0786ec37fbb6a654a404d6 ql/test/extractor-tests/generated/type/BuiltinIntegerType/BuiltinIntegerType_getWidth.ql 61e99a3987c5a4b10d5d105184c60dacc1c08d8106cf41b81d491a7f0ac36ef2 b02395a219768e0f41cbf77e4111da3a271e777bfe448eea1ea5d6f0910ff1e8 ql/test/extractor-tests/generated/type/BuiltinType/BuiltinType.ql 48f3b997bdb2c37dc22fd3dc2d18bc853888503d0d8d8cb075c6cd18657553e2 278d18e1fae3d8693a4d363b67c6ff111c111464f104d72ccad37793bc425200 -ql/test/extractor-tests/generated/type/ClassType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/DependentMemberType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/DictionaryType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/ClassType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/DependentMemberType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/DictionaryType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/DynamicSelfType/DynamicSelfType.ql d2c942b55f3a9f5af2cde39999b736ce2d50ae4514f36cc1e3f750905b03c49b b7ccdcf083da1598eaf4b5ad22e393253b8d58577580048290651a20f6e6df2f -ql/test/extractor-tests/generated/type/EnumType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/ExistentialMetatypeType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/EnumType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/ExistentialMetatypeType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/ExistentialType/ExistentialType.ql f7894f01a440b5db281dfaa9c083be0898d15b67e1b0047be3f9c959b97bdeb0 725a54f6ed26d53603a3e25cbf78c90b1f16837c1c0c39b56e7d3bdd51a78265 -ql/test/extractor-tests/generated/type/FunctionType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/GenericFunctionType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/GenericTypeParamType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/FunctionType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/GenericFunctionType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/GenericTypeParamType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/InOutType/InOutType.ql 35b7c048fbd053f6821ab1d996fabf55dada014873f25c5ed7141b59eb5e0fb6 06ca9b5be9a999cbd7e1ab2f26918a5923d7d351dd9ec74137550f1947013b7d -ql/test/extractor-tests/generated/type/LValueType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/MetatypeType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/LValueType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/MetatypeType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/ModuleType/ModuleType.ql 8f798fea381d1b502f262b5ee790758b38008cadcdee848d0ddba1bd9f8ff4f9 4c3d623607be1a5f6503500f3331ee3b3e5200e9e78cca8a4ef3d24c83d0e7ba ql/test/extractor-tests/generated/type/OpaqueTypeArchetypeType/OpaqueTypeArchetypeType.ql e34e98f70a987fe9a5017c897a507f9de4fffff837e3e2cf6c13287bb6165381 e60a5754173210f3af543bea15eadb2a3349e2f71653249cc421b33266adf344 ql/test/extractor-tests/generated/type/OpaqueTypeArchetypeType/OpaqueTypeArchetypeType_getProtocol.ql fb9baf55660e0eedf1a387267d170ae066a8d1531156eab5447feca92f05b751 139529998fc2060a46a70cb645a9aa36240ab225bd9fbdb3decc3eaec3aa2261 @@ -896,23 +896,23 @@ ql/test/extractor-tests/generated/type/OpaqueTypeArchetypeType/OpaqueTypeArchety ql/test/extractor-tests/generated/type/OpenedArchetypeType/OpenedArchetypeType.ql d902b873db34a3b7f0bc4da82ecf59b01d283d4ca61be3b090cb47358c8dd6c2 656a938735cfa5bf5ca65a7c0e347fca993e966d568404ac204f60de18faa03f ql/test/extractor-tests/generated/type/OpenedArchetypeType/OpenedArchetypeType_getProtocol.ql c208618d6bd7d4759581f06fad2b452077a0d865b4fb4288eff591fc7b16cd67 3bd6b8e1d1bc14bd27144a8356e07520d36ea21b6ea4adb61e84a2013e8701fc ql/test/extractor-tests/generated/type/OpenedArchetypeType/OpenedArchetypeType_getSuperclass.ql bb7fc71b2d84e8c5492bb4c61492dabbce898bfb680979aadd88c4de44ea5af7 acae343087222e8eb7e4dfa0e256097d9592a9668afcb5706bcba5548afc0770 -ql/test/extractor-tests/generated/type/OptionalType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/OptionalType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/ParameterizedProtocolType/ParameterizedProtocolType.ql dad743465b62dca457d64ff04bde24027050edb6d80054738f59e6026fbb00d7 119d085d65930b0b286ccdb8dc3aecb7eb46133e9f4ea18a6733751713b8ae5c ql/test/extractor-tests/generated/type/ParameterizedProtocolType/ParameterizedProtocolType_getArg.ql 8d10c3c858dedba47f227ebc92745916a248cd040ad944b80bf0d7a19af229d3 a29e2e0df269034c4f1fbd8f6de6d5898e895ad8b90628d5c869a45b596b53fc -ql/test/extractor-tests/generated/type/ParenType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/ParenType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/PrimaryArchetypeType/PrimaryArchetypeType.ql 1d733e0447587d52a3b84ca19480e410c487c02541cd070ac80fcd2dbef5b57d 6ffd1e7ce8ec9b9fea0680805700262e472711b4d9a2b4336e57445e8f1a6d48 ql/test/extractor-tests/generated/type/PrimaryArchetypeType/PrimaryArchetypeType_getProtocol.ql 8af9b686cb9c3d988aea21cdaca42a0b625985111caa71d3eebaba4aea883e9c beecb31ab8fccb05c853926bccec33e298bed519385a25d6158646c94a019af9 ql/test/extractor-tests/generated/type/PrimaryArchetypeType/PrimaryArchetypeType_getSuperclass.ql 3b752a38eac8204ae6d902d03da8caeaad4072f30206420c97056e4bf3639eb4 fc5959969d5b229fa5d90dde7d997aa0d1b91bdb9d77cc6811377044eed4a6cb ql/test/extractor-tests/generated/type/ProtocolCompositionType/ProtocolCompositionType.ql 007c64d8ea8f69addc61e8759ce9cf2e32f5e8f73de6e35541a16ea19d4695ab 156ef6560aa5d866e6ed70237cf0335b2df0c75f87d23cc4d1024ee80fe0a543 ql/test/extractor-tests/generated/type/ProtocolCompositionType/ProtocolCompositionType_getMember.ql 8c1e8e5932cd775f0d0812a64954be5fd5b3eedd8a26eedb0bd6009cbc156e24 5c43ef8000bb67ed0e070bbd9d5fc167dcb7b6334ae34747d27eb8060af1a7e5 -ql/test/extractor-tests/generated/type/ProtocolType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/StructType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/ProtocolType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/StructType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/TupleType/TupleType.ql 3ef454f940299726c035f0472ae4362d4b34fbe18a9af2a7d3581b1c734fad66 b5756e68f4eef3a02e7f1d2a7e16e41dc90d53fc631e0bd0c91ad015d63b77ca ql/test/extractor-tests/generated/type/TupleType/TupleType_getName.ql ab5c578f6e257960aa43b84dd5d4a66e17f2312b5f9955af0953aaecbe9e093a 1ff62da991b35e946446ecee706ac0e07a80059f35654c022ffe06bf7ae32cfe ql/test/extractor-tests/generated/type/TupleType/TupleType_getType.ql 3f861729c996b37e170adab56200e0671415663ff319bbf87c7c46ec8532d575 96a9735d69f250f3d67716d6a1552909d2aaa9b7758275b1b9002dca19000d22 -ql/test/extractor-tests/generated/type/TypeAliasType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/TypeRepr/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd -ql/test/extractor-tests/generated/type/UnboundGenericType/MISSING_SOURCE.txt 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd 7e714762ffb48c436102027d560fb5addc1f7dc6dd6936b06e0d3cca031d67fd +ql/test/extractor-tests/generated/type/TypeAliasType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/TypeRepr/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 +ql/test/extractor-tests/generated/type/UnboundGenericType/MISSING_SOURCE.txt 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 66846d526b0bc4328735c3c4dd9c390a9325da5b5dfd42ec07622f9c7108a7d7 ql/test/extractor-tests/generated/type/UnmanagedStorageType/UnmanagedStorageType.ql 3047ed64cbdb03d719d096fd3b2c4c54c92a2b65e46943424e84eeca705ab2d3 a8ee8ca4bf257c7472fa8cd7e661d352e8856b9e5855ebb3681f4d313209141c ql/test/extractor-tests/generated/type/UnownedStorageType/UnownedStorageType.ql 11e205283b368b9c9dbc79636c6007df501c952e6f715a9f07e65ec452192b38 ceb1e9c1279df07c77f9b23356b71c3e7672ec4cd5253898e09b27b2b24e4b00 ql/test/extractor-tests/generated/type/VariadicSequenceType/VariadicSequenceType.ql 8c44ebc1fd1fa0b5caad5eb5b280f227f002dcfaddba45131b2959dad0b458f6 5f497990e2bd57a3ea8e2eb7da598af0c4ba7c7b4cc89b549e45de0ae3712e60 diff --git a/swift/ql/test/extractor-tests/generated/Comment/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/Comment/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/Comment/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/Comment/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/OtherAvailabilitySpec/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/PlatformVersionAvailabilitySpec/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/ConstructorDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/ConstructorDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/ConstructorDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/ConstructorDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/DestructorDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/DestructorDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/DestructorDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/DestructorDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/EnumCaseDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/EnumCaseDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/EnumCaseDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/EnumCaseDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/EnumElementDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/EnumElementDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/EnumElementDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/EnumElementDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/GenericTypeParamDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/GenericTypeParamDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/GenericTypeParamDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/GenericTypeParamDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/InfixOperatorDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/InfixOperatorDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/InfixOperatorDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/InfixOperatorDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/PatternBindingDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/PatternBindingDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/PatternBindingDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/PatternBindingDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/PostfixOperatorDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/PostfixOperatorDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/PostfixOperatorDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/PostfixOperatorDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/PrecedenceGroupDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/PrecedenceGroupDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/PrecedenceGroupDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/PrecedenceGroupDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/PrefixOperatorDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/PrefixOperatorDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/PrefixOperatorDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/PrefixOperatorDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/ProtocolDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/ProtocolDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/ProtocolDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/ProtocolDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/StructDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/StructDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/StructDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/StructDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/SubscriptDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/SubscriptDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/SubscriptDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/SubscriptDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/TopLevelCodeDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/TopLevelCodeDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/TopLevelCodeDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/TopLevelCodeDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/decl/TypeAliasDecl/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/decl/TypeAliasDecl/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/decl/TypeAliasDecl/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/decl/TypeAliasDecl/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/Argument/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/Argument/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/Argument/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/Argument/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/ArrayExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/ArrayExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/ArrayExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/ArrayExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/AssignExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/AssignExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/AssignExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/AssignExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/AutoClosureExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/AutoClosureExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/AutoClosureExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/AutoClosureExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/BinaryExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/BinaryExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/BinaryExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/BinaryExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/BindOptionalExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/BindOptionalExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/BindOptionalExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/BindOptionalExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/BooleanLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/BooleanLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/BooleanLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/BooleanLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/CallExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/CallExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/CallExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/CallExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/CaptureListExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/CaptureListExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/CaptureListExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/CaptureListExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/ClosureExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/ClosureExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/ClosureExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/ClosureExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/CoerceExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/CoerceExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/CoerceExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/CoerceExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/ConditionalCheckedCastExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/ConditionalCheckedCastExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/ConditionalCheckedCastExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/ConditionalCheckedCastExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/DeclRefExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/DeclRefExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/DeclRefExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/DeclRefExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/DefaultArgumentExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/DefaultArgumentExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/DefaultArgumentExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/DefaultArgumentExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/DictionaryExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/DictionaryExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/DictionaryExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/DictionaryExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/DiscardAssignmentExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/DiscardAssignmentExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/DiscardAssignmentExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/DiscardAssignmentExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/DotSyntaxBaseIgnoredExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/DotSyntaxBaseIgnoredExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/DotSyntaxBaseIgnoredExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/DotSyntaxBaseIgnoredExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/DynamicTypeExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/DynamicTypeExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/DynamicTypeExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/DynamicTypeExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/FloatLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/FloatLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/FloatLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/FloatLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/ForceTryExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/ForceTryExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/ForceTryExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/ForceTryExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/ForceValueExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/ForceValueExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/ForceValueExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/ForceValueExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/ForcedCheckedCastExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/ForcedCheckedCastExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/ForcedCheckedCastExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/ForcedCheckedCastExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/IfExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/IfExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/IfExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/IfExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/InOutExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/InOutExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/InOutExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/InOutExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/IntegerLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/IntegerLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/IntegerLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/IntegerLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/InterpolatedStringLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/IsExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/KeyPathApplicationExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/KeyPathDotExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/KeyPathExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/LazyInitializerExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/MagicIdentifierLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/MakeTemporarilyEscapableExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/MakeTemporarilyEscapableExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/MakeTemporarilyEscapableExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/MakeTemporarilyEscapableExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/MemberRefExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/MemberRefExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/MemberRefExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/MemberRefExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/NilLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/NilLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/NilLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/NilLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/OneWayExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/OneWayExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/OneWayExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/OneWayExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/OpaqueValueExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/OpaqueValueExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/OpaqueValueExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/OpaqueValueExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/OpenExistentialExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/OpenExistentialExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/OpenExistentialExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/OpenExistentialExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/OptionalEvaluationExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/OptionalEvaluationExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/OptionalEvaluationExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/OptionalEvaluationExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/OptionalTryExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/OptionalTryExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/OptionalTryExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/OptionalTryExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/OtherConstructorDeclRefExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/OtherConstructorDeclRefExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/OtherConstructorDeclRefExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/OtherConstructorDeclRefExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/PrefixUnaryExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/PrefixUnaryExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/PrefixUnaryExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/PrefixUnaryExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/RebindSelfInConstructorExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/RebindSelfInConstructorExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/RebindSelfInConstructorExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/RebindSelfInConstructorExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/RegexLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/RegexLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/RegexLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/RegexLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/StringLiteralExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/StringLiteralExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/StringLiteralExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/StringLiteralExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/SubscriptExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/SubscriptExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/SubscriptExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/SubscriptExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/SuperRefExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/SuperRefExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/SuperRefExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/SuperRefExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/TapExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/TapExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/TapExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/TapExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/TryExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/TryExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/TryExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/TryExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/TupleElementExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/TupleElementExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/TupleElementExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/TupleElementExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/TupleExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/TupleExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/TupleExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/TupleExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/TypeExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/TypeExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/TypeExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/TypeExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/expr/VarargExpansionExpr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/expr/VarargExpansionExpr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/expr/VarargExpansionExpr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/expr/VarargExpansionExpr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/AnyPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/AnyPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/AnyPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/AnyPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/BindingPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/BindingPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/BindingPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/BindingPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/BoolPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/BoolPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/BoolPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/BoolPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/EnumElementPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/EnumElementPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/EnumElementPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/EnumElementPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/ExprPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/ExprPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/ExprPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/ExprPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/IsPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/IsPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/IsPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/IsPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/NamedPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/NamedPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/NamedPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/NamedPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/OptionalSomePattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/OptionalSomePattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/OptionalSomePattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/OptionalSomePattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/ParenPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/ParenPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/ParenPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/ParenPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/TuplePattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/TuplePattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/TuplePattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/TuplePattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/pattern/TypedPattern/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/pattern/TypedPattern/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/pattern/TypedPattern/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/pattern/TypedPattern/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/BraceStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/BraceStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/BraceStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/BraceStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/BreakStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/BreakStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/BreakStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/BreakStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/CaseLabelItem/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/CaseLabelItem/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/CaseLabelItem/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/CaseLabelItem/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/CaseStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/CaseStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/CaseStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/CaseStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/ConditionElement/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/ConditionElement/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/ConditionElement/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/ConditionElement/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/ContinueStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/ContinueStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/ContinueStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/ContinueStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/DeferStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/DeferStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/DeferStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/DeferStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/DoCatchStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/DoCatchStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/DoCatchStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/DoCatchStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/DoStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/DoStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/DoStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/DoStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/FallthroughStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/FallthroughStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/FallthroughStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/FallthroughStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/ForEachStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/ForEachStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/ForEachStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/ForEachStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/GuardStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/GuardStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/GuardStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/GuardStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/IfStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/IfStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/IfStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/IfStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/RepeatWhileStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/RepeatWhileStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/RepeatWhileStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/RepeatWhileStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/ReturnStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/ReturnStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/ReturnStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/ReturnStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/StmtCondition/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/StmtCondition/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/StmtCondition/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/StmtCondition/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/SwitchStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/SwitchStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/SwitchStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/SwitchStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/ThrowStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/ThrowStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/ThrowStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/ThrowStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/WhileStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/WhileStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/WhileStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/WhileStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/stmt/YieldStmt/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/stmt/YieldStmt/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/stmt/YieldStmt/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/stmt/YieldStmt/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/ArraySliceType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/ArraySliceType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/ArraySliceType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/ArraySliceType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/BoundGenericClassType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/BoundGenericClassType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/BoundGenericClassType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/BoundGenericClassType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/BoundGenericEnumType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/BoundGenericEnumType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/BoundGenericEnumType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/BoundGenericEnumType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/BoundGenericStructType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/BoundGenericStructType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/BoundGenericStructType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/BoundGenericStructType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/ClassType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/ClassType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/ClassType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/ClassType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/DependentMemberType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/DependentMemberType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/DependentMemberType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/DependentMemberType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/DictionaryType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/DictionaryType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/DictionaryType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/DictionaryType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/EnumType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/EnumType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/EnumType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/EnumType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/ExistentialMetatypeType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/ExistentialMetatypeType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/ExistentialMetatypeType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/ExistentialMetatypeType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/FunctionType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/FunctionType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/FunctionType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/FunctionType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/GenericFunctionType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/GenericFunctionType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/GenericFunctionType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/GenericFunctionType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/GenericTypeParamType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/GenericTypeParamType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/GenericTypeParamType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/GenericTypeParamType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/LValueType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/LValueType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/LValueType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/LValueType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/MetatypeType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/MetatypeType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/MetatypeType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/MetatypeType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/OptionalType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/OptionalType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/OptionalType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/OptionalType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/ParenType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/ParenType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/ParenType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/ParenType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/ProtocolType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/ProtocolType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/ProtocolType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/ProtocolType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/StructType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/StructType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/StructType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/StructType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/TypeAliasType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/TypeAliasType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/TypeAliasType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/TypeAliasType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/TypeRepr/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/TypeRepr/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/TypeRepr/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/TypeRepr/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted diff --git a/swift/ql/test/extractor-tests/generated/type/UnboundGenericType/MISSING_SOURCE.txt b/swift/ql/test/extractor-tests/generated/type/UnboundGenericType/MISSING_SOURCE.txt index 0d319d9a669..25daf3d23a2 100644 --- a/swift/ql/test/extractor-tests/generated/type/UnboundGenericType/MISSING_SOURCE.txt +++ b/swift/ql/test/extractor-tests/generated/type/UnboundGenericType/MISSING_SOURCE.txt @@ -1,4 +1,4 @@ // generated by codegen/codegen.py -After a swift source file is added in this directory and codegen/codegen.py is run again, test queries +After a source file is added in this directory and codegen/codegen.py is run again, test queries will appear and this file will be deleted From 6d192cdcc130f231463b99951fc42b85d81986ce Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 23 Feb 2023 12:25:16 +0100 Subject: [PATCH 412/415] Swift: make C++ code generation language agnostic --- swift/BUILD.bazel | 8 ++++- swift/codegen/codegen.py | 20 +++++++---- swift/codegen/generators/cppgen.py | 3 +- swift/codegen/generators/dbschemegen.py | 4 +-- swift/codegen/generators/trapgen.py | 4 ++- swift/codegen/lib/cpp.py | 4 +++ swift/codegen/lib/render.py | 13 +++---- .../codegen/templates/cpp_classes_h.mustache | 4 +-- swift/codegen/templates/trap_traps_h.mustache | 6 ++-- swift/codegen/test/test_dbschemegen.py | 34 +++++++++---------- swift/codegen/test/test_render.py | 22 ++++++------ swift/extractor/trap/BUILD.bazel | 10 ++++-- 12 files changed, 77 insertions(+), 55 deletions(-) diff --git a/swift/BUILD.bazel b/swift/BUILD.bazel index b403c09e86e..eb7e6a86997 100644 --- a/swift/BUILD.bazel +++ b/swift/BUILD.bazel @@ -5,7 +5,13 @@ load("//misc/bazel:pkg_runfiles.bzl", "pkg_runfiles") filegroup( name = "schema", - srcs = ["schema.py"] + glob(["*.dbscheme"]), + srcs = ["schema.py"], + visibility = ["//swift:__subpackages__"], +) + +filegroup( + name = "schema_includes", + srcs = glob(["*.dbscheme"]), visibility = ["//swift:__subpackages__"], ) diff --git a/swift/codegen/codegen.py b/swift/codegen/codegen.py index 5e9f4e9ac50..c65502088a7 100755 --- a/swift/codegen/codegen.py +++ b/swift/codegen/codegen.py @@ -60,12 +60,19 @@ def _parse_args() -> argparse.Namespace: p.add_argument("--generated-registry", help="registry file containing information about checked-in generated code"), ] + p.add_argument("--script-name", + help="script name to put in header comments of generated files. By default, the path of this " + "script relative to the root directory") + p.add_argument("--trap-library", + help="path to the trap library from an include directory, required if generating C++ trap bindings"), p.add_argument("--ql-format", action="store_true", default=True, help="use codeql to autoformat QL files (which is the default)") p.add_argument("--no-ql-format", action="store_false", dest="ql_format", help="do not format QL files") p.add_argument("--codeql-binary", default="codeql", help="command to use for QL formatting (default %(default)s)") p.add_argument("--force", "-f", action="store_true", - help="generate all files without skipping unchanged files and overwriting modified ones"), + help="generate all files without skipping unchanged files and overwriting modified ones") + p.add_argument("--use-current-directory", action="store_true", + help="do not consider paths as relative to --root-dir or the configuration directory") opts = p.parse_args() if opts.configuration_file is not None: with open(opts.configuration_file) as config: @@ -75,16 +82,15 @@ def _parse_args() -> argparse.Namespace: setattr(opts, flag, getattr(defaults, flag)) if opts.root_dir is None: opts.root_dir = opts.configuration_file.parent - if opts.root_dir is None: - p.error("Either --configuration-file or --root-dir must be provided, or a codegen.conf file must be in a " - "containing directory") if not opts.generate: p.error("Nothing to do, specify --generate") - # absolutize all paths relative to --root-dir + # absolutize all paths for arg in path_arguments: path = getattr(opts, arg.dest) if path is not None: - setattr(opts, arg.dest, opts.root_dir / path) + setattr(opts, arg.dest, _abspath(path) if opts.use_current_directory else (opts.root_dir / path)) + if not opts.script_name: + opts.script_name = paths.exe_file.relative_to(opts.root_dir) return opts @@ -102,7 +108,7 @@ def run(): log_level = logging.INFO logging.basicConfig(format="{levelname} {message}", style='{', level=log_level) for target in opts.generate: - generate(target, opts, render.Renderer(opts.root_dir)) + generate(target, opts, render.Renderer(opts.script_name, opts.root_dir)) if __name__ == "__main__": diff --git a/swift/codegen/generators/cppgen.py b/swift/codegen/generators/cppgen.py index 82f41bdc3a5..9de53818f71 100644 --- a/swift/codegen/generators/cppgen.py +++ b/swift/codegen/generators/cppgen.py @@ -95,4 +95,5 @@ def generate(opts, renderer): out = opts.cpp_output for dir, classes in processor.get_classes().items(): renderer.render(cpp.ClassList(classes, opts.schema, - include_parent=bool(dir)), out / dir / "TrapClasses") + include_parent=bool(dir), + trap_library=opts.trap_library), out / dir / "TrapClasses") diff --git a/swift/codegen/generators/dbschemegen.py b/swift/codegen/generators/dbschemegen.py index 23591a41606..2c6ebca87f3 100755 --- a/swift/codegen/generators/dbschemegen.py +++ b/swift/codegen/generators/dbschemegen.py @@ -125,8 +125,8 @@ def generate(opts, renderer): data = schemaloader.load_file(input) - dbscheme = Scheme(src=input.relative_to(opts.root_dir), - includes=get_includes(data, include_dir=input.parent, root_dir=opts.root_dir), + dbscheme = Scheme(src=input.name, + includes=get_includes(data, include_dir=input.parent, root_dir=input.parent), declarations=get_declarations(data)) renderer.render(dbscheme, out) diff --git a/swift/codegen/generators/trapgen.py b/swift/codegen/generators/trapgen.py index 87ee104a972..67921486c86 100755 --- a/swift/codegen/generators/trapgen.py +++ b/swift/codegen/generators/trapgen.py @@ -72,6 +72,7 @@ def generate(opts, renderer): assert opts.cpp_output tag_graph = {} out = opts.cpp_output + trap_library = opts.trap_library traps = {pathlib.Path(): []} for e in dbschemeloader.iterload(opts.dbscheme): @@ -84,7 +85,8 @@ def generate(opts, renderer): for dir, entries in traps.items(): dir = dir or pathlib.Path() - renderer.render(cpp.TrapList(entries, opts.dbscheme), out / dir / "TrapEntries") + relative_gen_dir = pathlib.Path(*[".." for _ in dir.parents]) + renderer.render(cpp.TrapList(entries, opts.dbscheme, trap_library, relative_gen_dir), out / dir / "TrapEntries") tags = [] for tag in toposort_flatten(tag_graph): diff --git a/swift/codegen/lib/cpp.py b/swift/codegen/lib/cpp.py index 27bac12231b..9ca2d8e2ebc 100644 --- a/swift/codegen/lib/cpp.py +++ b/swift/codegen/lib/cpp.py @@ -1,3 +1,4 @@ +import pathlib import re from dataclasses import dataclass, field from typing import List, ClassVar @@ -110,6 +111,8 @@ class TrapList: extensions = ["h", "cpp"] traps: List[Trap] source: str + trap_library_dir: pathlib.Path + gen_dir: pathlib.Path @dataclass @@ -156,4 +159,5 @@ class ClassList: classes: List[Class] source: str + trap_library: str include_parent: bool = False diff --git a/swift/codegen/lib/render.py b/swift/codegen/lib/render.py index 5f710837151..697c2f8c2c9 100644 --- a/swift/codegen/lib/render.py +++ b/swift/codegen/lib/render.py @@ -25,13 +25,10 @@ class Error(Exception): class Renderer: """ Template renderer using mustache templates in the `templates` directory """ - def __init__(self, root_dir: pathlib.Path): + def __init__(self, generator: pathlib.Path, root_dir: pathlib.Path): self._r = pystache.Renderer(search_dirs=str(paths.templates_dir), escape=lambda u: u) self._root_dir = root_dir - try: - self._generator = self._get_path(paths.exe_file) - except ValueError: - self._generator = paths.exe_file.name + self._generator = generator def _get_path(self, file: pathlib.Path): return file.relative_to(self._root_dir) @@ -63,7 +60,7 @@ class Renderer: def manage(self, generated: typing.Iterable[pathlib.Path], stubs: typing.Iterable[pathlib.Path], registry: pathlib.Path, force: bool = False) -> "RenderManager": - return RenderManager(self._root_dir, generated, stubs, registry, force) + return RenderManager(self._generator, self._root_dir, generated, stubs, registry, force) class RenderManager(Renderer): @@ -88,10 +85,10 @@ class RenderManager(Renderer): pre: str post: typing.Optional[str] = None - def __init__(self, root_dir: pathlib.Path, generated: typing.Iterable[pathlib.Path], + def __init__(self, generator: pathlib.Path, root_dir: pathlib.Path, generated: typing.Iterable[pathlib.Path], stubs: typing.Iterable[pathlib.Path], registry: pathlib.Path, force: bool = False): - super().__init__(root_dir) + super().__init__(generator, root_dir) self._registry_path = registry self._force = force self._hashes = {} diff --git a/swift/codegen/templates/cpp_classes_h.mustache b/swift/codegen/templates/cpp_classes_h.mustache index a4a22170b2f..157bbc31217 100644 --- a/swift/codegen/templates/cpp_classes_h.mustache +++ b/swift/codegen/templates/cpp_classes_h.mustache @@ -6,8 +6,8 @@ #include #include -#include "swift/extractor/trap/TrapLabel.h" -#include "swift/extractor/trap/TrapTagTraits.h" +#include "{{trap_library}}/TrapLabel.h" +#include "{{trap_library}}/TrapTagTraits.h" #include "./TrapEntries.h" {{#include_parent}} #include "../TrapClasses.h" diff --git a/swift/codegen/templates/trap_traps_h.mustache b/swift/codegen/templates/trap_traps_h.mustache index d3bf7769bd7..987e980d24b 100644 --- a/swift/codegen/templates/trap_traps_h.mustache +++ b/swift/codegen/templates/trap_traps_h.mustache @@ -5,9 +5,9 @@ #include #include -#include "swift/extractor/trap/TrapLabel.h" -#include "swift/extractor/trap/TrapTagTraits.h" -#include "swift/extractor/trap/generated/TrapTags.h" +#include "{{trap_library_dir}}/TrapLabel.h" +#include "{{trap_library_dir}}/TrapTagTraits.h" +#include "{{gen_dir}}/TrapTags.h" namespace codeql { {{#traps}} diff --git a/swift/codegen/test/test_dbschemegen.py b/swift/codegen/test/test_dbschemegen.py index 4e560e8208e..74070967d1a 100644 --- a/swift/codegen/test/test_dbschemegen.py +++ b/swift/codegen/test/test_dbschemegen.py @@ -30,7 +30,7 @@ def generate(opts, input, renderer): def test_empty(generate): assert generate([]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[], ) @@ -43,10 +43,10 @@ def test_includes(input, opts, generate): write(opts.schema.parent / i, i + " data") assert generate([]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[ dbscheme.SchemeInclude( - src=schema_dir / i, + src=pathlib.Path(i), data=i + " data", ) for i in includes ], @@ -58,7 +58,7 @@ def test_empty_final_class(generate, dir_param): assert generate([ schema.Class("Object", group=dir_param.input), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Table( @@ -78,7 +78,7 @@ def test_final_class_with_single_scalar_field(generate, dir_param): schema.SingleProperty("foo", "bar"), ]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Table( @@ -98,7 +98,7 @@ def test_final_class_with_single_class_field(generate, dir_param): schema.SingleProperty("foo", "Bar"), ]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Table( @@ -118,7 +118,7 @@ def test_final_class_with_optional_field(generate, dir_param): schema.OptionalProperty("foo", "bar"), ]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Table( @@ -146,7 +146,7 @@ def test_final_class_with_repeated_field(generate, property_cls, dir_param): property_cls("foo", "bar"), ]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Table( @@ -174,7 +174,7 @@ def test_final_class_with_predicate_field(generate, dir_param): schema.PredicateProperty("foo"), ]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Table( @@ -205,7 +205,7 @@ def test_final_class_with_more_fields(generate, dir_param): schema.PredicateProperty("six"), ]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Table( @@ -259,7 +259,7 @@ def test_empty_class_with_derived(generate): schema.Class(name="Left", bases=["Base"]), schema.Class(name="Right", bases=["Base"]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Union( @@ -290,7 +290,7 @@ def test_class_with_derived_and_single_property(generate, dir_param): schema.Class(name="Left", bases=["Base"]), schema.Class(name="Right", bases=["Base"]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Union( @@ -330,7 +330,7 @@ def test_class_with_derived_and_optional_property(generate, dir_param): schema.Class(name="Left", bases=["Base"]), schema.Class(name="Right", bases=["Base"]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Union( @@ -370,7 +370,7 @@ def test_class_with_derived_and_repeated_property(generate, dir_param): schema.Class(name="Left", bases=["Base"]), schema.Class(name="Right", bases=["Base"]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Union( @@ -432,7 +432,7 @@ def test_null_class(generate): bases=["Base"], ), ], null="Null") == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Union( @@ -514,7 +514,7 @@ def test_ipa_classes_ignored(generate): schema.Class(name="B", ipa=schema.IpaInfo(from_class="A")), schema.Class(name="C", ipa=schema.IpaInfo(on_arguments={"x": "A"})), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[], ) @@ -526,7 +526,7 @@ def test_ipa_derived_classes_ignored(generate): schema.Class(name="B", bases=["A"], ipa=schema.IpaInfo()), schema.Class(name="C", bases=["A"]), ]) == dbscheme.Scheme( - src=schema_file, + src=schema_file.name, includes=[], declarations=[ dbscheme.Union("@a", ["@c"]), diff --git a/swift/codegen/test/test_render.py b/swift/codegen/test/test_render.py index 2e569c258b7..ce9c5b10b04 100644 --- a/swift/codegen/test/test_render.py +++ b/swift/codegen/test/test_render.py @@ -6,6 +6,8 @@ from swift.codegen.test.utils import * import hashlib +generator = "foo" + @pytest.fixture def pystache_renderer_cls(): @@ -22,7 +24,7 @@ def pystache_renderer(pystache_renderer_cls): @pytest.fixture def sut(pystache_renderer): - return render.Renderer(paths.root_dir) + return render.Renderer(generator, paths.root_dir) def assert_file(file, text): @@ -53,7 +55,7 @@ def test_render(pystache_renderer, sut): assert_file(output, text) assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] @@ -72,7 +74,7 @@ def test_managed_render(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(text)} {hash(text)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] @@ -90,7 +92,7 @@ def test_managed_render_with_no_registry(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(text)} {hash(text)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] @@ -111,7 +113,7 @@ def test_managed_render_with_post_processing(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(text)} {hash(postprocessed_text)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] @@ -149,7 +151,7 @@ def test_managed_render_with_skipping_of_generated_file(pystache_renderer, sut): assert_file(registry, f"some/output.txt {hash(some_output)} {hash(some_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] @@ -171,7 +173,7 @@ def test_managed_render_with_skipping_of_stub_file(pystache_renderer, sut): assert_file(registry, f"some/stub.txt {hash(some_output)} {hash(some_processed_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] @@ -277,7 +279,7 @@ def test_render_with_extensions(pystache_renderer, sut): sut.render(data, output) expected_templates = ["test_template_foo", "test_template_bar", "test_template_baz"] assert pystache_renderer.mock_calls == [ - mock.call.render_name(t, data, generator=paths.exe_file.relative_to(paths.root_dir)) + mock.call.render_name(t, data, generator=generator) for t in expected_templates ] for expected_output, expected_contents in zip(expected_outputs, rendered): @@ -301,7 +303,7 @@ def test_managed_render_with_force_not_skipping_generated_file(pystache_renderer assert_file(registry, f"some/output.txt {hash(some_output)} {hash(some_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] @@ -323,7 +325,7 @@ def test_managed_render_with_force_not_skipping_stub_file(pystache_renderer, sut assert_file(registry, f"some/stub.txt {hash(some_output)} {hash(some_output)}\n") assert pystache_renderer.mock_calls == [ - mock.call.render_name(data.template, data, generator=paths.exe_file.relative_to(paths.root_dir)), + mock.call.render_name(data.template, data, generator=generator), ] diff --git a/swift/extractor/trap/BUILD.bazel b/swift/extractor/trap/BUILD.bazel index 42725dbfb35..75e0caede55 100644 --- a/swift/extractor/trap/BUILD.bazel +++ b/swift/extractor/trap/BUILD.bazel @@ -16,10 +16,14 @@ genrule( cmd = " ".join([ "$(location //swift/codegen)", "--generate=dbscheme,trap,cpp", - "--dbscheme $(RULEDIR)/generated/swift.dbscheme", - "--cpp-output $(RULEDIR)/generated", + "--dbscheme=$(RULEDIR)/generated/swift.dbscheme", + "--cpp-output=$(RULEDIR)/generated", + "--trap-library=swift/extractor/trap", + "--use-current-dir", + "--schema=$(location //swift:schema)", + "--script-name=codegen/codegen.py", ]), - exec_tools = ["//swift/codegen"], + exec_tools = ["//swift/codegen", "//swift:schema"], ) filegroup( From cdd4e8021bf0dddc214f48b77768bad0ac53ccdb Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Fri, 24 Feb 2023 13:44:29 +0100 Subject: [PATCH 413/415] Move `swift/codegen` to `misc/codegen` --- .github/workflows/swift.yml | 2 ++ .pre-commit-config.yaml | 2 +- CODEOWNERS | 1 + misc/bazel/workspace.bzl | 10 ++++++++++ misc/bazel/workspace_deps.bzl | 6 ++++-- {swift => misc}/codegen/.pep8 | 0 misc/codegen/BUILD.bazel | 14 ++++++++++++++ {swift => misc}/codegen/README.md | 8 ++++---- {swift => misc}/codegen/codegen.py | 4 ++-- misc/codegen/generators/BUILD.bazel | 11 +++++++++++ {swift => misc}/codegen/generators/__init__.py | 0 {swift => misc}/codegen/generators/cppgen.py | 4 ++-- {swift => misc}/codegen/generators/dbschemegen.py | 6 +++--- {swift => misc}/codegen/generators/qlgen.py | 4 ++-- {swift => misc}/codegen/generators/trapgen.py | 4 ++-- {swift => misc}/codegen/lib/BUILD.bazel | 4 ++-- {swift => misc}/codegen/lib/cpp.py | 0 {swift => misc}/codegen/lib/dbscheme.py | 0 {swift => misc}/codegen/lib/paths.py | 7 ++++--- {swift => misc}/codegen/lib/ql.py | 0 {swift => misc}/codegen/lib/render.py | 0 {swift => misc}/codegen/lib/schema.py | 0 {swift/codegen => misc/codegen/lib}/schemadefs.py | 2 +- {swift => misc}/codegen/loaders/BUILD.bazel | 4 ++-- {swift => misc}/codegen/loaders/dbschemeloader.py | 2 +- {swift => misc}/codegen/loaders/schemaloader.py | 4 ++-- {swift => misc}/codegen/requirements.txt | 0 {swift/codegen/lib => misc/codegen}/schemadefs.py | 2 +- {swift => misc}/codegen/templates/BUILD.bazel | 2 +- .../codegen/templates/cpp_classes_cpp.mustache | 0 .../codegen/templates/cpp_classes_h.mustache | 0 .../codegen/templates/dbscheme.mustache | 0 .../codegen/templates/ql_class.mustache | 0 {swift => misc}/codegen/templates/ql_db.mustache | 0 .../codegen/templates/ql_imports.mustache | 0 .../templates/ql_ipa_constructor_stub.mustache | 0 .../codegen/templates/ql_ipa_types.mustache | 0 .../codegen/templates/ql_parent.mustache | 0 .../codegen/templates/ql_property_doc.mustache | 0 {swift => misc}/codegen/templates/ql_stub.mustache | 0 .../codegen/templates/ql_test_class.mustache | 0 .../codegen/templates/ql_test_missing.mustache | 0 .../codegen/templates/ql_test_property.mustache | 0 .../codegen/templates/trap_tags_h.mustache | 0 .../codegen/templates/trap_traps_cpp.mustache | 0 .../codegen/templates/trap_traps_h.mustache | 0 {swift => misc}/codegen/test/BUILD.bazel | 6 +++--- {swift => misc}/codegen/test/test_cpp.py | 2 +- {swift => misc}/codegen/test/test_cppgen.py | 6 +++--- {swift => misc}/codegen/test/test_dbscheme.py | 4 ++-- {swift => misc}/codegen/test/test_dbschemegen.py | 6 +++--- .../codegen/test/test_dbschemelaoder.py | 6 +++--- {swift => misc}/codegen/test/test_ql.py | 4 ++-- {swift => misc}/codegen/test/test_qlgen.py | 6 +++--- {swift => misc}/codegen/test/test_render.py | 2 +- {swift => misc}/codegen/test/test_schemaloader.py | 6 +++--- {swift => misc}/codegen/test/test_trapgen.py | 6 +++--- {swift => misc}/codegen/test/utils.py | 10 +++++----- swift/README.md | 2 ++ swift/actions/build-and-test/action.yml | 2 +- swift/codegen.conf | 2 ++ swift/codegen/BUILD.bazel | 12 ++++-------- swift/codegen/generators/BUILD.bazel | 11 ----------- swift/extractor/trap/BUILD.bazel | 4 ++-- swift/schema.py | 2 +- 65 files changed, 116 insertions(+), 86 deletions(-) rename {swift => misc}/codegen/.pep8 (100%) create mode 100644 misc/codegen/BUILD.bazel rename {swift => misc}/codegen/README.md (84%) rename {swift => misc}/codegen/codegen.py (98%) create mode 100644 misc/codegen/generators/BUILD.bazel rename {swift => misc}/codegen/generators/__init__.py (100%) rename {swift => misc}/codegen/generators/cppgen.py (97%) rename {swift => misc}/codegen/generators/dbschemegen.py (97%) rename {swift => misc}/codegen/generators/qlgen.py (99%) rename {swift => misc}/codegen/generators/trapgen.py (96%) rename {swift => misc}/codegen/lib/BUILD.bazel (56%) rename {swift => misc}/codegen/lib/cpp.py (100%) rename {swift => misc}/codegen/lib/dbscheme.py (100%) rename {swift => misc}/codegen/lib/paths.py (70%) rename {swift => misc}/codegen/lib/ql.py (100%) rename {swift => misc}/codegen/lib/render.py (100%) rename {swift => misc}/codegen/lib/schema.py (100%) rename {swift/codegen => misc/codegen/lib}/schemadefs.py (98%) rename {swift => misc}/codegen/loaders/BUILD.bazel (56%) rename {swift => misc}/codegen/loaders/dbschemeloader.py (97%) rename {swift => misc}/codegen/loaders/schemaloader.py (98%) rename {swift => misc}/codegen/requirements.txt (100%) rename {swift/codegen/lib => misc/codegen}/schemadefs.py (98%) rename {swift => misc}/codegen/templates/BUILD.bazel (68%) rename {swift => misc}/codegen/templates/cpp_classes_cpp.mustache (100%) rename {swift => misc}/codegen/templates/cpp_classes_h.mustache (100%) rename {swift => misc}/codegen/templates/dbscheme.mustache (100%) rename {swift => misc}/codegen/templates/ql_class.mustache (100%) rename {swift => misc}/codegen/templates/ql_db.mustache (100%) rename {swift => misc}/codegen/templates/ql_imports.mustache (100%) rename {swift => misc}/codegen/templates/ql_ipa_constructor_stub.mustache (100%) rename {swift => misc}/codegen/templates/ql_ipa_types.mustache (100%) rename {swift => misc}/codegen/templates/ql_parent.mustache (100%) rename {swift => misc}/codegen/templates/ql_property_doc.mustache (100%) rename {swift => misc}/codegen/templates/ql_stub.mustache (100%) rename {swift => misc}/codegen/templates/ql_test_class.mustache (100%) rename {swift => misc}/codegen/templates/ql_test_missing.mustache (100%) rename {swift => misc}/codegen/templates/ql_test_property.mustache (100%) rename {swift => misc}/codegen/templates/trap_tags_h.mustache (100%) rename {swift => misc}/codegen/templates/trap_traps_cpp.mustache (100%) rename {swift => misc}/codegen/templates/trap_traps_h.mustache (100%) rename {swift => misc}/codegen/test/BUILD.bazel (72%) rename {swift => misc}/codegen/test/test_cpp.py (98%) rename {swift => misc}/codegen/test/test_cppgen.py (98%) rename {swift => misc}/codegen/test/test_dbscheme.py (95%) rename {swift => misc}/codegen/test/test_dbschemegen.py (99%) rename {swift => misc}/codegen/test/test_dbschemelaoder.py (95%) rename {swift => misc}/codegen/test/test_ql.py (98%) rename {swift => misc}/codegen/test/test_qlgen.py (99%) rename {swift => misc}/codegen/test/test_render.py (99%) rename {swift => misc}/codegen/test/test_schemaloader.py (99%) rename {swift => misc}/codegen/test/test_trapgen.py (97%) rename {swift => misc}/codegen/test/utils.py (83%) delete mode 100644 swift/codegen/generators/BUILD.bazel diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index de0f11f0521..806e04e6c68 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -5,6 +5,7 @@ on: paths: - "swift/**" - "misc/bazel/**" + - "misc/codegen/**" - "*.bazel*" - .github/workflows/swift.yml - .github/actions/** @@ -19,6 +20,7 @@ on: paths: - "swift/**" - "misc/bazel/**" + - "misc/codegen/**" - "*.bazel*" - .github/workflows/swift.yml - .github/actions/** diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5f35c2c183b..e612a423462 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,5 +53,5 @@ repos: name: Run Swift code generation unit tests files: ^swift/codegen/.*\.py$ language: system - entry: bazel test //swift/codegen/test + entry: bazel test //misc/codegen/test pass_filenames: false diff --git a/CODEOWNERS b/CODEOWNERS index 27ac245e959..8371dd768cd 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,6 +6,7 @@ /python/ @github/codeql-dynamic /ruby/ @github/codeql-dynamic /swift/ @github/codeql-swift +/misc/codegen/ @github/codeql-swift /java/kotlin-extractor/ @github/codeql-kotlin /java/kotlin-explorer/ @github/codeql-kotlin diff --git a/misc/bazel/workspace.bzl b/misc/bazel/workspace.bzl index 46426f48d5c..ef89ccfb666 100644 --- a/misc/bazel/workspace.bzl +++ b/misc/bazel/workspace.bzl @@ -33,3 +33,13 @@ def codeql_workspace(repository_name = "codeql"): "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.8.1.tar.gz", ], ) + + maybe( + repo_rule = http_archive, + name = "bazel_skylib", + sha256 = "b8a1527901774180afc798aeb28c4634bdccf19c4d98e7bdd1ce79d1fe9aaad7", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz", + ], + ) diff --git a/misc/bazel/workspace_deps.bzl b/misc/bazel/workspace_deps.bzl index 987fd144fd8..674be778d78 100644 --- a/misc/bazel/workspace_deps.bzl +++ b/misc/bazel/workspace_deps.bzl @@ -1,9 +1,11 @@ load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies") load("@rules_python//python:pip.bzl", "pip_install") +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") def codeql_workspace_deps(repository_name = "codeql"): pip_install( - name = "swift_codegen_deps", - requirements = "@%s//swift/codegen:requirements.txt" % repository_name, + name = "codegen_deps", + requirements = "@%s//misc/codegen:requirements.txt" % repository_name, ) + bazel_skylib_workspace() rules_pkg_dependencies() diff --git a/swift/codegen/.pep8 b/misc/codegen/.pep8 similarity index 100% rename from swift/codegen/.pep8 rename to misc/codegen/.pep8 diff --git a/misc/codegen/BUILD.bazel b/misc/codegen/BUILD.bazel new file mode 100644 index 00000000000..102e52fb10b --- /dev/null +++ b/misc/codegen/BUILD.bazel @@ -0,0 +1,14 @@ +load("@codegen_deps//:requirements.bzl", "requirement") + +py_binary( + name = "codegen", + srcs = ["codegen.py"], + data = [ + "//misc/codegen/templates:cpp", + "//misc/codegen/templates:trap", + ], + visibility = ["//visibility:public"], + deps = [ + "//misc/codegen/generators", + ], +) diff --git a/swift/codegen/README.md b/misc/codegen/README.md similarity index 84% rename from swift/codegen/README.md rename to misc/codegen/README.md index db94d327da6..149c673dab5 100644 --- a/swift/codegen/README.md +++ b/misc/codegen/README.md @@ -3,7 +3,7 @@ This directory contains the code generation suite used by the Swift extractor and the QL library. This suite will use the abstract class specification of [`schema.yml`](schema.yml) to generate: -* [the `dbscheme` file](../ql/lib/swift.dbscheme) (see [`dbschemegen.py`](generators/dbschemegen.py)) +* [the `dbscheme` file](../ql/lib/misc.dbscheme) (see [`dbschemegen.py`](generators/dbschemegen.py)) * [the QL generated code](../ql/lib/codeql/swift/generated) and when appropriate [the corresponding stubs](../ql/lib/codeql/swift/elements) (see [`qlgen.py`](generators/qlgen.py)) * C++ tags and trap entries (see [`trapgen.py`](generators/trapgen.py)) @@ -11,9 +11,9 @@ the abstract class specification of [`schema.yml`](schema.yml) to generate: ## Usage -By default `bazel run //swift/codegen` will update all checked-in generated files (`dbscheme` and QL sources). You can +By default `bazel run //misc/codegen` will update all checked-in generated files (`dbscheme` and QL sources). You can append `--` followed by other options to tweak the behaviour, which is mainly intended for debugging. -See `bazel run //swift/codegen -- --help` for a list of all options. In particular `--generate` can be used with a comma +See `bazel run //misc/codegen -- --help` for a list of all options. In particular `--generate` can be used with a comma separated list to select what to generate (choosing among `dbscheme`, `ql`, `trap` and `cpp`). C++ code is generated during build (see [`swift/extractor/trap/BUILD.bazel`](../extractor/trap/BUILD.bazel)). After a @@ -38,7 +38,7 @@ specified as the `generate` function in the modules within [the `generators` dir Finally, [`codegen.py`](codegen.py) is the driver script gluing everything together and specifying the command line options. -Unit tests are in [the `test` directory](test) and can be run via `bazel test //swift/codegen/test`. +Unit tests are in [the `test` directory](test) and can be run via `bazel test //misc/codegen/test`. For more details about each specific generation target, please refer to the module docstrings in [the `generators` directory](generators). diff --git a/swift/codegen/codegen.py b/misc/codegen/codegen.py similarity index 98% rename from swift/codegen/codegen.py rename to misc/codegen/codegen.py index c65502088a7..11f6fbe4a7b 100755 --- a/swift/codegen/codegen.py +++ b/misc/codegen/codegen.py @@ -14,8 +14,8 @@ if 'BUILD_WORKSPACE_DIRECTORY' not in os.environ: _repo_root = pathlib.Path(__file__).resolve().parents[2] sys.path.append(str(_repo_root)) -from swift.codegen.lib import render, paths -from swift.codegen.generators import generate +from misc.codegen.lib import render, paths +from misc.codegen.generators import generate def _parse_args() -> argparse.Namespace: diff --git a/misc/codegen/generators/BUILD.bazel b/misc/codegen/generators/BUILD.bazel new file mode 100644 index 00000000000..df328a7df7f --- /dev/null +++ b/misc/codegen/generators/BUILD.bazel @@ -0,0 +1,11 @@ +load("@codegen_deps//:requirements.bzl", "requirement") + +py_library( + name = "generators", + srcs = glob(["*.py"]), + visibility = ["//misc/codegen:__subpackages__"], + deps = [ + "//misc/codegen/lib", + "//misc/codegen/loaders", + ], +) diff --git a/swift/codegen/generators/__init__.py b/misc/codegen/generators/__init__.py similarity index 100% rename from swift/codegen/generators/__init__.py rename to misc/codegen/generators/__init__.py diff --git a/swift/codegen/generators/cppgen.py b/misc/codegen/generators/cppgen.py similarity index 97% rename from swift/codegen/generators/cppgen.py rename to misc/codegen/generators/cppgen.py index 9de53818f71..f6a7f8d792c 100644 --- a/swift/codegen/generators/cppgen.py +++ b/misc/codegen/generators/cppgen.py @@ -16,8 +16,8 @@ import typing import inflection -from swift.codegen.lib import cpp, schema -from swift.codegen.loaders import schemaloader +from misc.codegen.lib import cpp, schema +from misc.codegen.loaders import schemaloader def _get_type(t: str, add_or_none_except: typing.Optional[str] = None) -> str: diff --git a/swift/codegen/generators/dbschemegen.py b/misc/codegen/generators/dbschemegen.py similarity index 97% rename from swift/codegen/generators/dbschemegen.py rename to misc/codegen/generators/dbschemegen.py index 2c6ebca87f3..05483748db5 100755 --- a/swift/codegen/generators/dbschemegen.py +++ b/misc/codegen/generators/dbschemegen.py @@ -17,9 +17,9 @@ import typing import inflection -from swift.codegen.lib import schema -from swift.codegen.loaders import schemaloader -from swift.codegen.lib.dbscheme import * +from misc.codegen.lib import schema +from misc.codegen.loaders import schemaloader +from misc.codegen.lib.dbscheme import * log = logging.getLogger(__name__) diff --git a/swift/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py similarity index 99% rename from swift/codegen/generators/qlgen.py rename to misc/codegen/generators/qlgen.py index bb140ab4f82..aec610fe4cd 100755 --- a/swift/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -29,8 +29,8 @@ import itertools import inflection -from swift.codegen.lib import schema, ql -from swift.codegen.loaders import schemaloader +from misc.codegen.lib import schema, ql +from misc.codegen.loaders import schemaloader log = logging.getLogger(__name__) diff --git a/swift/codegen/generators/trapgen.py b/misc/codegen/generators/trapgen.py similarity index 96% rename from swift/codegen/generators/trapgen.py rename to misc/codegen/generators/trapgen.py index 67921486c86..e22b3e4e0e7 100755 --- a/swift/codegen/generators/trapgen.py +++ b/misc/codegen/generators/trapgen.py @@ -17,8 +17,8 @@ import pathlib import inflection from toposort import toposort_flatten -from swift.codegen.lib import dbscheme, cpp -from swift.codegen.loaders import dbschemeloader +from misc.codegen.lib import dbscheme, cpp +from misc.codegen.loaders import dbschemeloader log = logging.getLogger(__name__) diff --git a/swift/codegen/lib/BUILD.bazel b/misc/codegen/lib/BUILD.bazel similarity index 56% rename from swift/codegen/lib/BUILD.bazel rename to misc/codegen/lib/BUILD.bazel index fd2607448b4..482d1ac178f 100644 --- a/swift/codegen/lib/BUILD.bazel +++ b/misc/codegen/lib/BUILD.bazel @@ -1,9 +1,9 @@ -load("@swift_codegen_deps//:requirements.bzl", "requirement") +load("@codegen_deps//:requirements.bzl", "requirement") py_library( name = "lib", srcs = glob(["*.py"]), - visibility = ["//swift/codegen:__subpackages__"], + visibility = ["//misc/codegen:__subpackages__"], deps = [ requirement("pystache"), requirement("inflection"), diff --git a/swift/codegen/lib/cpp.py b/misc/codegen/lib/cpp.py similarity index 100% rename from swift/codegen/lib/cpp.py rename to misc/codegen/lib/cpp.py diff --git a/swift/codegen/lib/dbscheme.py b/misc/codegen/lib/dbscheme.py similarity index 100% rename from swift/codegen/lib/dbscheme.py rename to misc/codegen/lib/dbscheme.py diff --git a/swift/codegen/lib/paths.py b/misc/codegen/lib/paths.py similarity index 70% rename from swift/codegen/lib/paths.py rename to misc/codegen/lib/paths.py index eae5192c0d9..b102987a226 100644 --- a/swift/codegen/lib/paths.py +++ b/misc/codegen/lib/paths.py @@ -4,15 +4,16 @@ import pathlib import sys import os +_this_file = pathlib.Path(__file__).resolve() + try: workspace_dir = pathlib.Path(os.environ['BUILD_WORKSPACE_DIRECTORY']).resolve() # <- means we are using bazel run root_dir = workspace_dir / 'swift' except KeyError: - _this_file = pathlib.Path(__file__).resolve() root_dir = _this_file.parents[2] workspace_dir = root_dir.parent -lib_dir = root_dir / 'codegen' / 'lib' -templates_dir = root_dir / 'codegen' / 'templates' +lib_dir = _this_file.parents[2] / 'codegen' / 'lib' +templates_dir = _this_file.parents[2] / 'codegen' / 'templates' exe_file = pathlib.Path(sys.argv[0]).resolve() diff --git a/swift/codegen/lib/ql.py b/misc/codegen/lib/ql.py similarity index 100% rename from swift/codegen/lib/ql.py rename to misc/codegen/lib/ql.py diff --git a/swift/codegen/lib/render.py b/misc/codegen/lib/render.py similarity index 100% rename from swift/codegen/lib/render.py rename to misc/codegen/lib/render.py diff --git a/swift/codegen/lib/schema.py b/misc/codegen/lib/schema.py similarity index 100% rename from swift/codegen/lib/schema.py rename to misc/codegen/lib/schema.py diff --git a/swift/codegen/schemadefs.py b/misc/codegen/lib/schemadefs.py similarity index 98% rename from swift/codegen/schemadefs.py rename to misc/codegen/lib/schemadefs.py index d972e5a63e5..6c9457490e7 100644 --- a/swift/codegen/schemadefs.py +++ b/misc/codegen/lib/schemadefs.py @@ -1,5 +1,5 @@ from typing import Callable as _Callable -from swift.codegen.lib import schema as _schema +from misc.codegen.lib import schema as _schema import inspect as _inspect from dataclasses import dataclass as _dataclass diff --git a/swift/codegen/loaders/BUILD.bazel b/misc/codegen/loaders/BUILD.bazel similarity index 56% rename from swift/codegen/loaders/BUILD.bazel rename to misc/codegen/loaders/BUILD.bazel index de1d8dfe5db..be07c6d884b 100644 --- a/swift/codegen/loaders/BUILD.bazel +++ b/misc/codegen/loaders/BUILD.bazel @@ -1,9 +1,9 @@ -load("@swift_codegen_deps//:requirements.bzl", "requirement") +load("@codegen_deps//:requirements.bzl", "requirement") py_library( name = "loaders", srcs = glob(["*.py"]), - visibility = ["//swift/codegen:__subpackages__"], + visibility = ["//misc/codegen:__subpackages__"], deps = [ requirement("toposort"), requirement("inflection"), diff --git a/swift/codegen/loaders/dbschemeloader.py b/misc/codegen/loaders/dbschemeloader.py similarity index 97% rename from swift/codegen/loaders/dbschemeloader.py rename to misc/codegen/loaders/dbschemeloader.py index eda299c77b1..51e362362a7 100644 --- a/swift/codegen/loaders/dbschemeloader.py +++ b/misc/codegen/loaders/dbschemeloader.py @@ -1,6 +1,6 @@ import pathlib import re -from swift.codegen.lib import dbscheme +from misc.codegen.lib import dbscheme class _Re: diff --git a/swift/codegen/loaders/schemaloader.py b/misc/codegen/loaders/schemaloader.py similarity index 98% rename from swift/codegen/loaders/schemaloader.py rename to misc/codegen/loaders/schemaloader.py index cb276ed11c2..5fd392b112d 100644 --- a/swift/codegen/loaders/schemaloader.py +++ b/misc/codegen/loaders/schemaloader.py @@ -8,7 +8,7 @@ import importlib.util from dataclasses import dataclass from toposort import toposort_flatten -from swift.codegen.lib import schema, schemadefs +from misc.codegen.lib import schema, schemadefs @dataclass @@ -99,7 +99,7 @@ def load(m: types.ModuleType) -> schema.Schema: classes = {} known = {"int", "string", "boolean"} known.update(n for n in m.__dict__ if not n.startswith("__")) - import swift.codegen.lib.schemadefs as defs + import misc.codegen.lib.schemadefs as defs null = None for name, data in m.__dict__.items(): if hasattr(defs, name): diff --git a/swift/codegen/requirements.txt b/misc/codegen/requirements.txt similarity index 100% rename from swift/codegen/requirements.txt rename to misc/codegen/requirements.txt diff --git a/swift/codegen/lib/schemadefs.py b/misc/codegen/schemadefs.py similarity index 98% rename from swift/codegen/lib/schemadefs.py rename to misc/codegen/schemadefs.py index d972e5a63e5..6c9457490e7 100644 --- a/swift/codegen/lib/schemadefs.py +++ b/misc/codegen/schemadefs.py @@ -1,5 +1,5 @@ from typing import Callable as _Callable -from swift.codegen.lib import schema as _schema +from misc.codegen.lib import schema as _schema import inspect as _inspect from dataclasses import dataclass as _dataclass diff --git a/swift/codegen/templates/BUILD.bazel b/misc/codegen/templates/BUILD.bazel similarity index 68% rename from swift/codegen/templates/BUILD.bazel rename to misc/codegen/templates/BUILD.bazel index 7745e7ea2ac..a86346245af 100644 --- a/swift/codegen/templates/BUILD.bazel +++ b/misc/codegen/templates/BUILD.bazel @@ -1,4 +1,4 @@ -package(default_visibility = ["//swift:__subpackages__"]) +package(default_visibility = ["//misc/codegen:__subpackages__"]) filegroup( name = "trap", diff --git a/swift/codegen/templates/cpp_classes_cpp.mustache b/misc/codegen/templates/cpp_classes_cpp.mustache similarity index 100% rename from swift/codegen/templates/cpp_classes_cpp.mustache rename to misc/codegen/templates/cpp_classes_cpp.mustache diff --git a/swift/codegen/templates/cpp_classes_h.mustache b/misc/codegen/templates/cpp_classes_h.mustache similarity index 100% rename from swift/codegen/templates/cpp_classes_h.mustache rename to misc/codegen/templates/cpp_classes_h.mustache diff --git a/swift/codegen/templates/dbscheme.mustache b/misc/codegen/templates/dbscheme.mustache similarity index 100% rename from swift/codegen/templates/dbscheme.mustache rename to misc/codegen/templates/dbscheme.mustache diff --git a/swift/codegen/templates/ql_class.mustache b/misc/codegen/templates/ql_class.mustache similarity index 100% rename from swift/codegen/templates/ql_class.mustache rename to misc/codegen/templates/ql_class.mustache diff --git a/swift/codegen/templates/ql_db.mustache b/misc/codegen/templates/ql_db.mustache similarity index 100% rename from swift/codegen/templates/ql_db.mustache rename to misc/codegen/templates/ql_db.mustache diff --git a/swift/codegen/templates/ql_imports.mustache b/misc/codegen/templates/ql_imports.mustache similarity index 100% rename from swift/codegen/templates/ql_imports.mustache rename to misc/codegen/templates/ql_imports.mustache diff --git a/swift/codegen/templates/ql_ipa_constructor_stub.mustache b/misc/codegen/templates/ql_ipa_constructor_stub.mustache similarity index 100% rename from swift/codegen/templates/ql_ipa_constructor_stub.mustache rename to misc/codegen/templates/ql_ipa_constructor_stub.mustache diff --git a/swift/codegen/templates/ql_ipa_types.mustache b/misc/codegen/templates/ql_ipa_types.mustache similarity index 100% rename from swift/codegen/templates/ql_ipa_types.mustache rename to misc/codegen/templates/ql_ipa_types.mustache diff --git a/swift/codegen/templates/ql_parent.mustache b/misc/codegen/templates/ql_parent.mustache similarity index 100% rename from swift/codegen/templates/ql_parent.mustache rename to misc/codegen/templates/ql_parent.mustache diff --git a/swift/codegen/templates/ql_property_doc.mustache b/misc/codegen/templates/ql_property_doc.mustache similarity index 100% rename from swift/codegen/templates/ql_property_doc.mustache rename to misc/codegen/templates/ql_property_doc.mustache diff --git a/swift/codegen/templates/ql_stub.mustache b/misc/codegen/templates/ql_stub.mustache similarity index 100% rename from swift/codegen/templates/ql_stub.mustache rename to misc/codegen/templates/ql_stub.mustache diff --git a/swift/codegen/templates/ql_test_class.mustache b/misc/codegen/templates/ql_test_class.mustache similarity index 100% rename from swift/codegen/templates/ql_test_class.mustache rename to misc/codegen/templates/ql_test_class.mustache diff --git a/swift/codegen/templates/ql_test_missing.mustache b/misc/codegen/templates/ql_test_missing.mustache similarity index 100% rename from swift/codegen/templates/ql_test_missing.mustache rename to misc/codegen/templates/ql_test_missing.mustache diff --git a/swift/codegen/templates/ql_test_property.mustache b/misc/codegen/templates/ql_test_property.mustache similarity index 100% rename from swift/codegen/templates/ql_test_property.mustache rename to misc/codegen/templates/ql_test_property.mustache diff --git a/swift/codegen/templates/trap_tags_h.mustache b/misc/codegen/templates/trap_tags_h.mustache similarity index 100% rename from swift/codegen/templates/trap_tags_h.mustache rename to misc/codegen/templates/trap_tags_h.mustache diff --git a/swift/codegen/templates/trap_traps_cpp.mustache b/misc/codegen/templates/trap_traps_cpp.mustache similarity index 100% rename from swift/codegen/templates/trap_traps_cpp.mustache rename to misc/codegen/templates/trap_traps_cpp.mustache diff --git a/swift/codegen/templates/trap_traps_h.mustache b/misc/codegen/templates/trap_traps_h.mustache similarity index 100% rename from swift/codegen/templates/trap_traps_h.mustache rename to misc/codegen/templates/trap_traps_h.mustache diff --git a/swift/codegen/test/BUILD.bazel b/misc/codegen/test/BUILD.bazel similarity index 72% rename from swift/codegen/test/BUILD.bazel rename to misc/codegen/test/BUILD.bazel index 9ae41c14941..dde67283335 100644 --- a/swift/codegen/test/BUILD.bazel +++ b/misc/codegen/test/BUILD.bazel @@ -1,11 +1,11 @@ -load("@swift_codegen_deps//:requirements.bzl", "requirement") +load("@codegen_deps//:requirements.bzl", "requirement") py_library( name = "utils", testonly = True, srcs = ["utils.py"], deps = [ - "//swift/codegen/lib", + "//misc/codegen/lib", requirement("pytest"), ], ) @@ -17,7 +17,7 @@ py_library( srcs = [src], deps = [ ":utils", - "//swift/codegen/generators", + "//misc/codegen/generators", ], ) for src in glob(["test_*.py"]) diff --git a/swift/codegen/test/test_cpp.py b/misc/codegen/test/test_cpp.py similarity index 98% rename from swift/codegen/test/test_cpp.py rename to misc/codegen/test/test_cpp.py index d04877e38c4..c4bee337a4f 100644 --- a/swift/codegen/test/test_cpp.py +++ b/misc/codegen/test/test_cpp.py @@ -3,7 +3,7 @@ from copy import deepcopy import pytest -from swift.codegen.lib import cpp +from misc.codegen.lib import cpp @pytest.mark.parametrize("keyword", cpp.cpp_keywords) diff --git a/swift/codegen/test/test_cppgen.py b/misc/codegen/test/test_cppgen.py similarity index 98% rename from swift/codegen/test/test_cppgen.py rename to misc/codegen/test/test_cppgen.py index 3c62143e86a..278f184fcbc 100644 --- a/swift/codegen/test/test_cppgen.py +++ b/misc/codegen/test/test_cppgen.py @@ -1,8 +1,8 @@ import sys -from swift.codegen.generators import cppgen -from swift.codegen.lib import cpp -from swift.codegen.test.utils import * +from misc.codegen.generators import cppgen +from misc.codegen.lib import cpp +from misc.codegen.test.utils import * output_dir = pathlib.Path("path", "to", "output") diff --git a/swift/codegen/test/test_dbscheme.py b/misc/codegen/test/test_dbscheme.py similarity index 95% rename from swift/codegen/test/test_dbscheme.py rename to misc/codegen/test/test_dbscheme.py index a520cc2b66b..e2635ecee5a 100644 --- a/swift/codegen/test/test_dbscheme.py +++ b/misc/codegen/test/test_dbscheme.py @@ -1,8 +1,8 @@ import sys from copy import deepcopy -from swift.codegen.lib import dbscheme -from swift.codegen.test.utils import * +from misc.codegen.lib import dbscheme +from misc.codegen.test.utils import * def test_dbcolumn_name(): diff --git a/swift/codegen/test/test_dbschemegen.py b/misc/codegen/test/test_dbschemegen.py similarity index 99% rename from swift/codegen/test/test_dbschemegen.py rename to misc/codegen/test/test_dbschemegen.py index 74070967d1a..7a986538b06 100644 --- a/swift/codegen/test/test_dbschemegen.py +++ b/misc/codegen/test/test_dbschemegen.py @@ -1,9 +1,9 @@ import collections import sys -from swift.codegen.generators import dbschemegen -from swift.codegen.lib import dbscheme -from swift.codegen.test.utils import * +from misc.codegen.generators import dbschemegen +from misc.codegen.lib import dbscheme +from misc.codegen.test.utils import * InputExpectedPair = collections.namedtuple("InputExpectedPair", ("input", "expected")) diff --git a/swift/codegen/test/test_dbschemelaoder.py b/misc/codegen/test/test_dbschemelaoder.py similarity index 95% rename from swift/codegen/test/test_dbschemelaoder.py rename to misc/codegen/test/test_dbschemelaoder.py index 6212b860cbb..ab4efbff75a 100644 --- a/swift/codegen/test/test_dbschemelaoder.py +++ b/misc/codegen/test/test_dbschemelaoder.py @@ -1,9 +1,9 @@ import sys from copy import deepcopy -from swift.codegen.lib import dbscheme -from swift.codegen.loaders.dbschemeloader import iterload -from swift.codegen.test.utils import * +from misc.codegen.lib import dbscheme +from misc.codegen.loaders.dbschemeloader import iterload +from misc.codegen.test.utils import * @pytest.fixture diff --git a/swift/codegen/test/test_ql.py b/misc/codegen/test/test_ql.py similarity index 98% rename from swift/codegen/test/test_ql.py rename to misc/codegen/test/test_ql.py index f5b5218bd43..0006bbb96e4 100644 --- a/swift/codegen/test/test_ql.py +++ b/misc/codegen/test/test_ql.py @@ -1,8 +1,8 @@ import sys from copy import deepcopy -from swift.codegen.lib import ql -from swift.codegen.test.utils import * +from misc.codegen.lib import ql +from misc.codegen.test.utils import * def test_property_has_first_table_param_marked(): diff --git a/swift/codegen/test/test_qlgen.py b/misc/codegen/test/test_qlgen.py similarity index 99% rename from swift/codegen/test/test_qlgen.py rename to misc/codegen/test/test_qlgen.py index e543bd9c1a9..f16b1404c2e 100644 --- a/swift/codegen/test/test_qlgen.py +++ b/misc/codegen/test/test_qlgen.py @@ -4,9 +4,9 @@ import sys import pytest -from swift.codegen.generators import qlgen -from swift.codegen.lib import ql -from swift.codegen.test.utils import * +from misc.codegen.generators import qlgen +from misc.codegen.lib import ql +from misc.codegen.test.utils import * @pytest.fixture(autouse=True) diff --git a/swift/codegen/test/test_render.py b/misc/codegen/test/test_render.py similarity index 99% rename from swift/codegen/test/test_render.py rename to misc/codegen/test/test_render.py index ce9c5b10b04..f9129178f04 100644 --- a/swift/codegen/test/test_render.py +++ b/misc/codegen/test/test_render.py @@ -2,7 +2,7 @@ import sys import pytest -from swift.codegen.test.utils import * +from misc.codegen.test.utils import * import hashlib diff --git a/swift/codegen/test/test_schemaloader.py b/misc/codegen/test/test_schemaloader.py similarity index 99% rename from swift/codegen/test/test_schemaloader.py rename to misc/codegen/test/test_schemaloader.py index 2428636609e..9724a82da8f 100644 --- a/swift/codegen/test/test_schemaloader.py +++ b/misc/codegen/test/test_schemaloader.py @@ -2,9 +2,9 @@ import sys import pytest -from swift.codegen.test.utils import * -from swift.codegen.lib import schemadefs as defs -from swift.codegen.loaders.schemaloader import load +from misc.codegen.test.utils import * +from misc.codegen.lib import schemadefs as defs +from misc.codegen.loaders.schemaloader import load def test_empty_schema(): diff --git a/swift/codegen/test/test_trapgen.py b/misc/codegen/test/test_trapgen.py similarity index 97% rename from swift/codegen/test/test_trapgen.py rename to misc/codegen/test/test_trapgen.py index c8121ce48ba..a81f40e0dd8 100644 --- a/swift/codegen/test/test_trapgen.py +++ b/misc/codegen/test/test_trapgen.py @@ -1,8 +1,8 @@ import sys -from swift.codegen.generators import trapgen -from swift.codegen.lib import cpp, dbscheme -from swift.codegen.test.utils import * +from misc.codegen.generators import trapgen +from misc.codegen.lib import cpp, dbscheme +from misc.codegen.test.utils import * output_dir = pathlib.Path("path", "to", "output") diff --git a/swift/codegen/test/utils.py b/misc/codegen/test/utils.py similarity index 83% rename from swift/codegen/test/utils.py rename to misc/codegen/test/utils.py index 70db539f3f2..e33500711f2 100644 --- a/swift/codegen/test/utils.py +++ b/misc/codegen/test/utils.py @@ -3,7 +3,7 @@ from unittest import mock import pytest -from swift.codegen.lib import render, schema, paths +from misc.codegen.lib import render, schema, paths schema_dir = pathlib.Path("a", "dir") schema_file = schema_dir / "schema.py" @@ -39,15 +39,15 @@ def opts(): @pytest.fixture(autouse=True) def override_paths(tmp_path): - with mock.patch("swift.codegen.lib.paths.root_dir", tmp_path), \ - mock.patch("swift.codegen.lib.paths.exe_file", tmp_path / "exe"): + with mock.patch("misc.codegen.lib.paths.root_dir", tmp_path), \ + mock.patch("misc.codegen.lib.paths.exe_file", tmp_path / "exe"): yield @pytest.fixture def input(opts, tmp_path): opts.schema = tmp_path / schema_file - with mock.patch("swift.codegen.loaders.schemaloader.load_file") as load_mock: + with mock.patch("misc.codegen.loaders.schemaloader.load_file") as load_mock: load_mock.return_value = schema.Schema([]) yield load_mock.return_value assert load_mock.mock_calls == [ @@ -58,7 +58,7 @@ def input(opts, tmp_path): @pytest.fixture def dbscheme_input(opts, tmp_path): opts.dbscheme = tmp_path / dbscheme_file - with mock.patch("swift.codegen.loaders.dbschemeloader.iterload") as load_mock: + with mock.patch("misc.codegen.loaders.dbschemeloader.iterload") as load_mock: load_mock.entities = [] load_mock.side_effect = lambda _: load_mock.entities yield load_mock diff --git a/swift/README.md b/swift/README.md index b6d7f1d57d2..766c5ff1dce 100644 --- a/swift/README.md +++ b/swift/README.md @@ -39,6 +39,8 @@ bazel run //swift/codegen to update generated files. This can be shortened to `bazel run codegen` if you are in the `swift` directory. +You can also run `../misc/codegen/codegen.py`, as long as you are beneath the `swift` directory. + ## IDE setup ### CLion and the native bazel plugin diff --git a/swift/actions/build-and-test/action.yml b/swift/actions/build-and-test/action.yml index c0c1e7f7e31..2e084e9a97b 100644 --- a/swift/actions/build-and-test/action.yml +++ b/swift/actions/build-and-test/action.yml @@ -62,7 +62,7 @@ runs: if : ${{ github.event_name == 'pull_request' }} shell: bash run: | - bazel test //swift/codegen/test + bazel test //misc/codegen/test - name: Run qltest tests if : ${{ github.event_name == 'pull_request' }} shell: bash diff --git a/swift/codegen.conf b/swift/codegen.conf index 8f5965bef5c..b620e52d04f 100644 --- a/swift/codegen.conf +++ b/swift/codegen.conf @@ -5,3 +5,5 @@ --ql-stub-output=ql/lib/codeql/swift/elements --ql-test-output=ql/test/extractor-tests/generated --generated-registry=ql/.generated.list +--script-name=codegen/codegen.py +--trap-library=swift/extractor/trap diff --git a/swift/codegen/BUILD.bazel b/swift/codegen/BUILD.bazel index fcf72c0c2ae..bc807e9329a 100644 --- a/swift/codegen/BUILD.bazel +++ b/swift/codegen/BUILD.bazel @@ -1,19 +1,15 @@ -load("@swift_codegen_deps//:requirements.bzl", "requirement") +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") -py_binary( +native_binary( name = "codegen", - srcs = ["codegen.py"], + out = "codegen", + src = "//misc/codegen", data = [ "//swift:schema", "//swift:codegen_conf", - "//swift/codegen/templates:cpp", - "//swift/codegen/templates:trap", ], args = [ "--configuration-file=$(location //swift:codegen_conf)", ], visibility = ["//swift:__subpackages__"], - deps = [ - "//swift/codegen/generators", - ], ) diff --git a/swift/codegen/generators/BUILD.bazel b/swift/codegen/generators/BUILD.bazel deleted file mode 100644 index dbcf529037c..00000000000 --- a/swift/codegen/generators/BUILD.bazel +++ /dev/null @@ -1,11 +0,0 @@ -load("@swift_codegen_deps//:requirements.bzl", "requirement") - -py_library( - name = "generators", - srcs = glob(["*.py"]), - visibility = ["//swift/codegen:__subpackages__"], - deps = [ - "//swift/codegen/lib", - "//swift/codegen/loaders", - ], -) diff --git a/swift/extractor/trap/BUILD.bazel b/swift/extractor/trap/BUILD.bazel index 75e0caede55..0db9b3b3248 100644 --- a/swift/extractor/trap/BUILD.bazel +++ b/swift/extractor/trap/BUILD.bazel @@ -14,7 +14,7 @@ genrule( for ext in ("h", "cpp") ], cmd = " ".join([ - "$(location //swift/codegen)", + "$(location //misc/codegen)", "--generate=dbscheme,trap,cpp", "--dbscheme=$(RULEDIR)/generated/swift.dbscheme", "--cpp-output=$(RULEDIR)/generated", @@ -23,7 +23,7 @@ genrule( "--schema=$(location //swift:schema)", "--script-name=codegen/codegen.py", ]), - exec_tools = ["//swift/codegen", "//swift:schema"], + exec_tools = ["//misc/codegen", "//swift:schema"], ) filegroup( diff --git a/swift/schema.py b/swift/schema.py index 82eab1b4119..9c94a642369 100644 --- a/swift/schema.py +++ b/swift/schema.py @@ -9,7 +9,7 @@ This file should be kept simple: For how documentation of generated QL code works, please read schema_documentation.md. """ -from swift.codegen.lib.schemadefs import * +from misc.codegen.lib.schemadefs import * include("prefix.dbscheme") From 06a6450be41daa9b36387bc42fff91998f9e227e Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Fri, 24 Feb 2023 13:48:41 +0100 Subject: [PATCH 414/415] Codegen: make `--qltest-output` optional --- misc/codegen/generators/qlgen.py | 50 +++++++++++++++++--------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index aec610fe4cd..68b3a6d7ef3 100755 --- a/misc/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -320,8 +320,9 @@ def generate(opts, renderer): generated = {q for q in out.rglob("*.qll")} generated.add(include_file) - generated.update(q for q in test_out.rglob("*.ql")) - generated.update(q for q in test_out.rglob(missing_test_source_filename)) + if test_out: + generated.update(q for q in test_out.rglob("*.ql")) + generated.update(q for q in test_out.rglob(missing_test_source_filename)) stubs = {q for q in stub_out.rglob("*.qll")} @@ -373,28 +374,29 @@ def generate(opts, renderer): ), out / 'ParentChild.qll') - for c in data.classes.values(): - if _should_skip_qltest(c, data.classes): - continue - test_dir = test_out / c.group / c.name - test_dir.mkdir(parents=True, exist_ok=True) - if all(f.suffix in (".txt", ".ql", ".actual", ".expected") for f in test_dir.glob("*.*")): - log.warning(f"no test source in {test_dir.relative_to(test_out)}") - renderer.render(ql.MissingTestInstructions(), - test_dir / missing_test_source_filename) - continue - total_props, partial_props = _partition(_get_all_properties_to_be_tested(c, data.classes), - lambda p: p.is_total) - renderer.render(ql.ClassTester(class_name=c.name, - properties=total_props, - elements_module=elements_module, - # in case of collapsed hierarchies we want to see the actual QL class in results - show_ql_class="qltest_collapse_hierarchy" in c.pragmas), - test_dir / f"{c.name}.ql") - for p in partial_props: - renderer.render(ql.PropertyTester(class_name=c.name, - elements_module=elements_module, - property=p), test_dir / f"{c.name}_{p.getter}.ql") + if test_out: + for c in data.classes.values(): + if _should_skip_qltest(c, data.classes): + continue + test_dir = test_out / c.group / c.name + test_dir.mkdir(parents=True, exist_ok=True) + if all(f.suffix in (".txt", ".ql", ".actual", ".expected") for f in test_dir.glob("*.*")): + log.warning(f"no test source in {test_dir.relative_to(test_out)}") + renderer.render(ql.MissingTestInstructions(), + test_dir / missing_test_source_filename) + continue + total_props, partial_props = _partition(_get_all_properties_to_be_tested(c, data.classes), + lambda p: p.is_total) + renderer.render(ql.ClassTester(class_name=c.name, + properties=total_props, + elements_module=elements_module, + # in case of collapsed hierarchies we want to see the actual QL class in results + show_ql_class="qltest_collapse_hierarchy" in c.pragmas), + test_dir / f"{c.name}.ql") + for p in partial_props: + renderer.render(ql.PropertyTester(class_name=c.name, + elements_module=elements_module, + property=p), test_dir / f"{c.name}_{p.getter}.ql") final_ipa_types = [] non_final_ipa_types = [] From 1218145259da11e37aea5e06f87536d12e631589 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Mon, 27 Feb 2023 10:01:50 +0100 Subject: [PATCH 415/415] Codegen: update `README.md` files --- misc/codegen/README.md | 26 ++++++++++---------------- swift/codegen/README.md | 10 ++++++++++ 2 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 swift/codegen/README.md diff --git a/misc/codegen/README.md b/misc/codegen/README.md index 149c673dab5..2d45ac67ac2 100644 --- a/misc/codegen/README.md +++ b/misc/codegen/README.md @@ -1,31 +1,25 @@ # Code generation suite This directory contains the code generation suite used by the Swift extractor and the QL library. This suite will use -the abstract class specification of [`schema.yml`](schema.yml) to generate: +the abstract class specification of `schema.py` to generate: -* [the `dbscheme` file](../ql/lib/misc.dbscheme) (see [`dbschemegen.py`](generators/dbschemegen.py)) -* [the QL generated code](../ql/lib/codeql/swift/generated) and when - appropriate [the corresponding stubs](../ql/lib/codeql/swift/elements) (see [`qlgen.py`](generators/qlgen.py)) +* the `dbscheme` file (see [`dbschemegen.py`](generators/dbschemegen.py)) +* the QL generated code and when appropriate the corresponding stubs (see [`qlgen.py`](generators/qlgen.py)) * C++ tags and trap entries (see [`trapgen.py`](generators/trapgen.py)) * C++ structured classes (see [`cppgen.py`](generators/cppgen.py)) +An example `schema.py` [can be found in the Swift package](../../swift/schema.py). + ## Usage -By default `bazel run //misc/codegen` will update all checked-in generated files (`dbscheme` and QL sources). You can -append `--` followed by other options to tweak the behaviour, which is mainly intended for debugging. +By default `bazel run //misc/codegen -- -c your-codegen.conf` will load options from `your-codegen.conf`. See +the [Swift configuration](../../swift/codegen.conf) for an example. Calling `misc/codegen/codegen.py` directly (provided +you installed dependencies via `pip3 install -r misc/codegen/requirements.txt`) will use a file named `codegen.conf` +contained in an ancestor directory if any exists. + See `bazel run //misc/codegen -- --help` for a list of all options. In particular `--generate` can be used with a comma separated list to select what to generate (choosing among `dbscheme`, `ql`, `trap` and `cpp`). -C++ code is generated during build (see [`swift/extractor/trap/BUILD.bazel`](../extractor/trap/BUILD.bazel)). After a -build you can browse the generated code in `bazel-bin/swift/extractor/trap/generated`. - -For debugging you can also run `./codegen.py` directly. You must then ensure dependencies are installed, which you can -with the command - -```bash -pip3 install -r ./requirements.txt -``` - ## Implementation notes The suite uses [mustache templating](https://mustache.github.io/) for generation. Templates are diff --git a/swift/codegen/README.md b/swift/codegen/README.md new file mode 100644 index 00000000000..eb869cf6a99 --- /dev/null +++ b/swift/codegen/README.md @@ -0,0 +1,10 @@ +This package aliases [`misc/codegen`](../misc/codegen) providing the Swift-specific options +in [`swift/codegen.conf`](../codegen.conf). + +Running `bazel run //swift/codegen` will generate all checked in +files ([dbscheme](../ql/lib/swift.dbscheme), [QL generated code](../ql/lib/codeql/swift/generated), +[generated QL stubs](../ql/lib/codeql/swift/elements), [generated QL tests](../ql/test/extractor-tests/generated)). + +C++ code is generated during build (see [`swift/extractor/trap/BUILD.bazel`](../extractor/trap/BUILD.bazel)). After a +build you can browse the generated code in `bazel-bin/swift/extractor/trap/generated` from the root of the `codeql` +repository.