@@ -10,6 +10,7 @@ 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
1314
1415class Node = DataFlowPublic:: Node ;
1516
@@ -220,6 +221,25 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet conten
220221 nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
221222 nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
222223 )
224+ or
225+ // Hash literals
226+ exists ( Cfg:: CfgNodes:: ExprNodes:: PairCfgNode pair |
227+ hashLiteralStore ( nodeTo , any ( DataFlow:: Node n | n .asExpr ( ) = pair ) ) and
228+ nodeFrom .asExpr ( ) = pair .getValue ( )
229+ |
230+ exists ( ConstantValue constant |
231+ constant = pair .getKey ( ) .getConstantValue ( ) and
232+ contents .isSingleton ( DataFlow:: Content:: getElementContent ( constant ) )
233+ )
234+ or
235+ not exists ( pair .getKey ( ) .getConstantValue ( ) ) and
236+ contents .isAnyElement ( )
237+ )
238+ }
239+
240+ private predicate hashLiteralStore ( DataFlow:: CallNode hashCreation , DataFlow:: Node argument ) {
241+ hashCreation .getExprNode ( ) .getExpr ( ) = Hash:: getAStaticHashCall ( "[]" ) and
242+ argument = hashCreation .getArgument ( _)
223243}
224244
225245/**
@@ -310,6 +330,14 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter)
310330 nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
311331 nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
312332 )
333+ or
334+ // Hash-splat in a hash literal
335+ exists ( DataFlow:: Node node |
336+ hashLiteralStore ( nodeTo , node ) and
337+ node .asExpr ( ) .getExpr ( ) instanceof HashSplatExpr and
338+ nodeFrom .asExpr ( ) = node .asExpr ( ) .( Cfg:: CfgNodes:: ExprNodes:: UnaryOperationCfgNode ) .getOperand ( ) and
339+ filter = MkElementFilter ( )
340+ )
313341}
314342
315343/**
@@ -344,7 +372,8 @@ private predicate hasLoadStoreSummary(
344372) {
345373 callable
346374 .propagatesFlow ( push ( SummaryComponent:: content ( loadContents ) , input ) ,
347- push ( SummaryComponent:: content ( storeContents ) , output ) , true )
375+ push ( SummaryComponent:: content ( storeContents ) , output ) , true ) and
376+ callable != "Hash.[]" // Special-cased due to having a huge number of summaries
348377}
349378
350379/**
0 commit comments