Merge pull request #12982 from rdmarsh2/rdmarsh2/ir-guards-unreached

C++: Handle nonreturning functions in IR generation
This commit is contained in:
Jeroen Ketema
2023-05-03 23:20:46 +02:00
committed by GitHub
21 changed files with 542 additions and 35 deletions

View File

@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* 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.

View File

@@ -34,9 +34,13 @@ private module Cached {
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
exists(OldIR::Instruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
(
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
or
oldInstruction.getOpcode() instanceof Opcode::Unreached
)
)
}
@@ -366,21 +370,19 @@ private module Cached {
then
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
else
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
oldInstruction = getOldInstruction(instruction)
or
instruction = getChi(oldInstruction)
) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
}
cached

View File

@@ -19,6 +19,9 @@ newtype TInstruction =
) {
IRConstruction::Raw::hasInstruction(tag1, tag2)
} or
TRawUnreachedInstruction(IRFunctionBase irFunc) {
IRConstruction::hasUnreachedInstruction(irFunc)
} or
TUnaliasedSsaPhiInstruction(
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
) {

View File

@@ -178,9 +178,9 @@ module Raw {
}
}
class TStageInstruction = TRawInstruction;
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
predicate hasInstruction(TRawInstruction instr) { any() }
predicate hasInstruction(TStageInstruction instr) { any() }
predicate hasModeledMemoryResult(Instruction instruction) { none() }
@@ -368,6 +368,11 @@ private predicate isStrictlyForwardGoto(GotoStmt goto) {
Locatable getInstructionAst(TStageInstruction instr) {
result = getInstructionTranslatedElement(instr).getAst()
or
exists(IRFunction irFunc |
instr = TRawUnreachedInstruction(irFunc) and
result = irFunc.getFunction()
)
}
/** DEPRECATED: Alias for getInstructionAst */
@@ -377,14 +382,22 @@ deprecated Locatable getInstructionAST(TStageInstruction instr) {
CppType getInstructionResultType(TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
or
instr instanceof TRawUnreachedInstruction and
result = getVoidType()
}
predicate getInstructionOpcode(Opcode opcode, TStageInstruction instr) {
getInstructionTranslatedElement(instr).hasInstruction(opcode, getInstructionTag(instr), _)
or
instr instanceof TRawUnreachedInstruction and
opcode instanceof Opcode::Unreached
}
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
or
instr = TRawUnreachedInstruction(result)
}
Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) {
@@ -393,6 +406,16 @@ Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction
.getPrimaryInstructionForSideEffect(getInstructionTag(instruction))
}
predicate hasUnreachedInstruction(IRFunction func) {
exists(Call c |
c.getEnclosingFunction() = func.getFunction() and
any(Options opt).exits(c.getTarget())
) and
not exists(TranslatedUnreachableReturnStmt return |
return.getEnclosingFunction().getFunction() = func.getFunction()
)
}
import CachedForDebugging
cached

View File

@@ -34,6 +34,7 @@ newtype TInstructionTag =
CallTargetTag() or
CallTag() or
CallSideEffectTag() or
CallNoReturnTag() or
AllocationSizeTag() or
AllocationElementSizeTag() or
AllocationExtentConvertTag() or

View File

@@ -8,6 +8,7 @@ private import SideEffects
private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
private import DefaultOptions as DefaultOptions
/**
* Gets the `CallInstruction` from the `TranslatedCallExpr` for the specified expression.
@@ -66,7 +67,13 @@ abstract class TranslatedCall extends TranslatedExpr {
)
or
child = getSideEffects() and
result = getParent().getChildSuccessor(this)
if this.isNoReturn()
then
result =
any(UnreachedInstruction instr |
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
)
else result = this.getParent().getChildSuccessor(this)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -161,6 +168,8 @@ abstract class TranslatedCall extends TranslatedExpr {
*/
abstract predicate hasArguments();
predicate isNoReturn() { none() }
final TranslatedSideEffects getSideEffects() { result.getExpr() = expr }
}
@@ -266,6 +275,8 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedC
}
final override int getNumberOfArguments() { result = expr.getNumberOfArguments() }
final override predicate isNoReturn() { any(Options opt).exits(expr.getTarget()) }
}
/**

View File

@@ -7,6 +7,9 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge
)
or
instr.getSuccessor(kind) instanceof UnreachedInstruction and
kind instanceof GotoEdge
}
pragma[noinline]
@@ -41,7 +44,9 @@ class ReachableBlock extends IRBlockBase {
* An instruction that is contained in a reachable block.
*/
class ReachableInstruction extends Instruction {
ReachableInstruction() { this.getBlock() instanceof ReachableBlock }
ReachableInstruction() {
this.getBlock() instanceof ReachableBlock and not this instanceof UnreachedInstruction
}
}
module Graph {

View File

@@ -34,9 +34,13 @@ private module Cached {
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
exists(OldIR::Instruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
(
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
or
oldInstruction.getOpcode() instanceof Opcode::Unreached
)
)
}
@@ -366,21 +370,19 @@ private module Cached {
then
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
else
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
oldInstruction = getOldInstruction(instruction)
or
instruction = getChi(oldInstruction)
) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
}
cached

View File

@@ -7,6 +7,9 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge
)
or
instr.getSuccessor(kind) instanceof UnreachedInstruction and
kind instanceof GotoEdge
}
pragma[noinline]
@@ -41,7 +44,9 @@ class ReachableBlock extends IRBlockBase {
* An instruction that is contained in a reachable block.
*/
class ReachableInstruction extends Instruction {
ReachableInstruction() { this.getBlock() instanceof ReachableBlock }
ReachableInstruction() {
this.getBlock() instanceof ReachableBlock and not this instanceof UnreachedInstruction
}
}
module Graph {

View File

@@ -14408,6 +14408,60 @@ ir.cpp:
# 1894| Conversion = [IntegralConversion] integral conversion
# 1894| Type = [IntType] int
# 1894| ValueCategory = prvalue
# 1897| [TopLevelFunction] void noreturnFunc()
# 1897| <params>:
# 1899| [TopLevelFunction] int noreturnTest(int)
# 1899| <params>:
# 1899| getParameter(0): [Parameter] x
# 1899| Type = [IntType] int
# 1899| getEntryPoint(): [BlockStmt] { ... }
# 1900| getStmt(0): [IfStmt] if (...) ...
# 1900| getCondition(): [LTExpr] ... < ...
# 1900| Type = [BoolType] bool
# 1900| ValueCategory = prvalue
# 1900| getLesserOperand(): [VariableAccess] x
# 1900| Type = [IntType] int
# 1900| ValueCategory = prvalue(load)
# 1900| getGreaterOperand(): [Literal] 10
# 1900| Type = [IntType] int
# 1900| Value = [Literal] 10
# 1900| ValueCategory = prvalue
# 1900| getThen(): [BlockStmt] { ... }
# 1901| getStmt(0): [ReturnStmt] return ...
# 1901| getExpr(): [VariableAccess] x
# 1901| Type = [IntType] int
# 1901| ValueCategory = prvalue(load)
# 1902| getElse(): [BlockStmt] { ... }
# 1903| getStmt(0): [ExprStmt] ExprStmt
# 1903| getExpr(): [FunctionCall] call to noreturnFunc
# 1903| Type = [VoidType] void
# 1903| ValueCategory = prvalue
# 1905| getStmt(1): [ReturnStmt] return ...
# 1907| [TopLevelFunction] int noreturnTest2(int)
# 1907| <params>:
# 1907| getParameter(0): [Parameter] x
# 1907| Type = [IntType] int
# 1907| getEntryPoint(): [BlockStmt] { ... }
# 1908| getStmt(0): [IfStmt] if (...) ...
# 1908| getCondition(): [LTExpr] ... < ...
# 1908| Type = [BoolType] bool
# 1908| ValueCategory = prvalue
# 1908| getLesserOperand(): [VariableAccess] x
# 1908| Type = [IntType] int
# 1908| ValueCategory = prvalue(load)
# 1908| getGreaterOperand(): [Literal] 10
# 1908| Type = [IntType] int
# 1908| Value = [Literal] 10
# 1908| ValueCategory = prvalue
# 1908| getThen(): [BlockStmt] { ... }
# 1909| getStmt(0): [ExprStmt] ExprStmt
# 1909| getExpr(): [FunctionCall] call to noreturnFunc
# 1909| Type = [VoidType] void
# 1909| ValueCategory = prvalue
# 1911| getStmt(1): [ReturnStmt] return ...
# 1911| getExpr(): [VariableAccess] x
# 1911| Type = [IntType] int
# 1911| ValueCategory = prvalue(load)
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -1894,4 +1894,21 @@ int test_global_template_int() {
return local_int + (int)local_char;
}
[[noreturn]] void noreturnFunc();
int noreturnTest(int x) {
if (x < 10) {
return x;
} else {
noreturnFunc();
}
}
int noreturnTest2(int x) {
if (x < 10) {
noreturnFunc();
}
return x;
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -8783,6 +8783,44 @@
| ir.cpp:1894:29:1894:38 | Address | &:r1894_4 |
| ir.cpp:1894:29:1894:38 | Load | m1893_4 |
| ir.cpp:1894:29:1894:38 | Unary | r1894_5 |
| ir.cpp:1899:5:1899:16 | Address | &:r1899_7 |
| ir.cpp:1899:5:1899:16 | ChiPartial | partial:m1899_3 |
| ir.cpp:1899:5:1899:16 | ChiTotal | total:m1899_2 |
| ir.cpp:1899:5:1899:16 | Load | m1901_4 |
| ir.cpp:1899:5:1899:16 | SideEffect | m1899_3 |
| ir.cpp:1899:22:1899:22 | Address | &:r1899_5 |
| ir.cpp:1900:9:1900:9 | Address | &:r1900_1 |
| ir.cpp:1900:9:1900:9 | Left | r1900_2 |
| ir.cpp:1900:9:1900:9 | Load | m1899_6 |
| ir.cpp:1900:9:1900:14 | Condition | r1900_4 |
| ir.cpp:1900:13:1900:14 | Right | r1900_3 |
| ir.cpp:1901:9:1901:17 | Address | &:r1901_1 |
| ir.cpp:1901:16:1901:16 | Address | &:r1901_2 |
| ir.cpp:1901:16:1901:16 | Load | m1899_6 |
| ir.cpp:1901:16:1901:16 | StoreValue | r1901_3 |
| ir.cpp:1903:9:1903:20 | CallTarget | func:r1903_1 |
| ir.cpp:1903:9:1903:20 | ChiPartial | partial:m1903_3 |
| ir.cpp:1903:9:1903:20 | ChiTotal | total:m1899_4 |
| ir.cpp:1903:9:1903:20 | SideEffect | ~m1899_4 |
| ir.cpp:1907:5:1907:17 | Address | &:r1907_8 |
| ir.cpp:1907:5:1907:17 | ChiPartial | partial:m1907_3 |
| ir.cpp:1907:5:1907:17 | ChiTotal | total:m1907_2 |
| ir.cpp:1907:5:1907:17 | Load | m1911_4 |
| ir.cpp:1907:5:1907:17 | SideEffect | m1907_3 |
| ir.cpp:1907:23:1907:23 | Address | &:r1907_5 |
| ir.cpp:1908:9:1908:9 | Address | &:r1908_1 |
| ir.cpp:1908:9:1908:9 | Left | r1908_2 |
| ir.cpp:1908:9:1908:9 | Load | m1907_6 |
| ir.cpp:1908:9:1908:14 | Condition | r1908_4 |
| ir.cpp:1908:13:1908:14 | Right | r1908_3 |
| ir.cpp:1909:9:1909:20 | CallTarget | func:r1909_1 |
| ir.cpp:1909:9:1909:20 | ChiPartial | partial:m1909_3 |
| ir.cpp:1909:9:1909:20 | ChiTotal | total:m1907_4 |
| ir.cpp:1909:9:1909:20 | SideEffect | ~m1907_4 |
| ir.cpp:1911:5:1911:13 | Address | &:r1911_1 |
| ir.cpp:1911:12:1911:12 | Address | &:r1911_2 |
| ir.cpp:1911:12:1911:12 | Load | m1907_6 |
| ir.cpp:1911:12:1911:12 | StoreValue | r1911_3 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -10105,6 +10105,68 @@ ir.cpp:
# 1891| v1891_6(void) = AliasedUse : ~m?
# 1891| v1891_7(void) = ExitFunction :
# 1899| int noreturnTest(int)
# 1899| Block 0
# 1899| v1899_1(void) = EnterFunction :
# 1899| mu1899_2(unknown) = AliasedDefinition :
# 1899| mu1899_3(unknown) = InitializeNonLocal :
# 1899| r1899_4(glval<int>) = VariableAddress[x] :
# 1899| mu1899_5(int) = InitializeParameter[x] : &:r1899_4
# 1900| r1900_1(glval<int>) = VariableAddress[x] :
# 1900| r1900_2(int) = Load[x] : &:r1900_1, ~m?
# 1900| r1900_3(int) = Constant[10] :
# 1900| r1900_4(bool) = CompareLT : r1900_2, r1900_3
# 1900| v1900_5(void) = ConditionalBranch : r1900_4
#-----| False -> Block 2
#-----| True -> Block 1
# 1901| Block 1
# 1901| r1901_1(glval<int>) = VariableAddress[#return] :
# 1901| r1901_2(glval<int>) = VariableAddress[x] :
# 1901| r1901_3(int) = Load[x] : &:r1901_2, ~m?
# 1901| mu1901_4(int) = Store[#return] : &:r1901_1, r1901_3
# 1899| r1899_6(glval<int>) = VariableAddress[#return] :
# 1899| v1899_7(void) = ReturnValue : &:r1899_6, ~m?
# 1899| v1899_8(void) = AliasedUse : ~m?
# 1899| v1899_9(void) = ExitFunction :
# 1903| Block 2
# 1903| r1903_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 1903| v1903_2(void) = Call[noreturnFunc] : func:r1903_1
# 1903| mu1903_3(unknown) = ^CallSideEffect : ~m?
# 1905| v1905_1(void) = Unreached :
# 1907| int noreturnTest2(int)
# 1907| Block 0
# 1907| v1907_1(void) = EnterFunction :
# 1907| mu1907_2(unknown) = AliasedDefinition :
# 1907| mu1907_3(unknown) = InitializeNonLocal :
# 1907| r1907_4(glval<int>) = VariableAddress[x] :
# 1907| mu1907_5(int) = InitializeParameter[x] : &:r1907_4
# 1908| r1908_1(glval<int>) = VariableAddress[x] :
# 1908| r1908_2(int) = Load[x] : &:r1908_1, ~m?
# 1908| r1908_3(int) = Constant[10] :
# 1908| r1908_4(bool) = CompareLT : r1908_2, r1908_3
# 1908| v1908_5(void) = ConditionalBranch : r1908_4
#-----| False -> Block 2
#-----| True -> Block 1
# 1909| Block 1
# 1909| r1909_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 1909| v1909_2(void) = Call[noreturnFunc] : func:r1909_1
# 1909| mu1909_3(unknown) = ^CallSideEffect : ~m?
# 1907| v1907_6(void) = Unreached :
# 1911| Block 2
# 1911| r1911_1(glval<int>) = VariableAddress[#return] :
# 1911| r1911_2(glval<int>) = VariableAddress[x] :
# 1911| r1911_3(int) = Load[x] : &:r1911_2, ~m?
# 1911| mu1911_4(int) = Store[#return] : &:r1911_1, r1911_3
# 1907| r1907_7(glval<int>) = VariableAddress[#return] :
# 1907| v1907_8(void) = ReturnValue : &:r1907_7, ~m?
# 1907| v1907_9(void) = AliasedUse : ~m?
# 1907| v1907_10(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -2091,3 +2091,69 @@ ssa.cpp:
# 417| v417_5(void) = ReturnVoid :
# 417| v417_6(void) = AliasedUse : m417_3
# 417| v417_7(void) = ExitFunction :
# 423| int noreturnTest(int)
# 423| Block 0
# 423| v423_1(void) = EnterFunction :
# 423| m423_2(unknown) = AliasedDefinition :
# 423| m423_3(unknown) = InitializeNonLocal :
# 423| m423_4(unknown) = Chi : total:m423_2, partial:m423_3
# 423| r423_5(glval<int>) = VariableAddress[x] :
# 423| m423_6(int) = InitializeParameter[x] : &:r423_5
# 424| r424_1(glval<int>) = VariableAddress[x] :
# 424| r424_2(int) = Load[x] : &:r424_1, m423_6
# 424| r424_3(int) = Constant[10] :
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
# 424| v424_5(void) = ConditionalBranch : r424_4
#-----| False -> Block 2
#-----| True -> Block 1
# 425| Block 1
# 425| r425_1(glval<int>) = VariableAddress[#return] :
# 425| r425_2(glval<int>) = VariableAddress[x] :
# 425| r425_3(int) = Load[x] : &:r425_2, m423_6
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
# 423| r423_7(glval<int>) = VariableAddress[#return] :
# 423| v423_8(void) = ReturnValue : &:r423_7, m425_4
# 423| v423_9(void) = AliasedUse : m423_3
# 423| v423_10(void) = ExitFunction :
# 427| Block 2
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
# 427| m427_3(unknown) = ^CallSideEffect : ~m423_4
# 427| m427_4(unknown) = Chi : total:m423_4, partial:m427_3
# 423| v423_11(void) = Unreached :
# 431| int noreturnTest2(int)
# 431| Block 0
# 431| v431_1(void) = EnterFunction :
# 431| m431_2(unknown) = AliasedDefinition :
# 431| m431_3(unknown) = InitializeNonLocal :
# 431| m431_4(unknown) = Chi : total:m431_2, partial:m431_3
# 431| r431_5(glval<int>) = VariableAddress[x] :
# 431| m431_6(int) = InitializeParameter[x] : &:r431_5
# 432| r432_1(glval<int>) = VariableAddress[x] :
# 432| r432_2(int) = Load[x] : &:r432_1, m431_6
# 432| r432_3(int) = Constant[10] :
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
# 432| v432_5(void) = ConditionalBranch : r432_4
#-----| False -> Block 2
#-----| True -> Block 1
# 433| Block 1
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
# 433| m433_3(unknown) = ^CallSideEffect : ~m431_4
# 433| m433_4(unknown) = Chi : total:m431_4, partial:m433_3
# 431| v431_7(void) = Unreached :
# 435| Block 2
# 435| r435_1(glval<int>) = VariableAddress[#return] :
# 435| r435_2(glval<int>) = VariableAddress[x] :
# 435| r435_3(int) = Load[x] : &:r435_2, m431_6
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
# 431| r431_8(glval<int>) = VariableAddress[#return] :
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
# 431| v431_10(void) = AliasedUse : m431_3
# 431| v431_11(void) = ExitFunction :

View File

@@ -2080,3 +2080,69 @@ ssa.cpp:
# 417| v417_5(void) = ReturnVoid :
# 417| v417_6(void) = AliasedUse : m417_3
# 417| v417_7(void) = ExitFunction :
# 423| int noreturnTest(int)
# 423| Block 0
# 423| v423_1(void) = EnterFunction :
# 423| m423_2(unknown) = AliasedDefinition :
# 423| m423_3(unknown) = InitializeNonLocal :
# 423| m423_4(unknown) = Chi : total:m423_2, partial:m423_3
# 423| r423_5(glval<int>) = VariableAddress[x] :
# 423| m423_6(int) = InitializeParameter[x] : &:r423_5
# 424| r424_1(glval<int>) = VariableAddress[x] :
# 424| r424_2(int) = Load[x] : &:r424_1, m423_6
# 424| r424_3(int) = Constant[10] :
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
# 424| v424_5(void) = ConditionalBranch : r424_4
#-----| False -> Block 2
#-----| True -> Block 1
# 425| Block 1
# 425| r425_1(glval<int>) = VariableAddress[#return] :
# 425| r425_2(glval<int>) = VariableAddress[x] :
# 425| r425_3(int) = Load[x] : &:r425_2, m423_6
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
# 423| r423_7(glval<int>) = VariableAddress[#return] :
# 423| v423_8(void) = ReturnValue : &:r423_7, m425_4
# 423| v423_9(void) = AliasedUse : m423_3
# 423| v423_10(void) = ExitFunction :
# 427| Block 2
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
# 427| m427_3(unknown) = ^CallSideEffect : ~m423_4
# 427| m427_4(unknown) = Chi : total:m423_4, partial:m427_3
# 423| v423_11(void) = Unreached :
# 431| int noreturnTest2(int)
# 431| Block 0
# 431| v431_1(void) = EnterFunction :
# 431| m431_2(unknown) = AliasedDefinition :
# 431| m431_3(unknown) = InitializeNonLocal :
# 431| m431_4(unknown) = Chi : total:m431_2, partial:m431_3
# 431| r431_5(glval<int>) = VariableAddress[x] :
# 431| m431_6(int) = InitializeParameter[x] : &:r431_5
# 432| r432_1(glval<int>) = VariableAddress[x] :
# 432| r432_2(int) = Load[x] : &:r432_1, m431_6
# 432| r432_3(int) = Constant[10] :
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
# 432| v432_5(void) = ConditionalBranch : r432_4
#-----| False -> Block 2
#-----| True -> Block 1
# 433| Block 1
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
# 433| m433_3(unknown) = ^CallSideEffect : ~m431_4
# 433| m433_4(unknown) = Chi : total:m431_4, partial:m433_3
# 431| v431_7(void) = Unreached :
# 435| Block 2
# 435| r435_1(glval<int>) = VariableAddress[#return] :
# 435| r435_2(glval<int>) = VariableAddress[x] :
# 435| r435_3(int) = Load[x] : &:r435_2, m431_6
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
# 431| r431_8(glval<int>) = VariableAddress[#return] :
# 431| v431_9(void) = ReturnValue : &:r431_8, m435_4
# 431| v431_10(void) = AliasedUse : m431_3
# 431| v431_11(void) = ExitFunction :

View File

@@ -417,3 +417,20 @@ void vla(int n1, int n2, int n3, bool b1) {
void nested_array_designators() {
int x[1][2] = {[0][0] = 1234, [0][1] = 5678};
}
[[noreturn]] void noreturnFunc();
int noreturnTest(int x) {
if (x < 10) {
return x;
} else {
noreturnFunc();
}
}
int noreturnTest2(int x) {
if (x < 10) {
noreturnFunc();
}
return x;
}

View File

@@ -1940,3 +1940,65 @@ ssa.cpp:
# 417| v417_4(void) = ReturnVoid :
# 417| v417_5(void) = AliasedUse : ~m?
# 417| v417_6(void) = ExitFunction :
# 423| int noreturnTest(int)
# 423| Block 0
# 423| v423_1(void) = EnterFunction :
# 423| mu423_2(unknown) = AliasedDefinition :
# 423| mu423_3(unknown) = InitializeNonLocal :
# 423| r423_4(glval<int>) = VariableAddress[x] :
# 423| m423_5(int) = InitializeParameter[x] : &:r423_4
# 424| r424_1(glval<int>) = VariableAddress[x] :
# 424| r424_2(int) = Load[x] : &:r424_1, m423_5
# 424| r424_3(int) = Constant[10] :
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
# 424| v424_5(void) = ConditionalBranch : r424_4
#-----| False -> Block 2
#-----| True -> Block 1
# 425| Block 1
# 425| r425_1(glval<int>) = VariableAddress[#return] :
# 425| r425_2(glval<int>) = VariableAddress[x] :
# 425| r425_3(int) = Load[x] : &:r425_2, m423_5
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
# 423| r423_6(glval<int>) = VariableAddress[#return] :
# 423| v423_7(void) = ReturnValue : &:r423_6, m425_4
# 423| v423_8(void) = AliasedUse : ~m?
# 423| v423_9(void) = ExitFunction :
# 427| Block 2
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
# 427| mu427_3(unknown) = ^CallSideEffect : ~m?
# 423| v423_10(void) = Unreached :
# 431| int noreturnTest2(int)
# 431| Block 0
# 431| v431_1(void) = EnterFunction :
# 431| mu431_2(unknown) = AliasedDefinition :
# 431| mu431_3(unknown) = InitializeNonLocal :
# 431| r431_4(glval<int>) = VariableAddress[x] :
# 431| m431_5(int) = InitializeParameter[x] : &:r431_4
# 432| r432_1(glval<int>) = VariableAddress[x] :
# 432| r432_2(int) = Load[x] : &:r432_1, m431_5
# 432| r432_3(int) = Constant[10] :
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
# 432| v432_5(void) = ConditionalBranch : r432_4
#-----| False -> Block 2
#-----| True -> Block 1
# 433| Block 1
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
# 433| mu433_3(unknown) = ^CallSideEffect : ~m?
# 431| v431_6(void) = Unreached :
# 435| Block 2
# 435| r435_1(glval<int>) = VariableAddress[#return] :
# 435| r435_2(glval<int>) = VariableAddress[x] :
# 435| r435_3(int) = Load[x] : &:r435_2, m431_5
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
# 431| r431_7(glval<int>) = VariableAddress[#return] :
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
# 431| v431_9(void) = AliasedUse : ~m?
# 431| v431_10(void) = ExitFunction :

View File

@@ -1940,3 +1940,65 @@ ssa.cpp:
# 417| v417_4(void) = ReturnVoid :
# 417| v417_5(void) = AliasedUse : ~m?
# 417| v417_6(void) = ExitFunction :
# 423| int noreturnTest(int)
# 423| Block 0
# 423| v423_1(void) = EnterFunction :
# 423| mu423_2(unknown) = AliasedDefinition :
# 423| mu423_3(unknown) = InitializeNonLocal :
# 423| r423_4(glval<int>) = VariableAddress[x] :
# 423| m423_5(int) = InitializeParameter[x] : &:r423_4
# 424| r424_1(glval<int>) = VariableAddress[x] :
# 424| r424_2(int) = Load[x] : &:r424_1, m423_5
# 424| r424_3(int) = Constant[10] :
# 424| r424_4(bool) = CompareLT : r424_2, r424_3
# 424| v424_5(void) = ConditionalBranch : r424_4
#-----| False -> Block 2
#-----| True -> Block 1
# 425| Block 1
# 425| r425_1(glval<int>) = VariableAddress[#return] :
# 425| r425_2(glval<int>) = VariableAddress[x] :
# 425| r425_3(int) = Load[x] : &:r425_2, m423_5
# 425| m425_4(int) = Store[#return] : &:r425_1, r425_3
# 423| r423_6(glval<int>) = VariableAddress[#return] :
# 423| v423_7(void) = ReturnValue : &:r423_6, m425_4
# 423| v423_8(void) = AliasedUse : ~m?
# 423| v423_9(void) = ExitFunction :
# 427| Block 2
# 427| r427_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 427| v427_2(void) = Call[noreturnFunc] : func:r427_1
# 427| mu427_3(unknown) = ^CallSideEffect : ~m?
# 423| v423_10(void) = Unreached :
# 431| int noreturnTest2(int)
# 431| Block 0
# 431| v431_1(void) = EnterFunction :
# 431| mu431_2(unknown) = AliasedDefinition :
# 431| mu431_3(unknown) = InitializeNonLocal :
# 431| r431_4(glval<int>) = VariableAddress[x] :
# 431| m431_5(int) = InitializeParameter[x] : &:r431_4
# 432| r432_1(glval<int>) = VariableAddress[x] :
# 432| r432_2(int) = Load[x] : &:r432_1, m431_5
# 432| r432_3(int) = Constant[10] :
# 432| r432_4(bool) = CompareLT : r432_2, r432_3
# 432| v432_5(void) = ConditionalBranch : r432_4
#-----| False -> Block 2
#-----| True -> Block 1
# 433| Block 1
# 433| r433_1(glval<unknown>) = FunctionAddress[noreturnFunc] :
# 433| v433_2(void) = Call[noreturnFunc] : func:r433_1
# 433| mu433_3(unknown) = ^CallSideEffect : ~m?
# 431| v431_6(void) = Unreached :
# 435| Block 2
# 435| r435_1(glval<int>) = VariableAddress[#return] :
# 435| r435_2(glval<int>) = VariableAddress[x] :
# 435| r435_3(int) = Load[x] : &:r435_2, m431_5
# 435| m435_4(int) = Store[#return] : &:r435_1, r435_3
# 431| r431_7(glval<int>) = VariableAddress[#return] :
# 431| v431_8(void) = ReturnValue : &:r431_7, m435_4
# 431| v431_9(void) = AliasedUse : ~m?
# 431| v431_10(void) = ExitFunction :

View File

@@ -19,6 +19,9 @@ newtype TInstruction =
) {
IRConstruction::Raw::hasInstruction(tag1, tag2)
} or
TRawUnreachedInstruction(IRFunctionBase irFunc) {
IRConstruction::hasUnreachedInstruction(irFunc)
} or
TUnaliasedSsaPhiInstruction(
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
) {

View File

@@ -414,6 +414,8 @@ private module Cached {
}
}
predicate hasUnreachedInstruction(IRFunction func) { none() }
import CachedForDebugging
cached

View File

@@ -34,9 +34,13 @@ private module Cached {
cached
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
exists(OldInstruction oldInstruction |
exists(OldIR::Instruction oldInstruction |
irFunc = oldInstruction.getEnclosingIRFunction() and
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
(
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
or
oldInstruction.getOpcode() instanceof Opcode::Unreached
)
)
}
@@ -366,21 +370,19 @@ private module Cached {
then
result = getChi(getOldInstruction(instruction)) and
kind instanceof GotoEdge
else (
else
exists(OldInstruction oldInstruction |
oldInstruction = getOldInstruction(instruction) and
(
oldInstruction = getOldInstruction(instruction)
or
instruction = getChi(oldInstruction)
) and
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or
exists(OldInstruction oldInstruction |
instruction = getChi(oldInstruction) and
result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
}
cached