Skip to content

Commit cb37a0e

Browse files
committed
Ruby: Add summaries for Hash#deep_merge(!)
1 parent 3dea1d6 commit cb37a0e

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

ruby/ql/lib/codeql/ruby/frameworks/core/Hash.qll

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,11 @@ private class FetchValuesUnknownSummary extends FetchValuesSummary {
337337
}
338338

339339
private class MergeSummary extends SimpleSummarizedCallable {
340-
MergeSummary() { this = "merge" }
340+
MergeSummary() {
341+
// deep_merge is an ActiveSupport extension
342+
// https://api.rubyonrails.org/classes/Hash.html#method-i-deep_merge
343+
this = ["merge", "deep_merge"]
344+
}
341345

342346
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
343347
(
@@ -352,7 +356,11 @@ private class MergeSummary extends SimpleSummarizedCallable {
352356
}
353357

354358
private class MergeBangSummary extends SimpleSummarizedCallable {
355-
MergeBangSummary() { this = ["merge!", "update"] }
359+
MergeBangSummary() {
360+
// deep_merge! is an ActiveSupport extension
361+
// https://api.rubyonrails.org/classes/Hash.html#method-i-deep_merge-21
362+
this = ["merge!", "deep_merge!", "update"]
363+
}
356364

357365
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
358366
(

ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,3 +783,62 @@ def m46(x)
783783
end
784784

785785
m46(:c)
786+
787+
def m47()
788+
hash1 = {
789+
:a => taint(47.1),
790+
:b => 1,
791+
:c => taint(47.2)
792+
}
793+
hash2 = {
794+
:d => taint(47.3),
795+
:e => 1,
796+
:f => taint(47.4)
797+
}
798+
hash = hash1.deep_merge(hash2) do |key, old_value, new_value|
799+
sink key
800+
sink old_value # $ hasValueFlow=47.1 $ hasValueFlow=47.2 $ hasValueFlow=47.3 $ hasValueFlow=47.4
801+
sink new_value # $ hasValueFlow=47.1 $ hasValueFlow=47.2 $ hasValueFlow=47.3 $ hasValueFlow=47.4
802+
end
803+
sink (hash[:a]) # $ hasValueFlow=47.1
804+
sink (hash[:b])
805+
sink (hash[:c]) # $ hasValueFlow=47.2
806+
sink (hash[:d]) # $ hasValueFlow=47.3
807+
sink (hash[:e])
808+
sink (hash[:f]) # $ hasValueFlow=47.4
809+
end
810+
811+
m47()
812+
813+
def m48()
814+
hash1 = {
815+
:a => taint(48.1),
816+
:b => 1,
817+
:c => taint(48.2)
818+
}
819+
hash2 = {
820+
:d => taint(48.3),
821+
:e => 1,
822+
:f => taint(48.4)
823+
}
824+
hash = hash1.deep_merge!(hash2) do |key, old_value, new_value|
825+
sink key
826+
sink old_value # $ hasValueFlow=48.1 $ hasValueFlow=48.2 $ hasValueFlow=48.3 $ hasValueFlow=48.4
827+
sink new_value # $ hasValueFlow=48.1 $ hasValueFlow=48.2 $ hasValueFlow=48.3 $ hasValueFlow=48.4
828+
end
829+
sink (hash[:a]) # $ hasValueFlow=48.1
830+
sink (hash[:b])
831+
sink (hash[:c]) # $ hasValueFlow=48.2
832+
sink (hash[:d]) # $ hasValueFlow=48.3
833+
sink (hash[:e])
834+
sink (hash[:f]) # $ hasValueFlow=48.4
835+
836+
sink (hash1[:a]) # $ hasValueFlow=48.1
837+
sink (hash1[:b])
838+
sink (hash1[:c]) # $ hasValueFlow=48.2
839+
sink (hash1[:d]) # $ hasValueFlow=48.3
840+
sink (hash1[:e])
841+
sink (hash1[:f]) # $ hasValueFlow=48.4
842+
end
843+
844+
m48()

0 commit comments

Comments
 (0)