Skip to content

Commit ebb27fd

Browse files
committed
C++: Instantiate the shared guards library.
1 parent bd78773 commit ebb27fd

File tree

1 file changed

+362
-0
lines changed

1 file changed

+362
-0
lines changed

cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,372 @@
55

66
import cpp as Cpp
77
import semmle.code.cpp.ir.IR
8+
private import codeql.util.Void
9+
private import codeql.controlflow.Guards as SharedGuards
810
private import semmle.code.cpp.ir.ValueNumbering
911
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
1012
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
1113

14+
private class BasicBlock = IRCfg::BasicBlock;
15+
16+
/**
17+
* INTERNAL: Do not use.
18+
*/
19+
module GuardsInput implements SharedGuards::InputSig<Cpp::Location, Instruction, IRCfg::BasicBlock> {
20+
private import cpp as Cpp
21+
22+
class NormalExitNode = ExitFunctionInstruction;
23+
24+
class AstNode = Instruction;
25+
26+
class Expr extends Instruction {
27+
Instruction getControlFlowNode() { result = this }
28+
29+
IRCfg::BasicBlock getBasicBlock() { result = this.getBlock() }
30+
}
31+
32+
private newtype TConstantValue =
33+
TRange(string minValue, string maxValue) {
34+
minValue != maxValue and
35+
exists(EdgeKind::caseEdge(minValue, maxValue))
36+
}
37+
38+
class ConstantValue extends TConstantValue {
39+
predicate isRange(string minValue, string maxValue) { this = TRange(minValue, maxValue) }
40+
41+
string toString() {
42+
exists(string minValue, string maxValue |
43+
this.isRange(minValue, maxValue) and
44+
result = minValue + ".." + maxValue
45+
)
46+
}
47+
}
48+
49+
private class EqualityExpr extends CompareInstruction {
50+
EqualityExpr() {
51+
this instanceof CompareEQInstruction
52+
or
53+
this instanceof CompareNEInstruction
54+
}
55+
56+
boolean getPolarity() {
57+
result = true and
58+
this instanceof CompareEQInstruction
59+
or
60+
result = false and
61+
this instanceof CompareNEInstruction
62+
}
63+
}
64+
65+
abstract class ConstantExpr extends Expr {
66+
predicate isNull() { none() }
67+
68+
boolean asBooleanValue() { none() }
69+
70+
int asIntegerValue() { none() }
71+
72+
ConstantValue asConstantValue() { none() }
73+
}
74+
75+
private class NullConstant extends ConstantExpr instanceof ConstantInstruction {
76+
NullConstant() {
77+
this.getValue() = "0" and
78+
this.getResultIRType() instanceof IRAddressType
79+
}
80+
81+
override predicate isNull() { any() }
82+
}
83+
84+
private class BooleanConstant extends ConstantExpr instanceof ConstantInstruction {
85+
BooleanConstant() { this.getResultIRType() instanceof IRBooleanType }
86+
87+
override boolean asBooleanValue() {
88+
super.getValue() = "0" and
89+
result = false
90+
or
91+
super.getValue() = "1" and
92+
result = true
93+
}
94+
}
95+
96+
private class IntegerConstant extends ConstantExpr {
97+
int value;
98+
99+
IntegerConstant() {
100+
this.(ConstantInstruction).getValue().toInt() = value and
101+
this.getResultIRType() instanceof IRIntegerType
102+
or
103+
// In order to have an "integer constant" for a switch case
104+
// we misuse the first instruction (which is always a NoOp instruction)
105+
// as a constant with the switch case's value.
106+
exists(CaseEdge edge |
107+
this = any(SwitchInstruction switch).getSuccessor(edge) and
108+
value = edge.getValue().toInt()
109+
)
110+
}
111+
112+
override int asIntegerValue() { result = value }
113+
}
114+
115+
/**
116+
* The instruction representing the constant expression in a case statement.
117+
*
118+
* Since the IR does not have an instruction for this (as this is represented
119+
* by the edge) we use the `NoOp` instruction which is always generated.
120+
*/
121+
private class CaseConstant extends ConstantExpr instanceof NoOpInstruction {
122+
SwitchInstruction switch;
123+
SwitchEdge edge;
124+
125+
CaseConstant() { this = switch.getSuccessor(edge) }
126+
127+
override ConstantValue asConstantValue() {
128+
exists(string minValue, string maxValue |
129+
edge.getMinValue() = minValue and
130+
edge.getMaxValue() = maxValue and
131+
result.isRange(minValue, maxValue)
132+
)
133+
}
134+
135+
predicate hasEdge(SwitchInstruction switch_, SwitchEdge edge_) {
136+
switch_ = switch and
137+
edge_ = edge
138+
}
139+
}
140+
141+
private predicate nonNullExpr(Instruction i) {
142+
i instanceof VariableAddressInstruction
143+
or
144+
i.(PointerConstantInstruction).getValue() != "0"
145+
or
146+
i instanceof TypeidInstruction
147+
or
148+
nonNullExpr(i.(FieldAddressInstruction).getObjectAddress())
149+
or
150+
nonNullExpr(i.(PointerAddInstruction).getLeft())
151+
or
152+
nonNullExpr(i.(CopyInstruction).getSourceValue())
153+
or
154+
nonNullExpr(i.(ConvertInstruction).getUnary())
155+
or
156+
nonNullExpr(i.(CheckedConvertOrThrowInstruction).getUnary())
157+
or
158+
nonNullExpr(i.(CompleteObjectAddressInstruction).getUnary())
159+
or
160+
nonNullExpr(i.(InheritanceConversionInstruction).getUnary())
161+
or
162+
nonNullExpr(i.(BitOrInstruction).getAnInput())
163+
}
164+
165+
class NonNullExpr extends Expr {
166+
NonNullExpr() { nonNullExpr(this) }
167+
}
168+
169+
class Case extends Expr {
170+
SwitchInstruction switch;
171+
SwitchEdge edge;
172+
173+
SwitchEdge getEdge() { result = edge }
174+
175+
Case() { switch.getSuccessor(edge) = this }
176+
177+
predicate matchEdge(BasicBlock bb1, BasicBlock bb2) {
178+
switch.getBlock() = bb1 and
179+
this.getBasicBlock() = bb2
180+
}
181+
182+
predicate nonMatchEdge(BasicBlock bb1, BasicBlock bb2) { none() }
183+
184+
Expr getSwitchExpr() { result = switch.getExpression() }
185+
186+
predicate isDefaultCase() { edge.isDefault() }
187+
188+
ConstantExpr asConstantCase() { result.(CaseConstant).hasEdge(switch, edge) }
189+
}
190+
191+
abstract private class BinExpr extends Expr instanceof BinaryInstruction {
192+
Expr getAnOperand() { result = super.getAnInput() }
193+
}
194+
195+
class AndExpr extends BinExpr instanceof BitAndInstruction { }
196+
197+
class OrExpr extends BinExpr instanceof BitOrInstruction { }
198+
199+
class NotExpr extends Expr instanceof UnaryInstruction {
200+
NotExpr() {
201+
this instanceof LogicalNotInstruction
202+
or
203+
this instanceof BitComplementInstruction
204+
}
205+
206+
Expr getOperand() { result = super.getUnary() }
207+
}
208+
209+
additional predicate isBoolToIntConversion(ConvertInstruction convert, Instruction unary) {
210+
convert.getUnary() = unary and
211+
unary.getResultIRType() instanceof IRBooleanType and
212+
convert.getResultIRType() instanceof IRIntegerType
213+
}
214+
215+
class IdExpr extends Expr {
216+
IdExpr() {
217+
this instanceof CopyInstruction
218+
or
219+
not isBoolToIntConversion(this, _) and
220+
this instanceof ConvertInstruction
221+
or
222+
this instanceof InheritanceConversionInstruction
223+
}
224+
225+
Expr getEqualChildExpr() {
226+
result = this.(CopyInstruction).getSourceValue()
227+
or
228+
result = this.(ConvertInstruction).getUnary()
229+
or
230+
result = this.(InheritanceConversionInstruction).getUnary()
231+
}
232+
}
233+
234+
pragma[nomagic]
235+
predicate equalityTest(Expr eqtest, Expr left, Expr right, boolean polarity) {
236+
exists(EqualityExpr eq | eqtest = eq |
237+
eq.getLeft() = left and
238+
eq.getRight() = right and
239+
polarity = eq.getPolarity()
240+
)
241+
}
242+
243+
additional predicate equalityTestSymmetric(Expr eqtest, Expr e1, Expr e2, boolean eqval) {
244+
equalityTest(eqtest, e1, e2, eqval)
245+
or
246+
equalityTest(eqtest, e2, e1, eqval)
247+
}
248+
249+
class ConditionalExpr extends Expr {
250+
ConditionalExpr() { none() }
251+
252+
Expr getCondition() { none() }
253+
254+
Expr getThen() { none() }
255+
256+
Expr getElse() { none() }
257+
}
258+
259+
private import semmle.code.cpp.dataflow.new.DataFlow::DataFlow as DataFlow
260+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
261+
262+
class Parameter = Cpp::Parameter;
263+
264+
private int parameterPosition() { result in [-1, any(Cpp::Parameter p).getIndex()] }
265+
266+
/** A parameter position represented by an integer. */
267+
class ParameterPosition extends int {
268+
ParameterPosition() { this = parameterPosition() }
269+
}
270+
271+
/** An argument position represented by an integer. */
272+
class ArgumentPosition extends int {
273+
ArgumentPosition() { this = parameterPosition() }
274+
}
275+
276+
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
277+
overlay[caller?]
278+
pragma[inline]
279+
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
280+
281+
final private class FinalMethod = Cpp::Function;
282+
283+
class NonOverridableMethod extends FinalMethod {
284+
NonOverridableMethod() {
285+
not this instanceof Cpp::MemberFunction
286+
or
287+
exists(Cpp::MemberFunction mf | this = mf |
288+
not mf.isVirtual()
289+
or
290+
mf.isFinal()
291+
)
292+
}
293+
294+
Parameter getParameter(ParameterPosition ppos) { super.getParameter(ppos) = result }
295+
296+
GuardsInput::Expr getAReturnExpr() {
297+
exists(ReturnValueInstruction ret |
298+
ret.getEnclosingFunction() = this and
299+
result = ret.getReturnValue()
300+
)
301+
}
302+
}
303+
304+
private predicate nonOverridableMethodCall(CallInstruction call, NonOverridableMethod m) {
305+
call.getStaticCallTarget() = m
306+
}
307+
308+
class NonOverridableMethodCall extends GuardsInput::Expr instanceof CallInstruction {
309+
NonOverridableMethodCall() { nonOverridableMethodCall(this, _) }
310+
311+
NonOverridableMethod getMethod() { nonOverridableMethodCall(this, result) }
312+
313+
GuardsInput::Expr getArgument(ArgumentPosition apos) { result = super.getArgument(apos) }
314+
}
315+
}
316+
317+
private module GuardsImpl = SharedGuards::Make<Cpp::Location, IRCfg, GuardsInput>;
318+
319+
private module LogicInput_v1 implements GuardsImpl::LogicInputSig {
320+
private import semmle.code.cpp.dataflow.new.DataFlow::DataFlow::Ssa
321+
322+
final private class FinalBaseSsaVariable = Definition;
323+
324+
class SsaDefinition extends FinalBaseSsaVariable {
325+
GuardsInput::Expr getARead() { result = this.getAUse().getDef() }
326+
}
327+
328+
class SsaWriteDefinition extends SsaDefinition instanceof ExplicitDefinition {
329+
GuardsInput::Expr getDefinition() { result = super.getAssignedInstruction() }
330+
}
331+
332+
class SsaPhiNode extends SsaDefinition instanceof PhiNode {
333+
predicate hasInputFromBlock(SsaDefinition inp, BasicBlock bb) {
334+
super.hasInputFromBlock(inp, bb)
335+
}
336+
}
337+
338+
predicate parameterDefinition(GuardsInput::Parameter p, SsaDefinition def) {
339+
def.isParameterDefinition(p)
340+
}
341+
342+
predicate additionalImpliesStep(
343+
GuardsImpl::PreGuard g1, GuardValue v1, GuardsImpl::PreGuard g2, GuardValue v2
344+
) {
345+
g1.(ConditionalBranchInstruction).getCondition() = g2 and
346+
v1.asBooleanValue() = v2.asBooleanValue()
347+
or
348+
exists(SwitchInstruction switch, SwitchEdge edge |
349+
g1 = switch.getSuccessor(edge) and
350+
g2 = switch.getExpression()
351+
|
352+
v1.asBooleanValue() = true and
353+
(
354+
v2.asIntValue() = edge.getValue().toInt()
355+
or
356+
v2.asConstantValue().isRange(edge.getMinValue(), edge.getMaxValue())
357+
)
358+
or
359+
v1.asBooleanValue() = false and
360+
(
361+
v2.getDualValue().asIntValue() = edge.getValue().toInt()
362+
or
363+
v2.getDualValue().asConstantValue().isRange(edge.getMinValue(), edge.getMaxValue())
364+
)
365+
)
366+
}
367+
}
368+
369+
class GuardValue = GuardsImpl::GuardValue;
370+
371+
/** INTERNAL: Don't use. */
372+
module Guards_v1 = GuardsImpl::Logic<LogicInput_v1>;
373+
12374
/**
13375
* Holds if `block` consists of an `UnreachedInstruction`.
14376
*

0 commit comments

Comments
 (0)