Skip to content

Commit 77250af

Browse files
authored
Merge pull request #12050 from MathiasVP/flow-out-of-iterators-3
2 parents 4317381 + 09a7573 commit 77250af

File tree

9 files changed

+188
-39
lines changed

9 files changed

+188
-39
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ private Operand fullyConvertedCallStep(Operand op) {
381381
*/
382382
private Instruction getUse(Operand op) {
383383
result = op.getUse() and
384-
not Ssa::ignoreOperand(op)
384+
not Ssa::ignoreInstruction(result)
385385
}
386386

387387
/** Gets a use of the instruction `instr` that is not ignored for dataflow purposes. */

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ private newtype TDefOrUseImpl =
155155
)
156156
} or
157157
TIteratorDef(
158-
Operand iteratorAddress, BaseSourceVariableInstruction container, int indirectionIndex
158+
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
159159
) {
160-
isIteratorDef(container, iteratorAddress, _, _, indirectionIndex) and
161-
any(SsaInternals0::Def def | def.isIteratorDef()).getAddressOperand() = iteratorAddress
160+
isIteratorDef(container, iteratorDerefAddress, _, _, indirectionIndex) and
161+
any(SsaInternals0::Def def | def.isIteratorDef()).getAddressOperand() = iteratorDerefAddress
162162
} or
163163
TIteratorUse(
164164
Operand iteratorAddress, BaseSourceVariableInstruction container, int indirectionIndex
@@ -618,11 +618,20 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
618618
nodeToDefOrUse(nTo, defOrUse, _) and
619619
adjacentDefRead(defOrUse, _)
620620
) and
621-
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
622-
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
623-
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
624-
instr = op2.getDef() and
625-
conversionFlow(op1, instr, _, _)
621+
(
622+
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
623+
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
624+
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
625+
instr = op2.getDef() and
626+
conversionFlow(op1, instr, _, _)
627+
)
628+
or
629+
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
630+
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
631+
hasOperandAndIndex(nTo, op2, indirectionIndex - 1) and
632+
instr = op2.getDef() and
633+
isDereference(instr, op1)
634+
)
626635
)
627636
}
628637

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll

Lines changed: 103 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,10 @@ private predicate isModifiableAtImpl(CppType cppType, int indirectionIndex) {
408408
(
409409
exists(Type pointerType, Type base, Type t |
410410
pointerType = t.getUnderlyingType() and
411-
(pointerType instanceof PointerOrReferenceType or pointerType instanceof Cpp::ArrayType) and
411+
(
412+
pointerType = any(Indirection ind).getUnderlyingType() or
413+
pointerType instanceof Cpp::ArrayType
414+
) and
412415
cppType.hasType(t, _) and
413416
base = getTypeImpl(pointerType, indirectionIndex)
414417
|
@@ -504,6 +507,81 @@ private module Cached {
504507
)
505508
}
506509

510+
private predicate isSource(Instruction instr, Operand iteratorAddress, int numberOfLoads) {
511+
getAUse(instr) = iteratorAddress and
512+
exists(BaseSourceVariableInstruction iteratorBase |
513+
iteratorBase.getResultType() instanceof Interfaces::Iterator and
514+
not iteratorBase.getResultType() instanceof Cpp::PointerType and
515+
isUse(_, iteratorAddress, iteratorBase, numberOfLoads - 1, 0)
516+
)
517+
}
518+
519+
private predicate isSink(Instruction instr, CallInstruction call) {
520+
getAUse(instr).(ArgumentOperand).getCall() = call and
521+
// Only include operations that may modify the object that the iterator points to.
522+
// The following is a non-exhaustive list of things that may modify the value of the
523+
// iterator, but never the value of what the iterator points to.
524+
// The more things we can exclude here, the faster the small dataflow-like analysis
525+
// done by `convertsIntoArgument` will converge.
526+
not exists(Function f | f = call.getStaticCallTarget() |
527+
f instanceof Iterator::IteratorCrementOperator or
528+
f instanceof Iterator::IteratorBinaryArithmeticOperator or
529+
f instanceof Iterator::IteratorAssignArithmeticOperator or
530+
f instanceof Iterator::IteratorCrementMemberOperator or
531+
f instanceof Iterator::IteratorBinaryArithmeticMemberOperator or
532+
f instanceof Iterator::IteratorAssignArithmeticMemberOperator or
533+
f instanceof Iterator::IteratorAssignmentMemberOperator
534+
)
535+
}
536+
537+
private predicate convertsIntoArgumentFwd(Instruction instr) {
538+
isSource(instr, _, _)
539+
or
540+
exists(Instruction prev | convertsIntoArgumentFwd(prev) |
541+
conversionFlow(unique( | | getAUse(prev)), instr, false, _)
542+
)
543+
}
544+
545+
private predicate convertsIntoArgumentRev(Instruction instr) {
546+
convertsIntoArgumentFwd(instr) and
547+
(
548+
isSink(instr, _)
549+
or
550+
exists(Instruction next | convertsIntoArgumentRev(next) |
551+
conversionFlow(unique( | | getAUse(instr)), next, false, _)
552+
)
553+
)
554+
}
555+
556+
private predicate convertsIntoArgument(
557+
Operand iteratorAddress, CallInstruction call, int numberOfLoads
558+
) {
559+
exists(Instruction iteratorAddressDef |
560+
isSource(iteratorAddressDef, iteratorAddress, numberOfLoads) and
561+
isSink(iteratorAddressDef, call) and
562+
convertsIntoArgumentRev(pragma[only_bind_into](iteratorAddressDef))
563+
)
564+
}
565+
566+
private predicate isChiAfterIteratorArgument(
567+
Instruction memory, Operand iteratorAddress, int numberOfLoads
568+
) {
569+
// Ideally, `iteratorAddress` would be an `ArgumentOperand`, but there might be
570+
// various conversions applied to it before it becomes an argument.
571+
// So we do a small amount of flow to find the call that the iterator is passed to.
572+
exists(CallInstruction call | convertsIntoArgument(iteratorAddress, call, numberOfLoads) |
573+
exists(ReadSideEffectInstruction read |
574+
read.getPrimaryInstruction() = call and
575+
read.getSideEffectOperand().getAnyDef() = memory
576+
)
577+
or
578+
exists(LoadInstruction load |
579+
iteratorAddress.getDef() = load and
580+
memory = load.getSourceValueOperand().getAnyDef()
581+
)
582+
)
583+
}
584+
507585
/**
508586
* Holds if `iterator` is a `StoreInstruction` that stores the result of some function
509587
* returning an iterator into an address computed started at `containerBase`.
@@ -524,21 +602,22 @@ private module Cached {
524602
}
525603

526604
/**
527-
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
528-
* that is used for a read operation. The `memory` instruction represents the memory that
605+
* Holds if `iteratorAddress` is an address of an iterator that is used for
606+
* a read operation. The `memory` instruction represents the memory that
529607
* the IR's SSA analysis determined was read by the call to `operator*`.
530608
*
531-
* Finally, the `numberOfLoads` integer represents the number of dereferences this read
532-
* corresponds to on the underlying container that produced the iterator.
609+
* Finally, the `numberOfLoads` integer represents the number of dereferences
610+
* this read corresponds to on the underlying container that produced the iterator.
533611
*/
534612
private predicate isChiBeforeIteratorUse(
535-
Operand iteratorDerefAddress, Instruction memory, int numberOfLoads
613+
Operand iteratorAddress, Instruction memory, int numberOfLoads
536614
) {
537615
exists(
538616
BaseSourceVariableInstruction iteratorBase, LoadInstruction load,
539-
ReadSideEffectInstruction read
617+
ReadSideEffectInstruction read, Operand iteratorDerefAddress
540618
|
541619
numberOfLoads >= 0 and
620+
isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
542621
isUse(_, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
543622
iteratorBase.getResultType() instanceof Interfaces::Iterator and
544623
load.getSourceAddressOperand() = iteratorDerefAddress and
@@ -569,24 +648,35 @@ private module Cached {
569648
}
570649

571650
/**
572-
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
573-
* that is used for a read operation to read a value from a container that created the iterator.
574-
* `container` represents the base of the address of the container that was used to create
575-
* the iterator.
651+
* Holds if `iteratorAddress` is an address of an iterator that is used for a
652+
* read operation to read a value from a container that created the iterator.
653+
* `container` represents the base of the address of the container that was used
654+
* to create the iterator.
576655
*/
577656
cached
578657
predicate isIteratorUse(
579-
BaseSourceVariableInstruction container, Operand iteratorDerefAddress, int numberOfLoads,
658+
BaseSourceVariableInstruction container, Operand iteratorAddress, int numberOfLoads,
580659
int indirectionIndex
581660
) {
661+
// Direct use
582662
exists(Instruction begin, Instruction memory, int upper, int ind |
583-
isChiBeforeIteratorUse(iteratorDerefAddress, memory, numberOfLoads) and
663+
isChiBeforeIteratorUse(iteratorAddress, memory, numberOfLoads) and
584664
memorySucc*(begin, memory) and
585665
isChiAfterBegin(container, begin) and
586666
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
587667
ind = numberOfLoads + [1 .. upper] and
588668
indirectionIndex = ind - (numberOfLoads + 1)
589669
)
670+
or
671+
// Use through function output
672+
exists(Instruction memory, Instruction begin, int upper, int ind |
673+
isChiAfterIteratorArgument(memory, iteratorAddress, numberOfLoads) and
674+
memorySucc*(begin, memory) and
675+
isChiAfterBegin(container, begin) and
676+
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
677+
ind = numberOfLoads + [1 .. upper] and
678+
indirectionIndex = ind - (numberOfLoads - 1)
679+
)
590680
}
591681

592682
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */

cpp/ql/test/experimental/query-tests/Security/CWE/CWE-359/semmle/tests/PrivateCleartextWrite.expected

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ edges
33
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode |
44
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode |
55
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode |
6+
| test.cpp:74:24:74:30 | medical | test.cpp:74:11:74:15 | buff1 |
7+
| test.cpp:74:24:74:30 | medical | test.cpp:78:11:78:15 | buff2 |
68
| test.cpp:74:24:74:30 | medical | test.cpp:78:24:78:27 | temp |
79
| test.cpp:74:24:74:30 | medical | test.cpp:81:22:81:28 | medical |
10+
| test.cpp:77:16:77:22 | medical | test.cpp:78:11:78:15 | buff2 |
811
| test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp |
912
| test.cpp:77:16:77:22 | medical | test.cpp:81:22:81:28 | medical |
13+
| test.cpp:81:17:81:20 | call to func | test.cpp:82:11:82:15 | buff3 |
1014
| test.cpp:81:17:81:20 | call to func | test.cpp:82:24:82:28 | buff5 |
1115
| test.cpp:81:22:81:28 | medical | test.cpp:45:18:45:23 | buffer |
1216
| test.cpp:81:22:81:28 | medical | test.cpp:81:17:81:20 | call to func |
@@ -31,12 +35,15 @@ nodes
3135
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
3236
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
3337
| test.cpp:57:9:57:18 | theZipcode | semmle.label | theZipcode |
38+
| test.cpp:74:11:74:15 | buff1 | semmle.label | buff1 |
3439
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
3540
| test.cpp:74:24:74:30 | medical | semmle.label | medical |
3641
| test.cpp:77:16:77:22 | medical | semmle.label | medical |
42+
| test.cpp:78:11:78:15 | buff2 | semmle.label | buff2 |
3743
| test.cpp:78:24:78:27 | temp | semmle.label | temp |
3844
| test.cpp:81:17:81:20 | call to func | semmle.label | call to func |
3945
| test.cpp:81:22:81:28 | medical | semmle.label | medical |
46+
| test.cpp:82:11:82:15 | buff3 | semmle.label | buff3 |
4047
| test.cpp:82:24:82:28 | buff5 | semmle.label | buff5 |
4148
| test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode |
4249
| test.cpp:96:37:96:46 | theZipcode | semmle.label | theZipcode |
@@ -54,9 +61,15 @@ subpaths
5461
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@. | test.cpp:57:9:57:18 | theZipcode | this source of private data. |
5562
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@. | test.cpp:57:9:57:18 | theZipcode | this source of private data. |
5663
| test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | test.cpp:57:9:57:18 | theZipcode | This write into the external location 'theZipcode' may contain unencrypted data from $@. | test.cpp:57:9:57:18 | theZipcode | this source of private data. |
64+
| test.cpp:74:11:74:15 | buff1 | test.cpp:74:24:74:30 | medical | test.cpp:74:11:74:15 | buff1 | This write into the external location 'buff1' may contain unencrypted data from $@. | test.cpp:74:24:74:30 | medical | this source of private data. |
5765
| test.cpp:74:24:74:30 | medical | test.cpp:74:24:74:30 | medical | test.cpp:74:24:74:30 | medical | This write into the external location 'medical' may contain unencrypted data from $@. | test.cpp:74:24:74:30 | medical | this source of private data. |
66+
| test.cpp:78:11:78:15 | buff2 | test.cpp:74:24:74:30 | medical | test.cpp:78:11:78:15 | buff2 | This write into the external location 'buff2' may contain unencrypted data from $@. | test.cpp:74:24:74:30 | medical | this source of private data. |
67+
| test.cpp:78:11:78:15 | buff2 | test.cpp:77:16:77:22 | medical | test.cpp:78:11:78:15 | buff2 | This write into the external location 'buff2' may contain unencrypted data from $@. | test.cpp:77:16:77:22 | medical | this source of private data. |
5868
| test.cpp:78:24:78:27 | temp | test.cpp:74:24:74:30 | medical | test.cpp:78:24:78:27 | temp | This write into the external location 'temp' may contain unencrypted data from $@. | test.cpp:74:24:74:30 | medical | this source of private data. |
5969
| test.cpp:78:24:78:27 | temp | test.cpp:77:16:77:22 | medical | test.cpp:78:24:78:27 | temp | This write into the external location 'temp' may contain unencrypted data from $@. | test.cpp:77:16:77:22 | medical | this source of private data. |
70+
| test.cpp:82:11:82:15 | buff3 | test.cpp:74:24:74:30 | medical | test.cpp:82:11:82:15 | buff3 | This write into the external location 'buff3' may contain unencrypted data from $@. | test.cpp:74:24:74:30 | medical | this source of private data. |
71+
| test.cpp:82:11:82:15 | buff3 | test.cpp:77:16:77:22 | medical | test.cpp:82:11:82:15 | buff3 | This write into the external location 'buff3' may contain unencrypted data from $@. | test.cpp:77:16:77:22 | medical | this source of private data. |
72+
| test.cpp:82:11:82:15 | buff3 | test.cpp:81:22:81:28 | medical | test.cpp:82:11:82:15 | buff3 | This write into the external location 'buff3' may contain unencrypted data from $@. | test.cpp:81:22:81:28 | medical | this source of private data. |
6073
| test.cpp:82:24:82:28 | buff5 | test.cpp:74:24:74:30 | medical | test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@. | test.cpp:74:24:74:30 | medical | this source of private data. |
6174
| test.cpp:82:24:82:28 | buff5 | test.cpp:77:16:77:22 | medical | test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@. | test.cpp:77:16:77:22 | medical | this source of private data. |
6275
| test.cpp:82:24:82:28 | buff5 | test.cpp:81:22:81:28 | medical | test.cpp:82:24:82:28 | buff5 | This write into the external location 'buff5' may contain unencrypted data from $@. | test.cpp:81:22:81:28 | medical | this source of private data. |

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8090,20 +8090,20 @@
80908090
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:523:8:523:9 | vs | |
80918091
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:524:8:524:9 | vs | |
80928092
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:526:8:526:9 | vs | |
8093-
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:532:8:532:9 | vs | |
8094-
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:533:2:533:2 | vs | |
8093+
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:539:8:539:9 | vs | |
8094+
| vector.cpp:520:25:520:31 | call to vector | vector.cpp:540:2:540:2 | vs | |
80958095
| vector.cpp:520:30:520:30 | 0 | vector.cpp:520:25:520:31 | call to vector | TAINT |
80968096
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:524:8:524:9 | vs | |
80978097
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
8098-
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
8099-
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
8098+
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
8099+
| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
81008100
| vector.cpp:523:8:523:9 | vs | vector.cpp:523:10:523:10 | call to operator[] | TAINT |
81018101
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | |
8102-
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
8103-
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
8102+
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
8103+
| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
81048104
| vector.cpp:524:8:524:9 | vs | vector.cpp:524:10:524:10 | call to operator[] | TAINT |
8105-
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | |
8106-
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
8105+
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:539:8:539:9 | vs | |
8106+
| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
81078107
| vector.cpp:526:8:526:9 | vs | vector.cpp:526:11:526:15 | call to begin | TAINT |
81088108
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:526:3:526:17 | ... = ... | |
81098109
| vector.cpp:526:11:526:15 | call to begin | vector.cpp:527:9:527:10 | it | |
@@ -8128,5 +8128,5 @@
81288128
| vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | |
81298129
| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:3:530:4 | ref arg it | TAINT |
81308130
| vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT |
8131-
| vector.cpp:532:8:532:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | |
8132-
| vector.cpp:532:8:532:9 | vs | vector.cpp:532:10:532:10 | call to operator[] | TAINT |
8131+
| vector.cpp:539:8:539:9 | ref arg vs | vector.cpp:540:2:540:2 | vs | |
8132+
| vector.cpp:539:8:539:9 | vs | vector.cpp:539:10:539:10 | call to operator[] | TAINT |

cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ void test_vector_output_iterator(int b) {
354354
for(std::vector<int>::iterator it = v4.begin(); it != v4.end(); ++it) {
355355
taint_vector_output_iterator(it);
356356
}
357-
sink(v4); // $ ast MISSING: ir
357+
sink(v4); // $ ast,ir
358358

359359
std::vector<int>::iterator i5 = v5.begin();
360360
*i5 = source();
@@ -389,15 +389,15 @@ void test_vector_output_iterator(int b) {
389389
*i9 = source();
390390
taint_vector_output_iterator(i9);
391391

392-
sink(v9); // $ ast=330:10 ir SPURIOUS: ast=389:8
392+
sink(v9); // $ ast=330:10 ir=330:10 SPURIOUS: ast=389:8 ir=389:8
393393

394394
std::vector<int>::iterator i10 = v10.begin();
395395
vector_iterator_assign_wrapper(i10, 10);
396396
sink(v10);
397397

398398
std::vector<int>::iterator i11 = v11.begin();
399399
vector_iterator_assign_wrapper(i11, source());
400-
sink(v11); // $ ast MISSING: ir
400+
sink(v11); // $ ast,ir
401401

402402
std::vector<int>::iterator i12 = v12.begin();
403403
*i12++ = 0;
@@ -523,12 +523,19 @@ void test_vector_iterator() {
523523
sink(vs[1]);
524524
sink(vs[source()]); // $ MISSING: ast,ir
525525

526-
it = vs.begin();
526+
it = vs.begin(); // (1)
527527
sink(*it);
528528
it += 1;
529529
sink(*it);
530-
it += source();
531-
sink(*it); // $ ast,ir
532-
sink(vs[1]);
530+
it += source(); // (2)
531+
sink(*it); // $ ast,ir // (3)
532+
// This FP happens because of the following flows:
533+
// 1. There's a write to the iterator at (2)
534+
// 2. This write propagates to `it` on the next line at (3)
535+
// 3. There's a taint step from `it` to `*it` at (3)
536+
// 4. The `*it` is seen as a use of `vs` because of (1).
537+
// 5. There's use-use flow from `*it` at (3) (which is a use of `vs`) to `vs` at (4)
538+
// 6. There's a taint step from vs to vs[1]
539+
sink(vs[1]); // $ SPURIOUS: ir // (4)
533540
}
534541
}

0 commit comments

Comments
 (0)