Skip to content

Commit 445cca1

Browse files
committed
C++: Proper SSA support for post-crement reads.
1 parent db3f22a commit 445cca1

File tree

1 file changed

+209
-14
lines changed
  • cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal

1 file changed

+209
-14
lines changed

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

Lines changed: 209 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,79 @@ private import DataFlowPrivate
1515
import SsaImplCommon
1616

1717
private module SourceVariables {
18+
/**
19+
* Holds if `store` is the `StoreInstruction` generated by an postfix
20+
* increment or decrement operation `e`, and `postCrement` is the operand
21+
* that represents the use of the evaluated value of `e`.
22+
*/
23+
private predicate isUseAfterPostfixCrement0(StoreInstruction store, Operand postCrement) {
24+
exists(
25+
BinaryInstruction binary, IRBlock b, int iPre, int iPost, int iStore, Operand preCrement,
26+
Instruction left
27+
|
28+
binary instanceof AddInstruction
29+
or
30+
binary instanceof PointerAddInstruction
31+
or
32+
binary instanceof SubInstruction
33+
or
34+
binary instanceof PointerSubInstruction
35+
|
36+
store.getSourceValue() = binary and
37+
left = binary.getLeft() and
38+
strictcount(left.getAUse()) = 2 and
39+
left.getAUse() = preCrement and
40+
left.getAUse() = postCrement and
41+
b.getInstruction(iPre) = preCrement.getUse() and
42+
b.getInstruction(iPost) = postCrement.getUse() and
43+
b.getInstruction(iStore) = store and
44+
iPre < iStore and
45+
iStore < iPost
46+
)
47+
}
48+
49+
/**
50+
* Holds if `store` is the `StoreInstruction` generated by an postfix
51+
* increment or decrement operation `e`, and `postCrement` is the fully
52+
* converted operand that represents the use of the evaluated value of `e`.
53+
*/
54+
private predicate isUseAfterPostfixCrement(StoreInstruction store, Operand postCrement) {
55+
isUseAfterPostfixCrement0(store, postCrement) and
56+
conversionFlow(postCrement, _, false, _)
57+
or
58+
exists(Instruction instr, Operand postCrement0 |
59+
isUseAfterPostfixCrement(store, postCrement0) and
60+
conversionFlow(postCrement0, instr, false, _) and
61+
instr = postCrement.getDef()
62+
)
63+
}
64+
65+
private predicate hasSavedPostfixCrementSourceVariable(
66+
BaseSourceVariable base, StoreInstruction store, int ind
67+
) {
68+
exists(BaseSourceVariableInstruction inst, int ind0 |
69+
isUseAfterPostfixCrement(store, _) and
70+
inst.getBaseSourceVariable() = base and
71+
isDef(_, _, store.getDestinationAddressOperand(), inst, ind0, 0) and
72+
ind = [ind0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
73+
)
74+
}
75+
1876
cached
1977
private newtype TSourceVariable =
20-
TMkSourceVariable(BaseSourceVariable base, int ind) {
78+
TNormalSourceVariable(BaseSourceVariable base, int ind) {
2179
ind = [0 .. countIndirectionsForCppType(base.getLanguageType()) + 1]
80+
} or
81+
TSavedPostfixCrementSourceVariable(StoreInstruction store, int ind) {
82+
hasSavedPostfixCrementSourceVariable(_, store, ind)
2283
}
2384

24-
class SourceVariable extends TSourceVariable {
85+
abstract private class AbstractSourceVariable extends TSourceVariable {
2586
BaseSourceVariable base;
2687
int ind;
2788

28-
SourceVariable() { this = TMkSourceVariable(base, ind) }
89+
bindingset[ind]
90+
AbstractSourceVariable() { any() }
2991

3092
/** Gets the IR variable associated with this `SourceVariable`, if any. */
3193
IRVariable getIRVariable() { result = base.(BaseIRVariable).getIRVariable() }
@@ -37,7 +99,7 @@ private module SourceVariables {
3799
BaseSourceVariable getBaseVariable() { result = base }
38100

39101
/** Gets a textual representation of this element. */
40-
string toString() { result = repeatStars(this.getIndirection()) + base.toString() }
102+
abstract string toString();
41103

42104
/**
43105
* Gets the number of loads performed on the base source variable
@@ -62,6 +124,53 @@ private module SourceVariables {
62124
/** Gets the location of this variable. */
63125
Location getLocation() { result = this.getBaseVariable().getLocation() }
64126
}
127+
128+
final class SourceVariable = AbstractSourceVariable;
129+
130+
/**
131+
* A regular source variable. Most source variables are instances of this
132+
* class.
133+
*/
134+
class NormalSourceVariable extends AbstractSourceVariable, TNormalSourceVariable {
135+
NormalSourceVariable() { this = TNormalSourceVariable(base, ind) }
136+
137+
final override string toString() {
138+
result = repeatStars(this.getIndirection()) + base.toString()
139+
}
140+
}
141+
142+
/**
143+
* Before a value is postfix incremented (or decremented) we "save" its
144+
* current value so that the pre-incremented value can be returned to the
145+
* enclosing expression. We use the source variables represented by this
146+
* class to represent the "saved value".
147+
*/
148+
class SavedPostfixCrementSourceVariable extends AbstractSourceVariable,
149+
TSavedPostfixCrementSourceVariable
150+
{
151+
StoreInstruction store;
152+
153+
SavedPostfixCrementSourceVariable() {
154+
this = TSavedPostfixCrementSourceVariable(store, ind) and
155+
hasSavedPostfixCrementSourceVariable(base, store, ind)
156+
}
157+
158+
final override string toString() {
159+
result = repeatStars(this.getIndirection()) + base.toString() + " [before crement]"
160+
}
161+
162+
/**
163+
* Gets the `StoreInstruction` that writes the incremented (or decremented)
164+
* value.
165+
*/
166+
StoreInstruction getStoreInstruction() { result = store }
167+
168+
/**
169+
* Gets the fully converted `Operand` that represents the use of the
170+
* value before the increment.
171+
*/
172+
Operand getOperand() { isUseAfterPostfixCrement(store, result) }
173+
}
65174
}
66175

67176
import SourceVariables
@@ -109,17 +218,43 @@ private newtype TDefImpl =
109218
TDirectDefImpl(Operand address, int indirectionIndex) {
110219
isDef(_, _, address, _, _, indirectionIndex)
111220
} or
221+
TSavedPostfixCrementDefImpl(SavedPostfixCrementSourceVariable sv, int indirectionIndex) {
222+
isDef(_, _, sv.getStoreInstruction().getDestinationAddressOperand(), _, sv.getIndirection(),
223+
indirectionIndex)
224+
} or
112225
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
113226
// Represents the initial "definition" of a global variable when entering
114227
// a function body.
115228
isGlobalDefImpl(v, f, _, indirectionIndex)
116229
}
117230

231+
pragma[nomagic]
232+
private predicate hasOperandAndIndirection(
233+
SavedPostfixCrementSourceVariable sv, Operand operand, int indirection
234+
) {
235+
sv.getOperand() = operand and
236+
sv.getIndirection() = indirection
237+
}
238+
239+
private predicate hasBeforePostCrementUseImpl(
240+
SavedPostfixCrementSourceVariable sv, Operand operand, int indirectionIndex
241+
) {
242+
not isDef(true, _, operand, _, _, _) and
243+
exists(int indirection |
244+
hasOperandAndIndirection(sv, operand, indirection) and
245+
isUse(_, operand, _, indirection, indirectionIndex)
246+
)
247+
}
248+
118249
cached
119250
private newtype TUseImpl =
120251
TDirectUseImpl(Operand operand, int indirectionIndex) {
121252
isUse(_, operand, _, _, indirectionIndex) and
122-
not isDef(true, _, operand, _, _, _)
253+
not isDef(true, _, operand, _, _, _) and
254+
not hasBeforePostCrementUseImpl(_, operand, indirectionIndex)
255+
} or
256+
TSavedPostfixCrementUseImpl(SavedPostfixCrementSourceVariable sv, int indirectionIndex) {
257+
hasBeforePostCrementUseImpl(sv, _, indirectionIndex)
123258
} or
124259
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
125260
// Represents a final "use" of a global variable to ensure that
@@ -326,7 +461,7 @@ abstract private class DefAddressImpl extends DefImpl, TDefAddressImpl {
326461

327462
override Cpp::Location getLocation() { result = v.getLocation() }
328463

329-
final override SourceVariable getSourceVariable() {
464+
final override NormalSourceVariable getSourceVariable() {
330465
result.getBaseVariable() = v and
331466
result.getIndirection() = 0
332467
}
@@ -381,7 +516,7 @@ private class DirectDef extends DefImpl, TDirectDefImpl {
381516
indirection = this.getIndirection()
382517
}
383518

384-
final override SourceVariable getSourceVariable() {
519+
final override NormalSourceVariable getSourceVariable() {
385520
exists(BaseSourceVariable v, int indirection |
386521
sourceVariableHasBaseAndIndex(result, v, indirection) and
387522
this.hasBaseSourceVariableAndIndirection(v, indirection)
@@ -395,6 +530,32 @@ private class DirectDef extends DefImpl, TDirectDefImpl {
395530
override predicate isCertain() { isDef(true, _, address, _, _, indirectionIndex) }
396531
}
397532

533+
/**
534+
* A definition that "saves" the value of a variable before it is incremented
535+
* or decremented.
536+
*/
537+
private class SavedPostfixCrementDefImpl extends DefImpl, TSavedPostfixCrementDefImpl {
538+
SavedPostfixCrementSourceVariable sv;
539+
540+
SavedPostfixCrementDefImpl() { this = TSavedPostfixCrementDefImpl(sv, indirectionIndex) }
541+
542+
override Cpp::Location getLocation() { result = sv.getStoreInstruction().getLocation() }
543+
544+
final override predicate hasIndexInBlock(IRBlock block, int index) {
545+
sv.getStoreInstruction() = block.getInstruction(index)
546+
}
547+
548+
override string toString() { result = "Def of " + this.getSourceVariable() }
549+
550+
override SourceVariable getSourceVariable() { result = sv }
551+
552+
override int getIndirection() { result = sv.getIndirection() }
553+
554+
override predicate isCertain() {
555+
isDef(true, _, sv.getStoreInstruction().getDestinationAddressOperand(), _, _, indirectionIndex)
556+
}
557+
}
558+
398559
private class DirectUseImpl extends UseImpl, TDirectUseImpl {
399560
Operand operand;
400561

@@ -414,7 +575,7 @@ private class DirectUseImpl extends UseImpl, TDirectUseImpl {
414575
this.getIndirection() = indirection
415576
}
416577

417-
override SourceVariable getSourceVariable() {
578+
override NormalSourceVariable getSourceVariable() {
418579
exists(BaseSourceVariable v, int indirection |
419580
sourceVariableHasBaseAndIndex(result, v, indirection) and
420581
this.hasBaseSourceVariableAndIndirection(v, indirection)
@@ -432,6 +593,34 @@ private class DirectUseImpl extends UseImpl, TDirectUseImpl {
432593
override Node getNode() { nodeHasOperand(result, operand, indirectionIndex) }
433594
}
434595

596+
/**
597+
* The use of the original "saved" variable after the variable has been incremented
598+
* or decremented.
599+
*/
600+
private class SavedPostfixCrementUseImpl extends UseImpl, TSavedPostfixCrementUseImpl {
601+
SavedPostfixCrementSourceVariable sv;
602+
603+
SavedPostfixCrementUseImpl() { this = TSavedPostfixCrementUseImpl(sv, indirectionIndex) }
604+
605+
override string toString() { result = "Use of " + this.getSourceVariable() }
606+
607+
final override predicate hasIndexInBlock(IRBlock block, int index) {
608+
this.getOperand().getUse() = block.getInstruction(index)
609+
}
610+
611+
override SourceVariable getSourceVariable() { result = sv }
612+
613+
final Operand getOperand() { result = sv.getOperand() }
614+
615+
final override Cpp::Location getLocation() { result = this.getOperand().getLocation() }
616+
617+
override int getIndirection() { result = sv.getIndirection() }
618+
619+
override predicate isCertain() { isUse(true, this.getOperand(), _, _, indirectionIndex) }
620+
621+
override Node getNode() { nodeHasOperand(result, this.getOperand(), indirectionIndex) }
622+
}
623+
435624
pragma[nomagic]
436625
private predicate finalParameterNodeHasParameterAndIndex(
437626
FinalParameterNode n, Parameter p, int indirectionIndex
@@ -502,7 +691,7 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
502691
indirection = this.getIndirection()
503692
}
504693

505-
override SourceVariable getSourceVariable() {
694+
override NormalSourceVariable getSourceVariable() {
506695
exists(BaseIRVariable v, int indirection |
507696
sourceVariableHasBaseAndIndex(result, v, indirection) and
508697
this.hasBaseSourceVariableAndIndirectrion(v, indirection)
@@ -593,7 +782,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
593782
indirection = this.getIndirection()
594783
}
595784

596-
override SourceVariable getSourceVariable() {
785+
override NormalSourceVariable getSourceVariable() {
597786
exists(BaseIRVariable v, int indirection |
598787
sourceVariableHasBaseAndIndex(result, v, indirection) and
599788
this.hasBaseSourceVariableAndIndirection(v, indirection)
@@ -642,7 +831,7 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
642831
)
643832
}
644833

645-
final override SourceVariable getSourceVariable() {
834+
final override NormalSourceVariable getSourceVariable() {
646835
exists(BaseSourceVariable v |
647836
sourceVariableHasBaseAndIndex(result, v, indirectionIndex) and
648837
baseSourceVariableIsGlobal(v, global, f)
@@ -688,9 +877,15 @@ predicate defToNode(Node node, Definition def, SourceVariable sv) {
688877
}
689878

690879
private predicate defToNode(Node node, Definition def) {
691-
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
692-
or
693-
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
880+
// Only definitions of `NormalSourceVariable` need to be converted into
881+
// dataflow nodes. The other case, `SavedPostfixCrementSourceVariable`,
882+
// are internal definitions that don't have a dataflow node representation.
883+
def.getSourceVariable() instanceof NormalSourceVariable and
884+
(
885+
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
886+
or
887+
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
888+
)
694889
or
695890
node.(InitialGlobalValue).getGlobalDef() = def
696891
}

0 commit comments

Comments
 (0)