Skip to content

Commit

Permalink
src: handle TryCatch with empty message
Browse files Browse the repository at this point in the history
This bug needs a test case with a high goldilocks factor to trigger
but the synopsis is that `v8::TryCatch::Message()` returns an empty
handle when the TryCatch is declared at a time when an exception is
already pending.

We now recompute the message inside `node::ReportException()` and
all is well again.

PR-URL: #20708
Fixes: #8854
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
  • Loading branch information
bnoordhuis authored and apapirovski committed May 16, 2018
1 parent 9e4ae56 commit de4e0d7
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1414,9 +1414,11 @@ static void ReportException(Environment* env,
Local<Value> er,
Local<Message> message) {
CHECK(!er.IsEmpty());
CHECK(!message.IsEmpty());
HandleScope scope(env->isolate());

if (message.IsEmpty())
message = Exception::CreateMessage(env->isolate(), er);

AppendExceptionLine(env, er, message, FATAL_ERROR);

Local<Value> trace_value;
Expand Down
57 changes: 57 additions & 0 deletions test/parallel/test-tls-handshake-exception.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

// Verify that exceptions from a callback don't result in
// failed CHECKs when trying to print the exception message.

// This test is convoluted because it needs to trigger a callback
// into JS land at just the right time when an exception is pending,
// and does so by exploiting a weakness in the streams infrastructure.
// I won't shed any tears if this test ever becomes invalidated.

const common = require('../common');

if (!common.hasCrypto)
common.skip('missing crypto');

if (process.argv[2] === 'child') {
const fixtures = require('../common/fixtures');
const https = require('https');
const net = require('net');
const tls = require('tls');
const { Duplex } = require('stream');
const { mustCall } = common;

const cert = fixtures.readSync('test_cert.pem');
const key = fixtures.readSync('test_key.pem');

net.createServer(mustCall(onplaintext)).listen(0, mustCall(onlisten));

function onlisten() {
const { port } = this.address();
https.get({ port, rejectUnauthorized: false });
}

function onplaintext(c) {
const d = new class extends Duplex {
_read(n) {
const data = c.read(n);
if (data) d.push(data);
}
_write(...xs) {
c.write(...xs);
}
}();
c.on('data', d.push.bind(d));

const options = { key, cert };
const fail = () => { throw new Error('eyecatcher'); };
tls.createServer(options, mustCall(fail)).emit('connection', d);
}
} else {
const assert = require('assert');
const { spawnSync } = require('child_process');
const result = spawnSync(process.execPath, [__filename, 'child']);
const stderr = result.stderr.toString();
const ok = stderr.includes('Error: eyecatcher');
assert(ok, stderr);
}

0 comments on commit de4e0d7

Please sign in to comment.