blob: 05a6fda559ea5bbba9bfe8cc0b99a7d6f62c1cdb [file] [log] [blame]
/*
* Copyright (c) 2012 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <intrin.h>
#include <stdlib.h>
#include <stdio.h>
#include "native_client/src/include/portability.h"
#include "native_client/src/shared/platform/nacl_exit.h"
#include "native_client/src/trusted/service_runtime/nacl_signal.h"
/*
* The MSVC compiler wrongly gives an "unreachable code" warning for
* the contents of NaClAbort. Best guess is that it inlines NaClAbort
* into NaClExit, sees that the call is after the call to ExitProcess
* and ExitProcess is marked as never returning, and decides the body
* of NaClAbort is unreachable. As this is not the only call to
* NaClAbort, the compiler is just wrong and the only thing to do is
* just to suppress the warning.
*/
#pragma warning(disable:4702)
void NaClAbort(void) {
/*
* We crash the process with a HLT instruction so that the Breakpad
* crash reporter will be invoked when we are running inside Chrome.
*
* This has the disadvantage that an untrusted-code crash will not
* be distinguishable from a trusted-code NaClAbort() based on the
* process's exit status alone
*
* While we could use the INT3 breakpoint instruction to exit (via
* __debugbreak()), that does not work if NaCl's debug exception
* handler is attached, because that always resumes breakpoints (see
* http://code.google.com/p/nativeclient/issues/detail?id=2772).
*/
while (1) {
__halt();
}
}
void NaClExit(int err_code) {
#ifdef COVERAGE
/* Give coverage runs a chance to flush coverage data */
exit(err_code);
#else
/*
* We want to exit without running any finalization code, because
* that could cause currently-running threads to crash.
*
* We avoid using exit() because it calls atexit() handlers. We
* avoid using _exit() because it is documented as doing some
* internal C library shutdown.
*
* We avoid using TerminateProcess() because it terminates threads
* in a non-deterministic order. On Windows, the exit status of a
* process is taken to be the exit status of the last thread that
* exited. Using TerminateProcess() makes the exit status of the
* process unreliable; this used to cause many tests to be flaky.
* See https://code.google.com/p/nativeclient/issues/detail?id=2870
*
* ExitProcess() has the following properties:
*
* - It first terminates all threads except the calling thread.
* This prevents these threads from messing up the process exit
* status.
*
* - It calls loaded DLLs' finalization routines. This is not
* ideal, but it is OK because NaClExit() should only be used for
* graceful exits (when no internal errors have been detected),
* and because there will be no other threads at this point.
*/
ExitProcess(err_code);
/* Just in case. */
NaClAbort();
#endif
}