mpy-cross: Assertion failed when compiling tests/basics/exception_chain.py.
Port, board and/or hardware
Unix on Linux/amd64
MicroPython version
MicroPython v1.26.0-preview.261.gbcc8d4ee1.dirty on 2025-06-22; linux [GCC 15.1.1] version
Reproduction
- Build mpy-cross with no special flags (
make -C mpy-cross clean && make -C mpy-cross) - Compile
tests/basics/exception_chain.pyinto native code (arch does not matter) withmpy-cross -X emit=native -march=debug tests/basics/exception_chain.py mpy-crosswill crash.
Expected behaviour
Compiling tests/basics/exception_chain.py should not crash mpy-cross.
Observed behaviour
mpy-cross crashes with:
mpy-cross: ../py/emitnative.c:2947: emit_native_raise_varargs: Assertion `n_args == 1' failed.`
Additional Information
If having a multi-arg exception is not supported for native code compilation, then an error message should be printed rather than crashing the compiler.
Code of Conduct
Yes, I agree
mpy-cross: Make the debug emitter work again.
Summary
This PR fixes a regression introduced in 1b92bda5b8e5e2db8e57c4b7134930e52bc5207a when adding RV64 support, in which a new architecture was added to mpy-cross but it had no matching native emitter entry point table entry.
The result was that the architecture emitter entry point would be correctly calculated according to the native architecture index, but if the emitters entry points table was not updated to match the new number of architectures an out of bound access may be performed.
Unfortunately adding RV64IMC shifted the debug emitter index further down the table, that wasn't updated to reflect the lack of an emitter for RV64. Adding a NULL entry there would cause a NULL pointer access as there was no need to perform any check about the emitter entry point function's validity until now.
Testing
Running mpy-cross -X emit=native -march=debug <file> on current master would crash with a segment violation on Unix/x64. With the changes of this PR mpy-cross wouldn't crash any more and the compiled module output was printed to STDOUT. In addition, attempting to compile native code for RV64 triggers an error letting the user know there's no emitter for the chosen architecture.
To prevent situations like this in the future, a new test workflow has been added to make sure the debug emitter doesn't crash and reports output that seems correct. The test simply runs the debug emitter for tests/basics/0prelim.py and checks whether the command doesn't report an error and that the output contains an ENTRY and an EXIT line.
I thought about reusing .github/workflows/mpy_format.yml but then the trigger patterns would need to be extended to also cover py/** and mpy-cross/** making those checks run on more commits than needed.
Trade-offs and Alternatives
This could be implemented almost entirely within mpy-cross except for a new NULL entry in the emitter entry points table, although it is not a generic solution. Being generic, however, doesn't lessen the footprint impact on MicroPython's core. If that's unacceptable I can re-implement this PR to leave the compiler alone and add the necessary checks exclusively inside mpy-cross.