Conversation
- Add mpca_lang macro wrapper that auto-appends NULL sentinel - Add va_exhausted and error_msg fields to mpca_grammar_st_t - Add -Wno-variadic-macros to suppress warnings
- Check va_exhausted before reading va_arg - Set va_exhausted when NULL sentinel reached - Capture error_msg for proper reporting - Add case-insensitive suggestion for mismatched names
- Initialize va_exhausted=0 and error_msg=NULL at all 5 sites - Check error_msg after mpca_lang_st and convert to proper error - Rename mpca_lang to mpca_lang_internal
Error now caught at definition time instead of parse time
Tests case-insensitive suggestion when parser name differs by case
…grammar, mpca_lang_file, mpca_lang_pipe, mpca_lang_contents
|
Hi @Memnoc, Thanks for the hard work on this. This looks like a much more complicated change than I was expecting. Before this change, if you NULL terminate the list of parsers in I was aware this automatic NULL termination could be achieved my wrapping the function in a macro but opted against it to avoid the use of macros. Please tell me if you interpretation is not correct. Thanks, Dan |
Hey Daniel, Thank you for taking the time to respond. You raise an important point, one that I have initially pondered myself. You are correct in saying that you get an error on the first failed look up. The problem is when mcp continues parsing and makes a second look up, which causes the crash. While the macro adds I have considered other approaches, for example, do we need to do two lookups? My understanding is yes, we do, because the structure of the library wants a So ok, we need both; that said, a better strategy than my fix (Lazy Loading) would be Eager Loading - TL;DR: we call all data at once, at initialization, and thus we would not have any issue. But, this would have been a much bigger refactoring, so I have excluded it. Also, more philosophically, seems to me mpc is all about being scrappy and efficient, sacrificing maybe some formality, so I thought the fix embraced that spirit well 😄 That being said, please do feel free to correct my understanding and proposing a different approach, I'd be more than happy to help if I can! |
Hey Daniel,
Sorry about the long PR, this fix took me places 🛝 I have started with a much more naive fix that worked in my follow along repo, but that did not work for main, so here we are 😄
What I am proposing here is a change that spans various aspects of the library.
Full transparency, I fixed things as I went, AI helped a lot in double-checking the logic and suggesting useful changes, and as it stands all the suite of tests passes with the changes proposed.
I have made very intentionally heavy use of comments where I have changed, please feel free to not like that, but it helped me (and hopefully you) double checking the fix as a whole.
Problem
When a parser name in the grammar string doesn't match any supplied parser (e.g.,
<Lispy>vsmpc_new("lispy")),mpca_langsegfaults.The root cause:
va_argreturns garbage when called past the end of the argument list, notNULL. The existing code assumesNULLwould indicate exhaustion, but instead it dereferences garbage pointers.Example that crashes:
Solution
NULL addition via macro -
mpca_langnow auto-appends NULL to the argument list, guaranteeing a terminator existsExhaustion tracking - Added
va_exhaustedflag to prevent reading past the sentinel on subsequent callsError capture - Added
error_msgfield to preserve the first error for proper reportingError behavior - Errors now caught at definition time instead of silently deferring to parse time
Helpful suggestions - When parser not found, suggests similar names (e.g., "Did you mean 'lispy'?")
Here is an overview of the changes
mpc.h
mpca_lang_internaldeclarationmpca_langmacro wrapper that appends NULL sentinelmpc.c
va_exhaustedanderror_msgfields tompca_grammar_st_tmpca_grammar_find_parserto check exhaustion before callingva_arg, capture errors, and provide suggestionsmpca_grammar,mpca_lang_file,mpca_lang_pipe,mpca_lang_internal,mpca_lang_contentsto initialize new fields and surface captured errorstests/grammar.c
test_missingruleto expect fail-fast error behaviortests/issue_184.c (new)
tests/test.c
Makefile
-Wno-variadic-macrosflagBehavior Change
Errors are now caught at
mpca_langcall time rather than duringmpc_parse. This is intentional, and the idea is that failing fast is more desirable than silent corruption followed by a crash.Before:
After:
Testing
Fixes #184