@@ -8,6 +8,7 @@ private import codeql.ruby.dataflow.FlowSummary
8
8
private import codeql.ruby.dataflow.SSA
9
9
private import codeql.util.Boolean
10
10
private import codeql.util.Unit
11
+ private import codeql.ruby.controlflow.CfgNodes
11
12
12
13
/**
13
14
* A `LocalSourceNode` for a `self` variable. This is the implicit `self`
@@ -239,6 +240,7 @@ class NormalCall extends DataFlowCall, TNormalCall {
239
240
*/
240
241
private module ViewComponentRenderModeling {
241
242
private import codeql.ruby.frameworks.ViewComponent
243
+ private import codeql.ruby.frameworks.ActionController
242
244
243
245
private class RenderMethod extends SummarizedCallable , LibraryCallableToIncludeInTypeTracking {
244
246
RenderMethod ( ) { this = "render view component" }
@@ -250,12 +252,38 @@ private module ViewComponentRenderModeling {
250
252
// use a call-back summary, and adjust it to a method call below
251
253
output = "Argument[0].Parameter[self]" and
252
254
preservesValue = true
255
+ or
256
+ input = "Argument[self]" and
257
+ output = "Argument[self].Parameter[self]" and
258
+ preservesValue = true
253
259
}
254
260
}
255
261
256
262
private string invokeToplevelName ( ) { result = "__invoke__toplevel__erb__" }
257
263
258
- /** Holds if `call` should be adjusted to be a method call to `name` on `receiver`. */
264
+ /**
265
+ * Holds if `call` should be adjusted to be a method call to `name` on `receiver`.
266
+ * `call` is the callback call inside the flow summary.
267
+ * Effectively we generate something like
268
+ * ```rb
269
+ * def render(view)
270
+ * # ViewComponent
271
+ * view()
272
+ * # ActionController
273
+ * self()
274
+ * end
275
+ * ```
276
+ *
277
+ * And this adjustment changes it to
278
+ * ```rb
279
+ * def render(view)
280
+ * # ViewComponent
281
+ * view.__invoke__toplevel__erb__()
282
+ * # ActionController
283
+ * self.__invoke__toplevel__erb__()
284
+ * end
285
+ * ```
286
+ */
259
287
predicate adjustedMethodCall ( DataFlowCall call , FlowSummaryNode receiver , string name ) {
260
288
exists ( RenderMethod render |
261
289
call = TSummaryCall ( render , receiver .getSummaryNode ( ) ) and
@@ -265,14 +293,29 @@ private module ViewComponentRenderModeling {
265
293
266
294
/** Holds if `self` belongs to the top-level of an ERB file with matching view class `view`. */
267
295
pragma [ nomagic]
268
- predicate selfInErbToplevel ( SelfVariable self , ViewComponent:: ComponentClass view ) {
269
- self .getDeclaringScope ( ) .( Toplevel ) .getFile ( ) = view .getTemplate ( )
296
+ predicate selfInErbToplevel ( SelfVariable self , Module view ) {
297
+ self .getDeclaringScope ( ) .( Toplevel ) .getFile ( ) =
298
+ [
299
+ view .( ViewComponent:: ComponentClass ) .getTemplate ( ) ,
300
+ view .( ActionControllerClass ) .getAnAction ( ) .getDefaultTemplateFile ( )
301
+ ]
270
302
}
271
303
272
304
Toplevel lookupMethod ( ViewComponent:: ComponentClass m , string name ) {
273
305
result .getFile ( ) = m .getTemplate ( ) and
274
306
name = invokeToplevelName ( )
275
307
}
308
+
309
+ Toplevel lookupMethodCall ( DataFlowCall c , Module mod , DataFlow:: Node receiver , string name ) {
310
+ name = invokeToplevelName ( ) and
311
+ exists ( ActionControllerActionMethod m , Call summaryCall |
312
+ m .getControllerClass ( ) = mod and
313
+ result .getFile ( ) = m .getDefaultTemplateFile ( ) and
314
+ c .getEnclosingCallable ( ) .asLibraryCallable ( ) .getACallSimple ( ) = summaryCall and
315
+ summaryCall .getEnclosingCallable ( ) = m and
316
+ adjustedMethodCall ( c , receiver , name )
317
+ )
318
+ }
276
319
}
277
320
278
321
/** A call for which we want to compute call targets. */
@@ -801,7 +844,11 @@ private CfgScope lookupInstanceMethodCall(DataFlowCall call, string method, bool
801
844
exists ( Module tp , DataFlow:: Node receiver |
802
845
methodCall ( call , pragma [ only_bind_into ] ( receiver ) , pragma [ only_bind_into ] ( method ) ) and
803
846
receiver = trackInstance ( tp , exact ) and
804
- result = lookupMethod ( tp , pragma [ only_bind_into ] ( method ) , exact )
847
+ (
848
+ result = lookupMethod ( tp , pragma [ only_bind_into ] ( method ) , exact )
849
+ or
850
+ result = ViewComponentRenderModeling:: lookupMethodCall ( call , tp , receiver , method )
851
+ )
805
852
)
806
853
}
807
854
0 commit comments