Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d417d7

Browse files
committed
C++: Implement an 'Indirection' subtype for iterators.
1 parent ef110e7 commit 5d417d7

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

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

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,93 @@ private class PointerOrReferenceTypeIndirection extends Indirection instanceof P
188188
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) { none() }
189189
}
190190

191+
private module IteratorIndirections {
192+
import semmle.code.cpp.models.interfaces.Iterator as Interfaces
193+
import semmle.code.cpp.models.implementations.Iterator as Iterator
194+
import semmle.code.cpp.models.implementations.StdContainer as StdContainer
195+
196+
class IteratorIndirection extends Indirection instanceof Interfaces::Iterator {
197+
IteratorIndirection() {
198+
not this instanceof PointerOrReferenceTypeIndirection and baseType = super.getValueType()
199+
}
200+
201+
override int getNumberOfIndirections() { result = 1 + countIndirections(this.getBaseType()) }
202+
203+
override predicate isAdditionalDereference(Instruction deref, Operand address) {
204+
exists(CallInstruction call |
205+
operandForfullyConvertedCall(deref.getAUse(), call) and
206+
this = call.getStaticCallTarget().getClassAndName("operator*") and
207+
address = call.getThisArgumentOperand()
208+
)
209+
}
210+
211+
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
212+
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
213+
this = call.getStaticCallTarget().getClassAndName("operator=") and
214+
address = call.getThisArgumentOperand() and
215+
certain = false
216+
)
217+
}
218+
219+
override predicate isAdditionalTaintStep(Node node1, Node node2) {
220+
exists(CallInstruction call |
221+
// Taint through `operator+=` and `operator-=` on iterators.
222+
call.getStaticCallTarget() instanceof Iterator::IteratorAssignArithmeticOperator and
223+
node2.(IndirectArgumentOutNode).getPreUpdateNode() = node1 and
224+
node1.(IndirectOperand).getOperand() = call.getArgumentOperand(0) and
225+
node1.getType().getUnspecifiedType() = this
226+
)
227+
}
228+
229+
override predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
230+
// This is a bit annoying: Consider the following snippet:
231+
// ```
232+
// struct MyIterator {
233+
// ...
234+
// insert_iterator_by_trait operator*();
235+
// insert_iterator_by_trait operator=(int x);
236+
// };
237+
// ...
238+
// MyIterator it;
239+
// ...
240+
// *it = source();
241+
// ```
242+
// The qualifier to `operator*` will undergo prvalue-to-xvalue conversion and a
243+
// temporary object will be created. Thus, the IR for the call to `operator=` will
244+
// look like (simplified):
245+
// ```
246+
// r1(glval<MyIterator>) = VariableAddress[it] :
247+
// r2(glval<unknown>) = FunctionAddress[operator*] :
248+
// r3(MyIterator) = Call[operator*] : func:r2, this:r1
249+
// r4(glval<MyIterator>) = VariableAddress[#temp] :
250+
// m1(MyIterator) = Store[#temp] : &:r4, r3
251+
// r5(glval<unknown>) = FunctionAddress[operator=] :
252+
// r6(glval<unknown>) = FunctionAddress[source] :
253+
// r7(int) = Call[source] : func:r6
254+
// r8(MyIterator) = Call[operator=] : func:r5, this:r4, 0:r7
255+
// ```
256+
// in order to properly recognize that the qualifier to the call to `operator=` accesses
257+
// `it` we look for the store that writes to the temporary object, and use the source value
258+
// of that store as the "address" to continue searching for the base variable `it`.
259+
exists(StoreInstruction store, VariableInstruction var |
260+
var = instrTo and
261+
var.getIRVariable() instanceof IRTempVariable and
262+
opFrom.getType() = this and
263+
store.getSourceValueOperand() = opFrom and
264+
store.getDestinationAddress() = var
265+
)
266+
or
267+
// A call to `operator++` or `operator--` is the iterator equivalent version of a
268+
// pointer arithmetic instruction.
269+
exists(CallInstruction call |
270+
instrTo = call and
271+
call.getStaticCallTarget() instanceof Iterator::IteratorCrementMemberOperator and
272+
opFrom = call.getThisArgumentOperand()
273+
)
274+
}
275+
}
276+
}
277+
191278
predicate isDereference(Instruction deref, Operand address) {
192279
any(Indirection ind).isAdditionalDereference(deref, address)
193280
or

0 commit comments

Comments
 (0)