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