Skip to content

Commit 03ffaac

Browse files
authored
Merge pull request #17880 from hvitved/ruby/symbol-string-key-indifference
Ruby: Do not distinguish between symbols and strings in hash keys
2 parents 03aef50 + 6b60865 commit 03ffaac

File tree

8 files changed

+165
-95
lines changed

8 files changed

+165
-95
lines changed

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,28 @@ class ContentSet extends TContentSet {
829829
this.isAny() and
830830
exists(result)
831831
or
832-
result = this.getAnElementReadContent()
832+
exists(Content elementContent | elementContent = this.getAnElementReadContent() |
833+
result = elementContent
834+
or
835+
// Do not distinguish symbol keys from string keys. This allows us to
836+
// give more precise summaries for something like `with_indifferent_access`,
837+
// and the amount of false-positive flow arising from this should be very
838+
// limited.
839+
elementContent =
840+
any(Content::KnownElementContent known, ConstantValue cv |
841+
cv = known.getIndex() and
842+
result.(Content::KnownElementContent).getIndex() =
843+
any(ConstantValue cv2 |
844+
cv2.(ConstantValue::ConstantSymbolValue).getStringlikeValue() =
845+
cv.(ConstantValue::ConstantStringValue).getStringlikeValue()
846+
or
847+
cv2.(ConstantValue::ConstantStringValue).getStringlikeValue() =
848+
cv.(ConstantValue::ConstantSymbolValue).getStringlikeValue()
849+
)
850+
|
851+
known
852+
)
853+
)
833854
}
834855
}
835856

ruby/ql/lib/codeql/ruby/frameworks/ActiveSupport.qll

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,6 @@ module ActiveSupport {
121121
* Extensions to the `Hash` class.
122122
*/
123123
module Hash {
124-
private class WithIndifferentAccessSummary extends SimpleSummarizedCallable {
125-
WithIndifferentAccessSummary() { this = "with_indifferent_access" }
126-
127-
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
128-
input = "Argument[self].Element[any]" and
129-
output = "ReturnValue.Element[any]" and
130-
preservesValue = true
131-
}
132-
}
133-
134124
/**
135125
* Flow summary for `reverse_merge`, and its alias `with_defaults`.
136126
*/
@@ -167,8 +157,9 @@ module ActiveSupport {
167157
}
168158

169159
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
170-
input = "Argument[self].Element[any]" and
171-
output = "ReturnValue.Element[?]" and
160+
// keys are considered equal modulo string/symbol in our implementation
161+
input = "Argument[self].WithElement[any]" and
162+
output = "ReturnValue" and
172163
preservesValue = true
173164
}
174165
}

ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.expected

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,22 +458,40 @@ edges
458458
| semantics.rb:263:14:263:14 | h [element :foo] | semantics.rb:263:10:263:15 | call to s31 | provenance | |
459459
| semantics.rb:263:14:263:14 | h [element] | semantics.rb:263:10:263:15 | call to s31 | provenance | |
460460
| semantics.rb:263:14:263:14 | h [element] | semantics.rb:263:10:263:15 | call to s31 | provenance | |
461+
| semantics.rb:267:5:267:5 | [post] h [element :foo] | semantics.rb:268:5:268:5 | h [element :foo] | provenance | |
462+
| semantics.rb:267:5:267:5 | [post] h [element :foo] | semantics.rb:268:5:268:5 | h [element :foo] | provenance | |
463+
| semantics.rb:267:15:267:25 | call to source | semantics.rb:267:5:267:5 | [post] h [element :foo] | provenance | |
464+
| semantics.rb:267:15:267:25 | call to source | semantics.rb:267:5:267:5 | [post] h [element :foo] | provenance | |
465+
| semantics.rb:268:5:268:5 | [post] h [element :foo] | semantics.rb:269:5:269:5 | h [element :foo] | provenance | |
466+
| semantics.rb:268:5:268:5 | [post] h [element :foo] | semantics.rb:269:5:269:5 | h [element :foo] | provenance | |
461467
| semantics.rb:268:5:268:5 | [post] h [element foo] | semantics.rb:269:5:269:5 | h [element foo] | provenance | |
462468
| semantics.rb:268:5:268:5 | [post] h [element foo] | semantics.rb:269:5:269:5 | h [element foo] | provenance | |
469+
| semantics.rb:268:5:268:5 | h [element :foo] | semantics.rb:268:5:268:5 | [post] h [element :foo] | provenance | |
470+
| semantics.rb:268:5:268:5 | h [element :foo] | semantics.rb:268:5:268:5 | [post] h [element :foo] | provenance | |
463471
| semantics.rb:268:16:268:26 | call to source | semantics.rb:268:5:268:5 | [post] h [element foo] | provenance | |
464472
| semantics.rb:268:16:268:26 | call to source | semantics.rb:268:5:268:5 | [post] h [element foo] | provenance | |
473+
| semantics.rb:269:5:269:5 | [post] h [element :foo] | semantics.rb:270:5:270:5 | h [element :foo] | provenance | |
474+
| semantics.rb:269:5:269:5 | [post] h [element :foo] | semantics.rb:270:5:270:5 | h [element :foo] | provenance | |
465475
| semantics.rb:269:5:269:5 | [post] h [element foo] | semantics.rb:270:5:270:5 | h [element foo] | provenance | |
466476
| semantics.rb:269:5:269:5 | [post] h [element foo] | semantics.rb:270:5:270:5 | h [element foo] | provenance | |
477+
| semantics.rb:269:5:269:5 | h [element :foo] | semantics.rb:269:5:269:5 | [post] h [element :foo] | provenance | |
478+
| semantics.rb:269:5:269:5 | h [element :foo] | semantics.rb:269:5:269:5 | [post] h [element :foo] | provenance | |
467479
| semantics.rb:269:5:269:5 | h [element foo] | semantics.rb:269:5:269:5 | [post] h [element foo] | provenance | |
468480
| semantics.rb:269:5:269:5 | h [element foo] | semantics.rb:269:5:269:5 | [post] h [element foo] | provenance | |
481+
| semantics.rb:270:5:270:5 | [post] h [element :foo] | semantics.rb:273:14:273:14 | h [element :foo] | provenance | |
482+
| semantics.rb:270:5:270:5 | [post] h [element :foo] | semantics.rb:273:14:273:14 | h [element :foo] | provenance | |
469483
| semantics.rb:270:5:270:5 | [post] h [element foo] | semantics.rb:273:14:273:14 | h [element foo] | provenance | |
470484
| semantics.rb:270:5:270:5 | [post] h [element foo] | semantics.rb:273:14:273:14 | h [element foo] | provenance | |
485+
| semantics.rb:270:5:270:5 | h [element :foo] | semantics.rb:270:5:270:5 | [post] h [element :foo] | provenance | |
486+
| semantics.rb:270:5:270:5 | h [element :foo] | semantics.rb:270:5:270:5 | [post] h [element :foo] | provenance | |
471487
| semantics.rb:270:5:270:5 | h [element foo] | semantics.rb:270:5:270:5 | [post] h [element foo] | provenance | |
472488
| semantics.rb:270:5:270:5 | h [element foo] | semantics.rb:270:5:270:5 | [post] h [element foo] | provenance | |
473489
| semantics.rb:271:5:271:5 | [post] h [element] | semantics.rb:273:14:273:14 | h [element] | provenance | |
474490
| semantics.rb:271:5:271:5 | [post] h [element] | semantics.rb:273:14:273:14 | h [element] | provenance | |
475491
| semantics.rb:271:12:271:22 | call to source | semantics.rb:271:5:271:5 | [post] h [element] | provenance | |
476492
| semantics.rb:271:12:271:22 | call to source | semantics.rb:271:5:271:5 | [post] h [element] | provenance | |
493+
| semantics.rb:273:14:273:14 | h [element :foo] | semantics.rb:273:10:273:15 | call to s32 | provenance | |
494+
| semantics.rb:273:14:273:14 | h [element :foo] | semantics.rb:273:10:273:15 | call to s32 | provenance | |
477495
| semantics.rb:273:14:273:14 | h [element foo] | semantics.rb:273:10:273:15 | call to s32 | provenance | |
478496
| semantics.rb:273:14:273:14 | h [element foo] | semantics.rb:273:10:273:15 | call to s32 | provenance | |
479497
| semantics.rb:273:14:273:14 | h [element] | semantics.rb:273:10:273:15 | call to s32 | provenance | |
@@ -538,6 +556,8 @@ edges
538556
| semantics.rb:291:10:291:10 | x [element :foo] | semantics.rb:291:10:291:16 | ...[...] | provenance | |
539557
| semantics.rb:293:10:293:10 | x [element :foo] | semantics.rb:293:10:293:13 | ...[...] | provenance | |
540558
| semantics.rb:293:10:293:10 | x [element :foo] | semantics.rb:293:10:293:13 | ...[...] | provenance | |
559+
| semantics.rb:297:5:297:5 | x [element foo] | semantics.rb:298:10:298:10 | x [element foo] | provenance | |
560+
| semantics.rb:297:5:297:5 | x [element foo] | semantics.rb:298:10:298:10 | x [element foo] | provenance | |
541561
| semantics.rb:297:5:297:5 | x [element foo] | semantics.rb:299:10:299:10 | x [element foo] | provenance | |
542562
| semantics.rb:297:5:297:5 | x [element foo] | semantics.rb:299:10:299:10 | x [element foo] | provenance | |
543563
| semantics.rb:297:5:297:5 | x [element foo] | semantics.rb:301:10:301:10 | x [element foo] | provenance | |
@@ -546,6 +566,8 @@ edges
546566
| semantics.rb:297:9:297:24 | call to s36 [element foo] | semantics.rb:297:5:297:5 | x [element foo] | provenance | |
547567
| semantics.rb:297:13:297:23 | call to source | semantics.rb:297:9:297:24 | call to s36 [element foo] | provenance | |
548568
| semantics.rb:297:13:297:23 | call to source | semantics.rb:297:9:297:24 | call to s36 [element foo] | provenance | |
569+
| semantics.rb:298:10:298:10 | x [element foo] | semantics.rb:298:10:298:16 | ...[...] | provenance | |
570+
| semantics.rb:298:10:298:10 | x [element foo] | semantics.rb:298:10:298:16 | ...[...] | provenance | |
549571
| semantics.rb:299:10:299:10 | x [element foo] | semantics.rb:299:10:299:17 | ...[...] | provenance | |
550572
| semantics.rb:299:10:299:10 | x [element foo] | semantics.rb:299:10:299:17 | ...[...] | provenance | |
551573
| semantics.rb:301:10:301:10 | x [element foo] | semantics.rb:301:10:301:13 | ...[...] | provenance | |
@@ -1616,16 +1638,32 @@ nodes
16161638
| semantics.rb:263:14:263:14 | h [element :foo] | semmle.label | h [element :foo] |
16171639
| semantics.rb:263:14:263:14 | h [element] | semmle.label | h [element] |
16181640
| semantics.rb:263:14:263:14 | h [element] | semmle.label | h [element] |
1641+
| semantics.rb:267:5:267:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
1642+
| semantics.rb:267:5:267:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
1643+
| semantics.rb:267:15:267:25 | call to source | semmle.label | call to source |
1644+
| semantics.rb:267:15:267:25 | call to source | semmle.label | call to source |
1645+
| semantics.rb:268:5:268:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
1646+
| semantics.rb:268:5:268:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
16191647
| semantics.rb:268:5:268:5 | [post] h [element foo] | semmle.label | [post] h [element foo] |
16201648
| semantics.rb:268:5:268:5 | [post] h [element foo] | semmle.label | [post] h [element foo] |
1649+
| semantics.rb:268:5:268:5 | h [element :foo] | semmle.label | h [element :foo] |
1650+
| semantics.rb:268:5:268:5 | h [element :foo] | semmle.label | h [element :foo] |
16211651
| semantics.rb:268:16:268:26 | call to source | semmle.label | call to source |
16221652
| semantics.rb:268:16:268:26 | call to source | semmle.label | call to source |
1653+
| semantics.rb:269:5:269:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
1654+
| semantics.rb:269:5:269:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
16231655
| semantics.rb:269:5:269:5 | [post] h [element foo] | semmle.label | [post] h [element foo] |
16241656
| semantics.rb:269:5:269:5 | [post] h [element foo] | semmle.label | [post] h [element foo] |
1657+
| semantics.rb:269:5:269:5 | h [element :foo] | semmle.label | h [element :foo] |
1658+
| semantics.rb:269:5:269:5 | h [element :foo] | semmle.label | h [element :foo] |
16251659
| semantics.rb:269:5:269:5 | h [element foo] | semmle.label | h [element foo] |
16261660
| semantics.rb:269:5:269:5 | h [element foo] | semmle.label | h [element foo] |
1661+
| semantics.rb:270:5:270:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
1662+
| semantics.rb:270:5:270:5 | [post] h [element :foo] | semmle.label | [post] h [element :foo] |
16271663
| semantics.rb:270:5:270:5 | [post] h [element foo] | semmle.label | [post] h [element foo] |
16281664
| semantics.rb:270:5:270:5 | [post] h [element foo] | semmle.label | [post] h [element foo] |
1665+
| semantics.rb:270:5:270:5 | h [element :foo] | semmle.label | h [element :foo] |
1666+
| semantics.rb:270:5:270:5 | h [element :foo] | semmle.label | h [element :foo] |
16291667
| semantics.rb:270:5:270:5 | h [element foo] | semmle.label | h [element foo] |
16301668
| semantics.rb:270:5:270:5 | h [element foo] | semmle.label | h [element foo] |
16311669
| semantics.rb:271:5:271:5 | [post] h [element] | semmle.label | [post] h [element] |
@@ -1634,6 +1672,8 @@ nodes
16341672
| semantics.rb:271:12:271:22 | call to source | semmle.label | call to source |
16351673
| semantics.rb:273:10:273:15 | call to s32 | semmle.label | call to s32 |
16361674
| semantics.rb:273:10:273:15 | call to s32 | semmle.label | call to s32 |
1675+
| semantics.rb:273:14:273:14 | h [element :foo] | semmle.label | h [element :foo] |
1676+
| semantics.rb:273:14:273:14 | h [element :foo] | semmle.label | h [element :foo] |
16371677
| semantics.rb:273:14:273:14 | h [element foo] | semmle.label | h [element foo] |
16381678
| semantics.rb:273:14:273:14 | h [element foo] | semmle.label | h [element foo] |
16391679
| semantics.rb:273:14:273:14 | h [element] | semmle.label | h [element] |
@@ -1708,6 +1748,10 @@ nodes
17081748
| semantics.rb:297:9:297:24 | call to s36 [element foo] | semmle.label | call to s36 [element foo] |
17091749
| semantics.rb:297:13:297:23 | call to source | semmle.label | call to source |
17101750
| semantics.rb:297:13:297:23 | call to source | semmle.label | call to source |
1751+
| semantics.rb:298:10:298:10 | x [element foo] | semmle.label | x [element foo] |
1752+
| semantics.rb:298:10:298:10 | x [element foo] | semmle.label | x [element foo] |
1753+
| semantics.rb:298:10:298:16 | ...[...] | semmle.label | ...[...] |
1754+
| semantics.rb:298:10:298:16 | ...[...] | semmle.label | ...[...] |
17111755
| semantics.rb:299:10:299:10 | x [element foo] | semmle.label | x [element foo] |
17121756
| semantics.rb:299:10:299:10 | x [element foo] | semmle.label | x [element foo] |
17131757
| semantics.rb:299:10:299:17 | ...[...] | semmle.label | ...[...] |

ruby/ql/test/library-tests/dataflow/flow-summaries/semantics.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ def m32(h, i)
270270
h[1] = source("d")
271271
h[i] = source("e")
272272

273-
sink s32(h) # $ hasValueFlow=b hasValueFlow=e
273+
sink s32(h) # $ hasValueFlow=b $ hasValueFlow=e $ SPURIOUS: hasValueFlow=a
274274
end
275275

276276
def m33(h, i)
@@ -295,7 +295,7 @@ def m35(h, i)
295295

296296
def m36(h, i)
297297
x = s36(source("a"))
298-
sink x[:foo]
298+
sink x[:foo] # $ SPURIOUS: hasValueFlow=a
299299
sink x["foo"] # $ hasValueFlow=a
300300
sink x[:bar]
301301
sink x[i] # $ hasValueFlow=a

0 commit comments

Comments
 (0)