-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Ruby: Add Improper Memoization query #9267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
QHelp previews: ruby/ql/src/experimental/improper-memoization/ImproperMemoization.qhelperrors/warnings: |
525ffb5 to
9b68e4e
Compare
|
QHelp previews: ruby/ql/src/experimental/improper-memoization/ImproperMemoization.qhelperrors/warnings: |
9b68e4e to
02a73f0
Compare
|
QHelp previews: ruby/ql/src/experimental/improper-memoization/ImproperMemoization.qhelpImproper MemoizationA common pattern in Ruby is to memoize the result of a method by storing it in an instance variable. If the method has no parameters, it can simply be stored directly in a variable. def answer
@answer ||= calculate_answer
end
If the method takes parameters, then there are multiple results to store (one for each combination of parameter value). In this case the values should be stored in a hash, keyed by the parameter values. def answer(x, y)
@answer ||= {}
@answer[x] ||= {}
@answer[x][y] ||= calculate_answer
end
If a memoization method takes parameters but does not include them in the memoization key, subsequent calls to the method with different parameter values may incorrectly return the same result. This can lead to the method returning stale data, or leaking sensitive information. ExampleIn this example, the method does not include its parameters in the memoization key. The first call to this method will cache the result, and subsequent calls will return the same result regardless of what arguments are given. def answer(x, y)
@answer ||= calculate_answer(x, y)
end
This can be fixed by storing the result of def answer(x, y)
@answer ||= {}
@answer[x] ||= {}
@answer[x][y] ||= calculate_answer(x, y)
end
Note that if the result of def answer(x, y)
@answer ||= Hash.new do |h1, x|
h1[x] = Hash.new do |h2, y|
h2[y] = calculate_answer(x, y)
end
end
@answer[x][y]
end
|
02a73f0 to
e87eb44
Compare
83f95e4 to
fd1e920
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a nice query! I have just a few questions and nitpicks.
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.
5b328e7 to
3112964
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🚀
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.
I've added it to
experimentalinitally, as it can flag methods which aren't security vulnerabilities.