Reputation: 9349
I am trying to Parse JS in my embedded V8 application and I get a SIGSEGV always. I am not sure what is happening.
My code to parse json,
v8::Handle<v8::Value> FromJSONString(
v8::Handle<v8::Value> json_string) {
v8::HandleScope scope;
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
v8::Handle<v8::Object> global = context->Global();
v8::Handle<v8::Value> JSON_value = global->Get(v8::String::New("JSON"));
if (!IsObject(JSON_value)) {
return scope.Close(v8::Undefined());
}
v8::Handle<v8::Object> JSON = JSON_value->ToObject();
v8::Handle<v8::Value> JSON_parse_value = JSON->Get(v8::String::New("parse"));
if (JSON_parse_value.IsEmpty() || JSON_parse_value->IsNull() ||
JSON_parse_value->IsUndefined() ||!JSON_parse_value->IsFunction()) {
return scope.Close(v8::Undefined());
}
v8::Handle<v8::Function> JSON_parse =
v8::Handle<v8::Function>::Cast(JSON_parse_value);
return scope.Close(JSON_parse->Call(JSON, 1, &json_string));
}
The specific site which crashes =>
bool extractSource(std::string* source, std::string& body) {
v8::HandleScope scope; // this is needed and clears the memory
if (body.empty()) {
return false;
}
v8::Handle<v8::Value> value = v8_server_utils::FromJSONString(body);
if (value->IsEmpty()) { // CRASHES HERE.
return false;
}
if (value->IsNull()) {
return false;
}
if (value->IsUndefined()) {
return false;
}
if (!value->IsObject()) {
return false;
}
auto object = value->ToObject();
auto source_key = v8::String::New("source");
if (object.IsEmpty() || object->IsNull() || object->IsUndefined() ||
!object->Has(source_key)) {
return false;
}
auto source_obj = object->Get(source_key);
*source = v8_server_utils::JSStringToCString(source_obj->ToString());
return true;
}
Upvotes: 6
Views: 5912
Reputation: 3388
I'm adding this additional answer because my prior answer is still correct, but as of now a newer and better answer is available.
NAN version 2.6.2 was released on April 12, 2017. This version introduces a new object, Nan::JSON
The Nan::JSON
object provides c++ versions of the methods offered by the JSON
object in javascript, in a way that is backwards compatible with all versions of Node.js supported by NAN. V8 otherwise exposes these methods via the v8::JSON
object.
A simple wrapper around v8::JSON::Parse
.
Definition:
Nan::MaybeLocal<v8::Value> Nan::JSON::Parse(v8::Local<v8::String> json_string);
Use JSON.Parse(json_string)
to parse a string into a v8::Value
.
Example:
v8::Local<v8::String> json_string = Nan::New("{ \"JSON\": \"object\" }").ToLocalChecked();
Nan::JSON NanJSON;
Nan::MaybeLocal<v8::Value> result = NanJSON.Parse(json_string);
if (!result.IsEmpty()) {
v8::Local<v8::Value> val = result.ToLocalChecked();
}
A simple wrapper around v8::JSON::Stringify
.
Definition:
Nan::MaybeLocal<v8::String> Nan::JSON::Stringify(v8::Local<v8::Object> json_object, v8::Local<v8::String> gap = v8::Local<v8::String>());
Use JSON.Stringify(value)
to stringify a v8::Object
.
Example:
v8::Local<v8::Object> obj = Nan::To<v8::Object>(val).ToLocalChecked();
Nan::JSON NanJSON;
Nan::MaybeLocal<v8::String> result = NanJSON.Stringify(obj);
if (!result.IsEmpty()) {
v8::Local<v8::String> stringified = result.ToLocalChecked();
}
Refer to the V8 JSON
object in the V8 documentation for more information about the original V8
versions these methods and their arguments.
The above was paraphrased from the NAN documentation
Upvotes: 0
Reputation: 3388
If you are writing a native node module and using NAN so that it will be supported across all major versions of Node.js, then I recommend that you try using the native-json npm package.
The package exposes the following methods:
static Nan::MaybeLocal<v8::Value> Native::JSON::Parse(v8::Local<v8::String> jsonString);
static Nan::MaybeLocal<v8::String> Native::JSON::Stringify(v8::Local<v8::Object> jsonObject, v8::Local<v8::String> gap = v8::Local<v8::String>())
As for the changes in v8::JSON
in the versions of node supported by NAN:
v8::JSON::Parse
was first available in node version 0.12.x - it is not otherwise available in versions 0.8 or 0.10.x
v8::JSON::Stringify
was first available in node version 7 - it is not otherwise available in earlier versions
The native-json
package's Native::JSON
singleton class will perform the requests in the most efficient way available depending on the version of Node.js being built against. If the method is available in that version of V8 then it will be called. Otherwise, the Native::JSON
singleton class falls back to grabbing the JSON
object from the global context.
Source code is available on the github repository: node-native-json
Here is an example of how to use Native::JSON::Parse
:
v8::Local<v8::String> json_string = Nan::New("{ \"JSON\": \"object\" }").ToLocalChecked();
v8::Local<v8::Value> val = Native::JSON::Parse(json_string).ToLocalChecked();
Upvotes: 1
Reputation: 9097
The following code should work provided that you're on an older V8 version, such as v3.14:
v8::Handle<v8::Value> FromJsonString (v8::Handle<v8::Value> jsonString) {
v8::HandleScope scope;
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
v8::Handle<v8::Object> global = context->Global();
// find JSON object in global scope
v8::Handle<v8::Value> jsonValue = global->Get(v8::String::New("JSON"));
if (! jsonValue->IsObject()) {
return scope.Close(v8::Undefined());
}
v8::Handle<v8::Object> json = jsonValue->ToObject();
// find "parse" attribute
v8::Handle<v8::Value> parse = json->Get(v8::String::New("parse"));
if (parse.IsEmpty() ||
! parse->IsFunction()) {
return scope.Close(v8::Undefined());
}
// cast into a function
v8::Handle<v8::Function> parseFunction = v8::Handle<v8::Function>::Cast(parse);
// and call it
return scope.Close(parseFunction->Call(json, 1, &jsonString));
}
static bool ExtractSource (std::string& source, std::string const& body) {
v8::HandleScope scope;
// convert whole body from cstring to V8 string
v8::Handle<v8::String> bodyString = v8::String::New(body.c_str(), body.size());
// call JSON.parse() on the body
v8::Handle<v8::Value> value = FromJsonString(bodyString);
// check if result is valid
if (value.IsEmpty() ||
value->IsNull() ||
value->IsUndefined() ||
! value->IsObject()) {
return false;
}
auto object = value->ToObject();
// extract "source" attribute from result
auto sourceKey = v8::String::New("source");
if (object.IsEmpty() ||
object->IsNull() ||
object->IsUndefined() ||
! object->Has(sourceKey)) {
return false;
}
auto sourceValue = object->Get(sourceKey);
if (! sourceValue->IsString()) {
return false;
}
// convert the v8 string value into a cstring
v8::String::Utf8Value sourceString(sourceValue->ToString());
if (*sourceString == nullptr) {
return false;
}
source.assign(*sourceString, sourceString.length());
return true;
}
int main () {
// test data
std::string body = "{ \"body\": \"test\", \"source\": \"some string value\" }";
// result
std::string source;
// call function and dump result
std::cout << "is valid: " << ExtractSource(source, body) << std::endl;
std::cout << "value of source: '" << source << "'" << std::endl;
}
Upvotes: 3
Reputation: 1146
You can use JSON Parse function exposed through API:
v8::Local<v8::String> str; // some string
v8::Local<v8::Value> result = v8::JSON::Parse(str);
Newer versions of V8 provide EscapableHandleScope
you need to use to return handle from function:
v8::EscapableHandleScope scope(isolate);
return scope.Escape(value);
This
if (value->IsEmpty()) { // CRASHES HERE.
should probably be
if (value.IsEmpty())
Hope this helps.
Upvotes: 7