@@ -10,7 +10,6 @@ private import codeql.ruby.dataflow.internal.SsaImpl as SsaImpl
1010private import codeql.ruby.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1111private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
1212private import codeql.ruby.dataflow.internal.AccessPathSyntax
13- private import codeql.ruby.frameworks.core.Hash
1413
1514class Node = DataFlowPublic:: Node ;
1615
@@ -61,6 +60,15 @@ class ContentFilter extends TContentFilter {
6160 }
6261}
6362
63+ /** Module for getting `ContentFilter` values. */
64+ module ContentFilter {
65+ /** Gets the filter that only allow element contents. */
66+ ContentFilter hasElements ( ) { result = MkElementFilter ( ) }
67+
68+ /** Gets the filter that only allow pair-value contents. */
69+ ContentFilter hasPairValue ( ) { result = MkPairValueFilter ( ) }
70+ }
71+
6472/**
6573 * Holds if a value stored with `storeContents` can be read back with `loadContents`.
6674 */
@@ -226,28 +234,9 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet conten
226234 nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
227235 )
228236 or
229- // Hash literals
230- exists ( Cfg:: CfgNodes:: ExprNodes:: PairCfgNode pair |
231- hashLiteralStore ( nodeTo , any ( DataFlow:: Node n | n .asExpr ( ) = pair ) ) and
232- nodeFrom .asExpr ( ) = pair .getValue ( )
233- |
234- exists ( ConstantValue constant |
235- constant = pair .getKey ( ) .getConstantValue ( ) and
236- contents .isSingleton ( DataFlow:: Content:: getElementContent ( constant ) )
237- )
238- or
239- not exists ( pair .getKey ( ) .getConstantValue ( ) ) and
240- contents .isAnyElement ( )
241- )
242- or
243237 TypeTrackingStep:: storeStep ( nodeFrom , nodeTo , contents )
244238}
245239
246- private predicate hashLiteralStore ( DataFlow:: CallNode hashCreation , DataFlow:: Node argument ) {
247- hashCreation .getExprNode ( ) .getExpr ( ) = Hash:: getAStaticHashCall ( "[]" ) and
248- argument = hashCreation .getArgument ( _)
249- }
250-
251240/**
252241 * Holds if a store step `nodeFrom -> nodeTo` with `contents` exists, where the destination node
253242 * is a post-update node that should be treated as a local source node.
@@ -343,14 +332,6 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter)
343332 nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
344333 )
345334 or
346- // Hash-splat in a hash literal
347- exists ( DataFlow:: Node node |
348- hashLiteralStore ( nodeTo , node ) and
349- node .asExpr ( ) .getExpr ( ) instanceof HashSplatExpr and
350- nodeFrom .asExpr ( ) = node .asExpr ( ) .( Cfg:: CfgNodes:: ExprNodes:: UnaryOperationCfgNode ) .getOperand ( ) and
351- filter = MkElementFilter ( )
352- )
353- or
354335 TypeTrackingStep:: withContentStep ( nodeFrom , nodeTo , filter )
355336}
356337
@@ -368,6 +349,7 @@ private predicate hasStoreSummary(
368349 SummarizedCallable callable , DataFlow:: ContentSet contents , SummaryComponentStack input ,
369350 SummaryComponentStack output
370351) {
352+ not TypeTrackingStep:: suppressSummary ( callable ) and
371353 callable .propagatesFlow ( input , push ( SummaryComponent:: content ( contents ) , output ) , true ) and
372354 not isNonLocal ( input .head ( ) ) and
373355 not isNonLocal ( output .head ( ) )
@@ -378,6 +360,7 @@ private predicate hasLoadSummary(
378360 SummarizedCallable callable , DataFlow:: ContentSet contents , SummaryComponentStack input ,
379361 SummaryComponentStack output
380362) {
363+ not TypeTrackingStep:: suppressSummary ( callable ) and
381364 callable .propagatesFlow ( push ( SummaryComponent:: content ( contents ) , input ) , output , true ) and
382365 not isNonLocal ( input .head ( ) ) and
383366 not isNonLocal ( output .head ( ) )
@@ -388,12 +371,12 @@ private predicate hasLoadStoreSummary(
388371 SummarizedCallable callable , DataFlow:: ContentSet loadContents ,
389372 DataFlow:: ContentSet storeContents , SummaryComponentStack input , SummaryComponentStack output
390373) {
374+ not TypeTrackingStep:: suppressSummary ( callable ) and
391375 callable
392376 .propagatesFlow ( push ( SummaryComponent:: content ( loadContents ) , input ) ,
393377 push ( SummaryComponent:: content ( storeContents ) , output ) , true ) and
394378 not isNonLocal ( input .head ( ) ) and
395- not isNonLocal ( output .head ( ) ) and
396- callable != "Hash.[]" // Special-cased due to having a huge number of summaries
379+ not isNonLocal ( output .head ( ) )
397380}
398381
399382/**
@@ -426,6 +409,7 @@ private predicate hasWithoutContentSummary(
426409 SummaryComponentStack output
427410) {
428411 exists ( DataFlow:: ContentSet content |
412+ not TypeTrackingStep:: suppressSummary ( callable ) and
429413 callable .propagatesFlow ( push ( SummaryComponent:: withoutContent ( content ) , input ) , output , true ) and
430414 filter = getFilterFromWithoutContentStep ( content ) and
431415 not isNonLocal ( input .head ( ) ) and
@@ -464,6 +448,7 @@ private predicate hasWithContentSummary(
464448 SummaryComponentStack output
465449) {
466450 exists ( DataFlow:: ContentSet content |
451+ not TypeTrackingStep:: suppressSummary ( callable ) and
467452 callable .propagatesFlow ( push ( SummaryComponent:: withContent ( content ) , input ) , output , true ) and
468453 filter = getFilterFromWithContentStep ( content ) and
469454 not isNonLocal ( input .head ( ) ) and
@@ -508,6 +493,7 @@ private predicate dependsOnSummaryComponentStack(
508493 SummarizedCallable callable , SummaryComponentStack stack
509494) {
510495 exists ( callable .getACallSimple ( ) ) and
496+ not TypeTrackingStep:: suppressSummary ( callable ) and
511497 (
512498 callable .propagatesFlow ( stack , _, true )
513499 or
@@ -592,6 +578,13 @@ class TypeTrackingStep extends TUnit {
592578 /** Gets the string `"unit"`. */
593579 string toString ( ) { result = "unit" }
594580
581+ /**
582+ * Holds if type-tracking should not attempt to derive steps from (simple) calls to `callable`.
583+ *
584+ * This can be done to manually control how steps are generated from such calls.
585+ */
586+ predicate suppressSummary ( SummarizedCallable callable ) { none ( ) }
587+
595588 /**
596589 * Holds if type-tracking should step from `pred` to `succ`.
597590 */
@@ -630,6 +623,15 @@ class TypeTrackingStep extends TUnit {
630623
631624/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
632625module TypeTrackingStep {
626+ /**
627+ * Holds if type-tracking should not attempt to derive steps from (simple) calls to `callable`.
628+ *
629+ * This can be done to manually control how steps are generated from such calls.
630+ */
631+ predicate suppressSummary ( SummarizedCallable callable ) {
632+ any ( TypeTrackingStep st ) .suppressSummary ( callable )
633+ }
634+
633635 /**
634636 * Holds if type-tracking should step from `pred` to `succ`.
635637 */
0 commit comments