Binary operations on undefined variables crash the native emitter.
Port, board and/or hardware
unix
MicroPython version
MicroPython v1.24.0-preview.206.ge9814e987.dirty on 2024-08-16; linux [GCC 14.2.1] version
Reproduction
Run the following code:
@micropython.native
def f():
a += 0 # Or anything else, really
f()
Expected behaviour
A NameError exception should be raised. (CPython raises NameError: name 'a' is not defined)
Observed behaviour
This is the backtrace of the crash when running the interpreter under GDB:
Program received signal SIGSEGV, Segmentation fault.
mp_obj_get_type (o_in=o_in@entry=0x0) at ../../py/obj.c:61
61 return o->type;
(gdb) bt
#0 mp_obj_get_type (o_in=o_in@entry=0x0) at ../../py/obj.c:61
#1 0x0000555555591333 in mp_binary_op (op=MP_BINARY_OP_INPLACE_ADD, lhs=0x0, rhs=0x1) at ../../py/runtime.c:630
#2 0x00007ffff7fc0053 in ?? ()
#3 0x00007ffff7a06440 in ?? ()
#4 0x00007ffff7fc006d in ?? ()
#5 0x00007fffffff9610 in ?? ()
#6 0x0000000000000003 in ?? ()
#7 0x00007fffffff9760 in ?? ()
#8 0x0000000000000000 in ?? ()
Additional Information
No, I've provided everything above.
Code of Conduct
Yes, I agree
py/runtime: Check for null objects coming from native functions.
Summary
When performing inplace binary operations (eg +=, -=, etc) from a native emitted context, the left hand side operand would be NULL if it wasn't defined earlier. The code assumed the operand would always be non-NULL and hence a crash occurred when accessing the operand object.
This commit turns that crash into an exception being raised, with the same name and message as if the same error occurred in a bytecode context. Also, the exception is raised at runtime, following the same behaviour as if the function was not decorated as native.
To reproduce the issue just try to execute the following Python code:
@micropython.native
def f():
a += 10
f()
Whilst this is a minor issue, the very fact that it would crash the whole interpreter because of a typo in a native function makes it quite annoying to have...
This fixes issue #15670.
Testing
This was tested on the Unix port, but the issue would happen on any target that supports native compilation.
Trade-offs and Alternatives
This patch is only enabled if MICROPY_ENABLE_COMPILER is enabled, and should add a hundred bytes or so of code. Rather than patching the runtime this issue could maybe be fixed when compiling the incorrect statement that emits the binary operation, but I'm quite new to that part of the codebase. At least it follows the same behaviour as the VM, better than nothing...