Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(13)

Side by Side Diff: src/client/linux/handler/exception_handler_unittest.cc

Issue 194001: Write a memory around the instruction pointer from the crashing thread to the minidump on Linux (Closed)
Patch Set: Created 14 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 Google Inc. 1 // Copyright (c) 2010 Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 14 matching lines...) Expand all
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 #include <string> 30 #include <string>
31 31
32 #include <stdint.h> 32 #include <stdint.h>
33 #include <unistd.h> 33 #include <unistd.h>
34 #include <signal.h> 34 #include <signal.h>
35 #include <sys/mman.h>
35 #include <sys/poll.h> 36 #include <sys/poll.h>
36 #include <sys/socket.h> 37 #include <sys/socket.h>
37 #include <sys/uio.h> 38 #include <sys/uio.h>
38 39
39 #include "breakpad_googletest_includes.h" 40 #include "breakpad_googletest_includes.h"
40 #include "client/linux/handler/exception_handler.h" 41 #include "client/linux/handler/exception_handler.h"
41 #include "client/linux/minidump_writer/minidump_writer.h" 42 #include "client/linux/minidump_writer/minidump_writer.h"
42 #include "common/linux/eintr_wrapper.h" 43 #include "common/linux/eintr_wrapper.h"
43 #include "common/linux/linux_libc_support.h" 44 #include "common/linux/linux_libc_support.h"
44 #include "third_party/lss/linux_syscall_support.h" 45 #include "third_party/lss/linux_syscall_support.h"
46 #include "google_breakpad/processor/minidump.h"
45 47
46 using namespace google_breakpad; 48 using namespace google_breakpad;
47 49
48 static void sigchld_handler(int signo) { } 50 static void sigchld_handler(int signo) { }
49 51
50 class ExceptionHandlerTest : public ::testing::Test { 52 class ExceptionHandlerTest : public ::testing::Test {
51 protected: 53 protected:
52 void SetUp() { 54 void SetUp() {
53 // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN. 55 // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
54 struct sigaction sa; 56 struct sigaction sa;
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 filename[len] = 0; 121 filename[len] = 0;
120 close(fds[0]); 122 close(fds[0]);
121 123
122 const std::string minidump_filename = std::string("/tmp/") + filename + 124 const std::string minidump_filename = std::string("/tmp/") + filename +
123 ".dmp"; 125 ".dmp";
124 126
125 struct stat st; 127 struct stat st;
126 ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0); 128 ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
127 ASSERT_GT(st.st_size, 0u); 129 ASSERT_GT(st.st_size, 0u);
128 unlink(minidump_filename.c_str()); 130 unlink(minidump_filename.c_str());
131 }
132
133 TEST(ExceptionHandlerTest, InstructionPointerMemory) {
134 int fds[2];
135 ASSERT_NE(pipe(fds), -1);
136
137 const pid_t child = fork();
138 if (child == 0) {
139 close(fds[0]);
140 ExceptionHandler handler("/tmp", NULL, DoneCallback, (void*) fds[1],
141 true);
142 // Get some executable memory.
143 const size_t memory_size = 256; // bytes
144 char* memory =
145 reinterpret_cast<char*>(mmap(NULL,
146 memory_size,
147 PROT_READ | PROT_WRITE | PROT_EXEC,
148 MAP_PRIVATE | MAP_ANON,
149 -1,
150 0));
151 if (!memory)
152 exit(0);
153
154 // Write some instructions that will crash. Put them in the middle
155 // of the block of memory, because the minidump should contain 128
156 // bytes on either side of the instruction pointer.
157 const int offset = memory_size / 2;
158 // This crashes with SIGILL on x86/x86-64/arm.
159 const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff };
160 memcpy(memory + offset, instructions, sizeof(instructions));
161
162 // Now execute the instructions, which should crash.
163 typedef void (*void_function)(void);
164 void_function memory_function =
165 reinterpret_cast<void_function>(memory + offset);
166 memory_function();
167 }
168 close(fds[1]);
169
170 int status;
171 ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
172 ASSERT_TRUE(WIFSIGNALED(status));
173 ASSERT_EQ(WTERMSIG(status), SIGILL);
174
175 struct pollfd pfd;
176 memset(&pfd, 0, sizeof(pfd));
177 pfd.fd = fds[0];
178 pfd.events = POLLIN | POLLERR;
179
180 const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
181 ASSERT_EQ(r, 1);
182 ASSERT_TRUE(pfd.revents & POLLIN);
183
184 uint32_t len;
185 ASSERT_EQ(read(fds[0], &len, sizeof(len)), (ssize_t)sizeof(len));
186 ASSERT_LT(len, (uint32_t)2048);
187 char* filename = reinterpret_cast<char*>(malloc(len + 1));
188 ASSERT_EQ(read(fds[0], filename, len), len);
189 filename[len] = 0;
190 close(fds[0]);
191
192 const std::string minidump_filename = std::string("/tmp/") + filename +
193 ".dmp";
194
195 struct stat st;
196 ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
197 ASSERT_GT(st.st_size, 0u);
198
199 // Read the minidump. Locate the exception record and the
200 // memory list, and then ensure that there is a memory region
201 // in the memory list that covers the instruction pointer from
202 // the exception record.
203 Minidump minidump(minidump_filename);
204 ASSERT_TRUE(minidump.Read());
205
206 MinidumpException* exception = minidump.GetException();
207 MinidumpMemoryList* memory_list = minidump.GetMemoryList();
208 ASSERT_TRUE(exception);
209 ASSERT_TRUE(memory_list);
210 ASSERT_LT(0, memory_list->region_count());
211
212 MinidumpContext* context = exception->GetContext();
213 ASSERT_TRUE(context);
214
215 u_int64_t instruction_pointer;
216 switch (context->GetContextCPU()) {
217 case MD_CONTEXT_X86:
218 instruction_pointer = context->GetContextX86()->eip;
219 break;
220 case MD_CONTEXT_AMD64:
221 instruction_pointer = context->GetContextAMD64()->rip;
222 break;
223 case MD_CONTEXT_ARM:
224 instruction_pointer = context->GetContextARM()->iregs[15];
225 break;
226 default:
227 FAIL() << "Unknown context CPU: " << context->GetContextCPU();
228 break;
229 }
230
231 MinidumpMemoryRegion* region =
232 memory_list->GetMemoryRegionForAddress(instruction_pointer);
233 EXPECT_TRUE(region);
234 //TODO(ted): verify contents of memory region
mochalatte 2010/09/16 20:50:22 if verifying the contents is too complicated for t
235
236 unlink(minidump_filename.c_str());
129 free(filename); 237 free(filename);
130 } 238 }
131 239
132 static const unsigned kControlMsgSize = 240 static const unsigned kControlMsgSize =
133 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); 241 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
134 242
135 static bool 243 static bool
136 CrashHandler(const void* crash_context, size_t crash_context_size, 244 CrashHandler(const void* crash_context, size_t crash_context_size,
137 void* context) { 245 void* context) {
138 const int fd = (intptr_t) context; 246 const int fd = (intptr_t) context;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 int status; 344 int status;
237 ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1); 345 ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
238 ASSERT_TRUE(WIFSIGNALED(status)); 346 ASSERT_TRUE(WIFSIGNALED(status));
239 ASSERT_EQ(WTERMSIG(status), SIGSEGV); 347 ASSERT_EQ(WTERMSIG(status), SIGSEGV);
240 348
241 struct stat st; 349 struct stat st;
242 ASSERT_EQ(stat(templ, &st), 0); 350 ASSERT_EQ(stat(templ, &st), 0);
243 ASSERT_GT(st.st_size, 0u); 351 ASSERT_GT(st.st_size, 0u);
244 unlink(templ); 352 unlink(templ);
245 } 353 }
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 1004:630ec63f810e-tainted