Merge pull request #14102 from alexet/alexet/remove-unreachable-ir

CPP: Remove sucessors of non-returning IR calls transitively.
This commit is contained in:
Mathias Vorreiter Pedersen
2023-09-09 14:48:26 +01:00
committed by GitHub
13 changed files with 13394 additions and 7 deletions

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
non-returning in the IR and dataflow.

View File

@@ -10,6 +10,65 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
or
instr.getSuccessor(kind) instanceof UnreachedInstruction and
kind instanceof GotoEdge
or
isCallToNonReturningFunction(instr) and exists(instr.getSuccessor(kind))
}
/**
* Holds if all calls to `f` never return (e.g. they call `exit` or loop forever)
*/
private predicate isNonReturningFunction(IRFunction f) {
// If the function has an instruction with a missing successor then
// the analysis is probably going to be incorrect, so assume they exit.
not hasInstructionWithMissingSuccessor(f) and
(
// If all flows to the exit block are pass through an unreachable then f never returns.
any(UnreachedInstruction instr).getBlock().postDominates(f.getEntryBlock())
or
// If there is no flow to the exit block then f never returns.
not exists(IRBlock entry, IRBlock exit |
exit = f.getExitFunctionInstruction().getBlock() and
entry = f.getEntryBlock() and
exit = entry.getASuccessor*()
)
or
// If all flows to the exit block are pass through a call that never returns then f never returns.
exists(CallInstruction ci |
ci.getBlock().postDominates(f.getEntryBlock()) and
isCallToNonReturningFunction(ci)
)
)
}
/**
* Holds if `f` has an instruction with a missing successor.
* This matches `instructionWithoutSuccessor` from `IRConsistency`, but
* avoids generating the error strings.
*/
predicate hasInstructionWithMissingSuccessor(IRFunction f) {
exists(Instruction missingSucc |
missingSucc.getEnclosingIRFunction() = f and
not exists(missingSucc.getASuccessor()) and
not missingSucc instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not missingSucc instanceof PhiInstruction and
not missingSucc instanceof UnreachedInstruction
)
}
/**
* Holds if the call `ci` never returns.
*/
private predicate isCallToNonReturningFunction(CallInstruction ci) {
exists(IRFunction callee, Language::Function staticTarget |
staticTarget = ci.getStaticCallTarget() and
staticTarget = callee.getFunction() and
// We can't easily tell if the call is virtual or not
// if the callee is virtual. So assume that the call is virtual
// if the target is.
not staticTarget.isVirtual() and
isNonReturningFunction(callee)
)
}
pragma[noinline]

View File

@@ -1,2 +1,3 @@
import semmle.code.cpp.ir.implementation.raw.IR as IR
import semmle.code.cpp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

@@ -10,6 +10,65 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
or
instr.getSuccessor(kind) instanceof UnreachedInstruction and
kind instanceof GotoEdge
or
isCallToNonReturningFunction(instr) and exists(instr.getSuccessor(kind))
}
/**
* Holds if all calls to `f` never return (e.g. they call `exit` or loop forever)
*/
private predicate isNonReturningFunction(IRFunction f) {
// If the function has an instruction with a missing successor then
// the analysis is probably going to be incorrect, so assume they exit.
not hasInstructionWithMissingSuccessor(f) and
(
// If all flows to the exit block are pass through an unreachable then f never returns.
any(UnreachedInstruction instr).getBlock().postDominates(f.getEntryBlock())
or
// If there is no flow to the exit block then f never returns.
not exists(IRBlock entry, IRBlock exit |
exit = f.getExitFunctionInstruction().getBlock() and
entry = f.getEntryBlock() and
exit = entry.getASuccessor*()
)
or
// If all flows to the exit block are pass through a call that never returns then f never returns.
exists(CallInstruction ci |
ci.getBlock().postDominates(f.getEntryBlock()) and
isCallToNonReturningFunction(ci)
)
)
}
/**
* Holds if `f` has an instruction with a missing successor.
* This matches `instructionWithoutSuccessor` from `IRConsistency`, but
* avoids generating the error strings.
*/
predicate hasInstructionWithMissingSuccessor(IRFunction f) {
exists(Instruction missingSucc |
missingSucc.getEnclosingIRFunction() = f and
not exists(missingSucc.getASuccessor()) and
not missingSucc instanceof ExitFunctionInstruction and
// Phi instructions aren't linked into the instruction-level flow graph.
not missingSucc instanceof PhiInstruction and
not missingSucc instanceof UnreachedInstruction
)
}
/**
* Holds if the call `ci` never returns.
*/
private predicate isCallToNonReturningFunction(CallInstruction ci) {
exists(IRFunction callee, Language::Function staticTarget |
staticTarget = ci.getStaticCallTarget() and
staticTarget = callee.getFunction() and
// We can't easily tell if the call is virtual or not
// if the callee is virtual. So assume that the call is virtual
// if the target is.
not staticTarget.isVirtual() and
isNonReturningFunction(callee)
)
}
pragma[noinline]

View File

@@ -1,2 +1,3 @@
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
import semmle.code.cpp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
in cases where a non-returning function is called.

View File

@@ -15740,6 +15740,112 @@ ir.cpp:
# 2072| Value = [VariableAccess] 116
# 2072| ValueCategory = prvalue(load)
# 2073| getStmt(2): [ReturnStmt] return ...
# 2075| [TopLevelFunction] void exit(int)
# 2075| <params>:
# 2075| getParameter(0): [Parameter] code
# 2075| Type = [IntType] int
# 2077| [TopLevelFunction] int NonExit()
# 2077| <params>:
# 2077| getEntryPoint(): [BlockStmt] { ... }
# 2078| getStmt(0): [DeclStmt] declaration
# 2078| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2078| Type = [IntType] int
# 2078| getVariable().getInitializer(): [Initializer] initializer for x
# 2078| getExpr(): [FunctionCall] call to Add
# 2078| Type = [IntType] int
# 2078| ValueCategory = prvalue
# 2078| getArgument(0): [Literal] 3
# 2078| Type = [IntType] int
# 2078| Value = [Literal] 3
# 2078| ValueCategory = prvalue
# 2078| getArgument(1): [Literal] 4
# 2078| Type = [IntType] int
# 2078| Value = [Literal] 4
# 2078| ValueCategory = prvalue
# 2079| getStmt(1): [IfStmt] if (...) ...
# 2079| getCondition(): [EQExpr] ... == ...
# 2079| Type = [BoolType] bool
# 2079| ValueCategory = prvalue
# 2079| getLeftOperand(): [VariableAccess] x
# 2079| Type = [IntType] int
# 2079| ValueCategory = prvalue(load)
# 2079| getRightOperand(): [Literal] 7
# 2079| Type = [IntType] int
# 2079| Value = [Literal] 7
# 2079| ValueCategory = prvalue
# 2080| getThen(): [ExprStmt] ExprStmt
# 2080| getExpr(): [FunctionCall] call to exit
# 2080| Type = [VoidType] void
# 2080| ValueCategory = prvalue
# 2080| getArgument(0): [Literal] 3
# 2080| Type = [IntType] int
# 2080| Value = [Literal] 3
# 2080| ValueCategory = prvalue
# 2081| getStmt(2): [ExprStmt] ExprStmt
# 2081| getExpr(): [FunctionCall] call to VoidFunc
# 2081| Type = [VoidType] void
# 2081| ValueCategory = prvalue
# 2082| getStmt(3): [ReturnStmt] return ...
# 2082| getExpr(): [VariableAccess] x
# 2082| Type = [IntType] int
# 2082| ValueCategory = prvalue(load)
# 2085| [TopLevelFunction] void CallsNonExit()
# 2085| <params>:
# 2085| getEntryPoint(): [BlockStmt] { ... }
# 2086| getStmt(0): [ExprStmt] ExprStmt
# 2086| getExpr(): [FunctionCall] call to VoidFunc
# 2086| Type = [VoidType] void
# 2086| ValueCategory = prvalue
# 2087| getStmt(1): [ExprStmt] ExprStmt
# 2087| getExpr(): [FunctionCall] call to exit
# 2087| Type = [VoidType] void
# 2087| ValueCategory = prvalue
# 2087| getArgument(0): [Literal] 3
# 2087| Type = [IntType] int
# 2087| Value = [Literal] 3
# 2087| ValueCategory = prvalue
# 2088| getStmt(2): [ReturnStmt] return ...
# 2090| [TopLevelFunction] int TransNonExit()
# 2090| <params>:
# 2090| getEntryPoint(): [BlockStmt] { ... }
# 2091| getStmt(0): [DeclStmt] declaration
# 2091| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 2091| Type = [IntType] int
# 2091| getVariable().getInitializer(): [Initializer] initializer for x
# 2091| getExpr(): [FunctionCall] call to Add
# 2091| Type = [IntType] int
# 2091| ValueCategory = prvalue
# 2091| getArgument(0): [Literal] 3
# 2091| Type = [IntType] int
# 2091| Value = [Literal] 3
# 2091| ValueCategory = prvalue
# 2091| getArgument(1): [Literal] 4
# 2091| Type = [IntType] int
# 2091| Value = [Literal] 4
# 2091| ValueCategory = prvalue
# 2092| getStmt(1): [IfStmt] if (...) ...
# 2092| getCondition(): [EQExpr] ... == ...
# 2092| Type = [BoolType] bool
# 2092| ValueCategory = prvalue
# 2092| getLeftOperand(): [VariableAccess] x
# 2092| Type = [IntType] int
# 2092| ValueCategory = prvalue(load)
# 2092| getRightOperand(): [Literal] 7
# 2092| Type = [IntType] int
# 2092| Value = [Literal] 7
# 2092| ValueCategory = prvalue
# 2093| getThen(): [ExprStmt] ExprStmt
# 2093| getExpr(): [FunctionCall] call to CallsNonExit
# 2093| Type = [VoidType] void
# 2093| ValueCategory = prvalue
# 2094| getStmt(2): [ExprStmt] ExprStmt
# 2094| getExpr(): [FunctionCall] call to VoidFunc
# 2094| Type = [VoidType] void
# 2094| ValueCategory = prvalue
# 2095| getStmt(3): [ReturnStmt] return ...
# 2095| getExpr(): [VariableAccess] x
# 2095| Type = [IntType] int
# 2095| ValueCategory = prvalue(load)
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
/**
* @kind graph
*/
private import cpp
private import semmle.code.cpp.ir.implementation.aliased_ssa.PrintIR
private import PrintConfig
private class PrintConfig extends PrintIRConfiguration {
override predicate shouldPrintDeclaration(Declaration decl) { shouldDumpDeclaration(decl) }
}

View File

@@ -2072,4 +2072,27 @@ void test_constant_folding() {
test_constant_folding_use(x);
}
void exit(int code);
int NonExit() {
int x = Add(3,4);
if (x == 7)
exit(3);
VoidFunc();
return x;
}
void CallsNonExit() {
VoidFunc();
exit(3);
}
int TransNonExit() {
int x = Add(3,4);
if (x == 7)
CallsNonExit();
VoidFunc();
return x;
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -9827,6 +9827,75 @@
| ir.cpp:2072:3:2072:27 | ChiTotal | total:m2070_4 |
| ir.cpp:2072:3:2072:27 | SideEffect | ~m2070_4 |
| ir.cpp:2072:29:2072:29 | Arg(0) | 0:r2072_2 |
| ir.cpp:2077:5:2077:11 | Address | &:r2077_6 |
| ir.cpp:2077:5:2077:11 | ChiPartial | partial:m2077_3 |
| ir.cpp:2077:5:2077:11 | ChiTotal | total:m2077_2 |
| ir.cpp:2077:5:2077:11 | Load | m2082_4 |
| ir.cpp:2077:5:2077:11 | SideEffect | ~m2081_4 |
| ir.cpp:2078:9:2078:9 | Address | &:r2078_1 |
| ir.cpp:2078:13:2078:15 | CallTarget | func:r2078_2 |
| ir.cpp:2078:13:2078:15 | ChiPartial | partial:m2078_6 |
| ir.cpp:2078:13:2078:15 | ChiTotal | total:m2077_4 |
| ir.cpp:2078:13:2078:15 | SideEffect | ~m2077_4 |
| ir.cpp:2078:13:2078:15 | StoreValue | r2078_5 |
| ir.cpp:2078:17:2078:17 | Arg(0) | 0:r2078_3 |
| ir.cpp:2078:19:2078:19 | Arg(1) | 1:r2078_4 |
| ir.cpp:2079:9:2079:9 | Address | &:r2079_1 |
| ir.cpp:2079:9:2079:9 | Left | r2079_2 |
| ir.cpp:2079:9:2079:9 | Load | m2078_8 |
| ir.cpp:2079:9:2079:14 | Condition | r2079_4 |
| ir.cpp:2079:14:2079:14 | Right | r2079_3 |
| ir.cpp:2080:9:2080:12 | CallTarget | func:r2080_1 |
| ir.cpp:2080:9:2080:12 | ChiPartial | partial:m2080_4 |
| ir.cpp:2080:9:2080:12 | ChiTotal | total:m2078_7 |
| ir.cpp:2080:9:2080:12 | SideEffect | ~m2078_7 |
| ir.cpp:2080:14:2080:14 | Arg(0) | 0:r2080_2 |
| ir.cpp:2081:5:2081:12 | CallTarget | func:r2081_1 |
| ir.cpp:2081:5:2081:12 | ChiPartial | partial:m2081_3 |
| ir.cpp:2081:5:2081:12 | ChiTotal | total:m2078_7 |
| ir.cpp:2081:5:2081:12 | SideEffect | ~m2078_7 |
| ir.cpp:2082:5:2082:13 | Address | &:r2082_1 |
| ir.cpp:2082:12:2082:12 | Address | &:r2082_2 |
| ir.cpp:2082:12:2082:12 | Load | m2078_8 |
| ir.cpp:2082:12:2082:12 | StoreValue | r2082_3 |
| ir.cpp:2085:6:2085:17 | ChiPartial | partial:m2085_3 |
| ir.cpp:2085:6:2085:17 | ChiTotal | total:m2085_2 |
| ir.cpp:2086:5:2086:12 | CallTarget | func:r2086_1 |
| ir.cpp:2086:5:2086:12 | ChiPartial | partial:m2086_3 |
| ir.cpp:2086:5:2086:12 | ChiTotal | total:m2085_4 |
| ir.cpp:2086:5:2086:12 | SideEffect | ~m2085_4 |
| ir.cpp:2087:5:2087:8 | CallTarget | func:r2087_1 |
| ir.cpp:2087:5:2087:8 | ChiPartial | partial:m2087_4 |
| ir.cpp:2087:5:2087:8 | ChiTotal | total:m2086_4 |
| ir.cpp:2087:5:2087:8 | SideEffect | ~m2086_4 |
| ir.cpp:2087:10:2087:10 | Arg(0) | 0:r2087_2 |
| ir.cpp:2090:5:2090:16 | Address | &:r2090_6 |
| ir.cpp:2090:5:2090:16 | ChiPartial | partial:m2090_3 |
| ir.cpp:2090:5:2090:16 | ChiTotal | total:m2090_2 |
| ir.cpp:2090:5:2090:16 | Load | m2095_4 |
| ir.cpp:2090:5:2090:16 | SideEffect | ~m2094_4 |
| ir.cpp:2091:9:2091:9 | Address | &:r2091_1 |
| ir.cpp:2091:13:2091:15 | CallTarget | func:r2091_2 |
| ir.cpp:2091:13:2091:15 | ChiPartial | partial:m2091_6 |
| ir.cpp:2091:13:2091:15 | ChiTotal | total:m2090_4 |
| ir.cpp:2091:13:2091:15 | SideEffect | ~m2090_4 |
| ir.cpp:2091:13:2091:15 | StoreValue | r2091_5 |
| ir.cpp:2091:17:2091:17 | Arg(0) | 0:r2091_3 |
| ir.cpp:2091:19:2091:19 | Arg(1) | 1:r2091_4 |
| ir.cpp:2092:9:2092:9 | Address | &:r2092_1 |
| ir.cpp:2092:9:2092:9 | Left | r2092_2 |
| ir.cpp:2092:9:2092:9 | Load | m2091_8 |
| ir.cpp:2092:9:2092:14 | Condition | r2092_4 |
| ir.cpp:2092:14:2092:14 | Right | r2092_3 |
| ir.cpp:2093:9:2093:20 | CallTarget | func:r2093_1 |
| ir.cpp:2094:5:2094:12 | CallTarget | func:r2094_1 |
| ir.cpp:2094:5:2094:12 | ChiPartial | partial:m2094_3 |
| ir.cpp:2094:5:2094:12 | ChiTotal | total:m2091_7 |
| ir.cpp:2094:5:2094:12 | SideEffect | ~m2091_7 |
| ir.cpp:2095:5:2095:13 | Address | &:r2095_1 |
| ir.cpp:2095:12:2095:12 | Address | &:r2095_2 |
| ir.cpp:2095:12:2095:12 | Load | m2091_8 |
| ir.cpp:2095:12:2095:12 | StoreValue | r2095_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

@@ -11330,6 +11330,105 @@ ir.cpp:
# 2070| v2070_5(void) = AliasedUse : ~m?
# 2070| v2070_6(void) = ExitFunction :
# 2077| int NonExit()
# 2077| Block 0
# 2077| v2077_1(void) = EnterFunction :
# 2077| mu2077_2(unknown) = AliasedDefinition :
# 2077| mu2077_3(unknown) = InitializeNonLocal :
# 2078| r2078_1(glval<int>) = VariableAddress[x] :
# 2078| r2078_2(glval<unknown>) = FunctionAddress[Add] :
# 2078| r2078_3(int) = Constant[3] :
# 2078| r2078_4(int) = Constant[4] :
# 2078| r2078_5(int) = Call[Add] : func:r2078_2, 0:r2078_3, 1:r2078_4
# 2078| mu2078_6(unknown) = ^CallSideEffect : ~m?
# 2078| mu2078_7(int) = Store[x] : &:r2078_1, r2078_5
# 2079| r2079_1(glval<int>) = VariableAddress[x] :
# 2079| r2079_2(int) = Load[x] : &:r2079_1, ~m?
# 2079| r2079_3(int) = Constant[7] :
# 2079| r2079_4(bool) = CompareEQ : r2079_2, r2079_3
# 2079| v2079_5(void) = ConditionalBranch : r2079_4
#-----| False -> Block 2
#-----| True -> Block 1
# 2080| Block 1
# 2080| r2080_1(glval<unknown>) = FunctionAddress[exit] :
# 2080| r2080_2(int) = Constant[3] :
# 2080| v2080_3(void) = Call[exit] : func:r2080_1, 0:r2080_2
# 2080| mu2080_4(unknown) = ^CallSideEffect : ~m?
# 2077| v2077_4(void) = Unreached :
# 2081| Block 2
# 2081| r2081_1(glval<unknown>) = FunctionAddress[VoidFunc] :
# 2081| v2081_2(void) = Call[VoidFunc] : func:r2081_1
# 2081| mu2081_3(unknown) = ^CallSideEffect : ~m?
# 2082| r2082_1(glval<int>) = VariableAddress[#return] :
# 2082| r2082_2(glval<int>) = VariableAddress[x] :
# 2082| r2082_3(int) = Load[x] : &:r2082_2, ~m?
# 2082| mu2082_4(int) = Store[#return] : &:r2082_1, r2082_3
# 2077| r2077_5(glval<int>) = VariableAddress[#return] :
# 2077| v2077_6(void) = ReturnValue : &:r2077_5, ~m?
# 2077| v2077_7(void) = AliasedUse : ~m?
# 2077| v2077_8(void) = ExitFunction :
# 2085| void CallsNonExit()
# 2085| Block 0
# 2085| v2085_1(void) = EnterFunction :
# 2085| mu2085_2(unknown) = AliasedDefinition :
# 2085| mu2085_3(unknown) = InitializeNonLocal :
# 2086| r2086_1(glval<unknown>) = FunctionAddress[VoidFunc] :
# 2086| v2086_2(void) = Call[VoidFunc] : func:r2086_1
# 2086| mu2086_3(unknown) = ^CallSideEffect : ~m?
# 2087| r2087_1(glval<unknown>) = FunctionAddress[exit] :
# 2087| r2087_2(int) = Constant[3] :
# 2087| v2087_3(void) = Call[exit] : func:r2087_1, 0:r2087_2
# 2087| mu2087_4(unknown) = ^CallSideEffect : ~m?
# 2085| v2085_4(void) = Unreached :
# 2088| Block 1
# 2088| v2088_1(void) = NoOp :
# 2085| v2085_5(void) = ReturnVoid :
# 2085| v2085_6(void) = AliasedUse : ~m?
# 2085| v2085_7(void) = ExitFunction :
# 2090| int TransNonExit()
# 2090| Block 0
# 2090| v2090_1(void) = EnterFunction :
# 2090| mu2090_2(unknown) = AliasedDefinition :
# 2090| mu2090_3(unknown) = InitializeNonLocal :
# 2091| r2091_1(glval<int>) = VariableAddress[x] :
# 2091| r2091_2(glval<unknown>) = FunctionAddress[Add] :
# 2091| r2091_3(int) = Constant[3] :
# 2091| r2091_4(int) = Constant[4] :
# 2091| r2091_5(int) = Call[Add] : func:r2091_2, 0:r2091_3, 1:r2091_4
# 2091| mu2091_6(unknown) = ^CallSideEffect : ~m?
# 2091| mu2091_7(int) = Store[x] : &:r2091_1, r2091_5
# 2092| r2092_1(glval<int>) = VariableAddress[x] :
# 2092| r2092_2(int) = Load[x] : &:r2092_1, ~m?
# 2092| r2092_3(int) = Constant[7] :
# 2092| r2092_4(bool) = CompareEQ : r2092_2, r2092_3
# 2092| v2092_5(void) = ConditionalBranch : r2092_4
#-----| False -> Block 2
#-----| True -> Block 1
# 2093| Block 1
# 2093| r2093_1(glval<unknown>) = FunctionAddress[CallsNonExit] :
# 2093| v2093_2(void) = Call[CallsNonExit] : func:r2093_1
# 2093| mu2093_3(unknown) = ^CallSideEffect : ~m?
#-----| Goto -> Block 2
# 2094| Block 2
# 2094| r2094_1(glval<unknown>) = FunctionAddress[VoidFunc] :
# 2094| v2094_2(void) = Call[VoidFunc] : func:r2094_1
# 2094| mu2094_3(unknown) = ^CallSideEffect : ~m?
# 2095| r2095_1(glval<int>) = VariableAddress[#return] :
# 2095| r2095_2(glval<int>) = VariableAddress[x] :
# 2095| r2095_3(int) = Load[x] : &:r2095_2, ~m?
# 2095| mu2095_4(int) = Store[#return] : &:r2095_1, r2095_3
# 2090| r2090_4(glval<int>) = VariableAddress[#return] :
# 2090| v2090_5(void) = ReturnValue : &:r2090_4, ~m?
# 2090| v2090_6(void) = AliasedUse : ~m?
# 2090| v2090_7(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -9,8 +9,6 @@ edges
| test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data |
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
| test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data |
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
| test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data |
| test.cpp:164:9:164:9 | c | test.cpp:165:2:165:2 | c |
| test.cpp:164:9:164:9 | c | test.cpp:166:3:166:4 | * ... |
| test.cpp:164:9:164:9 | c | test.cpp:166:4:166:4 | c |
@@ -39,9 +37,6 @@ nodes
| test.cpp:127:7:127:10 | data | semmle.label | data |
| test.cpp:127:7:127:10 | data | semmle.label | data |
| test.cpp:130:6:130:9 | data | semmle.label | data |
| test.cpp:138:7:138:10 | data | semmle.label | data |
| test.cpp:138:7:138:10 | data | semmle.label | data |
| test.cpp:141:6:141:9 | data | semmle.label | data |
| test.cpp:164:9:164:9 | c | semmle.label | c |
| test.cpp:165:2:165:2 | c | semmle.label | c |
| test.cpp:166:3:166:4 | * ... | semmle.label | * ... |
@@ -72,8 +67,6 @@ subpaths
| test.cpp:119:6:119:9 | data | test.cpp:116:7:116:10 | data | test.cpp:119:6:119:9 | data | Memory may have been previously freed by $@. | test.cpp:116:2:116:5 | call to free | call to free |
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
| test.cpp:130:6:130:9 | data | test.cpp:127:7:127:10 | data | test.cpp:130:6:130:9 | data | Memory may have been previously freed by $@. | test.cpp:127:2:127:5 | call to free | call to free |
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
| test.cpp:141:6:141:9 | data | test.cpp:138:7:138:10 | data | test.cpp:141:6:141:9 | data | Memory may have been previously freed by $@. | test.cpp:138:2:138:5 | call to free | call to free |
| test.cpp:165:2:165:2 | c | test.cpp:164:9:164:9 | c | test.cpp:165:2:165:2 | c | Memory may have been previously freed by $@. | test.cpp:164:2:164:10 | delete | delete |
| test.cpp:166:3:166:4 | * ... | test.cpp:164:9:164:9 | c | test.cpp:166:3:166:4 | * ... | Memory may have been previously freed by $@. | test.cpp:164:2:164:10 | delete | delete |
| test.cpp:166:4:166:4 | c | test.cpp:164:9:164:9 | c | test.cpp:166:4:166:4 | c | Memory may have been previously freed by $@. | test.cpp:164:2:164:10 | delete | delete |