lvgl / lv_binding_micropython

LVGL binding for MicroPython
MIT License
237 stars 156 forks source link

Segfault on Ubuntu 22.04 using example. #245

Closed racerxdl closed 1 year ago

racerxdl commented 1 year ago

When running on a Ubuntu 22.04 the example in wiki (https://docs.lvgl.io/latest/en/html/get-started/micropython.html#a-simple-example) I get a crash with segfault on scr = lv.obj():

Here is the trace. image

Looks like the issue lv_obj_mark_layout_as_dirty receiving a nullptr.

I thought it was related to #97 / #46 , but my stacktrace is completely different, and the crash also does happen using MESA mode (even running in a PC with only software renderer and no GPU or a Xvfb)., so I decided to open an issue.

amirgon commented 1 year ago

Hi @racerxdl !

Could you provide more information?

racerxdl commented 1 year ago

Hi @amirgon , sure. The complete example is the one I mentioned: https://docs.lvgl.io/latest/en/html/get-started/micropython.html#a-simple-example

import lvgl as lv
lv.init()
scr = lv.obj() # Crashes here
btn = lv.btn(scr)
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Button")
lv.scr_load(scr)

After the crash the screen open and close. I followed the tutorial according to the wiki for testing in a Unix (in this case linux).

StackTrace:

#0  lv_obj_mark_layout_as_dirty (obj=obj@entry=0x0) at ../../lib/lv_bindings/lvgl/src/core/lv_obj_pos.c:290
#1  0x0000555555606d01 in lv_obj_class_init_obj (obj=obj@entry=0x0) at ../../lib/lv_bindings/lvgl/src/core/lv_obj_class.c:106
#2  0x00005555555f786d in lv_obj_create (parent=<optimized out>) at ../../lib/lv_bindings/lvgl/src/core/lv_obj.c:278
#3  0x000055555568b485 in mp_lv_obj_create (mp_n_args=<optimized out>, mp_args=<optimized out>, lv_func_ptr=0x5555555f784e <lv_obj_create>) at build-standard/lvgl/lv_mpy.c:12637
#4  0x0000555555670741 in lv_fun_builtin_var_call (self_in=0x5555557428c0 <mp_lv_obj_create_mpobj>, n_args=1, n_kw=<optimized out>, args=0x7fffffffcc90) at build-standard/lvgl/lv_mpy.c:103
#5  0x00005555555cfb10 in mp_call_function_n_kw (fun_in=fun_in@entry=0x5555557428c0 <mp_lv_obj_create_mpobj>, n_args=n_args@entry=1, n_kw=n_kw@entry=0, args=args@entry=0x7fffffffcc90) at ../../py/runtime.c:684
#6  0x000055555567c7af in make_new (lv_obj_var=lv_obj_var@entry=0x5555557428c0 <mp_lv_obj_create_mpobj>, type=0x555555749860 <mp_lv_obj_type>, n_args=<optimized out>, n_kw=<optimized out>, args=<optimized out>) at build-standard/lvgl/lv_mpy.c:304
#7  0x000055555567ce4c in obj_make_new (type=<optimized out>, n_args=<optimized out>, n_kw=<optimized out>, args=<optimized out>) at build-standard/lvgl/lv_mpy.c:13037
#8  0x00005555555e1111 in type_call (self_in=<optimized out>, n_args=<optimized out>, n_kw=<optimized out>, args=<optimized out>) at ../../py/objtype.c:997
#9  0x00005555555cfb10 in mp_call_function_n_kw (fun_in=0x555555749860 <mp_lv_obj_type>, n_args=0, n_kw=0, args=0x7fffffffce48) at ../../py/runtime.c:684
#10 0x00005555555cfcd2 in mp_call_method_n_kw (n_args=<optimized out>, n_kw=<optimized out>, args=args@entry=0x7fffffffce38) at ../../py/runtime.c:700
#11 0x00005555555e909c in mp_execute_bytecode (code_state=code_state@entry=0x7fffffffce10, inject_exc=inject_exc@entry=0x0) at ../../py/vm.c:1026
#12 0x00005555555d7add in fun_bc_call (self_in=0x7fffed6db7a0, n_args=<optimized out>, n_kw=<optimized out>, args=0x0) at ../../py/objfun.c:288
#13 0x00005555555cfb10 in mp_call_function_n_kw (fun_in=0x7fffed6db7a0, n_args=n_args@entry=0, n_kw=n_kw@entry=0, args=args@entry=0x0) at ../../py/runtime.c:684
#14 0x00005555555cfb5a in mp_call_function_0 (fun=<optimized out>) at ../../py/runtime.c:658
#15 0x00005555555f4924 in execute_from_lexer (source_kind=source_kind@entry=2, source=source@entry=0x7fffffffcfa0, input_kind=input_kind@entry=MP_PARSE_SINGLE_INPUT, is_repl=is_repl@entry=true) at main.c:146
#16 0x00005555555f4b1b in do_repl () at main.c:257
#17 0x00005555555f51be in main_ (argc=argc@entry=1, argv=argv@entry=0x7fffffffd218) at main.c:690
#18 0x00005555555f5239 in main (argc=argc@entry=1, argv=argv@entry=0x7fffffffd218) at main.c:451
#19 0x00007ffff6032d90 in __libc_start_call_main (main=main@entry=0x5555555f5216 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffd218) at ../sysdeps/nptl/libc_start_call_main.h:58
#20 0x00007ffff6032e40 in __libc_start_main_impl (main=0x5555555f5216 <main>, argc=1, argv=0x7fffffffd218, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd208) at ../csu/libc-start.c:392
#21 0x00005555555b79e5 in _start ()
amirgon commented 1 year ago

The complete example is the one I mentioned: https://docs.lvgl.io/latest/en/html/get-started/micropython.html#a-simple-example

This "complete" example does not include driver registration. It only contains LVGL logic under the assumption that the user registered a driver. The docs should probably mention that...

Please see the SDL example in the README: https://github.com/lvgl/lv_micropython#super-simple-example

If you prefer to use Frame Buffer and not SDL, see: https://github.com/lvgl/lv_binding_micropython/blob/master/examples/fb_test.py

racerxdl commented 1 year ago

Oh, didn't noticed the readme had an example (I was just following the one from docs.lvgl.io). Now I get another crash in SDL, but probably isnt the scope of this.

Just as info (maybe it is) the stacktrace when calling SDL.init():

#0  __GI___libc_read (nbytes=1, buf=0x7fffffffcf67, fd=0) at ../sysdeps/unix/sysv/linux/read.c:26
#1  __GI___libc_read (fd=fd@entry=0, buf=buf@entry=0x7fffffffcf67, nbytes=nbytes@entry=1) at ../sysdeps/unix/sysv/linux/read.c:24
#2  0x00005555555f54cc in read (__nbytes=1, __buf=0x7fffffffcf67, __fd=0) at /usr/include/x86_64-linux-gnu/bits/unistd.h:38
#3  mp_hal_stdin_rx_chr () at unix_mphal.c:178
#4  0x00005555556a0011 in readline (line=line@entry=0x7fffffffcfa0, prompt=prompt@entry=0x5555556b94ea ">>> ") at ../../shared/readline/readline.c:557
#5  0x00005555555f4b43 in do_repl () at ../../py/repl.h:50
#6  0x00005555555f51be in main_ (argc=argc@entry=1, argv=argv@entry=0x7fffffffd218) at main.c:690
#7  0x00005555555f5239 in main (argc=argc@entry=1, argv=argv@entry=0x7fffffffd218) at main.c:451
#8  0x00007ffff6032d90 in __libc_start_call_main (main=main@entry=0x5555555f5216 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffd218) at ../sysdeps/nptl/libc_start_call_main.h:58
#9  0x00007ffff6032e40 in __libc_start_main_impl (main=0x5555555f5216 <main>, argc=1, argv=0x7fffffffd218, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd208) at ../csu/libc-start.c:392
#10 0x00005555555b79e5 in _start ()

But the framebuffer example works fine: image

So maybe we should close this issue?

amirgon commented 1 year ago

Just as info (maybe it is) the stacktrace when calling SDL.init():

Looks like it crashes on the REPL. How do you run it from the command line?
Try to add -i parameter and the script as a parameter.

racerxdl commented 1 year ago

I did run the REPL and just typed the code example, and crashed at line SDL.Init(). Tryed creating a test.py with the contents described in the readme and ran gdb --args ./micropython -i test.py. The crash looks the same.

#0  __GI___libc_read (nbytes=1, buf=0x7fffffffcf47, fd=0) at ../sysdeps/unix/sysv/linux/read.c:26
#1  __GI___libc_read (fd=fd@entry=0, buf=buf@entry=0x7fffffffcf47, nbytes=nbytes@entry=1) at ../sysdeps/unix/sysv/linux/read.c:24
#2  0x00005555555f54cc in read (__nbytes=1, __buf=0x7fffffffcf47, __fd=0) at /usr/include/x86_64-linux-gnu/bits/unistd.h:38
#3  mp_hal_stdin_rx_chr () at unix_mphal.c:178
#4  0x00005555556a0011 in readline (line=line@entry=0x7fffffffcf80, prompt=prompt@entry=0x5555556b94ea ">>> ") at ../../shared/readline/readline.c:557
#5  0x00005555555f4b43 in do_repl () at ../../py/repl.h:50
#6  0x00005555555f51be in main_ (argc=argc@entry=3, argv=argv@entry=0x7fffffffd1f8) at main.c:690
#7  0x00005555555f5239 in main (argc=argc@entry=3, argv=argv@entry=0x7fffffffd1f8) at main.c:451
#8  0x00007ffff6032d90 in __libc_start_call_main (main=main@entry=0x5555555f5216 <main>, argc=argc@entry=3, argv=argv@entry=0x7fffffffd1f8) at ../sysdeps/nptl/libc_start_call_main.h:58
#9  0x00007ffff6032e40 in __libc_start_main_impl (main=0x5555555f5216 <main>, argc=3, argv=0x7fffffffd1f8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffd1e8) at ../csu/libc-start.c:392
#10 0x00005555555b79e5 in _start ()

Funny enough, when gdb stops at the crash, the SDL Window is already opened, meaning it probably worked but crashed for another reason.

The commit currently in use for lv_binding_micropyton is c544c51c97b38907709a0cd7ea7ca8ab96410cbb which is referenced by the latest in master branch of lv_micropython (my current lv_micropython commit is b7ba3225d14350b1365ec71c04d9879be796396b )

Also for completeness, this is the contents of test.py:

import lvgl as lv
lv.init()

import SDL
SDL.init()

# Register SDL display driver.

draw_buf = lv.disp_draw_buf_t()
buf1_1 = bytearray(480*10)
draw_buf.init(buf1_1, None, len(buf1_1)//4)
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.draw_buf = draw_buf
disp_drv.flush_cb = SDL.monitor_flush
disp_drv.hor_res = 480
disp_drv.ver_res = 320
disp_drv.register()

# Regsiter SDL mouse driver

indev_drv = lv.indev_drv_t()
indev_drv.init()
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = SDL.mouse_read
indev_drv.register()
amirgon commented 1 year ago

@racerxdl I've tried to reproduce it on Linux (Ubuntu 20.04.5), but on my side it works flawlessly. Tried both ports/unix/micropython and ports/unix/micropython-dev.

So I'm not sure what is wrong on your side.

One thing I noticed is that the code you pasted above is wrong and causes syntax error on latest lv_micropython, because btn.align receives only 4 arguments.

After fixing this syntax error, this is what I run:

import lvgl as lv
lv.init()

import SDL
SDL.init()

# Register SDL display driver.

draw_buf = lv.disp_draw_buf_t()
buf1_1 = bytearray(480*10)
draw_buf.init(buf1_1, None, len(buf1_1)//4)
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.draw_buf = draw_buf
disp_drv.flush_cb = SDL.monitor_flush
disp_drv.hor_res = 480
disp_drv.ver_res = 320
disp_drv.register()

# Regsiter SDL mouse driver

indev_drv = lv.indev_drv_t()
indev_drv.init()
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = SDL.mouse_read
indev_drv.register()

scr = lv.obj() # Crashes here
btn = lv.btn(scr)
btn.align(lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Button")
lv.scr_load(scr)

Command line:

ports/unix/micropython -i test.py

Overall the problem you are seeing is unusual because the exception is thrown on read call of libc. On Micropython it's this line:

    MP_HAL_RETRY_SYSCALL(ret, read(STDIN_FILENO, &c, 1), {});

It's a very simply call that reads one character from standard input into a variable on the stack. I just can't see where it can go wrong so I guess there is a previous corruption that is not visible from your stack trace.

If you are adventurous, you can try running this with valgrind and see if it catches anything.

racerxdl commented 1 year ago

I think its somewhat a race-condition and gdb is printing the wrong thread backtrace. I ran with valgrind, and it correctly identifies the crash at NVidia Core.

==1960928==    at 0x11BD2890: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.510.108.03)
==1960928==    by 0x11BD2DF0: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.510.108.03)
==1960928==    by 0x11BB9DB5: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.510.108.03)
==1960928==    by 0x11BBCF42: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.510.108.03)
==1960928==    by 0x1185990D: ??? (in /usr/lib/x86_64-linux-gnu/libnvidia-glcore.so.510.108.03)
==1960928==    by 0x64ACE9E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.18.2)
==1960928==    by 0x649DF98: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.18.2)
==1960928==    by 0x64A362F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.18.2)
==1960928==    by 0x650EFA6: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.18.2)
==1960928==    by 0x6509AFF: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.18.2)
==1960928==    by 0x2544EE: window_update (sdl.c:371)
==1960928==    by 0x25457E: monitor_sdl_refr (sdl.c:293)
==1960928==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

I tried with __GLX_VENDOR_LIBRARY_NAME=mesa LIBGL_ALWAYS_SOFTWARE=1 and it did work fine, I havent tried after initializing the display driver (my bad). So its the same issue as #97 / #46 and for some reason the GDB didnt stopped at the thread that actually crashed. Valgrind did the trick.

I will close it now, since its pretty much solved (at least, the bug is already exposed in #97 / #46 ).

Thanks for the help @amirgon !