-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
ports/embed: segfault in mp_compile() #11781
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This might precisely be the reason that the unix port does
Probably the way to go, though should be configurable perhaps, and in any case an error/exit should be generated immediately if someone forgets to call it since otherwise the resulting errors might be quite obscure. FWIW I've been using a function similar to mp_embed_init for years and never had stack issues. Actually, also in light of #11430, looking at the current state where there's a myriad of variations on init/exec_str/exec_mpy/deinit/... spread over ports and utility functions I think it would be good to try and unify this into common functions which are either configurable at compiletime or else at runtime. Also by means of documentation. Take mp_embed_exec_str for example: it's there, it's an example, but once you actually want to use it it's going to take a couple of minutes and then you realize you need the return value and you're going to turn to one of th 5 or 10 other implementations which are all tiny variations on the same thing. Next you want to use MICROPYPATH and have to copy that from the unix port (or so), and so on. |
I have a reproducer: cwalther@b404d15. It’s not a segfault but an assert this time (apparently the thing the pointer is overwritten with isn’t that outlandish, but still sufficiently wrong), but that should be enough to illustrate the problem. The added Build the Actual result:
Expected result:
The expected result can be achieved by moving the call of |
Fixes: micropython#11781 Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com>
Fixes: micropython#11781 Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com>
Obtaining the stack-top via a few function calls may yield a pointer which is too deep within the stack. So require the user to obtain it from a higher level (or via some other means). Fixes issue micropython#11781. Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com>
Obtaining the stack-top via a few function calls may yield a pointer which is too deep within the stack. So require the user to obtain it from a higher level (or via some other means). Fixes issue micropython#11781. Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com>
Obtaining the stack-top via a few function calls may yield a pointer which is too deep within the stack. So require the user to obtain it from a higher level (or via some other means). Fixes issue micropython#11781. Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com>
Obtaining the stack-top via a few function calls may yield a pointer which is too deep within the stack. So require the user to obtain it from a higher level (or via some other means). Fixes issue micropython#11781. Signed-off-by: YAMAMOTO Takashi <yamamoto@midokura.com>
There is a bug in the
embed
port that can cause segfaults while compiling Python code in memory-constrained situations. I have not managed to construct a simple reproducer yet, since it depends on memory allocation patterns, but the root cause is easy to verify, so I’m reporting it already.mp_stack_ctrl_init()
, called two levels deep inmain()
→mp_embed_init()
→mp_stack_ctrl_init()
, captures a too lowstack_top
, so that the local variableparse_tree
ofmp_embed_exec_str()
, called only one level deep inmain()
→mp_embed_exec_str()
, ends up outside of the stack range looked at by the garbage collector ingc_helper_collect_regs_and_stack()
. When garbage collection is invoked at just the wrong moment during compilation, the blocks pointed at by the contents ofparse_tree
are therefore freed prematurely, and when they are later reused and overwritten, that corrupts the pointers inside them, which is likely to lead to memory access failures inmp_parse_tree_clear()
at the latest.This is easily verified with
This assert fails for me on macOS 13 x86_64, compiling with clang 14.
I am not sure how to best fix this. Ideas so far:
mp_stack_ctrl_init()
frommp_embed_init()
and require the application itself to call it, at the same or higher level than it will later callmp_embed_exec_str()
.mp_stack_ctrl_init()
apply some offset to the detected stack top to account for its own call depth. I have no idea how to generically and portably determine what that offset should be, though. (Underestimating will fail to fix the problem, overestimating might run into unmapped memory above the stack.)mp_embed_exec_str()
could check whetherparse_tree
is abovestack_top
and if so adjust the latter.Any opinions?
The text was updated successfully, but these errors were encountered: