@@ -6,6 +6,7 @@ private import cpp
66private import semmle.code.cpp.ir.IR
77private import semmle.code.cpp.controlflow.IRGuards
88private import semmle.code.cpp.ir.ValueNumbering
9+ private import semmle.code.cpp.models.interfaces.DataFlow
910
1011/**
1112 * A newtype wrapper to prevent accidental casts between `Node` and
@@ -282,7 +283,58 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
282283 // for variables that have escaped: for soundness, the IR has to assume that
283284 // every write to an unknown address can affect every escaped variable, and
284285 // this assumption shows up as data flowing through partial chi operands.
285- iTo .getAnOperand ( ) .( ChiTotalOperand ) .getDef ( ) = iFrom
286+ iTo .getAnOperand ( ) .( ChiTotalOperand ) .getDef ( ) = iFrom or
287+ // Flow from argument to return value
288+ iTo = any ( CallInstruction call |
289+ exists ( int indexIn |
290+ modelFlowToReturnValue ( call .getStaticCallTarget ( ) , indexIn ) and
291+ iFrom = getACallArgumentOrIndirection ( call , indexIn )
292+ )
293+ )
294+ or
295+ // Flow from input argument to output argument
296+ // TODO: This won't work in practice as long as all aliased memory is tracked
297+ // together in a single virtual variable.
298+ iTo = any ( WriteSideEffectInstruction outNode |
299+ exists ( CallInstruction call , int indexIn , int indexOut |
300+ modelFlowToParameter ( call .getStaticCallTarget ( ) , indexIn , indexOut ) and
301+ iFrom = getACallArgumentOrIndirection ( call , indexIn ) and
302+ outNode .getIndex ( ) = indexOut and
303+ outNode .getPrimaryInstruction ( ) = call
304+ )
305+ )
306+ }
307+
308+ /**
309+ * Get an instruction that goes into argument `argumentIndex` of `call`. This
310+ * can be either directly or through one pointer indirection.
311+ */
312+ private Instruction getACallArgumentOrIndirection ( CallInstruction call , int argumentIndex ) {
313+ result = call .getPositionalArgument ( argumentIndex )
314+ or
315+ exists ( ReadSideEffectInstruction readSE |
316+ // TODO: why are read side effect operands imprecise?
317+ result = readSE .getSideEffectOperand ( ) .getAnyDef ( ) and
318+ readSE .getPrimaryInstruction ( ) = call and
319+ readSE .getIndex ( ) = argumentIndex
320+ )
321+ }
322+
323+ private predicate modelFlowToParameter ( Function f , int parameterIn , int parameterOut ) {
324+ exists ( FunctionInput modelIn , FunctionOutput modelOut |
325+ f .( DataFlowFunction ) .hasDataFlow ( modelIn , modelOut ) and
326+ ( modelIn .isParameter ( parameterIn ) or modelIn .isParameterDeref ( parameterIn ) ) and
327+ modelOut .isParameterDeref ( parameterOut )
328+ )
329+ }
330+
331+ private predicate modelFlowToReturnValue ( Function f , int parameterIn ) {
332+ // Data flow from parameter to return value
333+ exists ( FunctionInput modelIn , FunctionOutput modelOut |
334+ f .( DataFlowFunction ) .hasDataFlow ( modelIn , modelOut ) and
335+ ( modelIn .isParameter ( parameterIn ) or modelIn .isParameterDeref ( parameterIn ) ) and
336+ ( modelOut .isReturnValue ( ) or modelOut .isReturnValueDeref ( ) )
337+ )
286338}
287339
288340/**
0 commit comments