Repository navigation
Conversation
otar
marked this pull request as draft
August 17, 2026 17:08
Author
|
Sorry @bukka and @kocsismate, I accidentally tagged you on this PR. Please ignore this draft... |
NickSdot
reviewed
Aug 18, 2026
Comment on lines
+35
to
+36
| } catch (JsonException $e) { | ||
| echo get_class($e), ': ', $e->getCode(), ': ', $e->getMessage(), "\n"; |
Contributor
There was a problem hiding this comment.
Suggested change
| } catch (JsonException $e) { | |
| echo get_class($e), ': ', $e->getCode(), ': ', $e->getMessage(), "\n"; | |
| } catch (Throwable $e) { | |
| echo $e::class, ': ', $e->getCode(), ': ', $e->getMessage(), "\n"; |
NickSdot
reviewed
Aug 18, 2026
Comment on lines
+31
to
+57
| } catch (JsonException $e) { | ||
| echo $e->getCode(), ': ', $e->getMessage(), "\n"; | ||
| } | ||
|
|
||
| ?> | ||
| --EXPECT-- | ||
| NULL | ||
| 5 | ||
| array(1) { | ||
| [0]=> | ||
| string(2) "ab" | ||
| } | ||
| 0 | ||
| array(1) { | ||
| [0]=> | ||
| string(5) "a�b" | ||
| } | ||
| 0 | ||
| NULL | ||
| 5 | ||
| int(1) | ||
| 0 | ||
| bool(false) | ||
| 5 | ||
| bool(true) | ||
| 0 | ||
| 5: Malformed UTF-8 characters, possibly incorrectly encoded near location 1:9 |
Contributor
There was a problem hiding this comment.
Suggested change
| } catch (JsonException $e) { | |
| echo $e->getCode(), ': ', $e->getMessage(), "\n"; | |
| } | |
| ?> | |
| --EXPECT-- | |
| NULL | |
| 5 | |
| array(1) { | |
| [0]=> | |
| string(2) "ab" | |
| } | |
| 0 | |
| array(1) { | |
| [0]=> | |
| string(5) "a�b" | |
| } | |
| 0 | |
| NULL | |
| 5 | |
| int(1) | |
| 0 | |
| bool(false) | |
| 5 | |
| bool(true) | |
| 0 | |
| 5: Malformed UTF-8 characters, possibly incorrectly encoded near location 1:9 | |
| } catch (Throwable $e) { | |
| echo $e::class, ': ', $e->getCode(), ': ', $e->getMessage(), "\n"; | |
| } | |
| ?> | |
| --EXPECT-- | |
| NULL | |
| 5 | |
| array(1) { | |
| [0]=> | |
| string(2) "ab" | |
| } | |
| 0 | |
| array(1) { | |
| [0]=> | |
| string(5) "a�b" | |
| } | |
| 0 | |
| NULL | |
| 5 | |
| int(1) | |
| 0 | |
| bool(false) | |
| 5 | |
| bool(true) | |
| 0 | |
| JsonException: 5: Malformed UTF-8 characters, possibly incorrectly encoded near location 1:9 |
NickSdot
reviewed
Aug 18, 2026
Comment on lines
+67
to
+96
| } catch (JsonException $e) { | ||
| echo $e->getCode(), ': ', $e->getMessage(), "\n"; | ||
| } | ||
|
|
||
| ?> | ||
| --EXPECT-- | ||
| [1] | ||
| [1] | ||
| [1] | ||
| {"a":1} | ||
| [[1],{"a":2}] | ||
| error 4: Syntax error near location 1:2 | ||
| error 4: Syntax error near location 1:2 | ||
| error 4: Syntax error near location 1:4 | ||
| error 4: Syntax error near location 1:4 | ||
| error 4: Syntax error near location 1:8 | ||
| error 4: Syntax error near location 1:4 | ||
| error 4: Syntax error near location 1:4 | ||
| error 4: Syntax error near location 1:4 | ||
| [1] | ||
| {"a":1} | ||
| error 2: State mismatch (invalid or malformed JSON) near location 1:4 | ||
| error 2: State mismatch (invalid or malformed JSON) near location 1:8 | ||
| bool(true) | ||
| bool(true) | ||
| bool(false) | ||
| bool(true) | ||
| bool(false) | ||
| bool(false) | ||
| 4: Syntax error near location 1:4 |
Contributor
There was a problem hiding this comment.
Suggested change
| } catch (JsonException $e) { | |
| echo $e->getCode(), ': ', $e->getMessage(), "\n"; | |
| } | |
| ?> | |
| --EXPECT-- | |
| [1] | |
| [1] | |
| [1] | |
| {"a":1} | |
| [[1],{"a":2}] | |
| error 4: Syntax error near location 1:2 | |
| error 4: Syntax error near location 1:2 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:8 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:4 | |
| [1] | |
| {"a":1} | |
| error 2: State mismatch (invalid or malformed JSON) near location 1:4 | |
| error 2: State mismatch (invalid or malformed JSON) near location 1:8 | |
| bool(true) | |
| bool(true) | |
| bool(false) | |
| bool(true) | |
| bool(false) | |
| bool(false) | |
| 4: Syntax error near location 1:4 | |
| } catch (Throwable $e) { | |
| echo $e::class, ': ', $e->getCode(), ': ', $e->getMessage(), "\n"; | |
| } | |
| ?> | |
| --EXPECT-- | |
| [1] | |
| [1] | |
| [1] | |
| {"a":1} | |
| [[1],{"a":2}] | |
| error 4: Syntax error near location 1:2 | |
| error 4: Syntax error near location 1:2 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:8 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:4 | |
| error 4: Syntax error near location 1:4 | |
| [1] | |
| {"a":1} | |
| error 2: State mismatch (invalid or malformed JSON) near location 1:4 | |
| error 2: State mismatch (invalid or malformed JSON) near location 1:8 | |
| bool(true) | |
| bool(true) | |
| bool(false) | |
| bool(true) | |
| bool(false) | |
| bool(false) | |
| JsonException: 4: Syntax error near location 1:4 |
NickSdot
reviewed
Aug 18, 2026
| try { | ||
| json_validate('{}', flags: RELAXED | $invalidFlag); | ||
| } catch (ValueError $e) { | ||
| echo get_class($e), "\n"; |
Contributor
There was a problem hiding this comment.
Maybe you want to assert the message here too. Same format as above.
Author
There was a problem hiding this comment.
@NickSdot thanks for the feedback. I really appreciate it and will take it into consideration.
…ma-parsing Resolve the conflict in sapi/fuzzer/fuzzer-json.c: keep the option sets that master added in 60ddc8f (php#23877) and append the JSON_ALLOW_COMMENTS and JSON_ALLOW_TRAILING_COMMAS sets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XaWra1qpfXbgU9JZ4LozYB
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.