vm: fix crash on fatal error in debug context
Ensure that the debug context has an Environment assigned in case a fatal error is raised. The fatal exception handler in node.cc is not equipped to deal with contexts that don't have one and can't easily be taught that due to a deficiency in the V8 API: there is no way for the embedder to tell if the data index is in use. Fixes: https://github.com/iojs/io.js/issues/1190 PR-URL: https://github.com/iojs/io.js/pull/1229 Reviewed-By: Fedor Indutny <fedor@indutny.com>
This commit is contained in:
parent
d8f383ba3f
commit
cf081a4712
@ -474,6 +474,8 @@ class Environment {
|
||||
inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; }
|
||||
inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; }
|
||||
|
||||
static const int kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX;
|
||||
|
||||
private:
|
||||
static const int kIsolateSlot = NODE_ISOLATE_SLOT;
|
||||
|
||||
@ -482,10 +484,6 @@ class Environment {
|
||||
inline ~Environment();
|
||||
inline IsolateData* isolate_data() const;
|
||||
|
||||
enum ContextEmbedderDataIndex {
|
||||
kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX
|
||||
};
|
||||
|
||||
v8::Isolate* const isolate_;
|
||||
IsolateData* const isolate_data_;
|
||||
uv_check_t immediate_check_handle_;
|
||||
|
@ -233,10 +233,32 @@ class ContextifyContext {
|
||||
|
||||
|
||||
static void RunInDebugContext(const FunctionCallbackInfo<Value>& args) {
|
||||
// Ensure that the debug context has an Environment assigned in case
|
||||
// a fatal error is raised. The fatal exception handler in node.cc
|
||||
// is not equipped to deal with contexts that don't have one and
|
||||
// can't easily be taught that due to a deficiency in the V8 API:
|
||||
// there is no way for the embedder to tell if the data index is
|
||||
// in use.
|
||||
struct ScopedEnvironment {
|
||||
ScopedEnvironment(Local<Context> context, Environment* env)
|
||||
: context_(context) {
|
||||
const int index = Environment::kContextEmbedderDataIndex;
|
||||
context->SetAlignedPointerInEmbedderData(index, env);
|
||||
}
|
||||
~ScopedEnvironment() {
|
||||
const int index = Environment::kContextEmbedderDataIndex;
|
||||
context_->SetAlignedPointerInEmbedderData(index, nullptr);
|
||||
}
|
||||
Local<Context> context_;
|
||||
};
|
||||
|
||||
Local<String> script_source(args[0]->ToString(args.GetIsolate()));
|
||||
if (script_source.IsEmpty())
|
||||
return; // Exception pending.
|
||||
Context::Scope context_scope(Debug::GetDebugContext());
|
||||
Local<Context> debug_context = Debug::GetDebugContext();
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
ScopedEnvironment env_scope(debug_context, env);
|
||||
Context::Scope context_scope(debug_context);
|
||||
Local<Script> script = Script::Compile(script_source);
|
||||
if (script.IsEmpty())
|
||||
return; // Exception pending.
|
||||
|
4
test/fixtures/vm-run-in-debug-context.js
vendored
Normal file
4
test/fixtures/vm-run-in-debug-context.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
if (process.argv[2] === 'handle-fatal-exception')
|
||||
process._fatalException = process.exit.bind(null, 42);
|
||||
|
||||
require('vm').runInDebugContext('*');
|
@ -1,6 +1,7 @@
|
||||
var common = require('../common');
|
||||
var assert = require('assert');
|
||||
var vm = require('vm');
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
assert.throws(function() {
|
||||
vm.runInDebugContext('*');
|
||||
@ -25,3 +26,25 @@ assert.strictEqual(vm.runInDebugContext(), undefined);
|
||||
assert.strictEqual(vm.runInDebugContext(0), 0);
|
||||
assert.strictEqual(vm.runInDebugContext(null), null);
|
||||
assert.strictEqual(vm.runInDebugContext(undefined), undefined);
|
||||
|
||||
// See https://github.com/iojs/io.js/issues/1190, fatal errors should not
|
||||
// crash the process.
|
||||
var script = common.fixturesDir + '/vm-run-in-debug-context.js';
|
||||
var proc = spawn(process.execPath, [script]);
|
||||
var data = [];
|
||||
proc.stdout.on('data', assert.fail);
|
||||
proc.stderr.on('data', data.push.bind(data));
|
||||
proc.once('exit', common.mustCall(function(exitCode, signalCode) {
|
||||
assert.equal(exitCode, 1);
|
||||
assert.equal(signalCode, null);
|
||||
var haystack = Buffer.concat(data).toString('utf8');
|
||||
assert(/SyntaxError: Unexpected token \*/.test(haystack));
|
||||
}));
|
||||
|
||||
var proc = spawn(process.execPath, [script, 'handle-fatal-exception']);
|
||||
proc.stdout.on('data', assert.fail);
|
||||
proc.stderr.on('data', assert.fail);
|
||||
proc.once('exit', common.mustCall(function(exitCode, signalCode) {
|
||||
assert.equal(exitCode, 42);
|
||||
assert.equal(signalCode, null);
|
||||
}));
|
||||
|
Loading…
x
Reference in New Issue
Block a user