Files
node/src/json_parser.cc
T
Keyhan Vakil 8e60189585 src: add IsolateScopes before using isolates
The V8 API requires entering an isolate before using it. We were often
not doing this, which worked fine in practice. However when (multi-cage)
pointer compression is enabled, the correct isolate needs to be active
in order to decompress pointers correctly, otherwise it causes crashes.

Fix this by sprinkling in some calls to v8::Isolate::Scope::Scope where
they were missing.

This also introduces RAIIIsolateWithoutEntering which is used in
JSONParser to avoid otherwise exposing the Isolate::Scope outside of the
class.

Tested by compiling with `--experimental-enable-pointer-compression`
locally and running all tests.

Refs: https://github.com/nodejs/build/issues/3204#issuecomment-1790213488
Refs: https://bugs.chromium.org/p/v8/issues/detail?id=14292
PR-URL: https://github.com/nodejs/node/pull/50680
Refs: https://github.com/v8/v8/commit/475c8cdf9a951bb06da3084794a0f659f8ef36c2
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2023-11-20 23:10:48 +00:00

105 lines
2.9 KiB
C++

#include "json_parser.h"
#include "node_errors.h"
#include "node_v8_platform-inl.h"
#include "util-inl.h"
namespace node {
using v8::Context;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
JSONParser::JSONParser() {}
bool JSONParser::Parse(const std::string& content) {
DCHECK(!parsed_);
Isolate* isolate = isolate_.get();
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
Local<Context> context = Context::New(isolate);
Context::Scope context_scope(context);
// It's not a real script, so don't print the source line.
errors::PrinterTryCatch bootstrapCatch(
isolate, errors::PrinterTryCatch::kDontPrintSourceLine);
Local<Value> json_string_value;
Local<Value> result_value;
if (!ToV8Value(context, content).ToLocal(&json_string_value) ||
!json_string_value->IsString() ||
!v8::JSON::Parse(context, json_string_value.As<String>())
.ToLocal(&result_value) ||
!result_value->IsObject()) {
return false;
}
context_.Reset(isolate, context);
content_.Reset(isolate, result_value.As<Object>());
parsed_ = true;
return true;
}
std::optional<std::string> JSONParser::GetTopLevelStringField(
std::string_view field) {
Isolate* isolate = isolate_.get();
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
Local<Context> context = context_.Get(isolate);
Context::Scope context_scope(context);
Local<Object> content_object = content_.Get(isolate);
Local<Value> value;
// It's not a real script, so don't print the source line.
errors::PrinterTryCatch bootstrapCatch(
isolate, errors::PrinterTryCatch::kDontPrintSourceLine);
Local<Value> field_local;
if (!ToV8Value(context, field, isolate).ToLocal(&field_local)) {
return {};
}
if (!content_object->Get(context, field_local).ToLocal(&value) ||
!value->IsString()) {
return {};
}
Utf8Value utf8_value(isolate, value);
return utf8_value.ToString();
}
std::optional<bool> JSONParser::GetTopLevelBoolField(std::string_view field) {
Isolate* isolate = isolate_.get();
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
Local<Context> context = context_.Get(isolate);
Context::Scope context_scope(context);
Local<Object> content_object = content_.Get(isolate);
Local<Value> value;
bool has_field;
// It's not a real script, so don't print the source line.
errors::PrinterTryCatch bootstrapCatch(
isolate, errors::PrinterTryCatch::kDontPrintSourceLine);
Local<Value> field_local;
if (!ToV8Value(context, field, isolate).ToLocal(&field_local)) {
return {};
}
if (!content_object->Has(context, field_local).To(&has_field)) {
return {};
}
if (!has_field) {
return false;
}
if (!content_object->Get(context, field_local).ToLocal(&value) ||
!value->IsBoolean()) {
return {};
}
return value->BooleanValue(isolate);
}
} // namespace node