-
Notifications
You must be signed in to change notification settings - Fork 473
Fix unsafe defaulted_state reductions and align with Bison defaulted_state reduction behavior #314
base: master
Are you sure you want to change the base?
Conversation
…cing 1. The original implementation did not prevent the defaulted_state from reducing in certain cases, which could lead to a deadlock when processing erroneous input. Although the previous condition if len(rules) == 1 and rules[0] < 0: was overly strict and made such a scenario highly unlikely, it was not completely safe. 2. Updated the defaulted_state rule to align with Bison’s behavior for handling defaulted_state reductions, and removed unnecessary lookahead checks to simplify state transitions—making it easier for the parser to trigger lexer state changes.
Since we now prevent reductions from defaulted_state during error recovery, error-handling rules that lack a right-hand symbol boundary are no longer meaningful and should be reconsidered or removed.
|
Interesting. Do you have a small example of a grammar that illustrates this bug? I'm just trying to better understand it before committing to making changes. |
|
Unfortunately, I’m currently unable to restore the setup needed to reproduce the error. Fortunately, I do have a log that shows exactly how the deadlock occurred. Some background on my parser: I’m developing a parser for a configuration file with very messy and loosely defined syntax. This required me to switch lexer states within the parser. I had previously implemented this successfully in a Java-based Bison parser. However, when I ported the implementation to PLY, I encountered an issue with an unwanted lookahead token—one that Bison would not normally look ahead for. After examining yacc.py, I discovered that the defaulted_state handling was different from Bison 3.3. I updated defaulted_state to match Bison’s behavior, but that change introduced a deadlock. The attached log provides detailed traces of how the deadlock occurred. After further investigation, I realized that defaulted_state should not be used during error handling. I then fixed the issue accordingly, as shown in the pull request. ( Bison’s “default reduction” conditions:
In this log, the earlier errors are all handled normally, but the last error leads to a deadlock due to the 'lex_state_skipLN' empty rule reducing based on defaulted_state. 'lex_state_skipLN' is used to change lexer state. (btw, L*T in the rules are keywords and operators like "var", "=") |
1 Update yacc.py
1.1 The original implementation did not prevent the defaulted_state from reducing in certain cases, which could lead to a deadlock when handling erroneous input. Although the condition if len(rules) == 1 and rules[0] < 0: was overly strict and made this scenario rare, it still posed a correctness risk.
1.2 Updated the defaulted_state rule to align with Bison’s behavior for handling default reductions, and removed unnecessary lookahead checks to simplify parser-initiated lexer state transitions.
2 Update tests/yacc_error5.py
2.1 Since we now prevent reductions from defaulted_state during error recovery, error-handling rules that lack a right-hand symbol boundary are no longer meaningful and should be reconsidered or removed.