Skip to content

Commit 8342385

Browse files
authored
Merge pull request github#11339 from aibaars/active_support_enumerable
Ruby: Active support enumerable
2 parents 3d59935 + 6103c57 commit 8342385

File tree

4 files changed

+495
-1
lines changed

4 files changed

+495
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Data flow through the `ActiveSupport` extensions `Enumerable#index_with`, `Enumerable#pick`, `Enumerable#pluck` and `Enumerable#sole` are now modeled.

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

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,143 @@ module ActiveSupport {
305305
preservesValue = true
306306
}
307307
}
308-
// TODO: index_with, pick, pluck (they require Hash dataflow)
308+
309+
private class IndexWithSummary extends SimpleSummarizedCallable {
310+
IndexWithSummary() { this = "index_with" }
311+
312+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
313+
input = "Argument[self].Element[any]" and
314+
output = "Argument[block].Parameter[0]" and
315+
preservesValue = true
316+
or
317+
input = ["Argument[0]", "Argument[block].ReturnValue"] and
318+
output = "ReturnValue.Element[?]" and
319+
preservesValue = true
320+
}
321+
}
322+
323+
private string getKeyArgument(MethodCall mc, int i) {
324+
mc.getMethodName() = ["pick", "pluck"] and
325+
result = DataFlow::Content::getKnownElementIndex(mc.getArgument(i)).serialize()
326+
}
327+
328+
private class PickSingleSummary extends SummarizedCallable {
329+
private MethodCall mc;
330+
private string key;
331+
332+
PickSingleSummary() {
333+
key = getKeyArgument(mc, 0) and
334+
this = "Enumerable.pick(" + key + ")" and
335+
mc.getMethodName() = "pick" and
336+
mc.getNumberOfArguments() = 1
337+
}
338+
339+
override MethodCall getACall() { result = mc }
340+
341+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
342+
input = "Argument[self].Element[0].Element[" + key + "]" and
343+
output = "ReturnValue" and
344+
preservesValue = true
345+
}
346+
}
347+
348+
private class PickMultipleSummary extends SummarizedCallable {
349+
private MethodCall mc;
350+
351+
PickMultipleSummary() {
352+
mc.getMethodName() = "pick" and
353+
mc.getNumberOfArguments() > 1 and
354+
exists(int maxKey |
355+
maxKey = max(int j | exists(getKeyArgument(mc, j))) and
356+
this =
357+
"Enumerable.pick(" +
358+
concat(int i, string key |
359+
key = getKeyArgument(mc, i)
360+
or
361+
key = "_" and
362+
not exists(getKeyArgument(mc, i)) and
363+
i in [0 .. maxKey]
364+
|
365+
key, "," order by i
366+
) + ")"
367+
)
368+
}
369+
370+
override MethodCall getACall() { result = mc }
371+
372+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
373+
exists(string s, int i |
374+
s = getKeyArgument(mc, i) and
375+
input = "Argument[self].Element[0].Element[" + s + "]" and
376+
output = "ReturnValue.Element[" + i + "]"
377+
) and
378+
preservesValue = true
379+
}
380+
}
381+
382+
private class PluckSingleSummary extends SummarizedCallable {
383+
private MethodCall mc;
384+
private string key;
385+
386+
PluckSingleSummary() {
387+
key = getKeyArgument(mc, 0) and
388+
this = "Enumerable.pluck(" + key + ")" and
389+
mc.getMethodName() = "pluck" and
390+
mc.getNumberOfArguments() = 1
391+
}
392+
393+
override MethodCall getACall() { result = mc }
394+
395+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
396+
input = "Argument[self].Element[any].Element[" + key + "]" and
397+
output = "ReturnValue.Element[any]" and
398+
preservesValue = true
399+
}
400+
}
401+
402+
private class PluckMultipleSummary extends SummarizedCallable {
403+
private MethodCall mc;
404+
405+
PluckMultipleSummary() {
406+
mc.getMethodName() = "pluck" and
407+
mc.getNumberOfArguments() > 1 and
408+
exists(int maxKey |
409+
maxKey = max(int j | exists(getKeyArgument(mc, j))) and
410+
this =
411+
"Enumerable.pluck(" +
412+
concat(int i, string key |
413+
key = getKeyArgument(mc, i)
414+
or
415+
key = "_" and
416+
not exists(getKeyArgument(mc, i)) and
417+
i in [0 .. maxKey]
418+
|
419+
key, "," order by i
420+
) + ")"
421+
)
422+
}
423+
424+
override MethodCall getACall() { result = mc }
425+
426+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
427+
exists(string s, int i |
428+
s = getKeyArgument(mc, i) and
429+
input = "Argument[self].Element[any].Element[" + s + "]" and
430+
output = "ReturnValue.Element[?].Element[" + i + "]"
431+
) and
432+
preservesValue = true
433+
}
434+
}
435+
436+
private class SoleSummary extends SimpleSummarizedCallable {
437+
SoleSummary() { this = "sole" }
438+
439+
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
440+
input = "Argument[self].Element[0]" and
441+
output = "ReturnValue" and
442+
preservesValue = true
443+
}
444+
}
309445
}
310446
}
311447

0 commit comments

Comments
 (0)