From 2b252acea47af3ebeac3d7e68277f015667264cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Geisend=C3=B6rfer?= Date: Sat, 14 Nov 2009 23:07:54 +0100 Subject: [PATCH] Implement process "uncaughtException" event This event can be used to overwrite the default exception mechanism which reports the exception and kills the node process. See google group post: http://groups.google.com/group/nodejs/browse_thread/thread/9721dc3a2638446f --- src/node.cc | 46 ++++++++++++++++++++++++-- src/node.js | 1 - test/mjsunit/test-exception-handler.js | 25 ++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 test/mjsunit/test-exception-handler.js diff --git a/src/node.cc b/src/node.cc index be86e20917..04f55f5d6b 100644 --- a/src/node.cc +++ b/src/node.cc @@ -524,9 +524,51 @@ static void OnFatalError(const char* location, const char* message) { exit(1); } +static int uncaught_exception_counter = 0; + void FatalException(TryCatch &try_catch) { - ReportException(&try_catch); - exit(1); + HandleScope scope; + + // Check if uncaught_exception_counter indicates a recursion + if (uncaught_exception_counter > 0) { + ReportException(&try_catch); + exit(1); + } + + Local listeners_v = process->Get(String::NewSymbol("listeners")); + assert(listeners_v->IsFunction()); + + Local listeners = Local::Cast(listeners_v); + + Local uncaught_exception = String::NewSymbol("uncaughtException"); + + Local argv[1] = { uncaught_exception }; + Local ret = listeners->Call(process, 1, argv); + + assert(ret->IsArray()); + + Local listener_array = Local::Cast(ret); + + uint32_t length = listener_array->Length(); + // Report and exit if process has no "uncaughtException" listener + if (length == 0) { + ReportException(&try_catch); + exit(1); + } + + // Otherwise fire the process "uncaughtException" event + Local emit_v = process->Get(String::NewSymbol("emit")); + assert(emit_v->IsFunction()); + + Local emit = Local::Cast(emit_v); + + Local error = try_catch.Exception(); + Local event_argv[2] = { uncaught_exception, error }; + + uncaught_exception_counter++; + emit->Call(process, 2, event_argv); + // Decrement so we know if the next exception is a recursion or not + uncaught_exception_counter--; } static ev_async eio_watcher; diff --git a/src/node.js b/src/node.js index 48c3841de0..6876a228e8 100644 --- a/src/node.js +++ b/src/node.js @@ -677,6 +677,5 @@ if (process.ARGV[1].charAt(0) != "/" && !/^http:\/\//.exec(process.ARGV[1])) { process.mainModule = createModule("."); var loadPromise = new process.Promise(); process.mainModule.load(process.ARGV[1], loadPromise); -loadPromise.wait(); }()); // end annonymous namespace diff --git a/test/mjsunit/test-exception-handler.js b/test/mjsunit/test-exception-handler.js new file mode 100644 index 0000000000..4a37769606 --- /dev/null +++ b/test/mjsunit/test-exception-handler.js @@ -0,0 +1,25 @@ +process.mixin(require("./common")); + +var MESSAGE = 'catch me if you can'; +var caughtException = false; + +process.addListener('uncaughtException', function (e) { + puts("uncaught exception! 1"); + assertEquals(MESSAGE, e.message); + caughtException = true; +}); + +process.addListener('uncaughtException', function (e) { + puts("uncaught exception! 2"); + assertEquals(MESSAGE, e.message); + caughtException = true; +}); + +setTimeout(function() { + throw new Error(MESSAGE); +}, 10); + +process.addListener("exit", function () { + puts("exit"); + assertTrue(caughtException); +});