Skip to content

Commit 0b2f560

Browse files
authored
Merge pull request github#12982 from rdmarsh2/rdmarsh2/ir-guards-unreached
C++: Handle nonreturning functions in IR generation
2 parents e42bf2e + a2503bd commit 0b2f560

File tree

21 files changed

+542
-35
lines changed

21 files changed

+542
-35
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: majorAnalysis
3+
---
4+
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ private module Cached {
3434

3535
cached
3636
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
37-
exists(OldInstruction oldInstruction |
37+
exists(OldIR::Instruction oldInstruction |
3838
irFunc = oldInstruction.getEnclosingIRFunction() and
39-
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
39+
(
40+
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
41+
or
42+
oldInstruction.getOpcode() instanceof Opcode::Unreached
43+
)
4044
)
4145
}
4246

@@ -366,21 +370,19 @@ private module Cached {
366370
then
367371
result = getChi(getOldInstruction(instruction)) and
368372
kind instanceof GotoEdge
369-
else (
373+
else
370374
exists(OldInstruction oldInstruction |
371-
oldInstruction = getOldInstruction(instruction) and
375+
(
376+
oldInstruction = getOldInstruction(instruction)
377+
or
378+
instruction = getChi(oldInstruction)
379+
) and
372380
(
373381
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
374382
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
375383
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
376384
)
377385
)
378-
or
379-
exists(OldInstruction oldInstruction |
380-
instruction = getChi(oldInstruction) and
381-
result = getNewInstruction(oldInstruction.getSuccessor(kind))
382-
)
383-
)
384386
}
385387

386388
cached

cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ newtype TInstruction =
1919
) {
2020
IRConstruction::Raw::hasInstruction(tag1, tag2)
2121
} or
22+
TRawUnreachedInstruction(IRFunctionBase irFunc) {
23+
IRConstruction::hasUnreachedInstruction(irFunc)
24+
} or
2225
TUnaliasedSsaPhiInstruction(
2326
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
2427
) {

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ module Raw {
178178
}
179179
}
180180

181-
class TStageInstruction = TRawInstruction;
181+
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
182182

183-
predicate hasInstruction(TRawInstruction instr) { any() }
183+
predicate hasInstruction(TStageInstruction instr) { any() }
184184

185185
predicate hasModeledMemoryResult(Instruction instruction) { none() }
186186

@@ -368,6 +368,11 @@ private predicate isStrictlyForwardGoto(GotoStmt goto) {
368368

369369
Locatable getInstructionAst(TStageInstruction instr) {
370370
result = getInstructionTranslatedElement(instr).getAst()
371+
or
372+
exists(IRFunction irFunc |
373+
instr = TRawUnreachedInstruction(irFunc) and
374+
result = irFunc.getFunction()
375+
)
371376
}
372377

373378
/** DEPRECATED: Alias for getInstructionAst */
@@ -377,14 +382,22 @@ deprecated Locatable getInstructionAST(TStageInstruction instr) {
377382

378383
CppType getInstructionResultType(TStageInstruction instr) {
379384
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
385+
or
386+
instr instanceof TRawUnreachedInstruction and
387+
result = getVoidType()
380388
}
381389

382390
predicate getInstructionOpcode(Opcode opcode, TStageInstruction instr) {
383391
getInstructionTranslatedElement(instr).hasInstruction(opcode, getInstructionTag(instr), _)
392+
or
393+
instr instanceof TRawUnreachedInstruction and
394+
opcode instanceof Opcode::Unreached
384395
}
385396

386397
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
387398
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
399+
or
400+
instr = TRawUnreachedInstruction(result)
388401
}
389402

390403
Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) {
@@ -393,6 +406,16 @@ Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction
393406
.getPrimaryInstructionForSideEffect(getInstructionTag(instruction))
394407
}
395408

409+
predicate hasUnreachedInstruction(IRFunction func) {
410+
exists(Call c |
411+
c.getEnclosingFunction() = func.getFunction() and
412+
any(Options opt).exits(c.getTarget())
413+
) and
414+
not exists(TranslatedUnreachableReturnStmt return |
415+
return.getEnclosingFunction().getFunction() = func.getFunction()
416+
)
417+
}
418+
396419
import CachedForDebugging
397420

398421
cached

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ newtype TInstructionTag =
3434
CallTargetTag() or
3535
CallTag() or
3636
CallSideEffectTag() or
37+
CallNoReturnTag() or
3738
AllocationSizeTag() or
3839
AllocationElementSizeTag() or
3940
AllocationExtentConvertTag() or

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import SideEffects
88
private import TranslatedElement
99
private import TranslatedExpr
1010
private import TranslatedFunction
11+
private import DefaultOptions as DefaultOptions
1112

1213
/**
1314
* Gets the `CallInstruction` from the `TranslatedCallExpr` for the specified expression.
@@ -66,7 +67,13 @@ abstract class TranslatedCall extends TranslatedExpr {
6667
)
6768
or
6869
child = getSideEffects() and
69-
result = getParent().getChildSuccessor(this)
70+
if this.isNoReturn()
71+
then
72+
result =
73+
any(UnreachedInstruction instr |
74+
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
75+
)
76+
else result = this.getParent().getChildSuccessor(this)
7077
}
7178

7279
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -161,6 +168,8 @@ abstract class TranslatedCall extends TranslatedExpr {
161168
*/
162169
abstract predicate hasArguments();
163170

171+
predicate isNoReturn() { none() }
172+
164173
final TranslatedSideEffects getSideEffects() { result.getExpr() = expr }
165174
}
166175

@@ -266,6 +275,8 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedC
266275
}
267276

268277
final override int getNumberOfArguments() { result = expr.getNumberOfArguments() }
278+
279+
final override predicate isNoReturn() { any(Options opt).exits(expr.getTarget()) }
269280
}
270281

271282
/**

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
77
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
88
if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge
99
)
10+
or
11+
instr.getSuccessor(kind) instanceof UnreachedInstruction and
12+
kind instanceof GotoEdge
1013
}
1114

1215
pragma[noinline]
@@ -41,7 +44,9 @@ class ReachableBlock extends IRBlockBase {
4144
* An instruction that is contained in a reachable block.
4245
*/
4346
class ReachableInstruction extends Instruction {
44-
ReachableInstruction() { this.getBlock() instanceof ReachableBlock }
47+
ReachableInstruction() {
48+
this.getBlock() instanceof ReachableBlock and not this instanceof UnreachedInstruction
49+
}
4550
}
4651

4752
module Graph {

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ private module Cached {
3434

3535
cached
3636
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
37-
exists(OldInstruction oldInstruction |
37+
exists(OldIR::Instruction oldInstruction |
3838
irFunc = oldInstruction.getEnclosingIRFunction() and
39-
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
39+
(
40+
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
41+
or
42+
oldInstruction.getOpcode() instanceof Opcode::Unreached
43+
)
4044
)
4145
}
4246

@@ -366,21 +370,19 @@ private module Cached {
366370
then
367371
result = getChi(getOldInstruction(instruction)) and
368372
kind instanceof GotoEdge
369-
else (
373+
else
370374
exists(OldInstruction oldInstruction |
371-
oldInstruction = getOldInstruction(instruction) and
375+
(
376+
oldInstruction = getOldInstruction(instruction)
377+
or
378+
instruction = getChi(oldInstruction)
379+
) and
372380
(
373381
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
374382
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
375383
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
376384
)
377385
)
378-
or
379-
exists(OldInstruction oldInstruction |
380-
instruction = getChi(oldInstruction) and
381-
result = getNewInstruction(oldInstruction.getSuccessor(kind))
382-
)
383-
)
384386
}
385387

386388
cached

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
77
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
88
if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge
99
)
10+
or
11+
instr.getSuccessor(kind) instanceof UnreachedInstruction and
12+
kind instanceof GotoEdge
1013
}
1114

1215
pragma[noinline]
@@ -41,7 +44,9 @@ class ReachableBlock extends IRBlockBase {
4144
* An instruction that is contained in a reachable block.
4245
*/
4346
class ReachableInstruction extends Instruction {
44-
ReachableInstruction() { this.getBlock() instanceof ReachableBlock }
47+
ReachableInstruction() {
48+
this.getBlock() instanceof ReachableBlock and not this instanceof UnreachedInstruction
49+
}
4550
}
4651

4752
module Graph {

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14408,6 +14408,60 @@ ir.cpp:
1440814408
# 1894| Conversion = [IntegralConversion] integral conversion
1440914409
# 1894| Type = [IntType] int
1441014410
# 1894| ValueCategory = prvalue
14411+
# 1897| [TopLevelFunction] void noreturnFunc()
14412+
# 1897| <params>:
14413+
# 1899| [TopLevelFunction] int noreturnTest(int)
14414+
# 1899| <params>:
14415+
# 1899| getParameter(0): [Parameter] x
14416+
# 1899| Type = [IntType] int
14417+
# 1899| getEntryPoint(): [BlockStmt] { ... }
14418+
# 1900| getStmt(0): [IfStmt] if (...) ...
14419+
# 1900| getCondition(): [LTExpr] ... < ...
14420+
# 1900| Type = [BoolType] bool
14421+
# 1900| ValueCategory = prvalue
14422+
# 1900| getLesserOperand(): [VariableAccess] x
14423+
# 1900| Type = [IntType] int
14424+
# 1900| ValueCategory = prvalue(load)
14425+
# 1900| getGreaterOperand(): [Literal] 10
14426+
# 1900| Type = [IntType] int
14427+
# 1900| Value = [Literal] 10
14428+
# 1900| ValueCategory = prvalue
14429+
# 1900| getThen(): [BlockStmt] { ... }
14430+
# 1901| getStmt(0): [ReturnStmt] return ...
14431+
# 1901| getExpr(): [VariableAccess] x
14432+
# 1901| Type = [IntType] int
14433+
# 1901| ValueCategory = prvalue(load)
14434+
# 1902| getElse(): [BlockStmt] { ... }
14435+
# 1903| getStmt(0): [ExprStmt] ExprStmt
14436+
# 1903| getExpr(): [FunctionCall] call to noreturnFunc
14437+
# 1903| Type = [VoidType] void
14438+
# 1903| ValueCategory = prvalue
14439+
# 1905| getStmt(1): [ReturnStmt] return ...
14440+
# 1907| [TopLevelFunction] int noreturnTest2(int)
14441+
# 1907| <params>:
14442+
# 1907| getParameter(0): [Parameter] x
14443+
# 1907| Type = [IntType] int
14444+
# 1907| getEntryPoint(): [BlockStmt] { ... }
14445+
# 1908| getStmt(0): [IfStmt] if (...) ...
14446+
# 1908| getCondition(): [LTExpr] ... < ...
14447+
# 1908| Type = [BoolType] bool
14448+
# 1908| ValueCategory = prvalue
14449+
# 1908| getLesserOperand(): [VariableAccess] x
14450+
# 1908| Type = [IntType] int
14451+
# 1908| ValueCategory = prvalue(load)
14452+
# 1908| getGreaterOperand(): [Literal] 10
14453+
# 1908| Type = [IntType] int
14454+
# 1908| Value = [Literal] 10
14455+
# 1908| ValueCategory = prvalue
14456+
# 1908| getThen(): [BlockStmt] { ... }
14457+
# 1909| getStmt(0): [ExprStmt] ExprStmt
14458+
# 1909| getExpr(): [FunctionCall] call to noreturnFunc
14459+
# 1909| Type = [VoidType] void
14460+
# 1909| ValueCategory = prvalue
14461+
# 1911| getStmt(1): [ReturnStmt] return ...
14462+
# 1911| getExpr(): [VariableAccess] x
14463+
# 1911| Type = [IntType] int
14464+
# 1911| ValueCategory = prvalue(load)
1441114465
perf-regression.cpp:
1441214466
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
1441314467
# 4| <params>:

0 commit comments

Comments
 (0)