6

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;
}

4 Answers 4

7

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.

Sign up to request clarification or add additional context in comments.

1 Comment

v8::JSON does not exist in v3.14.5.
3

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;
}

1 Comment

at some point the V8 API complete changed. For example, all New() methods and v8::HandleScopes now require a v8::Isolate instance. My solution was for older V8 versions, such as 3.14. If you're unsure what part of the code does not work in newer versions, try compiling it with a newer V8 version, and you'll see tons of errors.
1

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();

Comments

0

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.

Nan::JSON.Parse

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();
}

Nan::JSON.Stringify

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.