Skip to content

Commit

Permalink
[analyzer][StackAddressEscape] Tie warnings to the diagnostic checker…
Browse files Browse the repository at this point in the history
…s rather then core.StackAddrEscapeBase

Differential Revision: https://reviews.llvm.org/D78101
  • Loading branch information
Szelethus committed May 20, 2020
1 parent ca5bff1 commit 3a6ee4f
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,16 @@ class BuiltinBug : public BugType {
const char *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)
: BugType(checker, name, categories::LogicError), desc(name) {}

StringRef getDescription() const { return desc; }
};

} // end ento namespace
} // namespace ento

} // end clang namespace
#endif
24 changes: 14 additions & 10 deletions clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class StackAddrEscapeChecker
};

DefaultBool ChecksEnabled[CK_NumCheckKinds];
CheckerNameRef CheckNames[CK_NumCheckKinds];

void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
Expand Down Expand Up @@ -156,7 +157,8 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C,
return;
if (!BT_returnstack)
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.
SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
Expand Down Expand Up @@ -195,7 +197,8 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
continue;
if (!BT_capturedstackasync)
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;
llvm::raw_svector_ostream Out(Buf);
SourceRange Range = genName(Out, Region, C.getASTContext());
Expand All @@ -218,7 +221,8 @@ void StackAddrEscapeChecker::checkReturnedBlockCaptures(
continue;
if (!BT_capturedstackret)
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;
llvm::raw_svector_ostream Out(Buf);
SourceRange Range = genName(Out, Region, C.getASTContext());
Expand Down Expand Up @@ -277,7 +281,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,

// The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
// 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) &&
ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject) {
return;
Expand Down Expand Up @@ -333,7 +337,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,

if (!BT_stackleak)
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. "
"This is dangerous because the address will become "
"invalid after returning from the function");
Expand Down Expand Up @@ -371,14 +376,13 @@ bool ento::shouldRegisterStackAddrEscapeBase(const CheckerManager &mgr) {

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &Mgr) { \
StackAddrEscapeChecker *Chk = \
Mgr.getChecker<StackAddrEscapeChecker>(); \
StackAddrEscapeChecker *Chk = Mgr.getChecker<StackAddrEscapeChecker>(); \
Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \
Chk->CheckNames[StackAddrEscapeChecker::CK_##name] = \
Mgr.getCurrentCheckerName(); \
} \
\
bool ento::shouldRegister##name(const CheckerManager &mgr) { \
return true; \
}
bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }

REGISTER_CHECKER(StackAddrEscapeChecker)
REGISTER_CHECKER(StackAddrAsyncEscapeChecker)
9 changes: 8 additions & 1 deletion clang/test/Analysis/incorrect-checker-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@
int* stack_addr_escape_base() {
int x = 0;
// 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$}}}}
// Just a regular compiler warning.
// 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}}
32 changes: 31 additions & 1 deletion clang/test/Analysis/incorrect-checker-names.mm
Original file line number Diff line number Diff line change
@@ -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=alpha.core.StackAddressAsyncEscape \
// RUN: -analyzer-checker=nullability \
// RUN: -analyzer-checker=osx

Expand Down Expand Up @@ -126,3 +127,32 @@ void use_out_param_leak() {
// 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]}}
}

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

0 comments on commit 3a6ee4f

Please sign in to comment.