@@ -595,10 +595,33 @@ predicate indirectReturnOutNodeInstruction0(
595595 instructionForfullyConvertedCall ( instr , call )
596596}
597597
598+ /**
599+ * Holds if `node` is an indirect operand with columns `(operand, indirectionIndex)`, and
600+ * `operand` represents a use of the fully converted value of `call`.
601+ */
602+ private predicate hasOperand ( Node node , CallInstruction call , int indirectionIndex , Operand operand ) {
603+ indirectReturnOutNodeOperand0 ( call , operand , indirectionIndex ) and
604+ hasOperandAndIndex ( node , operand , indirectionIndex )
605+ }
606+
607+ /**
608+ * Holds if `node` is an indirect instruction with columns `(instr, indirectionIndex)`, and
609+ * `instr` represents a use of the fully converted value of `call`.
610+ *
611+ * Note that `hasOperand(node, _, _, _)` implies `not hasInstruction(node, _, _, _)`.
612+ */
613+ private predicate hasInstruction (
614+ Node node , CallInstruction call , int indirectionIndex , Instruction instr
615+ ) {
616+ indirectReturnOutNodeInstruction0 ( call , instr , indirectionIndex ) and
617+ hasInstructionAndIndex ( node , instr , indirectionIndex )
618+ }
619+
598620/**
599621 * INTERNAL: do not use.
600622 *
601- * A node representing the value of a function call.
623+ * A node representing the indirect value of a function call (i.e., a value hidden
624+ * behind a number of indirections).
602625 */
603626class IndirectReturnOutNode extends Node {
604627 CallInstruction call ;
@@ -607,20 +630,43 @@ class IndirectReturnOutNode extends Node {
607630 IndirectReturnOutNode ( ) {
608631 // Annoyingly, we need to pick the fully converted value as the output of the function to
609632 // make flow through in the shared dataflow library work correctly.
610- exists ( Operand operand |
611- indirectReturnOutNodeOperand0 ( call , operand , indirectionIndex ) and
612- hasOperandAndIndex ( this , operand , indirectionIndex )
613- )
633+ hasOperand ( this , call , indirectionIndex , _)
614634 or
615- exists ( Instruction instr |
616- indirectReturnOutNodeInstruction0 ( call , instr , indirectionIndex ) and
617- hasInstructionAndIndex ( this , instr , indirectionIndex )
618- )
635+ hasInstruction ( this , call , indirectionIndex , _)
619636 }
620637
621638 CallInstruction getCallInstruction ( ) { result = call }
622639
623640 int getIndirectionIndex ( ) { result = indirectionIndex }
641+
642+ /** Gets the operand associated with this node, if any. */
643+ Operand getOperand ( ) { hasOperand ( this , call , indirectionIndex , result ) }
644+
645+ /** Gets the instruction associated with this node, if any. */
646+ Instruction getInstruction ( ) { hasInstruction ( this , call , indirectionIndex , result ) }
647+ }
648+
649+ /**
650+ * An `IndirectReturnOutNode` which is used as a destination of a store operation.
651+ * When it's used for a store operation it's useful to have this be a `PostUpdateNode` for
652+ * the shared dataflow library's flow-through mechanism to detect flow in cases such as:
653+ * ```cpp
654+ * struct MyInt {
655+ * int i;
656+ * int& getRef() { return i; }
657+ * };
658+ * ...
659+ * MyInt mi;
660+ * mi.getRef() = source(); // this is detected as a store to `i` via flow-through.
661+ * sink(mi.i);
662+ * ```
663+ */
664+ private class PostIndirectReturnOutNode extends IndirectReturnOutNode , PostUpdateNode {
665+ PostIndirectReturnOutNode ( ) {
666+ any ( StoreInstruction store ) .getDestinationAddressOperand ( ) = this .getOperand ( )
667+ }
668+
669+ override Node getPreUpdateNode ( ) { result = this }
624670}
625671
626672private Type getTypeImpl ( Type t , int indirectionIndex ) {
0 commit comments