[analyzer][StackAddressEscape] Tie warnings to the diagnostic checkers rather then core.StackAddrEscapeBase

Differential Revision: https://reviews.llvm.org/D78101
This commit is contained in:
Kirstóf Umann 2020-04-11 00:21:48 +02:00
parent ca5bff18fc
commit 3a6ee4fefe
4 changed files with 57 additions and 13 deletions

View File

@ -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

View File

@ -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)

View File

@ -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}}

View File

@ -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]}}
}