Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2875)

Unified Diff: base/debug/stack_trace.cc

Issue 1975393002: Check stack pointer to be inside stack when unwinding. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Implement mincore() approach Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/debug/stack_trace.cc
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
index 1c96a569d9795544231714f0d0b1f9b0da036355..0150abe0a2a655489c8d295a349c66528d78dc44 100644
--- a/base/debug/stack_trace.cc
+++ b/base/debug/stack_trace.cc
@@ -11,6 +11,16 @@
#include "base/macros.h"
+#if HAVE_TRACE_STACK_FRAME_POINTERS && \
+ (defined(OS_ANDROID) || defined(OS_LINUX))
+#define HAVE_MINCORE
+#include <sys/mman.h>
+#include <unistd.h>
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#endif
+
+
namespace base {
namespace debug {
@@ -41,9 +51,61 @@ std::string StackTrace::ToString() const {
#if HAVE_TRACE_STACK_FRAME_POINTERS
+#ifdef HAVE_MINCORE
+
+// Attempts to advance |address| by PageCount pages, checking that all
+// pages are mapped.
+// Returns true if no unmapped pages were found, and adds PageCount
+// pages to |address| and rounds result down to a page.
+// Returns false if unmapped pages were detected, and sets |address| to
+// the address of the lowest unmapped page.
+template <size_t PageCount>
Primiano Tucci (use gerrit) 2016/05/31 16:13:06 why do you need a template function with a lambda
+bool AdvanceMappedPages(uintptr_t* address) {
+ auto probe = [](uintptr_t address, size_t size) -> bool {
+ uint8_t vec[PageCount];
+ int result = HANDLE_EINTR(
Primiano Tucci (use gerrit) 2016/05/31 16:13:07 accordin to its manpage mincore doesn't EINTR (vm
Dmitry Skiba 2016/05/31 21:52:18 Done.
+ mincore(reinterpret_cast<void*>(address), size, vec));
+ if (result == 0) {
+ return true;
+ }
+ // mincore() returns ENOMEM if address range contains unmapped pages.
+ CHECK_EQ(errno, ENOMEM);
Primiano Tucci (use gerrit) 2016/05/31 16:13:06 I'd remove this CHECK or make it a DCHECK. 1) you
Dmitry Skiba 2016/05/31 21:52:18 Done.
+ return false;
+ };
+
+ size_t page_size = GetPageSize();
+
+ // Rewind address to the page boundary.
+ *address -= *address % page_size;
+
+ // Probe the whole range first.
+ if (probe(*address, PageCount * page_size)) {
+ *address += PageCount * page_size;
+ return true;
+ }
+
+ // Binary search leftmost page that is not mapped.
+ for (size_t pages = PageCount; pages != 1;) {
Primiano Tucci (use gerrit) 2016/05/31 16:13:06 I think this is a bit hard to follow as you do a b
Dmitry Skiba 2016/05/31 21:52:18 I don't see how it can be a single loop. When bina
+ size_t half_pages = pages / 2;
+ if (!probe(*address, half_pages * page_size)) {
+ pages = half_pages;
+ continue;
+ }
+ *address += half_pages * page_size;
+ pages -= half_pages;
+ }
+ return false;
+}
+
+#endif // HAVE_MINCORE
+
+PerThreadStackInfo::PerThreadStackInfo()
+ : start_address(0), start_address_final(false) {}
+
size_t TraceStackFramePointers(const void** out_trace,
size_t max_depth,
- size_t skip_initial) {
+ size_t skip_initial,
+ PerThreadStackInfo* stack_info) {
// Usage of __builtin_frame_address() enables frame pointers in this
// function even if they are not enabled globally. So 'sp' will always
// be valid.
@@ -58,6 +120,26 @@ size_t TraceStackFramePointers(const void** out_trace,
sp -= sizeof(uintptr_t);
#endif
+#ifdef HAVE_MINCORE
+ if (stack_info) {
+ // Both sp[0] and s[1] must be valid.
+ uintptr_t max_sp = sp + 2 * sizeof(uintptr_t);
+ if (!stack_info->start_address) {
+ // Initialize start_address so that it satisfies while() below.
+ stack_info->start_address = max_sp - 1;
+ }
+ while (max_sp > stack_info->start_address &&
+ !stack_info->start_address_final) {
+ stack_info->start_address_final = !AdvanceMappedPages<32>(
+ &stack_info->start_address);
+ }
+ if (max_sp > stack_info->start_address &&
+ stack_info->start_address_final) {
+ break;
+ }
+ }
+#endif
+
if (skip_initial != 0) {
skip_initial--;
} else {

Powered by Google App Engine
This is Rietveld 408576698