src: properly report exceptions from AddressToJS()

Signed-off-by: Darshan Sen <raisinten@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/42054
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
Darshan Sen 2022-03-26 21:09:59 +05:30 committed by GitHub
parent 99c46a62da
commit bc395d4c53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 67 additions and 16 deletions

View File

@ -159,7 +159,7 @@ function startListening(socket) {
const state = socket[kStateSymbol];
state.handle.onmessage = onMessage;
// Todo: handle errors
state.handle.onerror = onError;
state.handle.recvStart();
state.receiving = true;
state.bindState = BIND_STATE_BOUND;
@ -923,6 +923,12 @@ function onMessage(nread, handle, buf, rinfo) {
}
function onError(nread, handle, error) {
const self = handle[owner_symbol];
return self.emit('error', error);
}
Socket.prototype.ref = function() {
const handle = this[kStateSymbol].handle;

View File

@ -5,6 +5,9 @@
#include <algorithm>
// TODO(RaisinTen): Replace all uses with empty `v8::Maybe`s.
#define JS_EXCEPTION_PENDING UV_EPROTO
namespace node {
using errors::TryCatchScope;
@ -60,7 +63,7 @@ int JSUDPWrap::RecvStart() {
Context::Scope context_scope(env()->context());
TryCatchScope try_catch(env());
Local<Value> value;
int32_t value_int = UV_EPROTO;
int32_t value_int = JS_EXCEPTION_PENDING;
if (!MakeCallback(env()->onreadstart_string(), 0, nullptr).ToLocal(&value) ||
!value->Int32Value(env()->context()).To(&value_int)) {
if (try_catch.HasCaught() && !try_catch.HasTerminated())
@ -74,7 +77,7 @@ int JSUDPWrap::RecvStop() {
Context::Scope context_scope(env()->context());
TryCatchScope try_catch(env());
Local<Value> value;
int32_t value_int = UV_EPROTO;
int32_t value_int = JS_EXCEPTION_PENDING;
if (!MakeCallback(env()->onreadstop_string(), 0, nullptr).ToLocal(&value) ||
!value->Int32Value(env()->context()).To(&value_int)) {
if (try_catch.HasCaught() && !try_catch.HasTerminated())
@ -90,7 +93,7 @@ ssize_t JSUDPWrap::Send(uv_buf_t* bufs,
Context::Scope context_scope(env()->context());
TryCatchScope try_catch(env());
Local<Value> value;
int64_t value_int = UV_EPROTO;
int64_t value_int = JS_EXCEPTION_PENDING;
size_t total_len = 0;
MaybeStackBuffer<Local<Value>, 16> buffers(nbufs);
@ -100,10 +103,13 @@ ssize_t JSUDPWrap::Send(uv_buf_t* bufs,
total_len += bufs[i].len;
}
Local<Object> address;
if (!AddressToJS(env(), addr).ToLocal(&address)) return value_int;
Local<Value> args[] = {
listener()->CreateSendWrap(total_len)->object(),
Array::New(env()->isolate(), buffers.out(), nbufs),
AddressToJS(env(), addr)
address,
};
if (!MakeCallback(env()->onwrite_string(), arraysize(args), args)

View File

@ -58,7 +58,7 @@ class Environment;
// Convert a struct sockaddr to a { address: '1.2.3.4', port: 1234 } JS object.
// Sets address and port properties on the info object and returns it.
// If |info| is omitted, a new object is returned.
v8::Local<v8::Object> AddressToJS(
v8::MaybeLocal<v8::Object> AddressToJS(
Environment* env,
const sockaddr* addr,
v8::Local<v8::Object> info = v8::Local<v8::Object>());

View File

@ -157,7 +157,7 @@ void SocketAddress::Update(const sockaddr* data, size_t len) {
memcpy(&address_, data, len);
}
v8::Local<v8::Object> SocketAddress::ToJS(
v8::MaybeLocal<v8::Object> SocketAddress::ToJS(
Environment* env,
v8::Local<v8::Object> info) const {
return AddressToJS(env, data(), info);

View File

@ -847,7 +847,9 @@ void SocketAddressBase::LegacyDetail(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBase* base;
ASSIGN_OR_RETURN_UNWRAP(&base, args.Holder());
args.GetReturnValue().Set(base->address_->ToJS(env));
Local<Object> address;
if (!base->address_->ToJS(env).ToLocal(&address)) return;
args.GetReturnValue().Set(address);
}
SocketAddressBase::SocketAddressBase(

View File

@ -131,7 +131,7 @@ class SocketAddress : public MemoryRetainer {
static SocketAddress FromPeerName(const uv_udp_t& handle);
static SocketAddress FromPeerName(const uv_tcp_t& handle);
inline v8::Local<v8::Object> ToJS(
inline v8::MaybeLocal<v8::Object> ToJS(
Environment* env,
v8::Local<v8::Object> obj = v8::Local<v8::Object>()) const;

View File

@ -342,9 +342,9 @@ void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args,
// also used by udp_wrap.cc
Local<Object> AddressToJS(Environment* env,
const sockaddr* addr,
Local<Object> info) {
MaybeLocal<Object> AddressToJS(Environment* env,
const sockaddr* addr,
Local<Object> info) {
EscapableHandleScope scope(env->isolate());
char ip[INET6_ADDRSTRLEN + UV_IF_NAMESIZE];
const sockaddr_in* a4;
@ -371,8 +371,7 @@ Local<Object> AddressToJS(Environment* env,
&scopeidlen);
if (r) {
env->ThrowUVException(r, "uv_if_indextoiid");
// TODO(addaleax): Do proper MaybeLocal handling here
return scope.Escape(info);
return {};
}
}
port = ntohs(a6->sin6_port);

View File

@ -22,6 +22,7 @@
#include "udp_wrap.h"
#include "env-inl.h"
#include "node_buffer.h"
#include "node_errors.h"
#include "node_sockaddr-inl.h"
#include "handle_wrap.h"
#include "req_wrap-inl.h"
@ -29,6 +30,7 @@
namespace node {
using errors::TryCatchScope;
using v8::Array;
using v8::ArrayBuffer;
using v8::BackingStore;
@ -728,9 +730,45 @@ void UDPWrap::OnRecv(ssize_t nread,
bs = BackingStore::Reallocate(isolate, std::move(bs), nread);
}
Local<Object> address;
{
bool has_caught = false;
{
TryCatchScope try_catch(env);
if (!AddressToJS(env, addr).ToLocal(&address)) {
DCHECK(try_catch.HasCaught() && !try_catch.HasTerminated());
argv[2] = try_catch.Exception();
DCHECK(!argv[2].IsEmpty());
has_caught = true;
}
}
if (has_caught) {
DCHECK(!argv[2].IsEmpty());
MakeCallback(env->onerror_string(), arraysize(argv), argv);
return;
}
}
Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, std::move(bs));
argv[2] = Buffer::New(env, ab, 0, ab->ByteLength()).ToLocalChecked();
argv[3] = AddressToJS(env, addr);
{
bool has_caught = false;
{
TryCatchScope try_catch(env);
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&argv[2])) {
DCHECK(try_catch.HasCaught() && !try_catch.HasTerminated());
argv[2] = try_catch.Exception();
DCHECK(!argv[2].IsEmpty());
has_caught = true;
}
}
if (has_caught) {
DCHECK(!argv[2].IsEmpty());
MakeCallback(env->onerror_string(), arraysize(argv), argv);
return;
}
}
argv[3] = address;
MakeCallback(env->onmessage_string(), arraysize(argv), argv);
}