From 7a8980997d0e0dcf3f3a5d8ccf3c1d8c2840ea27 Mon Sep 17 00:00:00 2001 From: Tobias Sargeant Date: Wed, 30 Nov 2016 16:47:04 +0000 Subject: Do not generate a microdump if there are no webview pointers on the stack. The stack interest range is passed in MicrodumpExtraInfo from the client. If the extracted stack does not contain a pointer in this range, then we assume that this is not a WebView crash, and do not generate a microdump. If the stack extraction fails, we still generate a microdump (without a stack). BUG=664460 Change-Id: Ic762497f76f074a3621c7ec88a8c20ed768b9211 Reviewed-on: https://chromium-review.googlesource.com/412781 Reviewed-by: Primiano Tucci --- .../microdump_writer/microdump_writer_unittest.cc | 125 ++++++++++++++++----- 1 file changed, 94 insertions(+), 31 deletions(-) (limited to 'src/client/linux/microdump_writer/microdump_writer_unittest.cc') diff --git a/src/client/linux/microdump_writer/microdump_writer_unittest.cc b/src/client/linux/microdump_writer/microdump_writer_unittest.cc index 58a73118..b3008052 100644 --- a/src/client/linux/microdump_writer/microdump_writer_unittest.cc +++ b/src/client/linux/microdump_writer/microdump_writer_unittest.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,11 @@ using namespace google_breakpad; +extern "C" { +extern char __executable_start; +extern char __etext; +} + namespace { typedef testing::Test MicrodumpWriterTest; @@ -54,18 +60,29 @@ typedef testing::Test MicrodumpWriterTest; MicrodumpExtraInfo MakeMicrodumpExtraInfo( const char* build_fingerprint, const char* product_info, - const char* gpu_fingerprint) { + const char* gpu_fingerprint, + bool suppress_microdump_based_on_interest_range = false, + uintptr_t interest_range_start = 0, + uintptr_t interest_range_end = 0) { MicrodumpExtraInfo info; info.build_fingerprint = build_fingerprint; info.product_info = product_info; info.gpu_fingerprint = gpu_fingerprint; + info.suppress_microdump_based_on_interest_range = + suppress_microdump_based_on_interest_range; + info.interest_range_start = interest_range_start; + info.interest_range_end = interest_range_end; return info; } -void CrashAndGetMicrodump( - const MappingList& mappings, - const MicrodumpExtraInfo& microdump_extra_info, - scoped_array* buf) { +void AssertContainsMicrodump(const std::string& buf) { + ASSERT_NE(std::string::npos, buf.find("-----BEGIN BREAKPAD MICRODUMP-----")); + ASSERT_NE(std::string::npos, buf.find("-----END BREAKPAD MICRODUMP-----")); +} + +void CrashAndGetMicrodump(const MappingList& mappings, + const MicrodumpExtraInfo& microdump_extra_info, + std::string* microdump) { int fds[2]; ASSERT_NE(-1, pipe(fds)); @@ -86,7 +103,10 @@ void CrashAndGetMicrodump( ExceptionHandler::CrashContext context; memset(&context, 0, sizeof(context)); - + // Pretend the current context is the child context (which is + // approximately right) so that we have a valid stack pointer, and + // can fetch child stack data via ptrace. + getcontext(&context.context); // Set a non-zero tid to avoid tripping asserts. context.tid = child; @@ -105,17 +125,17 @@ void CrashAndGetMicrodump( // Read back the stderr file and check for the microdump marker. fsync(err_fd); lseek(err_fd, 0, SEEK_SET); - const size_t kBufSize = 64 * 1024; - buf->reset(new char[kBufSize]); - ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0); + microdump->clear(); + char buf[1024]; + + while (true) { + int bytes_read = IGNORE_EINTR(read(err_fd, buf, 1024)); + if (bytes_read <= 0) break; + microdump->append(buf, buf + bytes_read); + } close(err_fd); close(fds[1]); - - ASSERT_NE(static_cast(0), strstr( - buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----")); - ASSERT_NE(static_cast(0), strstr( - buf->get(), "-----END BREAKPAD MICRODUMP-----")); } void CheckMicrodumpContents(const string& microdump_content, @@ -191,23 +211,64 @@ TEST(MicrodumpWriterTest, BasicWithMappings) { memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); mappings.push_back(mapping); - scoped_array buf; + std::string buf; CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf); + AssertContainsMicrodump(buf); #ifdef __LP64__ - ASSERT_NE(static_cast(0), strstr( - buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " - "33221100554477668899AABBCCDDEEFF0 libfoo.so")); + ASSERT_NE(std::string::npos, + buf.find("M 0000000000001000 000000000000002A 0000000000001000 " + "33221100554477668899AABBCCDDEEFF0 libfoo.so")); #else - ASSERT_NE(static_cast(0), strstr( - buf.get(), "M 00001000 0000002A 00001000 " - "33221100554477668899AABBCCDDEEFF0 libfoo.so")); + ASSERT_NE(std::string::npos, + buf.find("M 00001000 0000002A 00001000 " + "33221100554477668899AABBCCDDEEFF0 libfoo.so")); #endif // In absence of a product info in the minidump, the writer should just write // an unknown marker. - ASSERT_NE(static_cast(0), strstr( - buf.get(), "V UNKNOWN:0.0.0.0")); + ASSERT_NE(std::string::npos, buf.find("V UNKNOWN:0.0.0.0")); +} + +// Ensure that no output occurs if the interest region is set, but +// doesn't overlap anything on the stack. +TEST(MicrodumpWriterTest, NoOutputIfUninteresting) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint, + true, 0xdeadbeef, 0xdeadbeef - 1)); + + std::string buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf); + ASSERT_EQ(0, buf.size()); +} + +// Ensure that output occurs if the interest region is set, and +// does overlap something on the stack. +TEST(MicrodumpWriterTest, OutputIfInteresting) { + const char kProductInfo[] = "MockProduct:42.0.2311.99"; + const char kBuildFingerprint[] = + "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; + const char kGPUFingerprint[] = + "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; + + const MicrodumpExtraInfo kMicrodumpExtraInfo( + MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint, + true, + reinterpret_cast(&__executable_start), + reinterpret_cast(&__etext))); + + std::string buf; + MappingList no_mappings; + + CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf); + ASSERT_LT(0, buf.size()); } // Ensure that the product info and build fingerprint metadata show up in the @@ -220,38 +281,40 @@ TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; const MicrodumpExtraInfo kMicrodumpExtraInfo( MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); - scoped_array buf; + std::string buf; MappingList no_mappings; CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf); - CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo); + AssertContainsMicrodump(buf); + CheckMicrodumpContents(buf, kMicrodumpExtraInfo); } TEST(MicrodumpWriterTest, NoProductInfo) { const char kBuildFingerprint[] = "foobar"; const char kGPUFingerprint[] = "bazqux"; - scoped_array buf; + std::string buf; MappingList no_mappings; const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo( MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint)); CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf); - CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, - "UNKNOWN:0.0.0.0", kGPUFingerprint); + AssertContainsMicrodump(buf); + CheckMicrodumpContents(buf, kBuildFingerprint, "UNKNOWN:0.0.0.0", + kGPUFingerprint); } TEST(MicrodumpWriterTest, NoGPUInfo) { const char kProductInfo[] = "bazqux"; const char kBuildFingerprint[] = "foobar"; - scoped_array buf; + std::string buf; MappingList no_mappings; const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo( MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL)); CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf); - CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, - kProductInfo, "UNKNOWN"); + AssertContainsMicrodump(buf); + CheckMicrodumpContents(buf, kBuildFingerprint, kProductInfo, "UNKNOWN"); } } // namespace -- cgit v1.2.1