@@ -2,6 +2,7 @@ private import cpp
22private import DataFlowUtil
33private import semmle.code.cpp.ir.IR
44private import DataFlowDispatch
5+ private import semmle.code.cpp.models.interfaces.DataFlow
56
67/**
78 * A data flow node that occurs as the argument of a call and is passed as-is
@@ -271,16 +272,31 @@ private predicate callableWithoutDefinitionStoreStep(
271272) {
272273 exists (
273274 WriteSideEffectInstruction write , ChiInstruction chi , PostUpdateFieldNode post ,
274- Function callable
275+ Function callable , CallInstruction call
275276 |
276277 chi .getPartial ( ) = write and
277278 not chi .isResultConflated ( ) and
278279 post = node2 .getPartialDefinition ( ) and
279- node1 .asInstruction ( ) = write and
280280 post .getPreUpdateNode ( ) = getFieldNodeForFieldInstruction ( write .getDestinationAddress ( ) ) and
281281 f .getADirectField ( ) = post .getPreUpdateNode ( ) .getField ( ) and
282- callable = write .getPrimaryInstruction ( ) .( CallInstruction ) .getStaticCallTarget ( ) and
282+ call = write .getPrimaryInstruction ( ) and
283+ callable = call .getStaticCallTarget ( ) and
283284 not callable .hasDefinition ( )
285+ |
286+ exists ( OutParameterDeref out | out .getIndex ( ) = write .getIndex ( ) |
287+ callable .( DataFlowFunction ) .hasDataFlow ( _, out ) and
288+ node1 .asInstruction ( ) = write
289+ )
290+ or
291+ // Ideally we shouldn't need to do a store step from a read side effect, but if we don't have a
292+ // model for the callee there might not be flow to the write side effect (since the callee has no
293+ // definition). This case ensures that we propagate dataflow when a field is passed into a
294+ // function that has a write side effect, even though the write side effect doesn't have incoming
295+ // flow.
296+ not callable instanceof DataFlowFunction and
297+ exists ( ReadSideEffectInstruction read | call = read .getPrimaryInstruction ( ) |
298+ node1 .asInstruction ( ) = read .getSideEffectOperand ( ) .getAnyDef ( )
299+ )
284300 )
285301}
286302
0 commit comments