src: rework (mostly internal) functions to use Maybes
Rework all affected functions to use Maybes, thus improving error handling substantially in internal functions, API functions as well as utilities. Co-authored-by: Michaël Zasso <targos@protonmail.com> PR-URL: https://github.com/nodejs/node/pull/21935 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
67403b3a84
commit
a55c57b8c4
@ -236,7 +236,9 @@ MaybeLocal<Object> New(Isolate* isolate,
|
|||||||
enum encoding enc) {
|
enum encoding enc) {
|
||||||
EscapableHandleScope scope(isolate);
|
EscapableHandleScope scope(isolate);
|
||||||
|
|
||||||
const size_t length = StringBytes::Size(isolate, string, enc);
|
size_t length;
|
||||||
|
if (!StringBytes::Size(isolate, string, enc).To(&length))
|
||||||
|
return Local<Object>();
|
||||||
size_t actual = 0;
|
size_t actual = 0;
|
||||||
char* data = nullptr;
|
char* data = nullptr;
|
||||||
|
|
||||||
@ -828,7 +830,8 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
const size_t haystack_length = (enc == UCS2) ?
|
const size_t haystack_length = (enc == UCS2) ?
|
||||||
ts_obj_length &~ 1 : ts_obj_length; // NOLINT(whitespace/operators)
|
ts_obj_length &~ 1 : ts_obj_length; // NOLINT(whitespace/operators)
|
||||||
|
|
||||||
const size_t needle_length = StringBytes::Size(isolate, needle, enc);
|
size_t needle_length;
|
||||||
|
if (!StringBytes::Size(isolate, needle, enc).To(&needle_length)) return;
|
||||||
|
|
||||||
int64_t opt_offset = IndexOfOffset(haystack_length,
|
int64_t opt_offset = IndexOfOffset(haystack_length,
|
||||||
offset_i64,
|
offset_i64,
|
||||||
@ -868,7 +871,7 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (IsBigEndian()) {
|
if (IsBigEndian()) {
|
||||||
StringBytes::InlineDecoder decoder;
|
StringBytes::InlineDecoder decoder;
|
||||||
decoder.Decode(env, needle, args[3], UCS2);
|
if (decoder.Decode(env, needle, args[3], UCS2).IsNothing()) return;
|
||||||
const uint16_t* decoded_string =
|
const uint16_t* decoded_string =
|
||||||
reinterpret_cast<const uint16_t*>(decoder.out());
|
reinterpret_cast<const uint16_t*>(decoder.out());
|
||||||
|
|
||||||
|
@ -3059,7 +3059,8 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// Only copy the data if we have to, because it's a string
|
// Only copy the data if we have to, because it's a string
|
||||||
if (args[0]->IsString()) {
|
if (args[0]->IsString()) {
|
||||||
StringBytes::InlineDecoder decoder;
|
StringBytes::InlineDecoder decoder;
|
||||||
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8))
|
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8)
|
||||||
|
.FromMaybe(false))
|
||||||
return;
|
return;
|
||||||
r = cipher->Update(decoder.out(), decoder.size(), &out, &out_len);
|
r = cipher->Update(decoder.out(), decoder.size(), &out, &out_len);
|
||||||
} else {
|
} else {
|
||||||
@ -3249,7 +3250,8 @@ void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
bool r = false;
|
bool r = false;
|
||||||
if (args[0]->IsString()) {
|
if (args[0]->IsString()) {
|
||||||
StringBytes::InlineDecoder decoder;
|
StringBytes::InlineDecoder decoder;
|
||||||
if (decoder.Decode(env, args[0].As<String>(), args[1], UTF8)) {
|
if (decoder.Decode(env, args[0].As<String>(), args[1], UTF8)
|
||||||
|
.FromMaybe(false)) {
|
||||||
r = hmac->HmacUpdate(decoder.out(), decoder.size());
|
r = hmac->HmacUpdate(decoder.out(), decoder.size());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -3356,7 +3358,8 @@ void Hash::HashUpdate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
bool r = true;
|
bool r = true;
|
||||||
if (args[0]->IsString()) {
|
if (args[0]->IsString()) {
|
||||||
StringBytes::InlineDecoder decoder;
|
StringBytes::InlineDecoder decoder;
|
||||||
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8)) {
|
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8)
|
||||||
|
.FromMaybe(false)) {
|
||||||
args.GetReturnValue().Set(false);
|
args.GetReturnValue().Set(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ ssize_t DecodeBytes(Isolate* isolate,
|
|||||||
enum encoding encoding) {
|
enum encoding encoding) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
return StringBytes::Size(isolate, val, encoding);
|
return StringBytes::Size(isolate, val, encoding).FromMaybe(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns number of bytes written.
|
// Returns number of bytes written.
|
||||||
|
@ -1819,7 +1819,7 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
if (is_async) { // write(fd, string, pos, enc, req)
|
if (is_async) { // write(fd, string, pos, enc, req)
|
||||||
CHECK_NOT_NULL(req_wrap_async);
|
CHECK_NOT_NULL(req_wrap_async);
|
||||||
len = StringBytes::StorageSize(env->isolate(), value, enc);
|
if (!StringBytes::StorageSize(env->isolate(), value, enc).To(&len)) return;
|
||||||
FSReqBase::FSReqBuffer& stack_buffer =
|
FSReqBase::FSReqBuffer& stack_buffer =
|
||||||
req_wrap_async->Init("write", len, enc);
|
req_wrap_async->Init("write", len, enc);
|
||||||
// StorageSize may return too large a char, so correct the actual length
|
// StorageSize may return too large a char, so correct the actual length
|
||||||
@ -1847,7 +1847,8 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
FSReqWrapSync req_wrap_sync;
|
FSReqWrapSync req_wrap_sync;
|
||||||
FSReqBase::FSReqBuffer stack_buffer;
|
FSReqBase::FSReqBuffer stack_buffer;
|
||||||
if (buf == nullptr) {
|
if (buf == nullptr) {
|
||||||
len = StringBytes::StorageSize(env->isolate(), value, enc);
|
if (!StringBytes::StorageSize(env->isolate(), value, enc).To(&len))
|
||||||
|
return;
|
||||||
stack_buffer.AllocateSufficientStorage(len + 1);
|
stack_buffer.AllocateSufficientStorage(len + 1);
|
||||||
// StorageSize may return too large a char, so correct the actual length
|
// StorageSize may return too large a char, so correct the actual length
|
||||||
// by the write size
|
// by the write size
|
||||||
|
@ -37,7 +37,11 @@ using v8::FunctionCallbackInfo;
|
|||||||
using v8::HandleScope;
|
using v8::HandleScope;
|
||||||
using v8::Integer;
|
using v8::Integer;
|
||||||
using v8::Isolate;
|
using v8::Isolate;
|
||||||
|
using v8::Just;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
|
using v8::Maybe;
|
||||||
|
using v8::MaybeLocal;
|
||||||
|
using v8::Nothing;
|
||||||
using v8::Null;
|
using v8::Null;
|
||||||
using v8::Number;
|
using v8::Number;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
@ -372,7 +376,8 @@ void SyncProcessRunner::Spawn(const FunctionCallbackInfo<Value>& args) {
|
|||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
env->PrintSyncTrace();
|
env->PrintSyncTrace();
|
||||||
SyncProcessRunner p(env);
|
SyncProcessRunner p(env);
|
||||||
Local<Value> result = p.Run(args[0]);
|
Local<Value> result;
|
||||||
|
if (!p.Run(args[0]).ToLocal(&result)) return;
|
||||||
args.GetReturnValue().Set(result);
|
args.GetReturnValue().Set(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,22 +435,21 @@ Environment* SyncProcessRunner::env() const {
|
|||||||
return env_;
|
return env_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeLocal<Object> SyncProcessRunner::Run(Local<Value> options) {
|
||||||
Local<Object> SyncProcessRunner::Run(Local<Value> options) {
|
|
||||||
EscapableHandleScope scope(env()->isolate());
|
EscapableHandleScope scope(env()->isolate());
|
||||||
|
|
||||||
CHECK_EQ(lifecycle_, kUninitialized);
|
CHECK_EQ(lifecycle_, kUninitialized);
|
||||||
|
|
||||||
TryInitializeAndRunLoop(options);
|
Maybe<bool> r = TryInitializeAndRunLoop(options);
|
||||||
CloseHandlesAndDeleteLoop();
|
CloseHandlesAndDeleteLoop();
|
||||||
|
if (r.IsNothing()) return MaybeLocal<Object>();
|
||||||
|
|
||||||
Local<Object> result = BuildResultObject();
|
Local<Object> result = BuildResultObject();
|
||||||
|
|
||||||
return scope.Escape(result);
|
return scope.Escape(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<bool> SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
|
||||||
void SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
// There is no recovery from failure inside TryInitializeAndRunLoop - the
|
// There is no recovery from failure inside TryInitializeAndRunLoop - the
|
||||||
@ -454,18 +458,24 @@ void SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
|
|||||||
lifecycle_ = kInitialized;
|
lifecycle_ = kInitialized;
|
||||||
|
|
||||||
uv_loop_ = new uv_loop_t;
|
uv_loop_ = new uv_loop_t;
|
||||||
if (uv_loop_ == nullptr)
|
if (uv_loop_ == nullptr) {
|
||||||
return SetError(UV_ENOMEM);
|
SetError(UV_ENOMEM);
|
||||||
|
return Just(false);
|
||||||
|
}
|
||||||
CHECK_EQ(uv_loop_init(uv_loop_), 0);
|
CHECK_EQ(uv_loop_init(uv_loop_), 0);
|
||||||
|
|
||||||
r = ParseOptions(options);
|
if (!ParseOptions(options).To(&r)) return Nothing<bool>();
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
return SetError(r);
|
SetError(r);
|
||||||
|
return Just(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (timeout_ > 0) {
|
if (timeout_ > 0) {
|
||||||
r = uv_timer_init(uv_loop_, &uv_timer_);
|
r = uv_timer_init(uv_loop_, &uv_timer_);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
return SetError(r);
|
SetError(r);
|
||||||
|
return Just(false);
|
||||||
|
}
|
||||||
|
|
||||||
uv_unref(reinterpret_cast<uv_handle_t*>(&uv_timer_));
|
uv_unref(reinterpret_cast<uv_handle_t*>(&uv_timer_));
|
||||||
|
|
||||||
@ -477,22 +487,28 @@ void SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
|
|||||||
// which implicitly stops it, so there is no risk that the timeout callback
|
// which implicitly stops it, so there is no risk that the timeout callback
|
||||||
// runs when the process didn't start.
|
// runs when the process didn't start.
|
||||||
r = uv_timer_start(&uv_timer_, KillTimerCallback, timeout_, 0);
|
r = uv_timer_start(&uv_timer_, KillTimerCallback, timeout_, 0);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
return SetError(r);
|
SetError(r);
|
||||||
|
return Just(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uv_process_options_.exit_cb = ExitCallback;
|
uv_process_options_.exit_cb = ExitCallback;
|
||||||
r = uv_spawn(uv_loop_, &uv_process_, &uv_process_options_);
|
r = uv_spawn(uv_loop_, &uv_process_, &uv_process_options_);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
return SetError(r);
|
SetError(r);
|
||||||
|
return Just(false);
|
||||||
|
}
|
||||||
uv_process_.data = this;
|
uv_process_.data = this;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < stdio_count_; i++) {
|
for (uint32_t i = 0; i < stdio_count_; i++) {
|
||||||
SyncProcessStdioPipe* h = stdio_pipes_[i].get();
|
SyncProcessStdioPipe* h = stdio_pipes_[i].get();
|
||||||
if (h != nullptr) {
|
if (h != nullptr) {
|
||||||
r = h->Start();
|
r = h->Start();
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
return SetPipeError(r);
|
SetPipeError(r);
|
||||||
|
return Just(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,6 +519,7 @@ void SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
|
|||||||
|
|
||||||
// If we get here the process should have exited.
|
// If we get here the process should have exited.
|
||||||
CHECK_GE(exit_status_, 0);
|
CHECK_GE(exit_status_, 0);
|
||||||
|
return Just(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -724,46 +741,41 @@ Local<Array> SyncProcessRunner::BuildOutputArray() {
|
|||||||
return scope.Escape(js_output);
|
return scope.Escape(js_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<int> SyncProcessRunner::ParseOptions(Local<Value> js_value) {
|
||||||
int SyncProcessRunner::ParseOptions(Local<Value> js_value) {
|
|
||||||
HandleScope scope(env()->isolate());
|
HandleScope scope(env()->isolate());
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!js_value->IsObject())
|
if (!js_value->IsObject()) return Just<int>(UV_EINVAL);
|
||||||
return UV_EINVAL;
|
|
||||||
|
|
||||||
Local<Context> context = env()->context();
|
Local<Context> context = env()->context();
|
||||||
Local<Object> js_options = js_value.As<Object>();
|
Local<Object> js_options = js_value.As<Object>();
|
||||||
|
|
||||||
Local<Value> js_file =
|
Local<Value> js_file =
|
||||||
js_options->Get(context, env()->file_string()).ToLocalChecked();
|
js_options->Get(context, env()->file_string()).ToLocalChecked();
|
||||||
r = CopyJsString(js_file, &file_buffer_);
|
if (!CopyJsString(js_file, &file_buffer_).To(&r)) return Nothing<int>();
|
||||||
if (r < 0)
|
if (r < 0) return Just(r);
|
||||||
return r;
|
|
||||||
uv_process_options_.file = file_buffer_;
|
uv_process_options_.file = file_buffer_;
|
||||||
|
|
||||||
Local<Value> js_args =
|
Local<Value> js_args =
|
||||||
js_options->Get(context, env()->args_string()).ToLocalChecked();
|
js_options->Get(context, env()->args_string()).ToLocalChecked();
|
||||||
r = CopyJsStringArray(js_args, &args_buffer_);
|
if (!CopyJsStringArray(js_args, &args_buffer_).To(&r)) return Nothing<int>();
|
||||||
if (r < 0)
|
if (r < 0) return Just(r);
|
||||||
return r;
|
|
||||||
uv_process_options_.args = reinterpret_cast<char**>(args_buffer_);
|
uv_process_options_.args = reinterpret_cast<char**>(args_buffer_);
|
||||||
|
|
||||||
Local<Value> js_cwd =
|
Local<Value> js_cwd =
|
||||||
js_options->Get(context, env()->cwd_string()).ToLocalChecked();
|
js_options->Get(context, env()->cwd_string()).ToLocalChecked();
|
||||||
if (IsSet(js_cwd)) {
|
if (IsSet(js_cwd)) {
|
||||||
r = CopyJsString(js_cwd, &cwd_buffer_);
|
if (!CopyJsString(js_cwd, &cwd_buffer_).To(&r)) return Nothing<int>();
|
||||||
if (r < 0)
|
if (r < 0) return Just(r);
|
||||||
return r;
|
|
||||||
uv_process_options_.cwd = cwd_buffer_;
|
uv_process_options_.cwd = cwd_buffer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> js_env_pairs =
|
Local<Value> js_env_pairs =
|
||||||
js_options->Get(context, env()->env_pairs_string()).ToLocalChecked();
|
js_options->Get(context, env()->env_pairs_string()).ToLocalChecked();
|
||||||
if (IsSet(js_env_pairs)) {
|
if (IsSet(js_env_pairs)) {
|
||||||
r = CopyJsStringArray(js_env_pairs, &env_buffer_);
|
if (!CopyJsStringArray(js_env_pairs, &env_buffer_).To(&r))
|
||||||
if (r < 0)
|
return Nothing<int>();
|
||||||
return r;
|
if (r < 0) return Just(r);
|
||||||
|
|
||||||
uv_process_options_.env = reinterpret_cast<char**>(env_buffer_);
|
uv_process_options_.env = reinterpret_cast<char**>(env_buffer_);
|
||||||
}
|
}
|
||||||
@ -827,10 +839,9 @@ int SyncProcessRunner::ParseOptions(Local<Value> js_value) {
|
|||||||
Local<Value> js_stdio =
|
Local<Value> js_stdio =
|
||||||
js_options->Get(context, env()->stdio_string()).ToLocalChecked();
|
js_options->Get(context, env()->stdio_string()).ToLocalChecked();
|
||||||
r = ParseStdioOptions(js_stdio);
|
r = ParseStdioOptions(js_stdio);
|
||||||
if (r < 0)
|
if (r < 0) return Just(r);
|
||||||
return r;
|
|
||||||
|
|
||||||
return 0;
|
return Just(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -970,9 +981,8 @@ bool SyncProcessRunner::IsSet(Local<Value> value) {
|
|||||||
return !value->IsUndefined() && !value->IsNull();
|
return !value->IsUndefined() && !value->IsNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<int> SyncProcessRunner::CopyJsString(Local<Value> js_value,
|
||||||
int SyncProcessRunner::CopyJsString(Local<Value> js_value,
|
const char** target) {
|
||||||
const char** target) {
|
|
||||||
Isolate* isolate = env()->isolate();
|
Isolate* isolate = env()->isolate();
|
||||||
Local<String> js_string;
|
Local<String> js_string;
|
||||||
size_t size, written;
|
size_t size, written;
|
||||||
@ -980,12 +990,14 @@ int SyncProcessRunner::CopyJsString(Local<Value> js_value,
|
|||||||
|
|
||||||
if (js_value->IsString())
|
if (js_value->IsString())
|
||||||
js_string = js_value.As<String>();
|
js_string = js_value.As<String>();
|
||||||
else
|
else if (!js_value->ToString(env()->isolate()->GetCurrentContext())
|
||||||
js_string = js_value->ToString(env()->isolate()->GetCurrentContext())
|
.ToLocal(&js_string))
|
||||||
.ToLocalChecked();
|
return Nothing<int>();
|
||||||
|
|
||||||
// Include space for null terminator byte.
|
// Include space for null terminator byte.
|
||||||
size = StringBytes::StorageSize(isolate, js_string, UTF8) + 1;
|
if (!StringBytes::StorageSize(isolate, js_string, UTF8).To(&size))
|
||||||
|
return Nothing<int>();
|
||||||
|
size += 1;
|
||||||
|
|
||||||
buffer = new char[size];
|
buffer = new char[size];
|
||||||
|
|
||||||
@ -993,12 +1005,11 @@ int SyncProcessRunner::CopyJsString(Local<Value> js_value,
|
|||||||
buffer[written] = '\0';
|
buffer[written] = '\0';
|
||||||
|
|
||||||
*target = buffer;
|
*target = buffer;
|
||||||
return 0;
|
return Just(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<int> SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
|
||||||
int SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
|
char** target) {
|
||||||
char** target) {
|
|
||||||
Isolate* isolate = env()->isolate();
|
Isolate* isolate = env()->isolate();
|
||||||
Local<Array> js_array;
|
Local<Array> js_array;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
@ -1006,8 +1017,7 @@ int SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
|
|||||||
char** list;
|
char** list;
|
||||||
char* buffer;
|
char* buffer;
|
||||||
|
|
||||||
if (!js_value->IsArray())
|
if (!js_value->IsArray()) return Just<int>(UV_EINVAL);
|
||||||
return UV_EINVAL;
|
|
||||||
|
|
||||||
Local<Context> context = env()->context();
|
Local<Context> context = env()->context();
|
||||||
js_array = js_value.As<Array>()->Clone().As<Array>();
|
js_array = js_value.As<Array>()->Clone().As<Array>();
|
||||||
@ -1025,15 +1035,22 @@ int SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
|
|||||||
for (uint32_t i = 0; i < length; i++) {
|
for (uint32_t i = 0; i < length; i++) {
|
||||||
auto value = js_array->Get(context, i).ToLocalChecked();
|
auto value = js_array->Get(context, i).ToLocalChecked();
|
||||||
|
|
||||||
if (!value->IsString())
|
if (!value->IsString()) {
|
||||||
|
Local<String> string;
|
||||||
|
if (!value->ToString(env()->isolate()->GetCurrentContext())
|
||||||
|
.ToLocal(&string))
|
||||||
|
return Nothing<int>();
|
||||||
js_array
|
js_array
|
||||||
->Set(context,
|
->Set(context,
|
||||||
i,
|
i,
|
||||||
value->ToString(env()->isolate()->GetCurrentContext())
|
value->ToString(env()->isolate()->GetCurrentContext())
|
||||||
.ToLocalChecked())
|
.ToLocalChecked())
|
||||||
.FromJust();
|
.FromJust();
|
||||||
|
}
|
||||||
|
|
||||||
data_size += StringBytes::StorageSize(isolate, value, UTF8) + 1;
|
Maybe<size_t> maybe_size = StringBytes::StorageSize(isolate, value, UTF8);
|
||||||
|
if (maybe_size.IsNothing()) return Nothing<int>();
|
||||||
|
data_size += maybe_size.FromJust() + 1;
|
||||||
data_size = ROUND_UP(data_size, sizeof(void*));
|
data_size = ROUND_UP(data_size, sizeof(void*));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1057,7 +1074,7 @@ int SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
|
|||||||
list[length] = nullptr;
|
list[length] = nullptr;
|
||||||
|
|
||||||
*target = buffer;
|
*target = buffer;
|
||||||
return 0;
|
return Just(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,8 +152,8 @@ class SyncProcessRunner {
|
|||||||
|
|
||||||
inline Environment* env() const;
|
inline Environment* env() const;
|
||||||
|
|
||||||
v8::Local<v8::Object> Run(v8::Local<v8::Value> options);
|
v8::MaybeLocal<v8::Object> Run(v8::Local<v8::Value> options);
|
||||||
void TryInitializeAndRunLoop(v8::Local<v8::Value> options);
|
v8::Maybe<bool> TryInitializeAndRunLoop(v8::Local<v8::Value> options);
|
||||||
void CloseHandlesAndDeleteLoop();
|
void CloseHandlesAndDeleteLoop();
|
||||||
|
|
||||||
void CloseStdioPipes();
|
void CloseStdioPipes();
|
||||||
@ -172,7 +172,7 @@ class SyncProcessRunner {
|
|||||||
v8::Local<v8::Object> BuildResultObject();
|
v8::Local<v8::Object> BuildResultObject();
|
||||||
v8::Local<v8::Array> BuildOutputArray();
|
v8::Local<v8::Array> BuildOutputArray();
|
||||||
|
|
||||||
int ParseOptions(v8::Local<v8::Value> js_value);
|
v8::Maybe<int> ParseOptions(v8::Local<v8::Value> js_value);
|
||||||
int ParseStdioOptions(v8::Local<v8::Value> js_value);
|
int ParseStdioOptions(v8::Local<v8::Value> js_value);
|
||||||
int ParseStdioOption(int child_fd, v8::Local<v8::Object> js_stdio_option);
|
int ParseStdioOption(int child_fd, v8::Local<v8::Object> js_stdio_option);
|
||||||
|
|
||||||
@ -184,8 +184,10 @@ class SyncProcessRunner {
|
|||||||
inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd);
|
inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd);
|
||||||
|
|
||||||
static bool IsSet(v8::Local<v8::Value> value);
|
static bool IsSet(v8::Local<v8::Value> value);
|
||||||
int CopyJsString(v8::Local<v8::Value> js_value, const char** target);
|
v8::Maybe<int> CopyJsString(v8::Local<v8::Value> js_value,
|
||||||
int CopyJsStringArray(v8::Local<v8::Value> js_value, char** target);
|
const char** target);
|
||||||
|
v8::Maybe<int> CopyJsStringArray(v8::Local<v8::Value> js_value,
|
||||||
|
char** target);
|
||||||
|
|
||||||
static void ExitCallback(uv_process_t* handle,
|
static void ExitCallback(uv_process_t* handle,
|
||||||
int64_t exit_status,
|
int64_t exit_status,
|
||||||
|
@ -108,11 +108,12 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
|
|||||||
enum encoding encoding = ParseEncoding(env->isolate(),
|
enum encoding encoding = ParseEncoding(env->isolate(),
|
||||||
chunks->Get(i * 2 + 1));
|
chunks->Get(i * 2 + 1));
|
||||||
size_t chunk_size;
|
size_t chunk_size;
|
||||||
if (encoding == UTF8 && string->Length() > 65535)
|
if (encoding == UTF8 && string->Length() > 65535 &&
|
||||||
chunk_size = StringBytes::Size(env->isolate(), string, encoding);
|
!StringBytes::Size(env->isolate(), string, encoding).To(&chunk_size))
|
||||||
else
|
return 0;
|
||||||
chunk_size = StringBytes::StorageSize(env->isolate(), string, encoding);
|
else if (!StringBytes::StorageSize(env->isolate(), string, encoding)
|
||||||
|
.To(&chunk_size))
|
||||||
|
return 0;
|
||||||
storage_size += chunk_size;
|
storage_size += chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,10 +215,12 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// For UTF8 strings that are very long, go ahead and take the hit for
|
// For UTF8 strings that are very long, go ahead and take the hit for
|
||||||
// computing their actual size, rather than tripling the storage.
|
// computing their actual size, rather than tripling the storage.
|
||||||
size_t storage_size;
|
size_t storage_size;
|
||||||
if (enc == UTF8 && string->Length() > 65535)
|
if (enc == UTF8 && string->Length() > 65535 &&
|
||||||
storage_size = StringBytes::Size(env->isolate(), string, enc);
|
!StringBytes::Size(env->isolate(), string, enc).To(&storage_size))
|
||||||
else
|
return 0;
|
||||||
storage_size = StringBytes::StorageSize(env->isolate(), string, enc);
|
else if (!StringBytes::StorageSize(env->isolate(), string, enc)
|
||||||
|
.To(&storage_size))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (storage_size > INT_MAX)
|
if (storage_size > INT_MAX)
|
||||||
return UV_ENOBUFS;
|
return UV_ENOBUFS;
|
||||||
|
@ -41,8 +41,11 @@ namespace node {
|
|||||||
|
|
||||||
using v8::HandleScope;
|
using v8::HandleScope;
|
||||||
using v8::Isolate;
|
using v8::Isolate;
|
||||||
|
using v8::Just;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
|
using v8::Maybe;
|
||||||
using v8::MaybeLocal;
|
using v8::MaybeLocal;
|
||||||
|
using v8::Nothing;
|
||||||
using v8::String;
|
using v8::String;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
@ -399,19 +402,20 @@ bool StringBytes::IsValidString(Local<String> string,
|
|||||||
// Quick and dirty size calculation
|
// Quick and dirty size calculation
|
||||||
// Will always be at least big enough, but may have some extra
|
// Will always be at least big enough, but may have some extra
|
||||||
// UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes
|
// UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes
|
||||||
size_t StringBytes::StorageSize(Isolate* isolate,
|
Maybe<size_t> StringBytes::StorageSize(Isolate* isolate,
|
||||||
Local<Value> val,
|
Local<Value> val,
|
||||||
enum encoding encoding) {
|
enum encoding encoding) {
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
bool is_buffer = Buffer::HasInstance(val);
|
bool is_buffer = Buffer::HasInstance(val);
|
||||||
|
|
||||||
if (is_buffer && (encoding == BUFFER || encoding == LATIN1)) {
|
if (is_buffer && (encoding == BUFFER || encoding == LATIN1)) {
|
||||||
return Buffer::Length(val);
|
return Just(Buffer::Length(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<String> str =
|
Local<String> str;
|
||||||
val->ToString(isolate->GetCurrentContext()).ToLocalChecked();
|
if (!val->ToString(isolate->GetCurrentContext()).ToLocal(&str))
|
||||||
|
return Nothing<size_t>();
|
||||||
|
|
||||||
switch (encoding) {
|
switch (encoding) {
|
||||||
case ASCII:
|
case ASCII:
|
||||||
@ -445,40 +449,40 @@ size_t StringBytes::StorageSize(Isolate* isolate,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data_size;
|
return Just(data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<size_t> StringBytes::Size(Isolate* isolate,
|
||||||
size_t StringBytes::Size(Isolate* isolate,
|
Local<Value> val,
|
||||||
Local<Value> val,
|
enum encoding encoding) {
|
||||||
enum encoding encoding) {
|
|
||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
if (Buffer::HasInstance(val) && (encoding == BUFFER || encoding == LATIN1))
|
if (Buffer::HasInstance(val) && (encoding == BUFFER || encoding == LATIN1))
|
||||||
return Buffer::Length(val);
|
return Just(Buffer::Length(val));
|
||||||
|
|
||||||
Local<String> str =
|
Local<String> str;
|
||||||
val->ToString(isolate->GetCurrentContext()).ToLocalChecked();
|
if (!val->ToString(isolate->GetCurrentContext()).ToLocal(&str))
|
||||||
|
return Nothing<size_t>();
|
||||||
|
|
||||||
switch (encoding) {
|
switch (encoding) {
|
||||||
case ASCII:
|
case ASCII:
|
||||||
case LATIN1:
|
case LATIN1:
|
||||||
return str->Length();
|
return Just<size_t>(str->Length());
|
||||||
|
|
||||||
case BUFFER:
|
case BUFFER:
|
||||||
case UTF8:
|
case UTF8:
|
||||||
return str->Utf8Length(isolate);
|
return Just<size_t>(str->Utf8Length(isolate));
|
||||||
|
|
||||||
case UCS2:
|
case UCS2:
|
||||||
return str->Length() * sizeof(uint16_t);
|
return Just(str->Length() * sizeof(uint16_t));
|
||||||
|
|
||||||
case BASE64: {
|
case BASE64: {
|
||||||
String::Value value(isolate, str);
|
String::Value value(isolate, str);
|
||||||
return base64_decoded_size(*value, value.length());
|
return Just(base64_decoded_size(*value, value.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
case HEX:
|
case HEX:
|
||||||
return str->Length() / 2;
|
return Just<size_t>(str->Length() / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -35,29 +35,26 @@ class StringBytes {
|
|||||||
public:
|
public:
|
||||||
class InlineDecoder : public MaybeStackBuffer<char> {
|
class InlineDecoder : public MaybeStackBuffer<char> {
|
||||||
public:
|
public:
|
||||||
inline bool Decode(Environment* env,
|
inline v8::Maybe<bool> Decode(Environment* env,
|
||||||
v8::Local<v8::String> string,
|
v8::Local<v8::String> string,
|
||||||
v8::Local<v8::Value> encoding,
|
v8::Local<v8::Value> encoding,
|
||||||
enum encoding _default) {
|
enum encoding _default) {
|
||||||
enum encoding enc = ParseEncoding(env->isolate(), encoding, _default);
|
enum encoding enc = ParseEncoding(env->isolate(), encoding, _default);
|
||||||
if (!StringBytes::IsValidString(string, enc)) {
|
if (!StringBytes::IsValidString(string, enc)) {
|
||||||
env->ThrowTypeError("Bad input string");
|
env->ThrowTypeError("Bad input string");
|
||||||
return false;
|
return v8::Just(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t storage = StringBytes::StorageSize(env->isolate(),
|
size_t storage;
|
||||||
string,
|
if (!StringBytes::StorageSize(env->isolate(), string, enc).To(&storage))
|
||||||
enc);
|
return v8::Nothing<bool>();
|
||||||
AllocateSufficientStorage(storage);
|
AllocateSufficientStorage(storage);
|
||||||
const size_t length = StringBytes::Write(env->isolate(),
|
const size_t length =
|
||||||
out(),
|
StringBytes::Write(env->isolate(), out(), storage, string, enc);
|
||||||
storage,
|
|
||||||
string,
|
|
||||||
enc);
|
|
||||||
|
|
||||||
// No zero terminator is included when using this method.
|
// No zero terminator is included when using this method.
|
||||||
SetLength(length);
|
SetLength(length);
|
||||||
return true;
|
return v8::Just(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t size() const { return length(); }
|
inline size_t size() const { return length(); }
|
||||||
@ -71,15 +68,15 @@ class StringBytes {
|
|||||||
|
|
||||||
// Fast, but can be 2 bytes oversized for Base64, and
|
// Fast, but can be 2 bytes oversized for Base64, and
|
||||||
// as much as triple UTF-8 strings <= 65536 chars in length
|
// as much as triple UTF-8 strings <= 65536 chars in length
|
||||||
static size_t StorageSize(v8::Isolate* isolate,
|
static v8::Maybe<size_t> StorageSize(v8::Isolate* isolate,
|
||||||
v8::Local<v8::Value> val,
|
v8::Local<v8::Value> val,
|
||||||
enum encoding enc);
|
enum encoding enc);
|
||||||
|
|
||||||
// Precise byte count, but slightly slower for Base64 and
|
// Precise byte count, but slightly slower for Base64 and
|
||||||
// very much slower for UTF-8
|
// very much slower for UTF-8
|
||||||
static size_t Size(v8::Isolate* isolate,
|
static v8::Maybe<size_t> Size(v8::Isolate* isolate,
|
||||||
v8::Local<v8::Value> val,
|
v8::Local<v8::Value> val,
|
||||||
enum encoding enc);
|
enum encoding enc);
|
||||||
|
|
||||||
// Write the bytes from the string or buffer into the char*
|
// Write the bytes from the string or buffer into the char*
|
||||||
// returns the number of bytes written, which will always be
|
// returns the number of bytes written, which will always be
|
||||||
|
@ -41,7 +41,9 @@ static void MakeUtf8String(Isolate* isolate,
|
|||||||
Local<String> string;
|
Local<String> string;
|
||||||
if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
|
if (!value->ToString(isolate->GetCurrentContext()).ToLocal(&string)) return;
|
||||||
|
|
||||||
const size_t storage = StringBytes::StorageSize(isolate, string, UTF8) + 1;
|
size_t storage;
|
||||||
|
if (!StringBytes::StorageSize(isolate, string, UTF8).To(&storage)) return;
|
||||||
|
storage += 1;
|
||||||
target->AllocateSufficientStorage(storage);
|
target->AllocateSufficientStorage(storage);
|
||||||
const int flags =
|
const int flags =
|
||||||
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
|
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user