Repository navigation
Conversation
|
Sorry @bukka and @kocsismate, I accidentally tagged you on this PR. Please ignore this draft... |
a4cd163 to
340b078
Compare
|
Update: I did a |
Catch Throwable instead of a specific exception class, so that an unexpected exception type shows in the test output instead of escaping the try block. Print $e::class, the code and the message, and also assert the ValueError message for the invalid json_validate() flags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XaWra1qpfXbgU9JZ4LozYB
Outside comments, the JSON scanner treats a bare CR as whitespace and counts only LF and CRLF as line endings. The comment rules also counted a bare CR as a line ending. As a result, an error location after a bare CR in a comment did not agree with the same input without the comment. A bare CR still ends a line comment, but it no longer starts a new line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
Outside comments and inside strings, an embedded NUL byte is a control character error. The comment rules skipped it as comment text. Some other parsers end a comment at a NUL byte, so the same input decoded to different values in PHP and in those parsers. An embedded NUL in a line or block comment now gives JSON_ERROR_CTRL_CHAR at the NUL byte. Other control characters stay valid comment text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
The trailing-comma rules add a default reduction after a comma. Without JSON_ALLOW_TRAILING_COMMAS, this reduction also runs when the scanner returns an error, and only the errcode check in its action keeps the scanner's error code. The test ran only with the relaxed flags, so it did not run this check. Run the cases also without flags, add an object case, and check json_validate() too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
The block comment case had the invalid byte in the comment and also in the string. Without flags, the string also gave error 5, and the test did not print the location. Thus the test did not show that the comment itself reports the error. A block comment rule that always skipped invalid bytes also passed the test. The line comment case did not test JSON_INVALID_UTF8_SUBSTITUTE or json_validate(). Put the invalid byte only in the comment, run the same checks for both comment types, and print the error message so that the location is also checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
Two cases used '\n' in single quotes, so the input contained a backslash and an "n" instead of a newline. Use double quotes so that each case tests the input that its comment describes. The expected output does not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
Add regression tests for comment delimiters that touch: an empty block comment, an extra '*' before the closer, and a '/' right after the opener. Also test a comment directly after a float and an exponent, and a comment inside a number. All cases already behave correctly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
The "member ','" and "element ','" rules had the same action. When trailing commas were not allowed, each action freed the value by hand before YYERROR, because bison does not run %destructor for the symbols of the rule whose action calls YYERROR. Move the comma into its own trailing_comma rule, as object_end and array_end already do. YYERROR then removes only the comma, and the %destructor frees the member or element value. php_json_yyerror() keeps an error code that the scanner already set. There is no change in behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
While the scanner is in COMMENT_BLOCK, the rules jump to the condition label and do not pass the std label, so s->token keeps the position of the "/*" opener. The comment_token copy and its restore had no effect. Keep the line and line start copies, because the line ending rules change them. Correct the code comment, which said that comments are always fully consumed before the function returns. There is no change in behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
The dictionary had "//" and "/**/", but not the block comment delimiters alone, a trailing comma before a closer, or a bare CR, which ends a line comment. Add "/*", "*/", ",]", ",}" and "\x0d". libFuzzer only accepts \\, \" and \xNN escapes in a dictionary, so the CR is written as "\x0d". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
Describe the JSON_ALLOW_COMMENTS and JSON_ALLOW_TRAILING_COMMAS flags under New Features, the new json_decode() and json_validate() flags under Changed Functions, and the two constants under New Global Constants. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PCee9RRsbzYcC4ovMxhU6H
340b078 to
9342e09
Compare
|
I personally don't like non standard additions as they might complicate future optimizations in the parser. I think we need to consider them carefully so requesting RFC here. |
|
@bukka Thank you for the review. This PR already has an RFC, which is under discussion, I forgot to add that to the PR description, now updated it...
I planned to open the vote today. I will postpone it, because I want to answer your concern in the RFC first. Which optimizations do you have in mind? With some details I can describe the constraint correctly in the RFC. Some facts about the current design:
|
|
Hi @bukka and @kocsismate Should I wait for your review or is it OK if I open a voting on this feature? |
|
I meant completely replacing parser with something close to simdjson which would make it harder to support those extensions without sacrificing performance / maintainability. But thinking about it, we might just keep alternative (slow parser) for extensions like this one. I got some plans with JsonSchema support (that got a bit on hold) but it would effectively need the same so I guess it's probably fine. |
|
@bukka Thank you, this is clear. I will add this point to the RFC, with a link to your comment. After the cooldown period, I will open the vote. Review comments on the code are still welcome and I will apply them. |
RFC: https://wiki.php.net/rfc/json_comments_trailing_commas
Discussion: https://news-web.php.net/php.internals/132868
Configuration files often use a narrow JSON extension with JS-style comments, trailing commas, or both. PHP currently requires a separate parser or a string-aware preprocessing pass. This PR adds native parser support. Strict JSON remains the default.
Public API
JSON_ALLOW_COMMENTS1 << 23json_decode(),json_validate()//and non-nesting/* ... */comments at JSON whitespace boundaries.JSON_ALLOW_TRAILING_COMMAS1 << 24json_decode(),json_validate()The flags are independent. Neither flag applies to
json_encode()or is enabled by default.Semantics
*/.JSON_INVALID_UTF8_IGNORE, but notJSON_INVALID_UTF8_SUBSTITUTE.JSON_ERROR_SYNTAXat the opening slash.[,],{,}, and[1,,]remain invalid.php/php-src#22473 uses the same flag values (1<<23 and 1<<24) for JSON_DUPLICATE_KEY_MERGE and JSON_DUPLICATE_KEY_ARRAY. The PR that merges second must move its flags to the next free bits.