From b54bbcd93749e1fe43e3f996579ca1b868260209 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 31 Oct 2024 11:06:45 +0100 Subject: [PATCH] Ruby: Do not distinguish between symbols and strings in hash keys --- .../ruby/dataflow/internal/DataFlowPublic.qll | 23 ++++- .../codeql/ruby/frameworks/ActiveSupport.qll | 15 +--- .../dataflow/hash-flow/hash-flow.expected | 14 ++++ .../dataflow/hash-flow/hash_flow.rb | 4 +- .../ActiveSupportDataFlow.expected | 84 +++++++++---------- 5 files changed, 83 insertions(+), 57 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index c56501bad3eda..4daa5fc3011bc 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -829,7 +829,28 @@ class ContentSet extends TContentSet { this.isAny() and exists(result) or - result = this.getAnElementReadContent() + exists(Content elementContent | elementContent = this.getAnElementReadContent() | + result = elementContent + or + // Do not distinguish symbol keys from string keys. This allows us to + // give more precise summaries for something like `with_indifferent_access`, + // and the amount of false-positive flow arising from this should be very + // limited. + elementContent = + any(Content::KnownElementContent known, ConstantValue cv | + cv = known.getIndex() and + result.(Content::KnownElementContent).getIndex() = + any(ConstantValue cv2 | + cv2.(ConstantValue::ConstantSymbolValue).getStringlikeValue() = + cv.(ConstantValue::ConstantStringValue).getStringlikeValue() + or + cv2.(ConstantValue::ConstantStringValue).getStringlikeValue() = + cv.(ConstantValue::ConstantSymbolValue).getStringlikeValue() + ) + | + known + ) + ) } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActiveSupport.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActiveSupport.qll index baa6a0286799c..349a17bbeac3b 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActiveSupport.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActiveSupport.qll @@ -121,16 +121,6 @@ module ActiveSupport { * Extensions to the `Hash` class. */ module Hash { - private class WithIndifferentAccessSummary extends SimpleSummarizedCallable { - WithIndifferentAccessSummary() { this = "with_indifferent_access" } - - override predicate propagatesFlow(string input, string output, boolean preservesValue) { - input = "Argument[self].Element[any]" and - output = "ReturnValue.Element[any]" and - preservesValue = true - } - } - /** * Flow summary for `reverse_merge`, and its alias `with_defaults`. */ @@ -167,8 +157,9 @@ module ActiveSupport { } override predicate propagatesFlow(string input, string output, boolean preservesValue) { - input = "Argument[self].Element[any]" and - output = "ReturnValue.Element[?]" and + // keys are considered equal modulo string/symbol in our implementation + input = "Argument[self].WithElement[any]" and + output = "ReturnValue" and preservesValue = true } } diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected index a186efcf69b7a..638fab35152c0 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected @@ -40,12 +40,16 @@ edges | hash_flow.rb:42:17:42:26 | call to taint | hash_flow.rb:42:5:42:8 | [post] hash [element a] | provenance | | | hash_flow.rb:43:5:43:8 | [post] hash [element 0] | hash_flow.rb:44:10:44:13 | hash [element 0] | provenance | | | hash_flow.rb:43:5:43:8 | [post] hash [element :a] | hash_flow.rb:46:10:46:13 | hash [element :a] | provenance | | +| hash_flow.rb:43:5:43:8 | [post] hash [element :a] | hash_flow.rb:48:10:48:13 | hash [element :a] | provenance | | +| hash_flow.rb:43:5:43:8 | [post] hash [element a] | hash_flow.rb:46:10:46:13 | hash [element a] | provenance | | | hash_flow.rb:43:5:43:8 | [post] hash [element a] | hash_flow.rb:48:10:48:13 | hash [element a] | provenance | | | hash_flow.rb:43:5:43:8 | hash [element 0] | hash_flow.rb:43:5:43:8 | [post] hash [element 0] | provenance | | | hash_flow.rb:43:5:43:8 | hash [element :a] | hash_flow.rb:43:5:43:8 | [post] hash [element :a] | provenance | | | hash_flow.rb:43:5:43:8 | hash [element a] | hash_flow.rb:43:5:43:8 | [post] hash [element a] | provenance | | | hash_flow.rb:44:10:44:13 | hash [element 0] | hash_flow.rb:44:10:44:16 | ...[...] | provenance | | | hash_flow.rb:46:10:46:13 | hash [element :a] | hash_flow.rb:46:10:46:17 | ...[...] | provenance | | +| hash_flow.rb:46:10:46:13 | hash [element a] | hash_flow.rb:46:10:46:17 | ...[...] | provenance | | +| hash_flow.rb:48:10:48:13 | hash [element :a] | hash_flow.rb:48:10:48:18 | ...[...] | provenance | | | hash_flow.rb:48:10:48:13 | hash [element a] | hash_flow.rb:48:10:48:18 | ...[...] | provenance | | | hash_flow.rb:55:5:55:9 | hash1 [element :a] | hash_flow.rb:56:10:56:14 | hash1 [element :a] | provenance | | | hash_flow.rb:55:13:55:37 | ...[...] [element :a] | hash_flow.rb:55:5:55:9 | hash1 [element :a] | provenance | | @@ -583,7 +587,9 @@ edges | hash_flow.rb:626:11:626:11 | a [element] | hash_flow.rb:626:11:626:16 | ...[...] | provenance | | | hash_flow.rb:626:11:626:16 | ...[...] | hash_flow.rb:626:10:626:17 | ( ... ) | provenance | | | hash_flow.rb:632:5:632:8 | hash [element :a] | hash_flow.rb:639:5:639:8 | hash [element :a] | provenance | | +| hash_flow.rb:632:5:632:8 | hash [element :a] | hash_flow.rb:640:11:640:14 | hash [element :a] | provenance | | | hash_flow.rb:632:5:632:8 | hash [element :c] | hash_flow.rb:639:5:639:8 | hash [element :c] | provenance | | +| hash_flow.rb:632:5:632:8 | hash [element :c] | hash_flow.rb:642:11:642:14 | hash [element :c] | provenance | | | hash_flow.rb:632:12:636:5 | call to [] [element :a] | hash_flow.rb:632:5:632:8 | hash [element :a] | provenance | | | hash_flow.rb:632:12:636:5 | call to [] [element :c] | hash_flow.rb:632:5:632:8 | hash [element :c] | provenance | | | hash_flow.rb:633:15:633:25 | call to taint | hash_flow.rb:632:12:636:5 | call to [] [element :a] | provenance | | @@ -599,10 +605,12 @@ edges | hash_flow.rb:639:5:639:8 | hash [element :a] | hash_flow.rb:639:5:639:8 | [post] hash [element] | provenance | | | hash_flow.rb:639:5:639:8 | hash [element :c] | hash_flow.rb:639:5:639:8 | [post] hash [element] | provenance | | | hash_flow.rb:639:5:639:8 | hash [element] | hash_flow.rb:639:5:639:8 | [post] hash [element] | provenance | | +| hash_flow.rb:640:11:640:14 | hash [element :a] | hash_flow.rb:640:11:640:19 | ...[...] | provenance | | | hash_flow.rb:640:11:640:14 | hash [element] | hash_flow.rb:640:11:640:19 | ...[...] | provenance | | | hash_flow.rb:640:11:640:19 | ...[...] | hash_flow.rb:640:10:640:20 | ( ... ) | provenance | | | hash_flow.rb:641:11:641:14 | hash [element] | hash_flow.rb:641:11:641:19 | ...[...] | provenance | | | hash_flow.rb:641:11:641:19 | ...[...] | hash_flow.rb:641:10:641:20 | ( ... ) | provenance | | +| hash_flow.rb:642:11:642:14 | hash [element :c] | hash_flow.rb:642:11:642:19 | ...[...] | provenance | | | hash_flow.rb:642:11:642:14 | hash [element] | hash_flow.rb:642:11:642:19 | ...[...] | provenance | | | hash_flow.rb:642:11:642:19 | ...[...] | hash_flow.rb:642:10:642:20 | ( ... ) | provenance | | | hash_flow.rb:648:5:648:8 | hash [element :a] | hash_flow.rb:653:9:653:12 | hash [element :a] | provenance | | @@ -1149,7 +1157,9 @@ nodes | hash_flow.rb:44:10:44:13 | hash [element 0] | semmle.label | hash [element 0] | | hash_flow.rb:44:10:44:16 | ...[...] | semmle.label | ...[...] | | hash_flow.rb:46:10:46:13 | hash [element :a] | semmle.label | hash [element :a] | +| hash_flow.rb:46:10:46:13 | hash [element a] | semmle.label | hash [element a] | | hash_flow.rb:46:10:46:17 | ...[...] | semmle.label | ...[...] | +| hash_flow.rb:48:10:48:13 | hash [element :a] | semmle.label | hash [element :a] | | hash_flow.rb:48:10:48:13 | hash [element a] | semmle.label | hash [element a] | | hash_flow.rb:48:10:48:18 | ...[...] | semmle.label | ...[...] | | hash_flow.rb:55:5:55:9 | hash1 [element :a] | semmle.label | hash1 [element :a] | @@ -1740,12 +1750,14 @@ nodes | hash_flow.rb:639:5:639:8 | hash [element :c] | semmle.label | hash [element :c] | | hash_flow.rb:639:5:639:8 | hash [element] | semmle.label | hash [element] | | hash_flow.rb:640:10:640:20 | ( ... ) | semmle.label | ( ... ) | +| hash_flow.rb:640:11:640:14 | hash [element :a] | semmle.label | hash [element :a] | | hash_flow.rb:640:11:640:14 | hash [element] | semmle.label | hash [element] | | hash_flow.rb:640:11:640:19 | ...[...] | semmle.label | ...[...] | | hash_flow.rb:641:10:641:20 | ( ... ) | semmle.label | ( ... ) | | hash_flow.rb:641:11:641:14 | hash [element] | semmle.label | hash [element] | | hash_flow.rb:641:11:641:19 | ...[...] | semmle.label | ...[...] | | hash_flow.rb:642:10:642:20 | ( ... ) | semmle.label | ( ... ) | +| hash_flow.rb:642:11:642:14 | hash [element :c] | semmle.label | hash [element :c] | | hash_flow.rb:642:11:642:14 | hash [element] | semmle.label | hash [element] | | hash_flow.rb:642:11:642:19 | ...[...] | semmle.label | ...[...] | | hash_flow.rb:648:5:648:8 | hash [element :a] | semmle.label | hash [element :a] | @@ -2349,6 +2361,8 @@ hashLiteral | hash_flow.rb:30:10:30:16 | ...[...] | hash_flow.rb:19:14:19:23 | call to taint | hash_flow.rb:30:10:30:16 | ...[...] | $@ | hash_flow.rb:19:14:19:23 | call to taint | call to taint | | hash_flow.rb:44:10:44:16 | ...[...] | hash_flow.rb:38:15:38:24 | call to taint | hash_flow.rb:44:10:44:16 | ...[...] | $@ | hash_flow.rb:38:15:38:24 | call to taint | call to taint | | hash_flow.rb:46:10:46:17 | ...[...] | hash_flow.rb:40:16:40:25 | call to taint | hash_flow.rb:46:10:46:17 | ...[...] | $@ | hash_flow.rb:40:16:40:25 | call to taint | call to taint | +| hash_flow.rb:46:10:46:17 | ...[...] | hash_flow.rb:42:17:42:26 | call to taint | hash_flow.rb:46:10:46:17 | ...[...] | $@ | hash_flow.rb:42:17:42:26 | call to taint | call to taint | +| hash_flow.rb:48:10:48:18 | ...[...] | hash_flow.rb:40:16:40:25 | call to taint | hash_flow.rb:48:10:48:18 | ...[...] | $@ | hash_flow.rb:40:16:40:25 | call to taint | call to taint | | hash_flow.rb:48:10:48:18 | ...[...] | hash_flow.rb:42:17:42:26 | call to taint | hash_flow.rb:48:10:48:18 | ...[...] | $@ | hash_flow.rb:42:17:42:26 | call to taint | call to taint | | hash_flow.rb:56:10:56:18 | ...[...] | hash_flow.rb:55:21:55:30 | call to taint | hash_flow.rb:56:10:56:18 | ...[...] | $@ | hash_flow.rb:55:21:55:30 | call to taint | call to taint | | hash_flow.rb:61:10:61:18 | ...[...] | hash_flow.rb:59:13:59:22 | call to taint | hash_flow.rb:61:10:61:18 | ...[...] | $@ | hash_flow.rb:59:13:59:22 | call to taint | call to taint | diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb b/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb index edc1e325b09d7..d5d7ce4801edb 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb @@ -43,9 +43,9 @@ def m2() hash['b'] = 3 sink(hash[0]) # $ hasValueFlow=2.1 sink(hash[1]) - sink(hash[:a]) # $ hasValueFlow=2.2 + sink(hash[:a]) # $ hasValueFlow=2.2 $ SPURIOUS hasValueFlow=2.3 sink(hash[:b]) - sink(hash['a']) # $ hasValueFlow=2.3 + sink(hash['a']) # $ hasValueFlow=2.3 $ SPURIOUS hasValueFlow=2.2 sink(hash['b']) end diff --git a/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected b/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected index 5a21191ca89fb..bdca6b359acdf 100644 --- a/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected +++ b/ruby/ql/test/library-tests/frameworks/active_support/ActiveSupportDataFlow.expected @@ -60,45 +60,45 @@ edges | hash_extensions.rb:2:5:2:5 | h [element :a] | hash_extensions.rb:3:9:3:9 | h [element :a] | provenance | | | hash_extensions.rb:2:9:2:26 | call to [] [element :a] | hash_extensions.rb:2:5:2:5 | h [element :a] | provenance | | | hash_extensions.rb:2:14:2:24 | call to source | hash_extensions.rb:2:9:2:26 | call to [] [element :a] | provenance | | -| hash_extensions.rb:3:5:3:5 | x [element] | hash_extensions.rb:4:10:4:10 | x [element] | provenance | | -| hash_extensions.rb:3:9:3:9 | h [element :a] | hash_extensions.rb:3:9:3:24 | call to stringify_keys [element] | provenance | | -| hash_extensions.rb:3:9:3:24 | call to stringify_keys [element] | hash_extensions.rb:3:5:3:5 | x [element] | provenance | | -| hash_extensions.rb:4:10:4:10 | x [element] | hash_extensions.rb:4:10:4:15 | ...[...] | provenance | | +| hash_extensions.rb:3:5:3:5 | x [element :a] | hash_extensions.rb:4:10:4:10 | x [element :a] | provenance | | +| hash_extensions.rb:3:9:3:9 | h [element :a] | hash_extensions.rb:3:9:3:24 | call to stringify_keys [element :a] | provenance | | +| hash_extensions.rb:3:9:3:24 | call to stringify_keys [element :a] | hash_extensions.rb:3:5:3:5 | x [element :a] | provenance | | +| hash_extensions.rb:4:10:4:10 | x [element :a] | hash_extensions.rb:4:10:4:15 | ...[...] | provenance | | | hash_extensions.rb:10:5:10:5 | h [element a] | hash_extensions.rb:11:9:11:9 | h [element a] | provenance | | | hash_extensions.rb:10:9:10:30 | call to [] [element a] | hash_extensions.rb:10:5:10:5 | h [element a] | provenance | | | hash_extensions.rb:10:18:10:28 | call to source | hash_extensions.rb:10:9:10:30 | call to [] [element a] | provenance | | -| hash_extensions.rb:11:5:11:5 | x [element] | hash_extensions.rb:12:10:12:10 | x [element] | provenance | | -| hash_extensions.rb:11:9:11:9 | h [element a] | hash_extensions.rb:11:9:11:20 | call to to_options [element] | provenance | | -| hash_extensions.rb:11:9:11:20 | call to to_options [element] | hash_extensions.rb:11:5:11:5 | x [element] | provenance | | -| hash_extensions.rb:12:10:12:10 | x [element] | hash_extensions.rb:12:10:12:14 | ...[...] | provenance | | +| hash_extensions.rb:11:5:11:5 | x [element a] | hash_extensions.rb:12:10:12:10 | x [element a] | provenance | | +| hash_extensions.rb:11:9:11:9 | h [element a] | hash_extensions.rb:11:9:11:20 | call to to_options [element a] | provenance | | +| hash_extensions.rb:11:9:11:20 | call to to_options [element a] | hash_extensions.rb:11:5:11:5 | x [element a] | provenance | | +| hash_extensions.rb:12:10:12:10 | x [element a] | hash_extensions.rb:12:10:12:14 | ...[...] | provenance | | | hash_extensions.rb:18:5:18:5 | h [element a] | hash_extensions.rb:19:9:19:9 | h [element a] | provenance | | | hash_extensions.rb:18:9:18:30 | call to [] [element a] | hash_extensions.rb:18:5:18:5 | h [element a] | provenance | | | hash_extensions.rb:18:18:18:28 | call to source | hash_extensions.rb:18:9:18:30 | call to [] [element a] | provenance | | -| hash_extensions.rb:19:5:19:5 | x [element] | hash_extensions.rb:20:10:20:10 | x [element] | provenance | | -| hash_extensions.rb:19:9:19:9 | h [element a] | hash_extensions.rb:19:9:19:24 | call to symbolize_keys [element] | provenance | | -| hash_extensions.rb:19:9:19:24 | call to symbolize_keys [element] | hash_extensions.rb:19:5:19:5 | x [element] | provenance | | -| hash_extensions.rb:20:10:20:10 | x [element] | hash_extensions.rb:20:10:20:14 | ...[...] | provenance | | +| hash_extensions.rb:19:5:19:5 | x [element a] | hash_extensions.rb:20:10:20:10 | x [element a] | provenance | | +| hash_extensions.rb:19:9:19:9 | h [element a] | hash_extensions.rb:19:9:19:24 | call to symbolize_keys [element a] | provenance | | +| hash_extensions.rb:19:9:19:24 | call to symbolize_keys [element a] | hash_extensions.rb:19:5:19:5 | x [element a] | provenance | | +| hash_extensions.rb:20:10:20:10 | x [element a] | hash_extensions.rb:20:10:20:14 | ...[...] | provenance | | | hash_extensions.rb:26:5:26:5 | h [element :a] | hash_extensions.rb:27:9:27:9 | h [element :a] | provenance | | | hash_extensions.rb:26:9:26:26 | call to [] [element :a] | hash_extensions.rb:26:5:26:5 | h [element :a] | provenance | | | hash_extensions.rb:26:14:26:24 | call to source | hash_extensions.rb:26:9:26:26 | call to [] [element :a] | provenance | | -| hash_extensions.rb:27:5:27:5 | x [element] | hash_extensions.rb:28:10:28:10 | x [element] | provenance | | -| hash_extensions.rb:27:9:27:9 | h [element :a] | hash_extensions.rb:27:9:27:29 | call to deep_stringify_keys [element] | provenance | | -| hash_extensions.rb:27:9:27:29 | call to deep_stringify_keys [element] | hash_extensions.rb:27:5:27:5 | x [element] | provenance | | -| hash_extensions.rb:28:10:28:10 | x [element] | hash_extensions.rb:28:10:28:15 | ...[...] | provenance | | +| hash_extensions.rb:27:5:27:5 | x [element :a] | hash_extensions.rb:28:10:28:10 | x [element :a] | provenance | | +| hash_extensions.rb:27:9:27:9 | h [element :a] | hash_extensions.rb:27:9:27:29 | call to deep_stringify_keys [element :a] | provenance | | +| hash_extensions.rb:27:9:27:29 | call to deep_stringify_keys [element :a] | hash_extensions.rb:27:5:27:5 | x [element :a] | provenance | | +| hash_extensions.rb:28:10:28:10 | x [element :a] | hash_extensions.rb:28:10:28:15 | ...[...] | provenance | | | hash_extensions.rb:34:5:34:5 | h [element a] | hash_extensions.rb:35:9:35:9 | h [element a] | provenance | | | hash_extensions.rb:34:9:34:30 | call to [] [element a] | hash_extensions.rb:34:5:34:5 | h [element a] | provenance | | | hash_extensions.rb:34:18:34:28 | call to source | hash_extensions.rb:34:9:34:30 | call to [] [element a] | provenance | | -| hash_extensions.rb:35:5:35:5 | x [element] | hash_extensions.rb:36:10:36:10 | x [element] | provenance | | -| hash_extensions.rb:35:9:35:9 | h [element a] | hash_extensions.rb:35:9:35:29 | call to deep_symbolize_keys [element] | provenance | | -| hash_extensions.rb:35:9:35:29 | call to deep_symbolize_keys [element] | hash_extensions.rb:35:5:35:5 | x [element] | provenance | | -| hash_extensions.rb:36:10:36:10 | x [element] | hash_extensions.rb:36:10:36:14 | ...[...] | provenance | | +| hash_extensions.rb:35:5:35:5 | x [element a] | hash_extensions.rb:36:10:36:10 | x [element a] | provenance | | +| hash_extensions.rb:35:9:35:9 | h [element a] | hash_extensions.rb:35:9:35:29 | call to deep_symbolize_keys [element a] | provenance | | +| hash_extensions.rb:35:9:35:29 | call to deep_symbolize_keys [element a] | hash_extensions.rb:35:5:35:5 | x [element a] | provenance | | +| hash_extensions.rb:36:10:36:10 | x [element a] | hash_extensions.rb:36:10:36:14 | ...[...] | provenance | | | hash_extensions.rb:42:5:42:5 | h [element :a] | hash_extensions.rb:43:9:43:9 | h [element :a] | provenance | | | hash_extensions.rb:42:9:42:26 | call to [] [element :a] | hash_extensions.rb:42:5:42:5 | h [element :a] | provenance | | | hash_extensions.rb:42:14:42:24 | call to source | hash_extensions.rb:42:9:42:26 | call to [] [element :a] | provenance | | -| hash_extensions.rb:43:5:43:5 | x [element] | hash_extensions.rb:44:10:44:10 | x [element] | provenance | | -| hash_extensions.rb:43:9:43:9 | h [element :a] | hash_extensions.rb:43:9:43:33 | call to with_indifferent_access [element] | provenance | | -| hash_extensions.rb:43:9:43:33 | call to with_indifferent_access [element] | hash_extensions.rb:43:5:43:5 | x [element] | provenance | | -| hash_extensions.rb:44:10:44:10 | x [element] | hash_extensions.rb:44:10:44:15 | ...[...] | provenance | | +| hash_extensions.rb:43:5:43:5 | x [element :a] | hash_extensions.rb:44:10:44:10 | x [element :a] | provenance | | +| hash_extensions.rb:43:9:43:9 | h [element :a] | hash_extensions.rb:43:9:43:33 | call to with_indifferent_access [element :a] | provenance | | +| hash_extensions.rb:43:9:43:33 | call to with_indifferent_access [element :a] | hash_extensions.rb:43:5:43:5 | x [element :a] | provenance | | +| hash_extensions.rb:44:10:44:10 | x [element :a] | hash_extensions.rb:44:10:44:15 | ...[...] | provenance | | | hash_extensions.rb:50:5:50:5 | h [element :a] | hash_extensions.rb:51:9:51:9 | h [element :a] | provenance | | | hash_extensions.rb:50:5:50:5 | h [element :b] | hash_extensions.rb:51:9:51:9 | h [element :b] | provenance | | | hash_extensions.rb:50:5:50:5 | h [element :d] | hash_extensions.rb:51:9:51:9 | h [element :d] | provenance | | @@ -305,50 +305,50 @@ nodes | hash_extensions.rb:2:5:2:5 | h [element :a] | semmle.label | h [element :a] | | hash_extensions.rb:2:9:2:26 | call to [] [element :a] | semmle.label | call to [] [element :a] | | hash_extensions.rb:2:14:2:24 | call to source | semmle.label | call to source | -| hash_extensions.rb:3:5:3:5 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:3:5:3:5 | x [element :a] | semmle.label | x [element :a] | | hash_extensions.rb:3:9:3:9 | h [element :a] | semmle.label | h [element :a] | -| hash_extensions.rb:3:9:3:24 | call to stringify_keys [element] | semmle.label | call to stringify_keys [element] | -| hash_extensions.rb:4:10:4:10 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:3:9:3:24 | call to stringify_keys [element :a] | semmle.label | call to stringify_keys [element :a] | +| hash_extensions.rb:4:10:4:10 | x [element :a] | semmle.label | x [element :a] | | hash_extensions.rb:4:10:4:15 | ...[...] | semmle.label | ...[...] | | hash_extensions.rb:10:5:10:5 | h [element a] | semmle.label | h [element a] | | hash_extensions.rb:10:9:10:30 | call to [] [element a] | semmle.label | call to [] [element a] | | hash_extensions.rb:10:18:10:28 | call to source | semmle.label | call to source | -| hash_extensions.rb:11:5:11:5 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:11:5:11:5 | x [element a] | semmle.label | x [element a] | | hash_extensions.rb:11:9:11:9 | h [element a] | semmle.label | h [element a] | -| hash_extensions.rb:11:9:11:20 | call to to_options [element] | semmle.label | call to to_options [element] | -| hash_extensions.rb:12:10:12:10 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:11:9:11:20 | call to to_options [element a] | semmle.label | call to to_options [element a] | +| hash_extensions.rb:12:10:12:10 | x [element a] | semmle.label | x [element a] | | hash_extensions.rb:12:10:12:14 | ...[...] | semmle.label | ...[...] | | hash_extensions.rb:18:5:18:5 | h [element a] | semmle.label | h [element a] | | hash_extensions.rb:18:9:18:30 | call to [] [element a] | semmle.label | call to [] [element a] | | hash_extensions.rb:18:18:18:28 | call to source | semmle.label | call to source | -| hash_extensions.rb:19:5:19:5 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:19:5:19:5 | x [element a] | semmle.label | x [element a] | | hash_extensions.rb:19:9:19:9 | h [element a] | semmle.label | h [element a] | -| hash_extensions.rb:19:9:19:24 | call to symbolize_keys [element] | semmle.label | call to symbolize_keys [element] | -| hash_extensions.rb:20:10:20:10 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:19:9:19:24 | call to symbolize_keys [element a] | semmle.label | call to symbolize_keys [element a] | +| hash_extensions.rb:20:10:20:10 | x [element a] | semmle.label | x [element a] | | hash_extensions.rb:20:10:20:14 | ...[...] | semmle.label | ...[...] | | hash_extensions.rb:26:5:26:5 | h [element :a] | semmle.label | h [element :a] | | hash_extensions.rb:26:9:26:26 | call to [] [element :a] | semmle.label | call to [] [element :a] | | hash_extensions.rb:26:14:26:24 | call to source | semmle.label | call to source | -| hash_extensions.rb:27:5:27:5 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:27:5:27:5 | x [element :a] | semmle.label | x [element :a] | | hash_extensions.rb:27:9:27:9 | h [element :a] | semmle.label | h [element :a] | -| hash_extensions.rb:27:9:27:29 | call to deep_stringify_keys [element] | semmle.label | call to deep_stringify_keys [element] | -| hash_extensions.rb:28:10:28:10 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:27:9:27:29 | call to deep_stringify_keys [element :a] | semmle.label | call to deep_stringify_keys [element :a] | +| hash_extensions.rb:28:10:28:10 | x [element :a] | semmle.label | x [element :a] | | hash_extensions.rb:28:10:28:15 | ...[...] | semmle.label | ...[...] | | hash_extensions.rb:34:5:34:5 | h [element a] | semmle.label | h [element a] | | hash_extensions.rb:34:9:34:30 | call to [] [element a] | semmle.label | call to [] [element a] | | hash_extensions.rb:34:18:34:28 | call to source | semmle.label | call to source | -| hash_extensions.rb:35:5:35:5 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:35:5:35:5 | x [element a] | semmle.label | x [element a] | | hash_extensions.rb:35:9:35:9 | h [element a] | semmle.label | h [element a] | -| hash_extensions.rb:35:9:35:29 | call to deep_symbolize_keys [element] | semmle.label | call to deep_symbolize_keys [element] | -| hash_extensions.rb:36:10:36:10 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:35:9:35:29 | call to deep_symbolize_keys [element a] | semmle.label | call to deep_symbolize_keys [element a] | +| hash_extensions.rb:36:10:36:10 | x [element a] | semmle.label | x [element a] | | hash_extensions.rb:36:10:36:14 | ...[...] | semmle.label | ...[...] | | hash_extensions.rb:42:5:42:5 | h [element :a] | semmle.label | h [element :a] | | hash_extensions.rb:42:9:42:26 | call to [] [element :a] | semmle.label | call to [] [element :a] | | hash_extensions.rb:42:14:42:24 | call to source | semmle.label | call to source | -| hash_extensions.rb:43:5:43:5 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:43:5:43:5 | x [element :a] | semmle.label | x [element :a] | | hash_extensions.rb:43:9:43:9 | h [element :a] | semmle.label | h [element :a] | -| hash_extensions.rb:43:9:43:33 | call to with_indifferent_access [element] | semmle.label | call to with_indifferent_access [element] | -| hash_extensions.rb:44:10:44:10 | x [element] | semmle.label | x [element] | +| hash_extensions.rb:43:9:43:33 | call to with_indifferent_access [element :a] | semmle.label | call to with_indifferent_access [element :a] | +| hash_extensions.rb:44:10:44:10 | x [element :a] | semmle.label | x [element :a] | | hash_extensions.rb:44:10:44:15 | ...[...] | semmle.label | ...[...] | | hash_extensions.rb:50:5:50:5 | h [element :a] | semmle.label | h [element :a] | | hash_extensions.rb:50:5:50:5 | h [element :b] | semmle.label | h [element :b] |