[analyzer][StackAddressEscape] Tie warnings to the diagnostic checkers rather then core.StackAddrEscapeBase
Differential Revision: https://reviews.llvm.org/D78101
This commit is contained in:
parent
ca5bff18fc
commit
3a6ee4fefe
|
@ -78,13 +78,16 @@ public:
|
||||||
const char *description)
|
const char *description)
|
||||||
: BugType(checker, name, categories::LogicError), desc(description) {}
|
: BugType(checker, name, categories::LogicError), desc(description) {}
|
||||||
|
|
||||||
|
BuiltinBug(class CheckerNameRef checker, const char *name)
|
||||||
|
: BugType(checker, name, categories::LogicError), desc(name) {}
|
||||||
|
|
||||||
BuiltinBug(const CheckerBase *checker, const char *name)
|
BuiltinBug(const CheckerBase *checker, const char *name)
|
||||||
: BugType(checker, name, categories::LogicError), desc(name) {}
|
: BugType(checker, name, categories::LogicError), desc(name) {}
|
||||||
|
|
||||||
StringRef getDescription() const { return desc; }
|
StringRef getDescription() const { return desc; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end ento namespace
|
} // namespace ento
|
||||||
|
|
||||||
} // end clang namespace
|
} // end clang namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,6 +43,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
DefaultBool ChecksEnabled[CK_NumCheckKinds];
|
DefaultBool ChecksEnabled[CK_NumCheckKinds];
|
||||||
|
CheckerNameRef CheckNames[CK_NumCheckKinds];
|
||||||
|
|
||||||
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
|
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
|
||||||
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
|
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
|
||||||
|
@ -156,7 +157,8 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C,
|
||||||
return;
|
return;
|
||||||
if (!BT_returnstack)
|
if (!BT_returnstack)
|
||||||
BT_returnstack = std::make_unique<BuiltinBug>(
|
BT_returnstack = std::make_unique<BuiltinBug>(
|
||||||
this, "Return of address to stack-allocated memory");
|
CheckNames[CK_StackAddrEscapeChecker],
|
||||||
|
"Return of address to stack-allocated memory");
|
||||||
// Generate a report for this bug.
|
// Generate a report for this bug.
|
||||||
SmallString<128> buf;
|
SmallString<128> buf;
|
||||||
llvm::raw_svector_ostream os(buf);
|
llvm::raw_svector_ostream os(buf);
|
||||||
|
@ -195,7 +197,8 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
|
||||||
continue;
|
continue;
|
||||||
if (!BT_capturedstackasync)
|
if (!BT_capturedstackasync)
|
||||||
BT_capturedstackasync = std::make_unique<BuiltinBug>(
|
BT_capturedstackasync = std::make_unique<BuiltinBug>(
|
||||||
this, "Address of stack-allocated memory is captured");
|
CheckNames[CK_StackAddrAsyncEscapeChecker],
|
||||||
|
"Address of stack-allocated memory is captured");
|
||||||
SmallString<128> Buf;
|
SmallString<128> Buf;
|
||||||
llvm::raw_svector_ostream Out(Buf);
|
llvm::raw_svector_ostream Out(Buf);
|
||||||
SourceRange Range = genName(Out, Region, C.getASTContext());
|
SourceRange Range = genName(Out, Region, C.getASTContext());
|
||||||
|
@ -218,7 +221,8 @@ void StackAddrEscapeChecker::checkReturnedBlockCaptures(
|
||||||
continue;
|
continue;
|
||||||
if (!BT_capturedstackret)
|
if (!BT_capturedstackret)
|
||||||
BT_capturedstackret = std::make_unique<BuiltinBug>(
|
BT_capturedstackret = std::make_unique<BuiltinBug>(
|
||||||
this, "Address of stack-allocated memory is captured");
|
CheckNames[CK_StackAddrEscapeChecker],
|
||||||
|
"Address of stack-allocated memory is captured");
|
||||||
SmallString<128> Buf;
|
SmallString<128> Buf;
|
||||||
llvm::raw_svector_ostream Out(Buf);
|
llvm::raw_svector_ostream Out(Buf);
|
||||||
SourceRange Range = genName(Out, Region, C.getASTContext());
|
SourceRange Range = genName(Out, Region, C.getASTContext());
|
||||||
|
@ -277,7 +281,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
|
||||||
|
|
||||||
// The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
|
// The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
|
||||||
// so the stack address is not escaping here.
|
// so the stack address is not escaping here.
|
||||||
if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
|
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
|
||||||
if (isa<BlockDataRegion>(R) &&
|
if (isa<BlockDataRegion>(R) &&
|
||||||
ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject) {
|
ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject) {
|
||||||
return;
|
return;
|
||||||
|
@ -333,7 +337,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
|
||||||
|
|
||||||
if (!BT_stackleak)
|
if (!BT_stackleak)
|
||||||
BT_stackleak = std::make_unique<BuiltinBug>(
|
BT_stackleak = std::make_unique<BuiltinBug>(
|
||||||
this, "Stack address stored into global variable",
|
CheckNames[CK_StackAddrEscapeChecker],
|
||||||
|
"Stack address stored into global variable",
|
||||||
"Stack address was saved into a global variable. "
|
"Stack address was saved into a global variable. "
|
||||||
"This is dangerous because the address will become "
|
"This is dangerous because the address will become "
|
||||||
"invalid after returning from the function");
|
"invalid after returning from the function");
|
||||||
|
@ -371,14 +376,13 @@ bool ento::shouldRegisterStackAddrEscapeBase(const CheckerManager &mgr) {
|
||||||
|
|
||||||
#define REGISTER_CHECKER(name) \
|
#define REGISTER_CHECKER(name) \
|
||||||
void ento::register##name(CheckerManager &Mgr) { \
|
void ento::register##name(CheckerManager &Mgr) { \
|
||||||
StackAddrEscapeChecker *Chk = \
|
StackAddrEscapeChecker *Chk = Mgr.getChecker<StackAddrEscapeChecker>(); \
|
||||||
Mgr.getChecker<StackAddrEscapeChecker>(); \
|
|
||||||
Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \
|
Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \
|
||||||
|
Chk->CheckNames[StackAddrEscapeChecker::CK_##name] = \
|
||||||
|
Mgr.getCurrentCheckerName(); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
bool ento::shouldRegister##name(const CheckerManager &mgr) { \
|
bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
|
||||||
return true; \
|
|
||||||
}
|
|
||||||
|
|
||||||
REGISTER_CHECKER(StackAddrEscapeChecker)
|
REGISTER_CHECKER(StackAddrEscapeChecker)
|
||||||
REGISTER_CHECKER(StackAddrAsyncEscapeChecker)
|
REGISTER_CHECKER(StackAddrAsyncEscapeChecker)
|
||||||
|
|
|
@ -5,9 +5,16 @@
|
||||||
int* stack_addr_escape_base() {
|
int* stack_addr_escape_base() {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
// FIXME: This shouldn't be tied to a modeling checker.
|
// FIXME: This shouldn't be tied to a modeling checker.
|
||||||
return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller [core.StackAddrEscapeBase]}}
|
return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller [core.StackAddressEscape]}}
|
||||||
// expected-note-re@-1{{{{^Address of stack memory associated with local variable 'x' returned to caller$}}}}
|
// expected-note-re@-1{{{{^Address of stack memory associated with local variable 'x' returned to caller$}}}}
|
||||||
// Just a regular compiler warning.
|
// Just a regular compiler warning.
|
||||||
// expected-warning@-3{{address of stack memory associated with local variable 'x' returned}}
|
// expected-warning@-3{{address of stack memory associated with local variable 'x' returned}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char const *p;
|
||||||
|
|
||||||
|
void f0() {
|
||||||
|
char const str[] = "This will change";
|
||||||
|
p = str;
|
||||||
|
} // expected-warning{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference [core.StackAddressEscape]}}
|
||||||
|
// expected-note@-1{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// RUN: %clang_analyze_cc1 -fblocks -verify %s -Wno-objc-root-class \
|
// RUN: %clang_analyze_cc1 -fblocks -fobjc-arc -verify %s -Wno-objc-root-class \
|
||||||
// RUN: -analyzer-checker=core \
|
// RUN: -analyzer-checker=core \
|
||||||
|
// RUN: -analyzer-checker=alpha.core.StackAddressAsyncEscape \
|
||||||
// RUN: -analyzer-checker=nullability \
|
// RUN: -analyzer-checker=nullability \
|
||||||
// RUN: -analyzer-checker=osx
|
// RUN: -analyzer-checker=osx
|
||||||
|
|
||||||
|
@ -126,3 +127,32 @@ void use_out_param_leak() {
|
||||||
// FIXME: This shouldn't be tied to a modeling checker.
|
// FIXME: This shouldn't be tied to a modeling checker.
|
||||||
write_into_out_param_on_success(&obj); // expected-warning{{Potential leak of an object stored into 'obj' [osx.cocoa.RetainCountBase]}}
|
write_into_out_param_on_success(&obj); // expected-warning{{Potential leak of an object stored into 'obj' [osx.cocoa.RetainCountBase]}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct dispatch_queue_s *dispatch_queue_t;
|
||||||
|
typedef void (^dispatch_block_t)(void);
|
||||||
|
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
|
||||||
|
typedef long dispatch_once_t;
|
||||||
|
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
|
||||||
|
typedef long dispatch_time_t;
|
||||||
|
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
|
||||||
|
void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
|
||||||
|
|
||||||
|
extern dispatch_queue_t queue;
|
||||||
|
extern dispatch_once_t *predicate;
|
||||||
|
extern dispatch_time_t when;
|
||||||
|
|
||||||
|
dispatch_block_t get_leaking_block() {
|
||||||
|
int leaked_x = 791;
|
||||||
|
int *p = &leaked_x;
|
||||||
|
return ^void(void) {
|
||||||
|
*p = 1;
|
||||||
|
};
|
||||||
|
// expected-warning@-3 {{Address of stack memory associated with local variable 'leaked_x' \
|
||||||
|
is captured by a returned block [core.StackAddressEscape]}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_returned_from_func_block_async() {
|
||||||
|
dispatch_async(queue, get_leaking_block());
|
||||||
|
// expected-warning@-1 {{Address of stack memory associated with local variable 'leaked_x' \
|
||||||
|
is captured by an asynchronously-executed block [alpha.core.StackAddressAsyncEscape]}}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue