-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reviver can modify holder object, like inserting new object / array, which breaks invariant of parsing information #39
Comments
We observed invariant failures in JSC's prototype implementation, and we found that V8 crashes with the above example with |
https://bugs.webkit.org/show_bug.cgi?id=248031 rdar://102646189 Reviewed by NOBODY (OOPS!). This patch implements JSON.parse source text access proposal[1], which is now stage-3. However, we found that the proposal has a critical bug, which causes crash[2]. So, we do not enable this by default until it is fixed. Right now, JSC is adding non-specified guards to avoid crashes due to [2], but this breaks the compatibility of the behavior of JSON.parse, so we are not enabling this feature. We will expect that some semantics changes will happen in the proposal. This patch implements two major things in the proposal. 1. JSON.rawJSON mechaism. Now new object type is integrated, and JSON.rawJSON can wrap JSON text with this object, which is a tool to inject raw JSON text into JSON.stringify. JSON.stringify uses held string from rawJSON-created object. 2. JSON.parse collects source information during parsing, and offer substring of text as a third parameter of JSON.parse reviver function. (but right now, this has a spec bug). [1]: https://github.com/tc39/proposal-json-parse-with-source [2]: tc39/proposal-json-parse-with-source#39 * JSTests/stress/json-parse-source-text-access.js: Added. (shouldBe): * JSTests/stress/json-raw-json-stringify.js: Added. (shouldBe): (shouldBe.JSON.stringify): * JSTests/stress/json-raw-json.js: Added. (shouldBe): (shouldThrow): (SyntaxError.JSON.Parse.error.Single.quotes.shouldThrow): * Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj: * Source/JavaScriptCore/Sources.txt: * Source/JavaScriptCore/heap/Heap.cpp: * Source/JavaScriptCore/heap/Heap.h: * Source/JavaScriptCore/runtime/CommonIdentifiers.h: * Source/JavaScriptCore/runtime/JSGlobalObject.cpp: (JSC::createJSONProperty): (JSC::JSGlobalObject::init): * Source/JavaScriptCore/runtime/JSGlobalObject.h: (JSC::JSGlobalObject::rawJSONObjectStructure const): * Source/JavaScriptCore/runtime/JSONObject.cpp: (JSC::JSONObject::finishCreation): (JSC::Stringifier::appendStringifiedValue): (JSC::Walker::Walker): (JSC::Walker::callReviver): (JSC::Walker::walk): (JSC::JSC_DEFINE_HOST_FUNCTION): * Source/JavaScriptCore/runtime/JSONObject.h: * Source/JavaScriptCore/runtime/JSRawJSONObject.cpp: Added. (JSC::JSRawJSONObject::JSRawJSONObject): (JSC::JSRawJSONObject::finishCreation): (JSC::JSRawJSONObject::createStructure): (JSC::JSRawJSONObject::rawJSON): * Source/JavaScriptCore/runtime/JSRawJSONObject.h: Copied from Source/JavaScriptCore/runtime/JSONObject.h. * Source/JavaScriptCore/runtime/LiteralParser.cpp: (JSC::LiteralParser<CharType>::tryJSONPParse): (JSC::LiteralParser<CharType>::parse): * Source/JavaScriptCore/runtime/LiteralParser.h: (JSC::JSONRanges::JSONRanges): (JSC::JSONRanges::root const): (JSC::LiteralParser::tryLiteralParse): (JSC::LiteralParser::tryLiteralParsePrimitiveValue): (JSC::LiteralParser::Lexer::Lexer): (JSC::LiteralParser::Lexer::start const): * Source/JavaScriptCore/runtime/OptionsList.h:
This looks like ultimately the same root cause as #35, which was also noticed during V8's implementation. @gibson042 @mathiasbynens Needless to say this and #35 is a hard blocker for shipping. |
Nice find, @Constellation! This is a counterexample to our claim that bottom-up invocation renders moot the concern about divergence between live values and the source text from which they are derived, and will require a normative change to fix. I'll make a PR to take a shallow snapshot of arrays and other objects and suppress
|
What about deletion and recreation of an already processed object property? Values would be the same but order wouldn't. |
Would it be web compatible to use the snapshot of objects and arrays for the entries passed to the reviver, and ignore mutations past snapshot time? I mean which legitimate code mutates the object through the reviver? |
My plan is to preserve const reorderedSource = JSON.parse(
'{ "foo": 0, "bar": 1, "baz": 2 }',
function reviver(key, value, {source}) {
if (key === "foo") {
// Reposition the "bar" property.
const barVal = this.bar;
delete this.bar;
this.bar = barVal;
}
return key ? source : value;
},
);
assert.strictEqual(reorderedSource.bar, "1");
I don't think it would be (as evidenced in part by these two issues), and at any rate such a change is out of scope for this proposal. |
Let's have this example,
JSON.stringify
's result is[1,["Hello",["Hello"]]]
before this proposal because reviver modifiedarray[1]
at runtime and we visit this newly inserted["Hello"]
array.But for this array, we do not have correct corresponding parse information since this is not coming from text. source information for this property is still
2
's information.Thus,
This will crash since this newly inserted array does not have right source information. Source information for this property says
2
(it is coming from the original source).The text was updated successfully, but these errors were encountered: