-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
domains: fix handling of uncaught exceptions
Fix node exiting due to an exception being thrown rather than emitting an 'uncaughtException' event on the process object when: 1. no error handler is set on the domain within which an error is thrown 2. an 'uncaughtException' event listener is set on the process Also fix an issue where the process would not abort in the proper function call if an error is thrown within a domain with no error handler and --abort-on-uncaught-exception is used. Fixes #3607 and #3653.
- Loading branch information
Julien Gilli
committed
Nov 24, 2015
1 parent
ca97fb6
commit 007a7c2
Showing
6 changed files
with
703 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
'use strict'; | ||
|
||
// This test makes sure that when using --abort-on-uncaught-exception and | ||
// when throwing an error from within a domain that has an error handler | ||
// setup, the process _does not_ abort. | ||
|
||
var common = require('../common'); | ||
var assert = require('assert'); | ||
var domain = require('domain'); | ||
var child_process = require('child_process'); | ||
|
||
var errorHandlerCalled = false; | ||
|
||
var tests = [ | ||
function nextTick() { | ||
var d = domain.create(); | ||
|
||
d.once('error', function(err) { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
process.nextTick(function() { | ||
throw new Error('exceptional!'); | ||
}); | ||
}); | ||
}, | ||
|
||
function timer() { | ||
var d = domain.create(); | ||
|
||
d.on('error', function(err) { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
setTimeout(function() { | ||
throw new Error('exceptional!'); | ||
}, 33); | ||
}); | ||
}, | ||
|
||
function immediate() { | ||
console.log('starting test'); | ||
var d = domain.create(); | ||
|
||
d.on('error', function errorHandler() { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
setImmediate(function() { | ||
throw new Error('boom!'); | ||
}); | ||
}); | ||
}, | ||
|
||
function timerPlusNextTick() { | ||
var d = domain.create(); | ||
|
||
d.on('error', function(err) { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
setTimeout(function() { | ||
process.nextTick(function() { | ||
throw new Error('exceptional!'); | ||
}); | ||
}, 33); | ||
}); | ||
}, | ||
|
||
function firstRun() { | ||
var d = domain.create(); | ||
|
||
d.on('error', function(err) { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
throw new Error('exceptional!'); | ||
}); | ||
}, | ||
|
||
function fsAsync() { | ||
var d = domain.create(); | ||
|
||
d.on('error', function errorHandler() { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
var fs = require('fs'); | ||
fs.exists('/non/existing/file', function onExists(exists) { | ||
throw new Error('boom!'); | ||
}); | ||
}); | ||
}, | ||
|
||
function netServer() { | ||
var net = require('net'); | ||
var d = domain.create(); | ||
|
||
d.on('error', function(err) { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
var server = net.createServer(function(conn) { | ||
conn.pipe(conn); | ||
}); | ||
server.listen(common.PORT, '0.0.0.0', function() { | ||
var conn = net.connect(common.PORT, '0.0.0.0'); | ||
conn.once('data', function() { | ||
throw new Error('ok'); | ||
}); | ||
conn.end('ok'); | ||
server.close(); | ||
}); | ||
}); | ||
}, | ||
|
||
function firstRunNestedWithErrorHandler() { | ||
var d = domain.create(); | ||
var d2 = domain.create(); | ||
|
||
d2.on('error', function errorHandler() { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
d2.run(function() { | ||
throw new Error('boom!'); | ||
}); | ||
}); | ||
}, | ||
|
||
function timeoutNestedWithErrorHandler() { | ||
var d = domain.create(); | ||
var d2 = domain.create(); | ||
|
||
d2.on('error', function errorHandler() { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
d2.run(function() { | ||
setTimeout(function() { | ||
console.log('foo'); | ||
throw new Error('boom!'); | ||
}, 33); | ||
}); | ||
}); | ||
}, | ||
|
||
function setImmediateNestedWithErrorHandler() { | ||
var d = domain.create(); | ||
var d2 = domain.create(); | ||
|
||
d2.on('error', function errorHandler() { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
d2.run(function() { | ||
setImmediate(function() { | ||
throw new Error('boom!'); | ||
}); | ||
}); | ||
}); | ||
}, | ||
|
||
function nextTickNestedWithErrorHandler() { | ||
var d = domain.create(); | ||
var d2 = domain.create(); | ||
|
||
d2.on('error', function errorHandler() { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
d2.run(function() { | ||
process.nextTick(function() { | ||
throw new Error('boom!'); | ||
}); | ||
}); | ||
}); | ||
}, | ||
|
||
function fsAsyncNestedWithErrorHandler() { | ||
var d = domain.create(); | ||
var d2 = domain.create(); | ||
|
||
d2.on('error', function errorHandler() { | ||
errorHandlerCalled = true; | ||
}); | ||
|
||
d.run(function() { | ||
d2.run(function() { | ||
var fs = require('fs'); | ||
fs.exists('/non/existing/file', function onExists(exists) { | ||
throw new Error('boom!'); | ||
}); | ||
}); | ||
}); | ||
} | ||
]; | ||
|
||
if (process.argv[2] === 'child') { | ||
var testIndex = +process.argv[3]; | ||
|
||
tests[testIndex](); | ||
|
||
process.on('exit', function onExit() { | ||
assert.equal(errorHandlerCalled, true); | ||
}); | ||
} else { | ||
|
||
tests.forEach(function(test, testIndex) { | ||
var testCmd = ''; | ||
if (process.platform !== 'win32') { | ||
// Do not create core files, as it can take a lot of disk space on | ||
// continuous testing and developers' machines | ||
testCmd += 'ulimit -c 0 && '; | ||
} | ||
|
||
testCmd += process.argv[0]; | ||
testCmd += ' ' + '--abort-on-uncaught-exception'; | ||
testCmd += ' ' + process.argv[1]; | ||
testCmd += ' ' + 'child'; | ||
testCmd += ' ' + testIndex; | ||
|
||
var child = child_process.exec(testCmd); | ||
|
||
child.on('exit', function onExit(code, signal) { | ||
assert.equal(code, 0, 'Test at index ' + testIndex + | ||
' should have exited with exit code 0 but instead exited with code ' + | ||
code + ' and signal ' + signal); | ||
}); | ||
|
||
}); | ||
} |
Oops, something went wrong.