Skip to content

Commit 470ee00

Browse files
committed
C++: Alternate dataflow between operands and instructions
1 parent d7a9d3d commit 470ee00

2 files changed

Lines changed: 32 additions & 27 deletions

File tree

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -186,18 +186,19 @@ private class ArrayContent extends Content, TArrayContent {
186186

187187
private predicate storeStepNoChi(Node node1, Content f, PostUpdateNode node2) {
188188
exists(FieldAddressInstruction fa, StoreInstruction store |
189-
store = node2.asInstruction() and
189+
node2.asInstruction() = store and
190+
node1.asOperand() = store.getSourceValueOperand() and
190191
store.getDestinationAddress() = fa and
191-
store.getSourceValue() = node1.asInstruction() and
192192
f.(FieldContent).getField() = fa.getField()
193193
)
194194
}
195195

196196
private predicate storeStepChi(Node node1, Content f, PostUpdateNode node2) {
197-
exists(FieldAddressInstruction fa, StoreInstruction store |
198-
node1.asInstruction() = store and
197+
exists(FieldAddressInstruction fa, ChiInstruction chi, StoreInstruction store |
198+
node2.asInstruction() = chi and
199+
node1.asOperand() = chi.getPartialOperand() and
200+
chi.getPartial() = store and
199201
store.getDestinationAddress() = fa and
200-
node2.asInstruction().(ChiInstruction).getPartial() = store and
201202
f.(FieldContent).getField() = fa.getField()
202203
)
203204
}
@@ -219,10 +220,10 @@ predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
219220
*/
220221
predicate readStep(Node node1, Content f, Node node2) {
221222
exists(FieldAddressInstruction fa, LoadInstruction load |
223+
node2.asInstruction() = load and
224+
node1.asOperand() = load.getSourceValueOperand() and
222225
load.getSourceAddress() = fa and
223-
node1.asInstruction() = load.getSourceValueOperand().getAnyDef() and
224-
fa.getField() = f.(FieldContent).getField() and
225-
load = node2.asInstruction()
226+
fa.getField() = f.(FieldContent).getField()
226227
)
227228
}
228229

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,10 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
508508
* data flow. It may have less flow than the `localFlowStep` predicate.
509509
*/
510510
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
511-
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
511+
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
512+
or
513+
// Flow from an instruction to its operands
514+
nodeTo.asOperand().getAnyDef() = nodeFrom.asInstruction()
512515
}
513516

514517
pragma[noinline]
@@ -521,15 +524,15 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) {
521524
}
522525

523526
cached
524-
private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) {
525-
iTo.(CopyInstruction).getSourceValue() = iFrom
527+
private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) {
528+
iTo.(CopyInstruction).getSourceValue() = opFrom.getDef()
526529
or
527-
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom
530+
iTo.(PhiInstruction).getAnInput() = opFrom.getDef()
528531
or
529532
// A read side effect is almost never exact since we don't know exactly how
530533
// much memory the callee will read.
531-
iTo.(ReadSideEffectInstruction).getSideEffectOperand().getAnyDef() = iFrom and
532-
not iFrom.isResultConflated()
534+
iTo.(ReadSideEffectInstruction).getSideEffectOperand() = opFrom and
535+
not opFrom.getAnyDef().isResultConflated()
533536
or
534537
// Loading a single `int` from an `int *` parameter is not an exact load since
535538
// the parameter may point to an entire array rather than a single `int`. The
@@ -542,7 +545,7 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
542545
// reassignment of the parameter indirection, including a conditional one that
543546
// leads to a phi node.
544547
exists(InitializeIndirectionInstruction init |
545-
iFrom = init and
548+
opFrom.getAnyDef() = init and
546549
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = init and
547550
// Check that the types match. Otherwise we can get flow from an object to
548551
// its fields, which leads to field conflation when there's flow from other
@@ -552,11 +555,11 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
552555
)
553556
or
554557
// Treat all conversions as flow, even conversions between different numeric types.
555-
iTo.(ConvertInstruction).getUnary() = iFrom
558+
iTo.(ConvertInstruction).getUnary() = opFrom.getDef()
556559
or
557-
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom
560+
iTo.(CheckedConvertOrNullInstruction).getUnary() = opFrom.getDef()
558561
or
559-
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
562+
iTo.(InheritanceConversionInstruction).getUnary() = opFrom.getDef()
560563
or
561564
// A chi instruction represents a point where a new value (the _partial_
562565
// operand) may overwrite an old value (the _total_ operand), but the alias
@@ -569,7 +572,7 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
569572
//
570573
// Flow through the partial operand belongs in the taint-tracking libraries
571574
// for now.
572-
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
575+
iTo.getAnOperand().(ChiTotalOperand) = opFrom
573576
or
574577
// Add flow from write side-effects to non-conflated chi instructions through their
575578
// partial operands. From there, a `readStep` will find subsequent reads of that field.
@@ -584,24 +587,25 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
584587
// Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to
585588
// `setX`, which will be melded into `p` through a chi instruction.
586589
exists(ChiInstruction chi | chi = iTo |
587-
chi.getPartialOperand().getDef() = iFrom.(WriteSideEffectInstruction) and
590+
opFrom.getAnyDef() instanceof WriteSideEffectInstruction and
591+
chi.getPartialOperand() = opFrom and
588592
not chi.isResultConflated()
589593
)
590594
or
591595
// Flow from stores to structs with a single field to a load of that field.
592-
iTo.(LoadInstruction).getSourceValueOperand().getAnyDef() = iFrom and
596+
iTo.(LoadInstruction).getSourceValueOperand() = opFrom and
593597
exists(int size, Type type, Class cTo |
594-
type = iFrom.getResultType() and
598+
type = opFrom.getAnyDef().getResultType() and
595599
cTo = iTo.getResultType() and
596600
cTo.getSize() = size and
597601
getFieldSizeOfClass(cTo, type, size)
598602
)
599603
or
600604
// Flow through modeled functions
601-
modelFlow(iFrom, iTo)
605+
modelFlow(opFrom, iTo)
602606
}
603607

604-
private predicate modelFlow(Instruction iFrom, Instruction iTo) {
608+
private predicate modelFlow(Operand opFrom, Instruction iTo) {
605609
exists(
606610
CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut
607611
|
@@ -626,17 +630,17 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) {
626630
(
627631
exists(int index |
628632
modelIn.isParameter(index) and
629-
iFrom = call.getPositionalArgument(index)
633+
opFrom = call.getPositionalArgumentOperand(index)
630634
)
631635
or
632636
exists(int index, ReadSideEffectInstruction read |
633637
modelIn.isParameterDeref(index) and
634638
read = getSideEffectFor(call, index) and
635-
iFrom = read.getSideEffectOperand().getAnyDef()
639+
opFrom = read.getSideEffectOperand()
636640
)
637641
or
638642
modelIn.isQualifierAddress() and
639-
iFrom = call.getThisArgument()
643+
opFrom = call.getThisArgumentOperand()
640644
// TODO: add read side effects for qualifiers
641645
)
642646
)

0 commit comments

Comments
 (0)