Skip to content

Commit 1898d46

Browse files
committed
C++: Add reverse read and more field flow
1 parent eaec7cd commit 1898d46

File tree

1 file changed

+226
-41
lines changed

1 file changed

+226
-41
lines changed

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

Lines changed: 226 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ private import semmle.code.cpp.models.interfaces.DataFlow
1313

1414
private newtype TIRDataFlowNode =
1515
TInstructionNode(Instruction i) or
16-
TVariableNode(Variable var)
16+
TVariableNode(Variable var) or
17+
TSynthesizedStoreNode(StoreChain chain) or
18+
TSynthesizedLoadNode(LoadChain load)
1719

1820
/**
1921
* A node in a data flow graph.
@@ -71,9 +73,7 @@ class Node extends TIRDataFlowNode {
7173
* `x.set(taint())` is a partial definition of `x`, and `transfer(&x, taint())` is
7274
* a partial definition of `&x`).
7375
*/
74-
Expr asPartialDefinition() {
75-
result = this.(PartialDefinitionNode).getInstruction().getUnconvertedResultExpression()
76-
}
76+
Expr asPartialDefinition() { result = this.(PartialDefinitionNode).getDefiningExpr() }
7777

7878
/**
7979
* DEPRECATED: See UninitializedNode.
@@ -231,7 +231,7 @@ deprecated class UninitializedNode extends Node {
231231
* This class exists to match the interface used by Java. There are currently no non-abstract
232232
* classes that extend it. When we implement field flow, we can revisit this.
233233
*/
234-
abstract class PostUpdateNode extends InstructionNode {
234+
abstract class PostUpdateNode extends Node {
235235
/**
236236
* Gets the node before the state update.
237237
*/
@@ -251,42 +251,8 @@ abstract class PostUpdateNode extends InstructionNode {
251251
* setY(&x); // a partial definition of the object `x`.
252252
* ```
253253
*/
254-
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode { }
255-
256-
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
257-
override ChiInstruction instr;
258-
259-
ExplicitFieldStoreQualifierNode() {
260-
not instr.isResultConflated() and
261-
exists(StoreInstruction store, FieldInstruction field |
262-
instr.getPartial() = store and field = store.getDestinationAddress()
263-
)
264-
}
265-
266-
// There might be multiple `ChiInstructions` that has a particular instruction as
267-
// the total operand - so this definition gives consistency errors in
268-
// DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications
269-
// this consistency failure has.
270-
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
271-
}
272-
273-
/**
274-
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
275-
* For instance, an update to a field of a struct containing only one field. For these cases we
276-
* attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case
277-
* (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`.
278-
*/
279-
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
280-
override StoreInstruction instr;
281-
282-
ExplicitSingleFieldStoreQualifierNode() {
283-
exists(FieldAddressInstruction field |
284-
field = instr.getDestinationAddress() and
285-
not exists(ChiInstruction chi | chi.getPartial() = instr)
286-
)
287-
}
288-
289-
override Node getPreUpdateNode() { none() }
254+
abstract private class PartialDefinitionNode extends PostUpdateNode {
255+
abstract Expr getDefiningExpr();
290256
}
291257

292258
/**
@@ -368,18 +334,225 @@ class VariableNode extends Node, TVariableNode {
368334
override string toString() { result = v.toString() }
369335
}
370336

337+
/** The target node of a `readStep`. */
371338
abstract class ReadStepNode extends Node {
339+
/** Get the field that is read. */
372340
abstract Field getAField();
373341

342+
/** Get the node representing the value that is read. */
374343
abstract Node getReadValue();
375344
}
376345

346+
/** The target node of a `storeStep`. */
377347
abstract class StoreStepNode extends PostUpdateNode {
348+
/** Get the field that is stored into. */
378349
abstract Field getAField();
379350

351+
/** Get the node representing the value that is stored. */
380352
abstract Node getStoredValue();
381353
}
382354

355+
private newtype TStoreChain =
356+
TStore(FieldInstruction f, StoreInstruction store, ChiInstruction chi) {
357+
not chi.isResultConflated() and
358+
chi.getPartial() = store and
359+
store.getDestinationAddress() = f
360+
} or
361+
TStoreCons(FieldInstruction f, TStoreChain next) {
362+
next = TStoreCons(f.getAUse().getUse(), _) or
363+
next = TStore(f.getAUse().getUse(), _, _)
364+
}
365+
366+
private class StoreChain extends TStoreChain {
367+
string toString() { none() }
368+
369+
StoreChainCons getParent() { none() }
370+
371+
StoreChain getChild() { none() }
372+
373+
StoreInstruction getStoreInstruction() { none() }
374+
375+
ChiInstruction getChiInstruction() { none() }
376+
377+
FieldInstruction getFieldInstruction() { none() }
378+
}
379+
380+
private class StoreChainNil extends StoreChain, TStore {
381+
FieldInstruction f;
382+
StoreInstruction store;
383+
ChiInstruction chi;
384+
385+
StoreChainNil() { this = TStore(f, store, chi) }
386+
387+
override string toString() { result = f.getField().toString() }
388+
389+
override StoreChainCons getParent() { result = TStoreCons(_, this) }
390+
391+
override StoreInstruction getStoreInstruction() { result = store }
392+
393+
override ChiInstruction getChiInstruction() { result = chi }
394+
395+
override FieldInstruction getFieldInstruction() { result = f }
396+
}
397+
398+
private class StoreChainCons extends StoreChain, TStoreCons {
399+
FieldInstruction f;
400+
StoreChain next;
401+
402+
StoreChainCons() { this = TStoreCons(f, next) }
403+
404+
override string toString() { result = f.getField().toString() + "." + next.toString() }
405+
406+
override StoreChainCons getParent() { result.getChild() = this }
407+
408+
override StoreChain getChild() { result = next }
409+
410+
override FieldInstruction getFieldInstruction() { result = f }
411+
412+
override StoreInstruction getStoreInstruction() { result = next.getStoreInstruction() }
413+
414+
override ChiInstruction getChiInstruction() { result = next.getChiInstruction() }
415+
}
416+
417+
private Instruction getAUse(FieldAddressInstruction fa) { result = fa.getAUse().getUse() }
418+
419+
private newtype TLoadChain =
420+
TLoad(FieldAddressInstruction f) {
421+
not f.getObjectAddress() instanceof FieldInstruction and getAUse*(f) instanceof LoadInstruction
422+
} or
423+
TLoadChainCons(FieldAddressInstruction f, TLoadChain prev) {
424+
prev = TLoadChainCons(f.getObjectAddress(), _) or
425+
prev = TLoad(f.getObjectAddress())
426+
}
427+
428+
private class LoadChain extends TLoadChain {
429+
string toString() { none() }
430+
431+
LoadInstruction getLoadInstruction() { none() }
432+
433+
LoadChainCons getParent() { none() }
434+
435+
LoadChain getChild() { none() }
436+
437+
FieldInstruction getFieldInstruction() { none() }
438+
}
439+
440+
private class LoadNil extends LoadChain, TLoad {
441+
FieldInstruction f;
442+
443+
LoadNil() { this = TLoad(f) }
444+
445+
override string toString() { result = f.getField().toString() }
446+
447+
override LoadChainCons getParent() { result = TLoadChainCons(_, this) }
448+
449+
override LoadInstruction getLoadInstruction() {
450+
result.getSourceAddressOperand().getAnyDef() = f
451+
or
452+
result = getParent().getLoadInstruction()
453+
}
454+
455+
override FieldInstruction getFieldInstruction() { result = f }
456+
}
457+
458+
private class LoadChainCons extends LoadChain, TLoadChainCons {
459+
FieldInstruction f;
460+
LoadChain prev;
461+
462+
LoadChainCons() { this = TLoadChainCons(f, prev) }
463+
464+
override string toString() { result = prev.toString() + "." + f.getField().toString() }
465+
466+
override LoadInstruction getLoadInstruction() {
467+
result.getSourceAddressOperand().getAnyDef() = f
468+
or
469+
result = getParent().getLoadInstruction()
470+
}
471+
472+
override LoadChainCons getParent() { result.getChild() = this }
473+
474+
override LoadChain getChild() { result = prev }
475+
476+
override FieldInstruction getFieldInstruction() { result = f }
477+
}
478+
479+
private class SynthesizedStoreNode extends TSynthesizedStoreNode, StoreStepNode, ReadStepNode,
480+
PartialDefinitionNode {
481+
StoreChain storeChain;
482+
483+
SynthesizedStoreNode() { this = TSynthesizedStoreNode(storeChain) }
484+
485+
override string toString() { result = "[" + storeChain.toString() + "] (store)" }
486+
487+
StoreChain getStoreChain() { result = storeChain }
488+
489+
ChiInstruction getChiInstruction() { result = storeChain.getChiInstruction() }
490+
491+
StoreInstruction getStoreInstruction() { result = storeChain.getStoreInstruction() }
492+
493+
override Node getPreUpdateNode() {
494+
result.(SynthesizedStoreNode).getStoreChain() = storeChain.getParent()
495+
or
496+
not exists(storeChain.getParent()) and
497+
result.asInstruction() = this.getChiInstruction().getTotal()
498+
}
499+
500+
override Field getAField() { result = storeChain.getFieldInstruction().getField() }
501+
502+
override Node getStoredValue() {
503+
// Only the "end" of the chain stores a value (i.e., can be the target of a store step)
504+
not exists(storeChain.getChild()) and result.asInstruction() = this.getStoreInstruction()
505+
}
506+
507+
override Node getReadValue() {
508+
result.(SynthesizedStoreNode).getStoreChain() = storeChain.getParent()
509+
or
510+
not exists(storeChain.getParent()) and
511+
result.asInstruction() = this.getChiInstruction().getTotal()
512+
}
513+
514+
override Declaration getEnclosingCallable() { result = this.getFunction() }
515+
516+
override Function getFunction() { result = this.getStoreInstruction().getEnclosingFunction() }
517+
518+
override Type getType() { result = this.getStoreInstruction().getResultType() }
519+
520+
override Location getLocation() { result = this.getStoreInstruction().getLocation() }
521+
522+
override Expr getDefiningExpr() {
523+
result = this.getStoreInstruction().getSourceValue().getUnconvertedResultExpression()
524+
}
525+
}
526+
527+
private class SynthesizedLoadNode extends TSynthesizedLoadNode, ReadStepNode {
528+
LoadChain loadChain;
529+
530+
SynthesizedLoadNode() { this = TSynthesizedLoadNode(loadChain) }
531+
532+
override Field getAField() { result = loadChain.getFieldInstruction().getField() }
533+
534+
override Node getReadValue() {
535+
result.(SynthesizedLoadNode).getLoadChain() = loadChain.getChild()
536+
or
537+
not exists(loadChain.getChild()) and
538+
result.asInstruction() = this.getLoadInstruction().getSourceValueOperand().getAnyDef()
539+
}
540+
541+
LoadChain getLoadChain() { result = loadChain }
542+
543+
LoadInstruction getLoadInstruction() { result = loadChain.getLoadInstruction() }
544+
545+
override string toString() { result = "[" + loadChain.toString() + "] (load)" }
546+
547+
override Declaration getEnclosingCallable() { result = this.getFunction() }
548+
549+
override Function getFunction() { result = this.getLoadInstruction().getEnclosingFunction() }
550+
551+
override Type getType() { result = this.getLoadInstruction().getResultType() }
552+
553+
override Location getLocation() { result = this.getLoadInstruction().getLocation() }
554+
}
555+
383556
/**
384557
* Gets the node corresponding to `instr`.
385558
*/
@@ -433,6 +606,18 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
433606
*/
434607
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
435608
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
609+
or
610+
exists(SynthesizedStoreNode synthFrom |
611+
synthFrom = nodeFrom and
612+
not exists(synthFrom.getStoreChain().getParent()) and
613+
synthFrom.getChiInstruction() = nodeTo.asInstruction()
614+
)
615+
or
616+
exists(SynthesizedLoadNode synthFrom |
617+
synthFrom = nodeFrom and
618+
not exists(synthFrom.getLoadChain().getParent()) and
619+
synthFrom.getLoadInstruction() = nodeTo.asInstruction()
620+
)
436621
}
437622

438623
pragma[noinline]

0 commit comments

Comments
 (0)