forked from OSchip/llvm-project
[ASan] Make stack-buffer-overflow reports more robust
Summary: Fix the function that gets stack frame description by address in thread stack, so that it clearly indicates failures. Make this error non-fatal, and print as much information as we can in this case. Make all errors in ParseFrameDescription non-fatal. Test Plan: check-asan testsuite Reviewers: kcc Reviewed By: kcc Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D5554 llvm-svn: 218819
This commit is contained in:
parent
f795e4805e
commit
0470e24780
|
@ -28,19 +28,19 @@ void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
|
|||
descr->region_size = 0;
|
||||
descr->region_kind = "stack";
|
||||
|
||||
uptr offset = 0;
|
||||
uptr frame_pc = 0;
|
||||
const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
|
||||
AsanThread::StackFrameAccess access;
|
||||
if (!t->GetStackFrameAccessByAddr(addr, &access))
|
||||
return;
|
||||
InternalMmapVector<StackVarDescr> vars(16);
|
||||
if (!ParseFrameDescription(frame_descr, &vars)) {
|
||||
if (!ParseFrameDescription(access.frame_descr, &vars)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uptr i = 0; i < vars.size(); i++) {
|
||||
if (offset <= vars[i].beg + vars[i].size) {
|
||||
if (access.offset <= vars[i].beg + vars[i].size) {
|
||||
internal_strncat(descr->name, vars[i].name_pos,
|
||||
Min(descr->name_size, vars[i].name_len));
|
||||
descr->region_address = addr - (offset - vars[i].beg);
|
||||
descr->region_address = addr - (access.offset - vars[i].beg);
|
||||
descr->region_size = vars[i].size;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -381,9 +381,14 @@ void PrintAccessAndVarIntersection(const char *var_name,
|
|||
|
||||
bool ParseFrameDescription(const char *frame_descr,
|
||||
InternalMmapVector<StackVarDescr> *vars) {
|
||||
CHECK(frame_descr);
|
||||
char *p;
|
||||
// This string is created by the compiler and has the following form:
|
||||
// "n alloc_1 alloc_2 ... alloc_n"
|
||||
// where alloc_i looks like "offset size len ObjectName".
|
||||
uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
|
||||
CHECK_GT(n_objects, 0);
|
||||
if (n_objects == 0)
|
||||
return false;
|
||||
|
||||
for (uptr i = 0; i < n_objects; i++) {
|
||||
uptr beg = (uptr)internal_simple_strtoll(p, &p, 10);
|
||||
|
@ -404,31 +409,21 @@ bool ParseFrameDescription(const char *frame_descr,
|
|||
bool DescribeAddressIfStack(uptr addr, uptr access_size) {
|
||||
AsanThread *t = FindThreadByStackAddress(addr);
|
||||
if (!t) return false;
|
||||
const uptr kBufSize = 4095;
|
||||
char buf[kBufSize];
|
||||
uptr offset = 0;
|
||||
uptr frame_pc = 0;
|
||||
char tname[128];
|
||||
const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
|
||||
|
||||
#ifdef __powerpc64__
|
||||
// On PowerPC64, the address of a function actually points to a
|
||||
// three-doubleword data structure with the first field containing
|
||||
// the address of the function's code.
|
||||
frame_pc = *reinterpret_cast<uptr *>(frame_pc);
|
||||
#endif
|
||||
|
||||
// This string is created by the compiler and has the following form:
|
||||
// "n alloc_1 alloc_2 ... alloc_n"
|
||||
// where alloc_i looks like "offset size len ObjectName ".
|
||||
CHECK(frame_descr);
|
||||
Decorator d;
|
||||
char tname[128];
|
||||
Printf("%s", d.Location());
|
||||
Printf("Address %p is located in stack of thread T%d%s "
|
||||
"at offset %zu in frame\n",
|
||||
addr, t->tid(),
|
||||
ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
|
||||
offset);
|
||||
Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
|
||||
ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
|
||||
|
||||
// Try to fetch precise stack frame for this access.
|
||||
AsanThread::StackFrameAccess access;
|
||||
if (!t->GetStackFrameAccessByAddr(addr, &access)) {
|
||||
Printf("%s\n", d.EndLocation());
|
||||
return true;
|
||||
}
|
||||
Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
|
||||
|
||||
// Now we print the frame where the alloca has happened.
|
||||
// We print this frame as a stack trace with one element.
|
||||
// The symbolizer may print more than one frame if inlining was involved.
|
||||
|
@ -437,15 +432,21 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
|
|||
// especially given that the alloca may be from entirely different place
|
||||
// (e.g. use-after-scope, or different thread's stack).
|
||||
StackTrace alloca_stack;
|
||||
alloca_stack.trace[0] = frame_pc + 16;
|
||||
#ifdef __powerpc64__
|
||||
// On PowerPC64, the address of a function actually points to a
|
||||
// three-doubleword data structure with the first field containing
|
||||
// the address of the function's code.
|
||||
access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
|
||||
#endif
|
||||
alloca_stack.trace[0] = access.frame_pc + 16;
|
||||
alloca_stack.size = 1;
|
||||
Printf("%s", d.EndLocation());
|
||||
alloca_stack.Print();
|
||||
|
||||
InternalMmapVector<StackVarDescr> vars(16);
|
||||
if (!ParseFrameDescription(frame_descr, &vars)) {
|
||||
if (!ParseFrameDescription(access.frame_descr, &vars)) {
|
||||
Printf("AddressSanitizer can't parse the stack frame "
|
||||
"descriptor: |%s|\n", frame_descr);
|
||||
"descriptor: |%s|\n", access.frame_descr);
|
||||
// 'addr' is a stack address, so return true even if we can't parse frame
|
||||
return true;
|
||||
}
|
||||
|
@ -454,15 +455,16 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
|
|||
Printf(" This frame has %zu object(s):\n", n_objects);
|
||||
|
||||
// Report all objects in this frame.
|
||||
const uptr kBufSize = 4095;
|
||||
char buf[kBufSize];
|
||||
for (uptr i = 0; i < n_objects; i++) {
|
||||
buf[0] = 0;
|
||||
internal_strncat(buf, vars[i].name_pos,
|
||||
static_cast<uptr>(Min(kBufSize, vars[i].name_len)));
|
||||
uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
|
||||
uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
|
||||
PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size,
|
||||
offset, access_size,
|
||||
prev_var_end, next_var_beg);
|
||||
PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size, access.offset,
|
||||
access_size, prev_var_end, next_var_beg);
|
||||
}
|
||||
Printf("HINT: this may be a false positive if your program uses "
|
||||
"some custom stack unwind mechanism or swapcontext\n");
|
||||
|
|
|
@ -198,17 +198,18 @@ void AsanThread::ClearShadowForThreadStackAndTLS() {
|
|||
PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
|
||||
}
|
||||
|
||||
const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
|
||||
uptr *frame_pc) {
|
||||
bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
|
||||
StackFrameAccess *access) {
|
||||
uptr bottom = 0;
|
||||
if (AddrIsInStack(addr)) {
|
||||
bottom = stack_bottom();
|
||||
} else if (has_fake_stack()) {
|
||||
bottom = fake_stack()->AddrIsInFakeStack(addr);
|
||||
CHECK(bottom);
|
||||
*offset = addr - bottom;
|
||||
*frame_pc = ((uptr*)bottom)[2];
|
||||
return (const char *)((uptr*)bottom)[1];
|
||||
access->offset = addr - bottom;
|
||||
access->frame_pc = ((uptr*)bottom)[2];
|
||||
access->frame_descr = (const char *)((uptr*)bottom)[1];
|
||||
return true;
|
||||
}
|
||||
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
|
||||
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
|
||||
|
@ -225,15 +226,15 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
|
|||
}
|
||||
|
||||
if (shadow_ptr < shadow_bottom) {
|
||||
*offset = 0;
|
||||
return "UNKNOWN";
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
|
||||
CHECK(ptr[0] == kCurrentStackFrameMagic);
|
||||
*offset = addr - (uptr)ptr;
|
||||
*frame_pc = ptr[2];
|
||||
return (const char*)ptr[1];
|
||||
access->offset = addr - (uptr)ptr;
|
||||
access->frame_pc = ptr[2];
|
||||
access->frame_descr = (const char*)ptr[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
|
||||
|
|
|
@ -71,7 +71,12 @@ class AsanThread {
|
|||
AsanThreadContext *context() { return context_; }
|
||||
void set_context(AsanThreadContext *context) { context_ = context; }
|
||||
|
||||
const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
|
||||
struct StackFrameAccess {
|
||||
uptr offset;
|
||||
uptr frame_pc;
|
||||
const char *frame_descr;
|
||||
};
|
||||
bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
|
||||
|
||||
bool AddrIsInStack(uptr addr) {
|
||||
return addr >= stack_bottom_ && addr < stack_top_;
|
||||
|
|
Loading…
Reference in New Issue