Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates scripts/update_lit_checks.py to correctly handle parentheses nested inside string literals, including escaped quotes and backslashes, and adds a comprehensive unit test suite to verify this behavior. A review comment identifies an off-by-one bug in the loop termination logic of find_end that could truncate the closing parenthesis if it is the last character in the string, and provides a suggestion to fix it.
| for end in range(start + 1, len(module)): | ||
| if depth == 0: | ||
| break | ||
| if in_string: | ||
| if escaped: | ||
| escaped = False | ||
| elif module[end] == '\\': | ||
| escaped = True | ||
| elif module[end] == '"': | ||
| in_string = False | ||
| elif module[end] == '"': | ||
| in_string = True | ||
| elif module[end] == '(': | ||
| depth += 1 | ||
| elif module[end] == ')': | ||
| depth -= 1 | ||
| return end |
There was a problem hiding this comment.
There is an off-by-one bug in the loop termination logic. If the matching closing parenthesis is the very last character of the module string, the loop terminates naturally without executing the next iteration where depth == 0 is checked. As a result, end is returned as len(module) - 1 instead of len(module), which incorrectly truncates the closing parenthesis when slicing.
We can fix this and simplify the logic by checking if depth == 0 immediately after decrementing it, and returning end + 1 directly from within the loop.
| for end in range(start + 1, len(module)): | |
| if depth == 0: | |
| break | |
| if in_string: | |
| if escaped: | |
| escaped = False | |
| elif module[end] == '\\': | |
| escaped = True | |
| elif module[end] == '"': | |
| in_string = False | |
| elif module[end] == '"': | |
| in_string = True | |
| elif module[end] == '(': | |
| depth += 1 | |
| elif module[end] == ')': | |
| depth -= 1 | |
| return end | |
| for end in range(start + 1, len(module)): | |
| if in_string: | |
| if escaped: | |
| escaped = False | |
| elif module[end] == '\\': | |
| escaped = True | |
| elif module[end] == '"': | |
| in_string = False | |
| elif module[end] == '"': | |
| in_string = True | |
| elif module[end] == '(': | |
| depth += 1 | |
| elif module[end] == ')': | |
| depth -= 1 | |
| if depth == 0: | |
| return end + 1 | |
| return len(module) |
There was a problem hiding this comment.
Sounds like it's worth fixing this at the same time.
There was a problem hiding this comment.
Rather than a Python unit test, let's just have a small .wast lit test that contains parens inside strings and make sure that the auto-update script can properly generate output for it.
| for end in range(start + 1, len(module)): | ||
| if depth == 0: | ||
| break | ||
| if in_string: | ||
| if escaped: | ||
| escaped = False | ||
| elif module[end] == '\\': | ||
| escaped = True | ||
| elif module[end] == '"': | ||
| in_string = False | ||
| elif module[end] == '"': | ||
| in_string = True | ||
| elif module[end] == '(': | ||
| depth += 1 | ||
| elif module[end] == ')': | ||
| depth -= 1 | ||
| return end |
There was a problem hiding this comment.
Sounds like it's worth fixing this at the same time.
Description
This PR fixes an issue in
scripts/update_lit_checks.pywhere the lit check updater incorrectly counts unbalanced parentheses inside strings (such as"hello("or"hello)") as part of the WebAssembly syntax structure. This bug causesCHECKassertions to map incorrectly to subsequent functions inside data segments.Solution
Modified
find_endto handle string boundaries and escaped characters by implementingin_stringandescapedstate tracking. Parentheses inside string literals are now successfully skipped, ensuring accurate structure parsing.Validation Results (WSL Ubuntu)
Local regression test suite executed using
test/unit/test_update_lit_checks_strings.py:beforelog status: 5 expected subcase failures detected (string='hello(',hello)',hello((),hello\"(,hello\\().afterlog status:OK(Ran 1 test containing all subcases successfully).No issues or PR numbers are linked as this stems from an internal code
FIXME.