@@ -406,7 +406,10 @@ private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
406406 (
407407 exists ( Type pointerType , Type base , Type t |
408408 pointerType = t .getUnderlyingType ( ) and
409- ( pointerType instanceof PointerOrReferenceType or pointerType instanceof Cpp:: ArrayType ) and
409+ (
410+ pointerType = any ( Indirection ind ) .getUnderlyingType ( ) or
411+ pointerType instanceof Cpp:: ArrayType
412+ ) and
410413 cppType .hasType ( t , _) and
411414 base = getTypeImpl ( pointerType , indirectionIndex )
412415 |
@@ -478,9 +481,10 @@ private module Cached {
478481 }
479482
480483 /**
481- * Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
482- * that is used for a write operation that writes the value `value`. The `memory` instruction
483- * represents the memory that the IR's SSA analysis determined was read by the call to `operator*`.
484+ * Holds if `iteratorAddress` is an address of an iterator (i.e., `it`)
485+ * that is dereferenced and then used for a write operation that writes the value `value`.
486+ * The `memory` instruction represents the memory that the IR's SSA analysis determined was
487+ * read by the call to `operator*`.
484488 *
485489 * The `numberOfLoads` integer represents the number of dereferences this write corresponds to
486490 * on the underlying container that produced the iterator.
@@ -501,6 +505,77 @@ private module Cached {
501505 )
502506 }
503507
508+ private predicate isSource ( Instruction instr , Operand iteratorAddress , int numberOfLoads ) {
509+ getAUse ( instr ) = iteratorAddress and
510+ exists ( BaseSourceVariableInstruction iteratorBase |
511+ iteratorBase .getResultType ( ) instanceof Interfaces:: Iterator and
512+ not iteratorBase .getResultType ( ) instanceof Cpp:: PointerType and
513+ isUse ( _, iteratorAddress , iteratorBase , numberOfLoads - 1 , 0 )
514+ )
515+ }
516+
517+ private predicate isSink ( Instruction instr , CallInstruction call ) {
518+ getAUse ( instr ) .( ArgumentOperand ) .getCall ( ) = call and
519+ // Don't include various operations that don't modify what the iterator points to.
520+ not exists ( Function f | f = call .getStaticCallTarget ( ) |
521+ f instanceof Iterator:: IteratorCrementOperator or
522+ f instanceof Iterator:: IteratorBinaryArithmeticOperator or
523+ f instanceof Iterator:: IteratorAssignArithmeticOperator or
524+ f instanceof Iterator:: IteratorCrementMemberOperator or
525+ f instanceof Iterator:: IteratorBinaryArithmeticMemberOperator or
526+ f instanceof Iterator:: IteratorAssignArithmeticMemberOperator or
527+ f instanceof Iterator:: IteratorAssignmentMemberOperator
528+ )
529+ }
530+
531+ private predicate convertsIntoArgumentFwd ( Instruction instr ) {
532+ isSource ( instr , _, _)
533+ or
534+ exists ( Instruction prev | convertsIntoArgumentFwd ( prev ) |
535+ conversionFlow ( unique( | | getAUse ( prev ) ) , instr , false , _)
536+ )
537+ }
538+
539+ private predicate convertsIntoArgumentRev ( Instruction instr ) {
540+ convertsIntoArgumentFwd ( instr ) and
541+ (
542+ isSink ( instr , _)
543+ or
544+ exists ( Instruction next | convertsIntoArgumentRev ( next ) |
545+ conversionFlow ( unique( | | getAUse ( instr ) ) , next , false , _)
546+ )
547+ )
548+ }
549+
550+ private predicate convertsIntoArgument (
551+ Operand iteratorAddress , CallInstruction call , int numberOfLoads
552+ ) {
553+ exists ( Instruction iteratorAddressDef |
554+ isSource ( iteratorAddressDef , iteratorAddress , numberOfLoads ) and
555+ isSink ( iteratorAddressDef , call ) and
556+ convertsIntoArgumentRev ( pragma [ only_bind_into ] ( iteratorAddressDef ) )
557+ )
558+ }
559+
560+ private predicate isChiAfterIteratorArgument (
561+ Instruction memory , Operand iteratorAddress , int numberOfLoads
562+ ) {
563+ // Ideally, `iteratorAddress` would be an `ArgumentOperand`, but there might be
564+ // various conversions applied to it before it becomes an argument.
565+ // So we do a small amount of flow to find the call that the iterator is passed to.
566+ exists ( CallInstruction call | convertsIntoArgument ( iteratorAddress , call , numberOfLoads ) |
567+ exists ( ReadSideEffectInstruction read |
568+ read .getPrimaryInstruction ( ) = call and
569+ read .getSideEffectOperand ( ) .getAnyDef ( ) = memory
570+ )
571+ or
572+ exists ( LoadInstruction load |
573+ iteratorAddress .getDef ( ) = load and
574+ memory = load .getSourceValueOperand ( ) .getAnyDef ( )
575+ )
576+ )
577+ }
578+
504579 /**
505580 * Holds if `iterator` is a `StoreInstruction` that stores the result of some function
506581 * returning an iterator into an address computed started at `containerBase`.
@@ -521,21 +596,22 @@ private module Cached {
521596 }
522597
523598 /**
524- * Holds if `iteratorDerefAddress ` is an address of an iterator dereference (i.e., `*it`)
525- * that is used for a read operation. The `memory` instruction represents the memory that
599+ * Holds if `iteratorAddress ` is an address of an iterator that is used for
600+ * a read operation. The `memory` instruction represents the memory that
526601 * the IR's SSA analysis determined was read by the call to `operator*`.
527602 *
528- * Finally, the `numberOfLoads` integer represents the number of dereferences this read
529- * corresponds to on the underlying container that produced the iterator.
603+ * Finally, the `numberOfLoads` integer represents the number of dereferences
604+ * this read corresponds to on the underlying container that produced the iterator.
530605 */
531606 private predicate isChiBeforeIteratorUse (
532- Operand iteratorDerefAddress , Instruction memory , int numberOfLoads
607+ Operand iteratorAddress , Instruction memory , int numberOfLoads
533608 ) {
534609 exists (
535610 BaseSourceVariableInstruction iteratorBase , LoadInstruction load ,
536- ReadSideEffectInstruction read
611+ ReadSideEffectInstruction read , Operand iteratorDerefAddress
537612 |
538613 numberOfLoads >= 0 and
614+ isUse ( _, iteratorAddress , iteratorBase , numberOfLoads + 1 , 0 ) and
539615 isUse ( _, iteratorDerefAddress , iteratorBase , numberOfLoads + 2 , 0 ) and
540616 iteratorBase .getResultType ( ) instanceof Interfaces:: Iterator and
541617 load .getSourceAddressOperand ( ) = iteratorDerefAddress and
@@ -566,24 +642,35 @@ private module Cached {
566642 }
567643
568644 /**
569- * Holds if `iteratorDerefAddress ` is an address of an iterator dereference (i.e., `*it`)
570- * that is used for a read operation to read a value from a container that created the iterator.
571- * `container` represents the base of the address of the container that was used to create
572- * the iterator.
645+ * Holds if `iteratorAddress ` is an address of an iterator that is used for a
646+ * read operation to read a value from a container that created the iterator.
647+ * `container` represents the base of the address of the container that was used
648+ * to create the iterator.
573649 */
574650 cached
575651 predicate isIteratorUse (
576- BaseSourceVariableInstruction container , Operand iteratorDerefAddress , int numberOfLoads ,
652+ BaseSourceVariableInstruction container , Operand iteratorAddress , int numberOfLoads ,
577653 int indirectionIndex
578654 ) {
655+ // Direct use
579656 exists ( Instruction begin , Instruction memory , int upper , int ind |
580- isChiBeforeIteratorUse ( iteratorDerefAddress , memory , numberOfLoads ) and
657+ isChiBeforeIteratorUse ( iteratorAddress , memory , numberOfLoads ) and
581658 memorySucc * ( begin , memory ) and
582659 isChiAfterBegin ( container , begin ) and
583660 upper = countIndirectionsForCppType ( getResultLanguageType ( container ) ) and
584661 ind = numberOfLoads + [ 1 .. upper ] and
585662 indirectionIndex = ind - ( numberOfLoads + 1 )
586663 )
664+ or
665+ // Use through function output
666+ exists ( Instruction memory , Instruction begin , int upper , int ind |
667+ isChiAfterIteratorArgument ( memory , iteratorAddress , numberOfLoads ) and
668+ memorySucc * ( begin , memory ) and
669+ isChiAfterBegin ( container , begin ) and
670+ upper = countIndirectionsForCppType ( getResultLanguageType ( container ) ) and
671+ ind = numberOfLoads + [ 1 .. upper ] and
672+ indirectionIndex = ind - ( numberOfLoads - 1 )
673+ )
587674 }
588675
589676 /** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
0 commit comments