mirror of
https://github.com/github/codeql.git
synced 2025-12-21 11:16:30 +01:00
This query finds cases where a method memoizes its result but fails to include one or more of its parameters in the memoization key (or doesn't use memoization keys at all). This can lead to the method returning incorrect results when subsequently called with different arguments.
104 lines
2.1 KiB
Ruby
104 lines
2.1 KiB
Ruby
# GOOD - Should not trigger CodeQL rule
|
|
|
|
# No arguments passed to method
|
|
def m1
|
|
@m1 ||= long_running_method
|
|
end
|
|
|
|
# No arguments passed to method
|
|
def m2
|
|
@m2 ||= begin
|
|
long_running_method
|
|
end
|
|
end
|
|
|
|
# OK: argument used in key.
|
|
# May be incorrect if arg is `false` or `nil`.
|
|
def m3(arg)
|
|
@m3 ||= {}
|
|
@m3[arg] ||= long_running_method(arg)
|
|
end
|
|
|
|
# OK: both arguments used in key.
|
|
# May be incorrect if either arg is `false` or `nil`.
|
|
def m4(arg1, arg2)
|
|
@m4 ||= {}
|
|
@m4[[arg1, arg2]] ||= result(arg1, arg2)
|
|
end
|
|
|
|
# OK: argument used in key.
|
|
# Still correct if arg is `false` or `nil`.
|
|
def m5(arg)
|
|
@m5 ||= Hash.new do |h1, key|
|
|
h1[key] = long_running_method(key)
|
|
end
|
|
@m5[arg]
|
|
end
|
|
|
|
# OK: both arguments used in key.
|
|
# Still correct if either arg is `false` or `nil`.
|
|
def m6(arg1, arg2)
|
|
@m6 ||= Hash.new do |h1, arg1|
|
|
h1[arg1] = Hash.new do |h2, arg2|
|
|
h2[arg2] = result(arg1, arg2)
|
|
end
|
|
end
|
|
@m6[arg1][arg2]
|
|
end
|
|
|
|
# Bad: method has parameter but only one result is memoized.
|
|
def m7(arg) # $result=BAD
|
|
@m7 ||= begin
|
|
arg += 3
|
|
end
|
|
@m7
|
|
end
|
|
|
|
# Bad: method has parameter but only one result is memoized.
|
|
def m8(arg) # $result=BAD
|
|
@m8 ||= begin
|
|
long_running_method(arg)
|
|
end
|
|
@m8
|
|
end
|
|
|
|
# Bad: method has parameter but only one result is memoized.
|
|
def m9(arg) # $result=BAD
|
|
@m9 ||= long_running_method(arg)
|
|
end
|
|
|
|
# Bad: method has parameter but only one result is memoized.
|
|
def m10(arg1, arg2) # $result=BAD
|
|
@m10 ||= long_running_method(arg1, arg2)
|
|
end
|
|
|
|
# Bad: `arg2` not used in key.
|
|
def m11(arg1, arg2) # $result=BAD
|
|
@m11 ||= {}
|
|
@m11[arg1] ||= long_running_method(arg1, arg2)
|
|
end
|
|
|
|
# Bad: `arg2` not used in key.
|
|
def m12(arg1, arg2) # $result=BAD
|
|
@m12 ||= Hash.new do |h1, arg1|
|
|
h1[arg1] = result(arg1, arg2)
|
|
end
|
|
@m12[arg1]
|
|
end
|
|
|
|
# Bad: arg not used in key.
|
|
def m13(id:) # $result=BAD
|
|
@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
|
|
|
|
# Good (FP): arg is used in key via string interpolation.
|
|
def m14(arg)
|
|
@m14 ||= {}
|
|
key = "foo/#{arg}"
|
|
@m14[key] ||= long_running_method(arg)
|
|
end |