Skip to content

Commit 08e8604

Browse files
committed
C++: Change 'Expr' to be EquivalenceClasses instead of Instructions.
1 parent 59f2c75 commit 08e8604

File tree

1 file changed

+89
-1
lines changed

1 file changed

+89
-1
lines changed

cpp/ql/lib/experimental/semmle/code/cpp/semantic/SemanticExprSpecific.qll

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,95 @@ private import semmle.code.cpp.ir.ValueNumbering
1212
module SemanticExprConfig {
1313
class Location = Cpp::Location;
1414

15-
class Expr = IR::Instruction;
15+
/** A `ConvertInstruction` or a `CopyValueInstruction`. */
16+
private class Conversion extends IR::UnaryInstruction {
17+
Conversion() {
18+
this instanceof IR::CopyValueInstruction
19+
or
20+
this instanceof IR::ConvertInstruction
21+
}
22+
23+
/** Holds if this instruction converts a value of type `tFrom` to a value of type `tTo`. */
24+
predicate converts(SemType tFrom, SemType tTo) {
25+
exists(IR::ConvertInstruction convert |
26+
this = convert and
27+
tFrom = getSemanticType(convert.getUnary().getResultIRType()) and
28+
tTo = getSemanticType(convert.getResultIRType())
29+
)
30+
or
31+
exists(IR::CopyValueInstruction copy |
32+
this = copy and
33+
tFrom = getSemanticType(copy.getUnary().getResultIRType()) and
34+
tTo = getSemanticType(copy.getResultIRType())
35+
)
36+
}
37+
}
38+
39+
/**
40+
* Gets a conversion-like instruction that consumes `op`, and
41+
* which is guaranteed to not overflow.
42+
*/
43+
private IR::Instruction safeConversion(IR::Operand op) {
44+
exists(Conversion conv, SemType tFrom, SemType tTo |
45+
conv.converts(tFrom, tTo) and
46+
conversionCannotOverflow(tFrom, tTo) and
47+
conv.getUnaryOperand() = op and
48+
result = conv
49+
)
50+
}
51+
52+
/** Holds if `i1 = i2` or if `i2` is a safe conversion that consumes `i1`. */
53+
private predicate idOrSafeConversion(IR::Instruction i1, IR::Instruction i2) {
54+
not i1.getResultIRType() instanceof IR::IRVoidType and
55+
(
56+
i1 = i2
57+
or
58+
i2 = safeConversion(i1.getAUse())
59+
)
60+
}
61+
62+
module Equiv = QlBuiltins::EquivalenceRelation<IR::Instruction, idOrSafeConversion/2>;
63+
64+
/**
65+
* The expressions on which we perform range analysis.
66+
*/
67+
class Expr extends Equiv::EquivalenceClass {
68+
/** Gets the n'th instruction in this equivalence class. */
69+
private IR::Instruction getInstruction(int n) {
70+
result =
71+
rank[n + 1](IR::Instruction instr, int i, IR::IRBlock block |
72+
this = Equiv::getEquivalenceClass(instr) and block.getInstruction(i) = instr
73+
|
74+
instr order by i
75+
)
76+
}
77+
78+
/** Gets a textual representation of this element. */
79+
string toString() { result = this.getUnconverted().toString() }
80+
81+
/** Gets the basic block of this expression. */
82+
IR::IRBlock getBlock() { result = getInstruction(0).getBlock() }
83+
84+
/** Gets the unconverted instruction associated with this expression. */
85+
IR::Instruction getUnconverted() { result = this.getInstruction(0) }
86+
87+
/**
88+
* Gets the final instruction associated with this expression. This
89+
* represents the result after applying all the safe conversions.
90+
*/
91+
IR::Instruction getConverted() {
92+
exists(int n |
93+
result = this.getInstruction(n) and
94+
not exists(this.getInstruction(n + 1))
95+
)
96+
}
97+
98+
/** Gets the type of the result produced by this instruction. */
99+
IR::IRType getResultIRType() { result = this.getConverted().getResultIRType() }
100+
101+
/** Gets the location of the source code for this expression. */
102+
Location getLocation() { result = this.getUnconverted().getLocation() }
103+
}
16104

17105
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
18106

0 commit comments

Comments
 (0)