Skip to content

Commit b931e88

Browse files
authored
Merge pull request #67 from dave-bartolomeo/dave/CastToVoid
C++: Handle casts to `void` in IR
2 parents 5e6f34f + 332e944 commit b931e88

File tree

17 files changed

+382
-12
lines changed

17 files changed

+382
-12
lines changed

cpp/ql/src/semmle/code/cpp/exprs/Cast.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,20 @@ class BoolConversion extends Cast {
292292
}
293293
}
294294

295+
/**
296+
* A conversion to `void`.
297+
*/
298+
class VoidConversion extends Cast {
299+
VoidConversion() {
300+
conversionkinds(this, 0) and
301+
getType().getUnspecifiedType() instanceof VoidType
302+
}
303+
304+
override string getSemanticConversionString() {
305+
result = "conversion to void"
306+
}
307+
}
308+
295309
/**
296310
* A conversion between two pointers or glvalues related by inheritance. The
297311
* base class will always be either a direct base class of the derived class,

cpp/ql/src/semmle/code/cpp/ir/internal/Instruction.qll

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,40 @@ module InstructionSanity {
6767
not tag instanceof UnmodeledUseOperand
6868
}
6969

70+
/**
71+
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
72+
* the predecessor block `pred`.
73+
*/
74+
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
75+
pred = instr.getBlock().getAPredecessor() and
76+
not exists(PhiOperand operand |
77+
exists(instr.getOperand(operand)) and
78+
operand.getPredecessorBlock() = pred
79+
)
80+
}
81+
82+
/**
83+
* Holds if an instruction, other than `ExitFunction`, has no successors.
84+
*/
85+
query predicate instructionWithoutSuccessor(Instruction instr) {
86+
not exists(instr.getASuccessor()) and
87+
not instr instanceof ExitFunctionInstruction and
88+
// Phi instructions aren't linked into the instruction-level flow graph.
89+
not instr instanceof PhiInstruction
90+
}
91+
92+
/**
93+
* Holds if a `Phi` instruction is present in a block with fewer than two
94+
* predecessors.
95+
*/
96+
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
97+
count(instr.getBlock().getAPredecessor()) < 2
98+
}
99+
100+
/**
101+
* Holds if instruction `op` consumes an operand `operand` that was defined in
102+
* a different function.
103+
*/
70104
query predicate operandAcrossFunctions(
71105
Instruction op, Instruction operand, OperandTag tag
72106
) {
@@ -296,8 +330,7 @@ class Instruction extends Construction::TInstruction {
296330

297331
/**
298332
* Gets the size of the result produced by this instruction, in bytes. If the
299-
* instruction does not produce a result, or if the result does not have a
300-
* known constant size, this predicate does not hold.
333+
* result does not have a known constant size, this predicate does not hold.
301334
*
302335
* If `this.isGLValue()` holds for this instruction, the value of
303336
* `getResultSize()` will always be the size of a pointer.
@@ -312,7 +345,6 @@ class Instruction extends Construction::TInstruction {
312345
else if resultType instanceof UnknownType then
313346
result = Construction::getInstructionResultSize(this)
314347
else (
315-
not resultType instanceof VoidType and
316348
result = resultType.getSize()
317349
)
318350
}

cpp/ql/src/semmle/code/cpp/ir/internal/TranslatedElement.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ private predicate ignoreElement(Element element) {
8989
* a value.
9090
*/
9191
private predicate isNativeCondition(Expr expr) {
92-
expr instanceof BinaryLogicalOperation
92+
expr instanceof BinaryLogicalOperation and
93+
not expr.isConstant()
9394
}
9495

9596
/**
@@ -101,7 +102,8 @@ private predicate isFlexibleCondition(Expr expr) {
101102
expr instanceof ParenthesisExpr or
102103
expr instanceof NotExpr
103104
) and
104-
usedAsCondition(expr)
105+
usedAsCondition(expr) and
106+
not expr.isConstant()
105107
}
106108

107109
/**

cpp/ql/src/semmle/code/cpp/ir/internal/TranslatedExpr.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,8 @@ class TranslatedSimpleConversion extends TranslatedSingleInstructionConversion {
11391139
conv instanceof IntegralToPointerConversion or
11401140
conv instanceof GlvalueConversion or
11411141
conv instanceof ArrayToPointerConversion or
1142-
conv instanceof PrvalueAdjustmentConversion
1142+
conv instanceof PrvalueAdjustmentConversion or
1143+
conv instanceof VoidConversion
11431144
}
11441145

11451146
override Opcode getOpcode() {

cpp/ql/src/semmle/code/cpp/ssa/internal/aliased_ssa/Instruction.qll

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,40 @@ module InstructionSanity {
6767
not tag instanceof UnmodeledUseOperand
6868
}
6969

70+
/**
71+
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
72+
* the predecessor block `pred`.
73+
*/
74+
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
75+
pred = instr.getBlock().getAPredecessor() and
76+
not exists(PhiOperand operand |
77+
exists(instr.getOperand(operand)) and
78+
operand.getPredecessorBlock() = pred
79+
)
80+
}
81+
82+
/**
83+
* Holds if an instruction, other than `ExitFunction`, has no successors.
84+
*/
85+
query predicate instructionWithoutSuccessor(Instruction instr) {
86+
not exists(instr.getASuccessor()) and
87+
not instr instanceof ExitFunctionInstruction and
88+
// Phi instructions aren't linked into the instruction-level flow graph.
89+
not instr instanceof PhiInstruction
90+
}
91+
92+
/**
93+
* Holds if a `Phi` instruction is present in a block with fewer than two
94+
* predecessors.
95+
*/
96+
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
97+
count(instr.getBlock().getAPredecessor()) < 2
98+
}
99+
100+
/**
101+
* Holds if instruction `op` consumes an operand `operand` that was defined in
102+
* a different function.
103+
*/
70104
query predicate operandAcrossFunctions(
71105
Instruction op, Instruction operand, OperandTag tag
72106
) {
@@ -296,8 +330,7 @@ class Instruction extends Construction::TInstruction {
296330

297331
/**
298332
* Gets the size of the result produced by this instruction, in bytes. If the
299-
* instruction does not produce a result, or if the result does not have a
300-
* known constant size, this predicate does not hold.
333+
* result does not have a known constant size, this predicate does not hold.
301334
*
302335
* If `this.isGLValue()` holds for this instruction, the value of
303336
* `getResultSize()` will always be the size of a pointer.
@@ -312,7 +345,6 @@ class Instruction extends Construction::TInstruction {
312345
else if resultType instanceof UnknownType then
313346
result = Construction::getInstructionResultSize(this)
314347
else (
315-
not resultType instanceof VoidType and
316348
result = resultType.getSize()
317349
)
318350
}

cpp/ql/src/semmle/code/cpp/ssa/internal/ssa/Instruction.qll

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,40 @@ module InstructionSanity {
6767
not tag instanceof UnmodeledUseOperand
6868
}
6969

70+
/**
71+
* Holds if `Phi` instruction `instr` is missing an operand corresponding to
72+
* the predecessor block `pred`.
73+
*/
74+
query predicate missingPhiOperand(PhiInstruction instr, IRBlock pred) {
75+
pred = instr.getBlock().getAPredecessor() and
76+
not exists(PhiOperand operand |
77+
exists(instr.getOperand(operand)) and
78+
operand.getPredecessorBlock() = pred
79+
)
80+
}
81+
82+
/**
83+
* Holds if an instruction, other than `ExitFunction`, has no successors.
84+
*/
85+
query predicate instructionWithoutSuccessor(Instruction instr) {
86+
not exists(instr.getASuccessor()) and
87+
not instr instanceof ExitFunctionInstruction and
88+
// Phi instructions aren't linked into the instruction-level flow graph.
89+
not instr instanceof PhiInstruction
90+
}
91+
92+
/**
93+
* Holds if a `Phi` instruction is present in a block with fewer than two
94+
* predecessors.
95+
*/
96+
query predicate unnecessaryPhiInstruction(PhiInstruction instr) {
97+
count(instr.getBlock().getAPredecessor()) < 2
98+
}
99+
100+
/**
101+
* Holds if instruction `op` consumes an operand `operand` that was defined in
102+
* a different function.
103+
*/
70104
query predicate operandAcrossFunctions(
71105
Instruction op, Instruction operand, OperandTag tag
72106
) {
@@ -296,8 +330,7 @@ class Instruction extends Construction::TInstruction {
296330

297331
/**
298332
* Gets the size of the result produced by this instruction, in bytes. If the
299-
* instruction does not produce a result, or if the result does not have a
300-
* known constant size, this predicate does not hold.
333+
* result does not have a known constant size, this predicate does not hold.
301334
*
302335
* If `this.isGLValue()` holds for this instruction, the value of
303336
* `getResultSize()` will always be the size of a pointer.
@@ -312,7 +345,6 @@ class Instruction extends Construction::TInstruction {
312345
else if resultType instanceof UnknownType then
313346
result = Construction::getInstructionResultSize(this)
314347
else (
315-
not resultType instanceof VoidType and
316348
result = resultType.getSize()
317349
)
318350
}

cpp/ql/test/library-tests/conversions/conversions.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,16 @@ void FuncPtrConversions(int(*pfn)(int), void* p) {
235235
p = (void*)pfn;
236236
pfn = (int(*)(int))p;
237237
}
238+
239+
int Func();
240+
241+
void ConversionsToVoid() {
242+
int x;
243+
(void)x;
244+
static_cast<void>(x);
245+
(void)Func();
246+
static_cast<void>(Func());
247+
(void)1;
248+
static_cast<void>(1);
249+
}
250+

cpp/ql/test/library-tests/conversions/conversions.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,9 @@
143143
| conversions.cpp:231:28:231:63 | dynamic_cast<PolymorphicDerived>... | dynamic_cast | lval | PolymorphicDerived | PolymorphicBase |
144144
| conversions.cpp:235:7:235:16 | (void *)... | pointer conversion | prval | void * | ..(*)(..) |
145145
| conversions.cpp:236:9:236:22 | (..(*)(..))... | pointer conversion | prval | ..(*)(..) | void * |
146+
| conversions.cpp:243:3:243:9 | (void)... | conversion to void | prval | void | int |
147+
| conversions.cpp:244:3:244:22 | static_cast<void>... | conversion to void | prval | void | int |
148+
| conversions.cpp:245:3:245:14 | (void)... | conversion to void | prval | void | int |
149+
| conversions.cpp:246:3:246:27 | static_cast<void>... | conversion to void | prval | void | int |
150+
| conversions.cpp:247:3:247:9 | (void)... | conversion to void | prval | void | int |
151+
| conversions.cpp:248:3:248:22 | static_cast<void>... | conversion to void | prval | void | int |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
missingOperand
22
unexpectedOperand
33
duplicateOperand
4+
missingPhiOperand
5+
instructionWithoutSuccessor
6+
unnecessaryPhiInstruction
47
operandAcrossFunctions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
missingOperand
22
unexpectedOperand
33
duplicateOperand
4+
missingPhiOperand
5+
instructionWithoutSuccessor
6+
unnecessaryPhiInstruction
47
operandAcrossFunctions

0 commit comments

Comments
 (0)