[analyzer] Mark symbol values as dead in the environment.
This allows us to properly remove dead bindings at the end of the top-level stack frame, using the ReturnStmt, if there is one, to keep the return value live. This in turn removes the need for a check::EndPath callback in leak checkers. This does cause some changes in the path notes for leak checkers. Previously, a leak would be reported at the location of the closing brace in a function. Now, it gets reported at the last statement. This matches the way leaks are currently reported for inlined functions, but is less than ideal for both. llvm-svn: 168066
This commit is contained in:
parent
38990beed8
commit
b5b0fc196e
|
@ -154,26 +154,33 @@ public:
|
|||
const ExplodedGraph& getGraph() const { return G; }
|
||||
|
||||
/// \brief Run the analyzer's garbage collection - remove dead symbols and
|
||||
/// bindings.
|
||||
/// bindings from the state.
|
||||
///
|
||||
/// \param Node - The predecessor node, from which the processing should
|
||||
/// start.
|
||||
/// \param Out - The returned set of output nodes.
|
||||
/// \param ReferenceStmt - Run garbage collection using the symbols,
|
||||
/// which are live before the given statement.
|
||||
/// \param LC - The location context of the ReferenceStmt.
|
||||
/// \param DiagnosticStmt - the statement used to associate the diagnostic
|
||||
/// message, if any warnings should occur while removing the dead (leaks
|
||||
/// are usually reported here).
|
||||
/// \param K - In some cases it is possible to use PreStmt kind. (Do
|
||||
/// not use it unless you know what you are doing.)
|
||||
/// If the ReferenceStmt is NULL, everything is this and parent contexts is
|
||||
/// considered live.
|
||||
/// If the stack frame context is NULL, everything on stack is considered
|
||||
/// dead.
|
||||
/// Checkers can participate in this process with two callbacks:
|
||||
/// \c checkLiveSymbols and \c checkDeadSymbols. See the CheckerDocumentation
|
||||
/// class for more information.
|
||||
///
|
||||
/// \param Node The predecessor node, from which the processing should start.
|
||||
/// \param Out The returned set of output nodes.
|
||||
/// \param ReferenceStmt The statement which is about to be processed.
|
||||
/// Everything needed for this statement should be considered live.
|
||||
/// A null statement means that everything in child LocationContexts
|
||||
/// is dead.
|
||||
/// \param LC The location context of the \p ReferenceStmt. A null location
|
||||
/// context means that we have reached the end of analysis and that
|
||||
/// all statements and local variables should be considered dead.
|
||||
/// \param DiagnosticStmt Used as a location for any warnings that should
|
||||
/// occur while removing the dead (e.g. leaks). By default, the
|
||||
/// \p ReferenceStmt is used.
|
||||
/// \param K Denotes whether this is a pre- or post-statement purge. This
|
||||
/// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an
|
||||
/// entire location context is being cleared, in which case the
|
||||
/// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise,
|
||||
/// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default)
|
||||
/// and \p ReferenceStmt must be valid (non-null).
|
||||
void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
|
||||
const Stmt *ReferenceStmt, const StackFrameContext *LC,
|
||||
const Stmt *DiagnosticStmt,
|
||||
const Stmt *ReferenceStmt, const LocationContext *LC,
|
||||
const Stmt *DiagnosticStmt = 0,
|
||||
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
|
||||
|
||||
/// processCFGElement - Called by CoreEngine. Used to generate new successor
|
||||
|
|
|
@ -241,6 +241,10 @@ EnvironmentManager::removeDeadBindings(Environment Env,
|
|||
// Mark all symbols in the block expr's value live.
|
||||
RSScaner.scan(X);
|
||||
continue;
|
||||
} else {
|
||||
SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
|
||||
for (; SI != SE; ++SI)
|
||||
SymReaper.maybeDead(*SI);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -268,22 +268,39 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
|
|||
|
||||
void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
|
||||
const Stmt *ReferenceStmt,
|
||||
const StackFrameContext *LC,
|
||||
const LocationContext *LC,
|
||||
const Stmt *DiagnosticStmt,
|
||||
ProgramPoint::Kind K) {
|
||||
assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
|
||||
ReferenceStmt == 0)
|
||||
ReferenceStmt == 0 || isa<ReturnStmt>(ReferenceStmt))
|
||||
&& "PostStmt is not generally supported by the SymbolReaper yet");
|
||||
assert(LC && "Must pass the current (or expiring) LocationContext");
|
||||
|
||||
if (!DiagnosticStmt) {
|
||||
DiagnosticStmt = ReferenceStmt;
|
||||
assert(DiagnosticStmt && "Required for clearing a LocationContext");
|
||||
}
|
||||
|
||||
NumRemoveDeadBindings++;
|
||||
CleanedState = Pred->getState();
|
||||
SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager());
|
||||
|
||||
// LC is the location context being destroyed, but SymbolReaper wants a
|
||||
// location context that is still live. (If this is the top-level stack
|
||||
// frame, this will be null.)
|
||||
if (!ReferenceStmt) {
|
||||
assert(K == ProgramPoint::PostStmtPurgeDeadSymbolsKind &&
|
||||
"Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext");
|
||||
LC = LC->getParent();
|
||||
}
|
||||
|
||||
const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : 0;
|
||||
SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager());
|
||||
|
||||
getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
|
||||
|
||||
// Create a state in which dead bindings are removed from the environment
|
||||
// and the store. TODO: The function should just return new env and store,
|
||||
// not a new state.
|
||||
const StackFrameContext *SFC = LC->getCurrentStackFrame();
|
||||
CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
|
||||
|
||||
// Process any special transfer function for dead symbols.
|
||||
|
@ -345,8 +362,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
|
|||
EntryNode = Pred;
|
||||
ExplodedNodeSet CleanedStates;
|
||||
if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){
|
||||
removeDead(EntryNode, CleanedStates, currStmt,
|
||||
Pred->getStackFrame(), currStmt);
|
||||
removeDead(EntryNode, CleanedStates, currStmt, Pred->getLocationContext());
|
||||
} else
|
||||
CleanedStates.Add(EntryNode);
|
||||
|
||||
|
|
|
@ -168,27 +168,24 @@ static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
|
|||
void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
NodeBuilder Bldr(Pred, Dst, BC);
|
||||
|
||||
// Find the last statement in the function and the corresponding basic block.
|
||||
const Stmt *LastSt = 0;
|
||||
const CFGBlock *Blk = 0;
|
||||
llvm::tie(LastSt, Blk) = getLastStmt(Pred);
|
||||
if (!Blk || !LastSt) {
|
||||
Dst.Add(Pred);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the last statement is return, everything it references should stay live.
|
||||
if (isa<ReturnStmt>(LastSt))
|
||||
return;
|
||||
|
||||
// Here, we call the Symbol Reaper with 0 stack context telling it to clean up
|
||||
// everything on the stack. We use LastStmt as a diagnostic statement, with
|
||||
// which the PreStmtPurgeDead point will be associated.
|
||||
currBldrCtx = &BC;
|
||||
removeDead(Pred, Dst, 0, 0, LastSt,
|
||||
// which the program point will be associated. However, we only want to use
|
||||
// LastStmt as a reference for what to clean up if it's a ReturnStmt;
|
||||
// otherwise, everything is dead.
|
||||
SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC);
|
||||
removeDead(Pred, Dst, dyn_cast<ReturnStmt>(LastSt),
|
||||
Pred->getLocationContext(), LastSt,
|
||||
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
|
||||
currBldrCtx = 0;
|
||||
}
|
||||
|
||||
static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
|
||||
|
@ -290,11 +287,11 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
|
|||
|
||||
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
|
||||
currBldrCtx = &Ctx;
|
||||
// Here, we call the Symbol Reaper with 0 statement and caller location
|
||||
// Here, we call the Symbol Reaper with 0 statement and callee location
|
||||
// context, telling it to clean up everything in the callee's context
|
||||
// (and it's children). We use LastStmt as a diagnostic statement, which
|
||||
// which the PreStmtPurge Dead point will be associated.
|
||||
removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt,
|
||||
// (and its children). We use LastSt as a diagnostic statement, which
|
||||
// which the program point will be associated.
|
||||
removeDead(BindedRetNode, CleanedNodes, 0, calleeCtx, LastSt,
|
||||
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
|
||||
currBldrCtx = 0;
|
||||
} else {
|
||||
|
|
|
@ -517,13 +517,13 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>22</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>21</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>22</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>21</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
|
@ -534,8 +534,8 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>22</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>21</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <key>depth</key><integer>0</integer>
|
||||
|
@ -550,11 +550,11 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
|
||||
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK-NEXT: <key>issue_context</key><string>myArrayAllocation</string>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>22</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>21</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
@ -1301,13 +1301,13 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>46</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>45</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>46</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>45</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
|
@ -1318,8 +1318,8 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>46</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>45</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <key>depth</key><integer>0</integer>
|
||||
|
@ -1334,11 +1334,11 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
|
||||
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK-NEXT: <key>issue_context</key><string>test_wrapper</string>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>46</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>45</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
@ -2636,6 +2636,40 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>9</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>26</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>control</string>
|
||||
// CHECK-NEXT: <key>edges</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>start</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>9</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
@ -2648,13 +2682,13 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>87</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>87</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
|
@ -2665,8 +2699,8 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>87</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <key>depth</key><integer>0</integer>
|
||||
|
@ -2681,11 +2715,11 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
|
||||
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK-NEXT: <key>issue_context</key><string>use_ret</string>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>87</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>86</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
@ -4448,45 +4482,11 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <string>Returned allocated memory</string>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>control</string>
|
||||
// CHECK-NEXT: <key>edges</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>start</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>169</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>169</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>23</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>170</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>170</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>170</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>169</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <key>depth</key><integer>0</integer>
|
||||
|
@ -4501,11 +4501,11 @@ void use_function_with_leak7() {
|
|||
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
|
||||
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK-NEXT: <key>issue_context</key><string>use_function_with_leak7</string>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>170</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>169</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
|
|
@ -1030,6 +1030,11 @@ void *test(void *ptr) {
|
|||
return newPtr;
|
||||
}
|
||||
|
||||
|
||||
char *testLeakWithinReturn(char *str) {
|
||||
return strdup(strdup(str)); // expected-warning{{leak}}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// False negatives.
|
||||
|
||||
|
|
|
@ -1199,6 +1199,40 @@ void rdar8331641(int x) {
|
|||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>kind</key><string>control</string>
|
||||
// CHECK-NEXT: <key>edges</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>start</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>10</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
@ -1232,13 +1266,13 @@ void rdar8331641(int x) {
|
|||
// CHECK-NEXT: <key>end</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>58</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>58</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
|
@ -1249,10 +1283,25 @@ void rdar8331641(int x) {
|
|||
// CHECK-NEXT: <key>kind</key><string>event</string>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>58</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <key>ranges</key>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <array>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>14</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: </array>
|
||||
// CHECK-NEXT: <key>depth</key><integer>0</integer>
|
||||
// CHECK-NEXT: <key>extended_message</key>
|
||||
// CHECK-NEXT: <string>Object leaked: object allocated and stored into 'value' is not referenced later in this execution path and has a retain count of +1</string>
|
||||
|
@ -1265,11 +1314,11 @@ void rdar8331641(int x) {
|
|||
// CHECK-NEXT: <key>type</key><string>Leak</string>
|
||||
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
|
||||
// CHECK-NEXT: <key>issue_context</key><string>rdar8331641</string>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
|
||||
// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
|
||||
// CHECK-NEXT: <key>location</key>
|
||||
// CHECK-NEXT: <dict>
|
||||
// CHECK-NEXT: <key>line</key><integer>58</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>1</integer>
|
||||
// CHECK-NEXT: <key>line</key><integer>57</integer>
|
||||
// CHECK-NEXT: <key>col</key><integer>3</integer>
|
||||
// CHECK-NEXT: <key>file</key><integer>0</integer>
|
||||
// CHECK-NEXT: </dict>
|
||||
// CHECK-NEXT: </dict>
|
||||
|
|
Loading…
Reference in New Issue