xref: /aosp_15_r20/external/google-breakpad/src/client/windows/crash_generation/crash_generation_server.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2008 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>  // Must come first
31 #endif
32 
33 #include "client/windows/crash_generation/crash_generation_server.h"
34 #include <windows.h>
35 #include <cassert>
36 #include <list>
37 #include "client/windows/common/auto_critical_section.h"
38 #include "common/scoped_ptr.h"
39 
40 #include "client/windows/crash_generation/client_info.h"
41 
42 namespace google_breakpad {
43 
44 // Output buffer size.
45 static const size_t kOutBufferSize = 64;
46 
47 // Input buffer size.
48 static const size_t kInBufferSize = 64;
49 
50 // Access flags for the client on the dump request event.
51 static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
52 
53 // Access flags for the client on the dump generated event.
54 static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
55                                                SYNCHRONIZE;
56 
57 // Access flags for the client on the mutex.
58 static const DWORD kMutexAccess = SYNCHRONIZE;
59 
60 // Attribute flags for the pipe.
61 static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
62                                PIPE_ACCESS_DUPLEX |
63                                FILE_FLAG_OVERLAPPED;
64 
65 // Mode for the pipe.
66 static const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
67                                PIPE_READMODE_MESSAGE |
68                                PIPE_WAIT;
69 
70 // For pipe I/O, execute the callback in the wait thread itself,
71 // since the callback does very little work. The callback executes
72 // the code for one of the states of the server state machine and
73 // the code for all of the states perform async I/O and hence
74 // finish very quickly.
75 static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
76 
77 // Dump request threads will, most likely, generate dumps. That may
78 // take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
79 static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
80                                              WT_EXECUTELONGFUNCTION;
81 
IsClientRequestValid(const ProtocolMessage & msg)82 static bool IsClientRequestValid(const ProtocolMessage& msg) {
83   return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST ||
84          (msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
85           msg.id != 0 &&
86           msg.thread_id != NULL &&
87           msg.exception_pointers != NULL &&
88           msg.assert_info != NULL);
89 }
90 
91 #ifndef NDEBUG
CheckForIOIncomplete(bool success)92 static bool CheckForIOIncomplete(bool success) {
93   // We should never get an I/O incomplete since we should not execute this
94   // unless the operation has finished and the overlapped event is signaled. If
95   // we do get INCOMPLETE, we have a bug in our code.
96   return success ? false : (GetLastError() == ERROR_IO_INCOMPLETE);
97 }
98 #endif
99 
CrashGenerationServer(const std::wstring & pipe_name,SECURITY_ATTRIBUTES * pipe_sec_attrs,OnClientConnectedCallback connect_callback,void * connect_context,OnClientDumpRequestCallback dump_callback,void * dump_context,OnClientExitedCallback exit_callback,void * exit_context,OnClientUploadRequestCallback upload_request_callback,void * upload_context,bool generate_dumps,const std::wstring * dump_path)100 CrashGenerationServer::CrashGenerationServer(
101     const std::wstring& pipe_name,
102     SECURITY_ATTRIBUTES* pipe_sec_attrs,
103     OnClientConnectedCallback connect_callback,
104     void* connect_context,
105     OnClientDumpRequestCallback dump_callback,
106     void* dump_context,
107     OnClientExitedCallback exit_callback,
108     void* exit_context,
109     OnClientUploadRequestCallback upload_request_callback,
110     void* upload_context,
111     bool generate_dumps,
112     const std::wstring* dump_path)
113     : pipe_name_(pipe_name),
114       pipe_sec_attrs_(pipe_sec_attrs),
115       pipe_(NULL),
116       pipe_wait_handle_(NULL),
117       server_alive_handle_(NULL),
118       connect_callback_(connect_callback),
119       connect_context_(connect_context),
120       dump_callback_(dump_callback),
121       dump_context_(dump_context),
122       exit_callback_(exit_callback),
123       exit_context_(exit_context),
124       upload_request_callback_(upload_request_callback),
125       upload_context_(upload_context),
126       generate_dumps_(generate_dumps),
127       pre_fetch_custom_info_(true),
128       dump_path_(dump_path ? *dump_path : L""),
129       server_state_(IPC_SERVER_STATE_UNINITIALIZED),
130       shutting_down_(false),
131       overlapped_(),
132       client_info_(NULL) {
133   InitializeCriticalSection(&sync_);
134 }
135 
136 // This should never be called from the OnPipeConnected callback.
137 // Otherwise the UnregisterWaitEx call below will cause a deadlock.
~CrashGenerationServer()138 CrashGenerationServer::~CrashGenerationServer() {
139   // New scope to release the lock automatically.
140   {
141     // Make sure no clients are added or removed beyond this point.
142     // Before adding or removing any clients, the critical section
143     // must be entered and the shutting_down_ flag checked. The
144     // critical section is then exited only after the clients_ list
145     // modifications are done and the list is in a consistent state.
146     AutoCriticalSection lock(&sync_);
147 
148     // Indicate to existing threads that server is shutting down.
149     shutting_down_ = true;
150   }
151   // No one will modify the clients_ list beyond this point -
152   // not even from another thread.
153 
154   // Even if there are no current worker threads running, it is possible that
155   // an I/O request is pending on the pipe right now but not yet done.
156   // In fact, it's very likely this is the case unless we are in an ERROR
157   // state. If we don't wait for the pending I/O to be done, then when the I/O
158   // completes, it may write to invalid memory. AppVerifier will flag this
159   // problem too. So we disconnect from the pipe and then wait for the server
160   // to get into error state so that the pending I/O will fail and get
161   // cleared.
162   DisconnectNamedPipe(pipe_);
163   int num_tries = 100;
164   while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {
165     Sleep(10);
166   }
167 
168   // Unregister wait on the pipe.
169   if (pipe_wait_handle_) {
170     // Wait for already executing callbacks to finish.
171     UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
172   }
173 
174   // Close the pipe to avoid further client connections.
175   if (pipe_) {
176     CloseHandle(pipe_);
177   }
178 
179   // Request all ClientInfo objects to unregister all waits.
180   // No need to enter the critical section because no one is allowed to modify
181   // the clients_ list once the shutting_down_ flag is set.
182   std::list<ClientInfo*>::iterator iter;
183   for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
184     ClientInfo* client_info = *iter;
185     // Unregister waits. Wait for already executing callbacks to finish.
186     // Unregister the client process exit wait first and only then unregister
187     // the dump request wait.  The reason is that the OnClientExit callback
188     // also unregisters the dump request wait and such a race (doing the same
189     // unregistration from two threads) is undesirable.
190     client_info->UnregisterProcessExitWait(true);
191     client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending();
192 
193     // Destroying the ClientInfo here is safe because all wait operations for
194     // this ClientInfo were unregistered and no pending or running callbacks
195     // for this ClientInfo can possible exist (block_until_no_pending option
196     // was used).
197     delete client_info;
198   }
199 
200   if (server_alive_handle_) {
201     // Release the mutex before closing the handle so that clients requesting
202     // dumps wait for a long time for the server to generate a dump.
203     ReleaseMutex(server_alive_handle_);
204     CloseHandle(server_alive_handle_);
205   }
206 
207   if (overlapped_.hEvent) {
208     CloseHandle(overlapped_.hEvent);
209   }
210 
211   DeleteCriticalSection(&sync_);
212 }
213 
Start()214 bool CrashGenerationServer::Start() {
215   if (server_state_ != IPC_SERVER_STATE_UNINITIALIZED) {
216     return false;
217   }
218 
219   server_state_ = IPC_SERVER_STATE_INITIAL;
220 
221   server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
222   if (!server_alive_handle_) {
223     return false;
224   }
225 
226   // Event to signal the client connection and pipe reads and writes.
227   overlapped_.hEvent = CreateEvent(NULL,   // Security descriptor.
228                                    TRUE,   // Manual reset.
229                                    FALSE,  // Initially nonsignaled.
230                                    NULL);  // Name.
231   if (!overlapped_.hEvent) {
232     return false;
233   }
234 
235   // Register a callback with the thread pool for the client connection.
236   if (!RegisterWaitForSingleObject(&pipe_wait_handle_,
237                                    overlapped_.hEvent,
238                                    OnPipeConnected,
239                                    this,
240                                    INFINITE,
241                                    kPipeIOThreadFlags)) {
242     return false;
243   }
244 
245   pipe_ = CreateNamedPipe(pipe_name_.c_str(),
246                           kPipeAttr,
247                           kPipeMode,
248                           1,
249                           kOutBufferSize,
250                           kInBufferSize,
251                           0,
252                           pipe_sec_attrs_);
253   if (pipe_ == INVALID_HANDLE_VALUE) {
254     return false;
255   }
256 
257   // Kick-start the state machine. This will initiate an asynchronous wait
258   // for client connections.
259   if (!SetEvent(overlapped_.hEvent)) {
260     server_state_ = IPC_SERVER_STATE_ERROR;
261     return false;
262   }
263 
264   // If we are in error state, it's because we failed to start listening.
265   return true;
266 }
267 
268 // If the server thread serving clients ever gets into the
269 // ERROR state, reset the event, close the pipe and remain
270 // in the error state forever. Error state means something
271 // that we didn't account for has happened, and it's dangerous
272 // to do anything unknowingly.
HandleErrorState()273 void CrashGenerationServer::HandleErrorState() {
274   assert(server_state_ == IPC_SERVER_STATE_ERROR);
275 
276   // If the server is shutting down anyway, don't clean up
277   // here since shut down process will clean up.
278   if (shutting_down_) {
279     return;
280   }
281 
282   if (pipe_wait_handle_) {
283     UnregisterWait(pipe_wait_handle_);
284     pipe_wait_handle_ = NULL;
285   }
286 
287   if (pipe_) {
288     CloseHandle(pipe_);
289     pipe_ = NULL;
290   }
291 
292   if (overlapped_.hEvent) {
293     CloseHandle(overlapped_.hEvent);
294     overlapped_.hEvent = NULL;
295   }
296 }
297 
298 // When the server thread serving clients is in the INITIAL state,
299 // try to connect to the pipe asynchronously. If the connection
300 // finishes synchronously, directly go into the CONNECTED state;
301 // otherwise go into the CONNECTING state. For any problems, go
302 // into the ERROR state.
HandleInitialState()303 void CrashGenerationServer::HandleInitialState() {
304   assert(server_state_ == IPC_SERVER_STATE_INITIAL);
305 
306   if (!ResetEvent(overlapped_.hEvent)) {
307     EnterErrorState();
308     return;
309   }
310 
311   bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
312   DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
313 
314   // From MSDN, it is not clear that when ConnectNamedPipe is used
315   // in an overlapped mode, will it ever return non-zero value, and
316   // if so, in what cases.
317   assert(!success);
318 
319   switch (error_code) {
320     case ERROR_IO_PENDING:
321       EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING);
322       break;
323 
324     case ERROR_PIPE_CONNECTED:
325       EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
326       break;
327 
328     default:
329       EnterErrorState();
330       break;
331   }
332 }
333 
334 // When the server thread serving the clients is in the CONNECTING state,
335 // try to get the result of the asynchronous connection request using
336 // the OVERLAPPED object. If the result indicates the connection is done,
337 // go into the CONNECTED state. If the result indicates I/O is still
338 // INCOMPLETE, remain in the CONNECTING state. For any problems,
339 // go into the DISCONNECTING state.
HandleConnectingState()340 void CrashGenerationServer::HandleConnectingState() {
341   assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
342 
343   DWORD bytes_count = 0;
344   bool success = GetOverlappedResult(pipe_,
345                                      &overlapped_,
346                                      &bytes_count,
347                                      FALSE) != FALSE;
348   DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
349 
350   if (success) {
351     EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
352   } else if (error_code != ERROR_IO_INCOMPLETE) {
353     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
354   } else {
355     // remain in CONNECTING state
356   }
357 }
358 
359 // When the server thread serving the clients is in the CONNECTED state,
360 // try to issue an asynchronous read from the pipe. If read completes
361 // synchronously or if I/O is pending then go into the READING state.
362 // For any problems, go into the DISCONNECTING state.
HandleConnectedState()363 void CrashGenerationServer::HandleConnectedState() {
364   assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
365 
366   DWORD bytes_count = 0;
367   memset(&msg_, 0, sizeof(msg_));
368   bool success = ReadFile(pipe_,
369                           &msg_,
370                           sizeof(msg_),
371                           &bytes_count,
372                           &overlapped_) != FALSE;
373   DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
374 
375   // Note that the asynchronous read issued above can finish before the
376   // code below executes. But, it is okay to change state after issuing
377   // the asynchronous read. This is because even if the asynchronous read
378   // is done, the callback for it would not be executed until the current
379   // thread finishes its execution.
380   if (success || error_code == ERROR_IO_PENDING) {
381     EnterStateWhenSignaled(IPC_SERVER_STATE_READING);
382   } else {
383     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
384   }
385 }
386 
387 // When the server thread serving the clients is in the READING state,
388 // try to get the result of the async read. If async read is done,
389 // go into the READ_DONE state. For any problems, go into the
390 // DISCONNECTING state.
HandleReadingState()391 void CrashGenerationServer::HandleReadingState() {
392   assert(server_state_ == IPC_SERVER_STATE_READING);
393 
394   DWORD bytes_count = 0;
395   bool success = GetOverlappedResult(pipe_,
396                                      &overlapped_,
397                                      &bytes_count,
398                                      FALSE) != FALSE;
399   if (success && bytes_count == sizeof(ProtocolMessage)) {
400     EnterStateImmediately(IPC_SERVER_STATE_READ_DONE);
401     return;
402   }
403 
404   assert(!CheckForIOIncomplete(success));
405   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
406 }
407 
408 // When the server thread serving the client is in the READ_DONE state,
409 // validate the client's request message, register the client by
410 // creating appropriate objects and prepare the response.  Then try to
411 // write the response to the pipe asynchronously. If that succeeds,
412 // go into the WRITING state. For any problems, go into the DISCONNECTING
413 // state.
HandleReadDoneState()414 void CrashGenerationServer::HandleReadDoneState() {
415   assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
416 
417   if (!IsClientRequestValid(msg_)) {
418     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
419     return;
420   }
421 
422   if (msg_.tag == MESSAGE_TAG_UPLOAD_REQUEST) {
423     if (upload_request_callback_)
424       upload_request_callback_(upload_context_, msg_.id);
425     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
426     return;
427   }
428 
429   scoped_ptr<ClientInfo> client_info(
430       new ClientInfo(this,
431                      msg_.id,
432                      msg_.dump_type,
433                      msg_.thread_id,
434                      msg_.exception_pointers,
435                      msg_.assert_info,
436                      msg_.custom_client_info));
437 
438   if (!client_info->Initialize()) {
439     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
440     return;
441   }
442 
443   // Issues an asynchronous WriteFile call if successful.
444   // Iff successful, assigns ownership of the client_info pointer to the server
445   // instance, in which case we must be sure not to free it in this function.
446   if (!RespondToClient(client_info.get())) {
447     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
448     return;
449   }
450 
451   // This is only valid as long as it can be found in the clients_ list
452   client_info_ = client_info.release();
453 
454   // Note that the asynchronous write issued by RespondToClient function
455   // can finish before  the code below executes. But it is okay to change
456   // state after issuing the asynchronous write. This is because even if
457   // the asynchronous write is done, the callback for it would not be
458   // executed until the current thread finishes its execution.
459   EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING);
460 }
461 
462 // When the server thread serving the clients is in the WRITING state,
463 // try to get the result of the async write. If the async write is done,
464 // go into the WRITE_DONE state. For any problems, go into the
465 // DISONNECTING state.
HandleWritingState()466 void CrashGenerationServer::HandleWritingState() {
467   assert(server_state_ == IPC_SERVER_STATE_WRITING);
468 
469   DWORD bytes_count = 0;
470   bool success = GetOverlappedResult(pipe_,
471                                      &overlapped_,
472                                      &bytes_count,
473                                      FALSE) != FALSE;
474   if (success) {
475     EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE);
476     return;
477   }
478 
479   assert(!CheckForIOIncomplete(success));
480   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
481 }
482 
483 // When the server thread serving the clients is in the WRITE_DONE state,
484 // try to issue an async read on the pipe. If the read completes synchronously
485 // or if I/O is still pending then go into the READING_ACK state. For any
486 // issues, go into the DISCONNECTING state.
HandleWriteDoneState()487 void CrashGenerationServer::HandleWriteDoneState() {
488   assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
489 
490   DWORD bytes_count = 0;
491   bool success = ReadFile(pipe_,
492                            &msg_,
493                            sizeof(msg_),
494                            &bytes_count,
495                            &overlapped_) != FALSE;
496   DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
497 
498   if (success) {
499     EnterStateImmediately(IPC_SERVER_STATE_READING_ACK);
500   } else if (error_code == ERROR_IO_PENDING) {
501     EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK);
502   } else {
503     EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
504   }
505 }
506 
507 // When the server thread serving the clients is in the READING_ACK state,
508 // try to get result of async read. Go into the DISCONNECTING state.
HandleReadingAckState()509 void CrashGenerationServer::HandleReadingAckState() {
510   assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
511 
512   DWORD bytes_count = 0;
513   bool success = GetOverlappedResult(pipe_,
514                                      &overlapped_,
515                                      &bytes_count,
516                                      FALSE) != FALSE;
517   if (success) {
518     // The connection handshake with the client is now complete; perform
519     // the callback.
520     if (connect_callback_) {
521       // Note that there is only a single copy of the ClientInfo of the
522       // currently connected client.  However it is being referenced from
523       // two different places:
524       //  - the client_info_ member
525       //  - the clients_ list
526       // The lifetime of this ClientInfo depends on the lifetime of the
527       // client process - basically it can go away at any time.
528       // However, as long as it is referenced by the clients_ list it
529       // is guaranteed to be valid. Enter the critical section and check
530       // to see whether the client_info_ can be found in the list.
531       // If found, execute the callback and only then leave the critical
532       // section.
533       AutoCriticalSection lock(&sync_);
534 
535       bool client_is_still_alive = false;
536       std::list<ClientInfo*>::iterator iter;
537       for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
538         if (client_info_ == *iter) {
539           client_is_still_alive = true;
540           break;
541         }
542       }
543 
544       if (client_is_still_alive) {
545         connect_callback_(connect_context_, client_info_);
546       }
547     }
548   } else {
549     assert(!CheckForIOIncomplete(success));
550   }
551 
552   EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
553 }
554 
555 // When the server thread serving the client is in the DISCONNECTING state,
556 // disconnect from the pipe and reset the event. If anything fails, go into
557 // the ERROR state. If it goes well, go into the INITIAL state and set the
558 // event to start all over again.
HandleDisconnectingState()559 void CrashGenerationServer::HandleDisconnectingState() {
560   assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
561 
562   // Done serving the client.
563   client_info_ = NULL;
564 
565   overlapped_.Internal = NULL;
566   overlapped_.InternalHigh = NULL;
567   overlapped_.Offset = 0;
568   overlapped_.OffsetHigh = 0;
569   overlapped_.Pointer = NULL;
570 
571   if (!ResetEvent(overlapped_.hEvent)) {
572     EnterErrorState();
573     return;
574   }
575 
576   if (!DisconnectNamedPipe(pipe_)) {
577     EnterErrorState();
578     return;
579   }
580 
581   // If the server is shutting down do not connect to the
582   // next client.
583   if (shutting_down_) {
584     return;
585   }
586 
587   EnterStateImmediately(IPC_SERVER_STATE_INITIAL);
588 }
589 
EnterErrorState()590 void CrashGenerationServer::EnterErrorState() {
591   SetEvent(overlapped_.hEvent);
592   server_state_ = IPC_SERVER_STATE_ERROR;
593 }
594 
EnterStateWhenSignaled(IPCServerState state)595 void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) {
596   server_state_ = state;
597 }
598 
EnterStateImmediately(IPCServerState state)599 void CrashGenerationServer::EnterStateImmediately(IPCServerState state) {
600   server_state_ = state;
601 
602   if (!SetEvent(overlapped_.hEvent)) {
603     server_state_ = IPC_SERVER_STATE_ERROR;
604   }
605 }
606 
PrepareReply(const ClientInfo & client_info,ProtocolMessage * reply) const607 bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
608                                          ProtocolMessage* reply) const {
609   reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
610   reply->id = GetCurrentProcessId();
611 
612   if (CreateClientHandles(client_info, reply)) {
613     return true;
614   }
615 
616   // Closing of remote handles (belonging to a different process) can
617   // only be done through DuplicateHandle.
618   if (reply->dump_request_handle) {
619     DuplicateHandle(client_info.process_handle(),  // hSourceProcessHandle
620                     reply->dump_request_handle,    // hSourceHandle
621                     NULL,                          // hTargetProcessHandle
622                     0,                             // lpTargetHandle
623                     0,                             // dwDesiredAccess
624                     FALSE,                         // bInheritHandle
625                     DUPLICATE_CLOSE_SOURCE);       // dwOptions
626     reply->dump_request_handle = NULL;
627   }
628 
629   if (reply->dump_generated_handle) {
630     DuplicateHandle(client_info.process_handle(),  // hSourceProcessHandle
631                     reply->dump_generated_handle,  // hSourceHandle
632                     NULL,                          // hTargetProcessHandle
633                     0,                             // lpTargetHandle
634                     0,                             // dwDesiredAccess
635                     FALSE,                         // bInheritHandle
636                     DUPLICATE_CLOSE_SOURCE);       // dwOptions
637     reply->dump_generated_handle = NULL;
638   }
639 
640   if (reply->server_alive_handle) {
641     DuplicateHandle(client_info.process_handle(),  // hSourceProcessHandle
642                     reply->server_alive_handle,    // hSourceHandle
643                     NULL,                          // hTargetProcessHandle
644                     0,                             // lpTargetHandle
645                     0,                             // dwDesiredAccess
646                     FALSE,                         // bInheritHandle
647                     DUPLICATE_CLOSE_SOURCE);       // dwOptions
648     reply->server_alive_handle = NULL;
649   }
650 
651   return false;
652 }
653 
CreateClientHandles(const ClientInfo & client_info,ProtocolMessage * reply) const654 bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
655                                                 ProtocolMessage* reply) const {
656   HANDLE current_process = GetCurrentProcess();
657   if (!DuplicateHandle(current_process,
658                        client_info.dump_requested_handle(),
659                        client_info.process_handle(),
660                        &reply->dump_request_handle,
661                        kDumpRequestEventAccess,
662                        FALSE,
663                        0)) {
664     return false;
665   }
666 
667   if (!DuplicateHandle(current_process,
668                        client_info.dump_generated_handle(),
669                        client_info.process_handle(),
670                        &reply->dump_generated_handle,
671                        kDumpGeneratedEventAccess,
672                        FALSE,
673                        0)) {
674     return false;
675   }
676 
677   if (!DuplicateHandle(current_process,
678                        server_alive_handle_,
679                        client_info.process_handle(),
680                        &reply->server_alive_handle,
681                        kMutexAccess,
682                        FALSE,
683                        0)) {
684     return false;
685   }
686 
687   return true;
688 }
689 
RespondToClient(ClientInfo * client_info)690 bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
691   ProtocolMessage reply;
692   if (!PrepareReply(*client_info, &reply)) {
693     return false;
694   }
695 
696   DWORD bytes_count = 0;
697   bool success = WriteFile(pipe_,
698                             &reply,
699                             sizeof(reply),
700                             &bytes_count,
701                             &overlapped_) != FALSE;
702   DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
703 
704   if (!success && error_code != ERROR_IO_PENDING) {
705     return false;
706   }
707 
708   // Takes over ownership of client_info. We MUST return true if AddClient
709   // succeeds.
710   return AddClient(client_info);
711 }
712 
713 // The server thread servicing the clients runs this method. The method
714 // implements the state machine described in ReadMe.txt along with the
715 // helper methods HandleXXXState.
HandleConnectionRequest()716 void CrashGenerationServer::HandleConnectionRequest() {
717   // If the server is shutting down, get into ERROR state, reset the event so
718   // more workers don't run and return immediately.
719   if (shutting_down_) {
720     server_state_ = IPC_SERVER_STATE_ERROR;
721     ResetEvent(overlapped_.hEvent);
722     return;
723   }
724 
725   switch (server_state_) {
726     case IPC_SERVER_STATE_ERROR:
727       HandleErrorState();
728       break;
729 
730     case IPC_SERVER_STATE_INITIAL:
731       HandleInitialState();
732       break;
733 
734     case IPC_SERVER_STATE_CONNECTING:
735       HandleConnectingState();
736       break;
737 
738     case IPC_SERVER_STATE_CONNECTED:
739       HandleConnectedState();
740       break;
741 
742     case IPC_SERVER_STATE_READING:
743       HandleReadingState();
744       break;
745 
746     case IPC_SERVER_STATE_READ_DONE:
747       HandleReadDoneState();
748       break;
749 
750     case IPC_SERVER_STATE_WRITING:
751       HandleWritingState();
752       break;
753 
754     case IPC_SERVER_STATE_WRITE_DONE:
755       HandleWriteDoneState();
756       break;
757 
758     case IPC_SERVER_STATE_READING_ACK:
759       HandleReadingAckState();
760       break;
761 
762     case IPC_SERVER_STATE_DISCONNECTING:
763       HandleDisconnectingState();
764       break;
765 
766     default:
767       assert(false);
768       // This indicates that we added one more state without
769       // adding handling code.
770       server_state_ = IPC_SERVER_STATE_ERROR;
771       break;
772   }
773 }
774 
AddClient(ClientInfo * client_info)775 bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
776   HANDLE request_wait_handle = NULL;
777   if (!RegisterWaitForSingleObject(&request_wait_handle,
778                                    client_info->dump_requested_handle(),
779                                    OnDumpRequest,
780                                    client_info,
781                                    INFINITE,
782                                    kDumpRequestThreadFlags)) {
783     return false;
784   }
785 
786   client_info->set_dump_request_wait_handle(request_wait_handle);
787 
788   // OnClientEnd will be called when the client process terminates.
789   HANDLE process_wait_handle = NULL;
790   if (!RegisterWaitForSingleObject(&process_wait_handle,
791                                    client_info->process_handle(),
792                                    OnClientEnd,
793                                    client_info,
794                                    INFINITE,
795                                    WT_EXECUTEONLYONCE)) {
796     return false;
797   }
798 
799   client_info->set_process_exit_wait_handle(process_wait_handle);
800 
801   // New scope to hold the lock for the shortest time.
802   {
803     AutoCriticalSection lock(&sync_);
804     if (shutting_down_) {
805       // If server is shutting down, don't add new clients
806       return false;
807     }
808     clients_.push_back(client_info);
809   }
810 
811   return true;
812 }
813 
814 // static
OnPipeConnected(void * context,BOOLEAN)815 void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
816   assert(context);
817 
818   CrashGenerationServer* obj =
819       reinterpret_cast<CrashGenerationServer*>(context);
820   obj->HandleConnectionRequest();
821 }
822 
823 // static
OnDumpRequest(void * context,BOOLEAN)824 void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
825   assert(context);
826   ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
827 
828   CrashGenerationServer* crash_server = client_info->crash_server();
829   assert(crash_server);
830   if (crash_server->pre_fetch_custom_info_) {
831     client_info->PopulateCustomInfo();
832   }
833   crash_server->HandleDumpRequest(*client_info);
834 
835   ResetEvent(client_info->dump_requested_handle());
836 }
837 
838 // static
OnClientEnd(void * context,BOOLEAN)839 void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
840   assert(context);
841   ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
842 
843   CrashGenerationServer* crash_server = client_info->crash_server();
844   assert(crash_server);
845 
846   crash_server->HandleClientProcessExit(client_info);
847 }
848 
HandleClientProcessExit(ClientInfo * client_info)849 void CrashGenerationServer::HandleClientProcessExit(ClientInfo* client_info) {
850   assert(client_info);
851 
852   // Must unregister the dump request wait operation and wait for any
853   // dump requests that might be pending to finish before proceeding
854   // with the client_info cleanup.
855   client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending();
856 
857   if (exit_callback_) {
858     exit_callback_(exit_context_, client_info);
859   }
860 
861   // Start a new scope to release lock automatically.
862   {
863     AutoCriticalSection lock(&sync_);
864     if (shutting_down_) {
865       // The crash generation server is shutting down and as part of the
866       // shutdown process it will delete all clients from the clients_ list.
867       return;
868     }
869     clients_.remove(client_info);
870   }
871 
872   // Explicitly unregister the process exit wait using the non-blocking method.
873   // Otherwise, the destructor will attempt to unregister it using the blocking
874   // method which will lead to a deadlock because it is being called from the
875   // callback of the same wait operation
876   client_info->UnregisterProcessExitWait(false);
877 
878   delete client_info;
879 }
880 
HandleDumpRequest(const ClientInfo & client_info)881 void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
882   bool execute_callback = true;
883   // Generate the dump only if it's explicitly requested by the
884   // server application; otherwise the server might want to generate
885   // dump in the callback.
886   std::wstring dump_path;
887   if (generate_dumps_) {
888     if (!GenerateDump(client_info, &dump_path)) {
889       // client proccess terminated or some other error
890       execute_callback = false;
891     }
892   }
893 
894   if (dump_callback_ && execute_callback) {
895     std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path;
896     dump_callback_(dump_context_, &client_info, ptr_dump_path);
897   }
898 
899   SetEvent(client_info.dump_generated_handle());
900 }
901 
GenerateDump(const ClientInfo & client,std::wstring * dump_path)902 bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
903                                          std::wstring* dump_path) {
904   assert(client.pid() != 0);
905   assert(client.process_handle());
906 
907   // We have to get the address of EXCEPTION_INFORMATION from
908   // the client process address space.
909   EXCEPTION_POINTERS* client_ex_info = NULL;
910   if (!client.GetClientExceptionInfo(&client_ex_info)) {
911     return false;
912   }
913 
914   DWORD client_thread_id = 0;
915   if (!client.GetClientThreadId(&client_thread_id)) {
916     return false;
917   }
918 
919   MinidumpGenerator dump_generator(dump_path_,
920                                    client.process_handle(),
921                                    client.pid(),
922                                    client_thread_id,
923                                    GetCurrentThreadId(),
924                                    client_ex_info,
925                                    client.assert_info(),
926                                    client.dump_type(),
927                                    true);
928 
929   if (!dump_generator.GenerateDumpFile(dump_path)) {
930     return false;
931   }
932 
933   // If the client requests a full memory dump, we will write a normal mini
934   // dump and a full memory dump. Both dump files use the same uuid as file
935   // name prefix.
936   if (client.dump_type() & MiniDumpWithFullMemory) {
937     std::wstring full_dump_path;
938     if (!dump_generator.GenerateFullDumpFile(&full_dump_path)) {
939       return false;
940     }
941   }
942 
943   return dump_generator.WriteMinidump();
944 }
945 
946 }  // namespace google_breakpad
947