From f8cb03fe2634ee927b3b6aa6ecbdd824cd0bc940 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 13 Sep 2013 14:29:09 -0700 Subject: Report fatal translator errors to the browser Install a fatal error handler for the translator, which stores the error string, signals an error to the RPC thread, and terminates the thread (instead of terminating the whole program). This will cause the error to go to the Javascript console in Chrome BUG= https://code.google.com/p/nativeclient/issues/detail?id=3519 R=jvoung@chromium.org Review URL: https://codereview.chromium.org/23753003 --- tools/pnacl-llc/SRPCStreamer.cpp | 19 +++++++++++++++---- tools/pnacl-llc/SRPCStreamer.h | 9 +++++---- tools/pnacl-llc/pnacl-llc.cpp | 30 +++++++++++++++++++++++------- tools/pnacl-llc/srpc_main.cpp | 15 +++++++++++++-- 4 files changed, 56 insertions(+), 17 deletions(-) (limited to 'tools') diff --git a/tools/pnacl-llc/SRPCStreamer.cpp b/tools/pnacl-llc/SRPCStreamer.cpp index e6546aef5f..ddec846d2c 100644 --- a/tools/pnacl-llc/SRPCStreamer.cpp +++ b/tools/pnacl-llc/SRPCStreamer.cpp @@ -119,19 +119,30 @@ llvm::DataStreamer *SRPCStreamer::init(void *(*Callback)(void *), void *arg, } size_t SRPCStreamer::gotChunk(unsigned char *bytes, size_t len) { - if (Error) return 0; + if (__sync_fetch_and_add(&Error, 0)) return 0; // Atomic read. return Q.PutBytes(bytes, len); } int SRPCStreamer::streamEnd(std::string *ErrMsg) { Q.SetDone(); int err = pthread_join(CompileThread, NULL); - if (err) { + __sync_synchronize(); + if (Error) { + if (ErrMsg) + *ErrMsg = std::string("PNaCl Translator Error: " + ErrorMessage); + return 1; + } else if (err) { if (ErrMsg) *ErrMsg = std::string(strerror(errno)); return err; } - if (Error && ErrMsg) *ErrMsg = std::string("compile failed."); - return Error; + return 0; +} + +void SRPCStreamer::setFatalError(const std::string& message) { + __sync_fetch_and_add(&Error, 1); + ErrorMessage = message; + __sync_synchronize(); + pthread_exit(NULL); } #endif // __native_client__ diff --git a/tools/pnacl-llc/SRPCStreamer.h b/tools/pnacl-llc/SRPCStreamer.h index 805552be1f..bde86e5d9f 100644 --- a/tools/pnacl-llc/SRPCStreamer.h +++ b/tools/pnacl-llc/SRPCStreamer.h @@ -98,11 +98,12 @@ public: size_t gotChunk(unsigned char *bytes, size_t len); // Called by the RPC thread. Wait for the compilation thread to finish. int streamEnd(std::string *ErrMsg); - // Called by the compilation thread. Signal that there was a compilation - // error so the RPC thread can abort the stream. - void setError() { Error = true; } + // Called by the compilation thread. Set the error condition and also + // terminate the thread. + void setFatalError(const std::string& message); private: - bool Error; + int Error; + std::string ErrorMessage; QueueStreamer Q; pthread_t CompileThread; }; diff --git a/tools/pnacl-llc/pnacl-llc.cpp b/tools/pnacl-llc/pnacl-llc.cpp index 31d546ab3e..cac4fa83a4 100644 --- a/tools/pnacl-llc/pnacl-llc.cpp +++ b/tools/pnacl-llc/pnacl-llc.cpp @@ -28,6 +28,7 @@ #include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" @@ -52,6 +53,7 @@ using namespace llvm; int srpc_main(int argc, char **argv); int getObjectFileFD(); DataStreamer *getNaClBitcodeStreamer(); +fatal_error_handler_t getSRPCErrorHandler(); #endif cl::opt @@ -215,6 +217,10 @@ int llc_main(int argc, char **argv) { LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. +#if defined(__native_client__) + install_fatal_error_handler(getSRPCErrorHandler(), NULL); +#endif + // Initialize targets first, so that --version shows registered targets. InitializeAllTargets(); InitializeAllTargetMCs(); @@ -252,11 +258,15 @@ int llc_main(int argc, char **argv) { static void CheckABIVerifyErrors(PNaClABIErrorReporter &Reporter, const Twine &Name) { if (PNaClABIVerify && Reporter.getErrorCount() > 0) { - errs() << (PNaClABIVerifyFatalErrors ? "ERROR: " : "WARNING: "); - errs() << Name << " is not valid PNaCl bitcode:\n"; - Reporter.printErrors(errs()); - if (PNaClABIVerifyFatalErrors) - exit(1); + std::string errors; + raw_string_ostream os(errors); + os << (PNaClABIVerifyFatalErrors ? "ERROR: " : "WARNING: "); + os << Name << " is not valid PNaCl bitcode:\n"; + Reporter.printErrors(os); + if (PNaClABIVerifyFatalErrors) { + report_fatal_error(os.str()); + } + errs() << os.str(); } Reporter.reset(); } @@ -273,11 +283,12 @@ static int compileModule(StringRef ProgramName, LLVMContext &Context) { #if defined(__native_client__) if (LazyBitcode) { std::string StrError; + std::string DisplayFilename(""); M.reset(getNaClStreamedBitcodeModule( - std::string(""), + DisplayFilename, getNaClBitcodeStreamer(), Context, &StrError)); if (!StrError.empty()) - Err = SMDiagnostic(InputFilename, SourceMgr::DK_Error, StrError); + Err = SMDiagnostic(DisplayFilename, SourceMgr::DK_Error, StrError); } else { llvm_unreachable("native client SRPC only supports streaming"); } @@ -287,8 +298,13 @@ static int compileModule(StringRef ProgramName, LLVMContext &Context) { mod = M.get(); if (mod == 0) { +#if defined(__native_client__) + report_fatal_error(Err.getMessage()); +#else + // Err.print is prettier, so use it for the non-sandboxed translator. Err.print(ProgramName.data(), errs()); return 1; +#endif } if (PNaClABIVerify) { diff --git a/tools/pnacl-llc/srpc_main.cpp b/tools/pnacl-llc/srpc_main.cpp index 87178c2038..46d79ce441 100644 --- a/tools/pnacl-llc/srpc_main.cpp +++ b/tools/pnacl-llc/srpc_main.cpp @@ -32,6 +32,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Option/Option.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/system_error.h" using namespace llvm; @@ -202,8 +203,10 @@ void *run_streamed(void *arg) { StreamingThreadData *data = reinterpret_cast(arg); data->CmdLineVec()->push_back("-streaming-bitcode"); if (DoTranslate(data->CmdLineVec(), data->ObjectFD()) != 0) { - fprintf(stderr, "DoTranslate failed.\n"); - srpc_streamer->setError(); + // llc_main only returns 1 (as opposed to calling report_fatal_error) + // in conditions we never expect to see in the browser (e.g. bad + // command-line flags). + srpc_streamer->setFatalError("llc_main unspecified failure"); return NULL; } delete data; @@ -351,6 +354,14 @@ int getObjectFileFD() { return object_file_fd; } DataStreamer *getNaClBitcodeStreamer() { return NaClBitcodeStreamer; } +// Called from the compilation thread +void FatalErrorHandler(void *user_data, const std::string& reason, + bool gen_crash_diag) { + srpc_streamer->setFatalError(reason); +} + +fatal_error_handler_t getSRPCErrorHandler() { return FatalErrorHandler; } + int srpc_main(int argc, char **argv) { if (!NaClSrpcModuleInit()) { return 1; -- cgit v1.2.3-18-g5258