Application Segfaults In Library code on startup

Hello LVGL Community,

I’m experiencing persistent segmentation faults in my application built with LVGL version 9.1.0 using EEZ Studio. When I compile and load it on my embedded system, the application initializes correctly and is fully interactive—allowing screen switches and widget interactions—until I add one or two additional widgets. At that point, the application crashes with a segfault before even loading the first screen. Right now I might in theory just make changes to how things work and fix it, but I’m worried that if I keep going I’ll eventually reach a point where I can’t complete the project as it will just be infinitely unstable with each minor change. Something feels very wrong here, and I’m hoping for some community help.

Here’s a summary of what’s happening:

  • Environment:

    • LVGL Version: 9.1.0
    • Development Tool: EEZ Studio to build front end
    • Hardware: Beaglebone Green
    • OS: Custom Yocto Linux Build
    • Fonts Tested: Built-in stock fonts and custom fonts
  • Behavior:

    • Initial State: Application starts, interactive, screens and widgets function as expected.
    • After Adding Widgets:
      • Adding one or two new widgets causes the application to segfault before loading any screen.
      • Removing one widget allows the application to start, but interacting with the remaining widget leads to a segfault.
      • Segfaults occur within LVGL library code, as confirmed by GDB and stack traces. And always in different places depending on what tweaks I make to the layout / code.
  • Attempts to Resolve:

    • Tried both stock and custom fonts without success.
    • Moved the problematic widgets to a separate screen, but the application still segfaults consistently.

Questions:

  1. Are there any known limitations or common issues with LVGL 9.1.0 that could cause these segfaults when adding multiple widgets?
  2. Could this be related to memory management or resource allocation within EEZ Studio when handling additional widgets?
  3. Are there specific debugging steps or tools you recommend to pinpoint the exact cause within the library code?

Additional Information:

  • I have examined the stack traces using GDB, and the segfaults occur within the LVGL library functions. However, I haven’t been able to identify the root cause.
  • The issue persists regardless of whether the widgets are on the same screen or moved to a different one.

What I’ve Tried So Far:

  • Using Stock Fonts: No change in behavior.
  • Using Custom Fonts: Same issue persists.
  • Removing Widgets Individually: Application starts with one widget but crashes upon interaction. Both widgets just crash it immediately.
  • Moving Widgets to a New Screen: Still results in continuous segfaults.
  • Changing styling: I have tried totally restyling the widgets in a variety of ways, as it seems often like its a fault related to applying a style to the widgets.

Any insights or suggestions would be greatly appreciated!

Here is an example stack trace of a segfault with both of the new widgets on the screen:

update_obj_state (obj=0xb6d3feb8 <work_mem_int+64632>, new_state=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj.c:772
warning: Source file is more recent than executable.
772                     ts[tsi].delay = tr->delay;
(gdb) bt
#0  update_obj_state (obj=0xb6d3feb8 <work_mem_int+64632>, new_state=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj.c:772
#1  0xb6ce9656 in lv_obj_event_base (class_p=class_p@entry=0xb6d2f074 <lv_textarea_class>, e=e@entry=0xbefff9e0) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_event.c:86
#2  0xb6d27f0c in lv_textarea_event (class_p=<optimized out>, e=0xbefff9e0) at /usr/src/debug/lvgl/9.1.0/src/widgets/textarea/lv_textarea.c:890
#3  0xb6ce9656 in lv_obj_event_base (class_p=class_p@entry=0x0, e=e@entry=0xbefff9e0) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_event.c:86
#4  0xb6ce96a2 in event_send_core (e=e@entry=0xbefff9e0) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_event.c:359
#5  0xb6ce973a in lv_obj_send_event (obj=obj@entry=0xb6d3feb8 <work_mem_int+64632>, event_code=event_code@entry=LV_EVENT_SCROLL_BEGIN, param=param@entry=0xbefffa14)
    at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_event.c:64
#6  0xb6cebf7c in lv_obj_scroll_by (anim_en=<optimized out>, dy=<optimized out>, dx=<optimized out>, obj=0xb6d3feb8 <work_mem_int+64632>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_scroll.c:339
#7  lv_obj_scroll_by (obj=0xb6d3feb8 <work_mem_int+64632>, dx=<optimized out>, dy=<optimized out>, anim_en=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_scroll.c:304
#8  0xb6d27432 in lv_textarea_set_cursor_pos (obj=obj@entry=0xb6d3feb8 <work_mem_int+64632>, pos=<optimized out>, pos@entry=32767) at /usr/src/debug/lvgl/9.1.0/src/widgets/textarea/lv_textarea.c:388
#9  0xb6d27c08 in lv_textarea_set_text (obj=obj@entry=0xb6d3feb8 <work_mem_int+64632>, txt=0x415900 "999999") at /usr/src/debug/lvgl/9.1.0/src/widgets/textarea/lv_textarea.c:294
#10 0x00408c48 in create_screen_settings () at /mnt/c/Users/danie/ClionProjects/HandController/src/ui/screens.c:2255
#11 0x004092b0 in create_screens () at /mnt/c/Users/danie/ClionProjects/HandController/src/ui/screens.c:2429
#12 0x0040964c in ui_init () at /mnt/c/Users/danie/ClionProjects/HandController/src/ui/ui.c:57
#13 0x00402ae0 in main () at /mnt/c/Users/danie/ClionProjects/HandController/main.c:187

And here is the code up until the lv_text_area_set_text() line that is triggering the cascade of the crash. No removing the set_text from the text entry box does not help, it just moves the segfault elsewhere.

lv_obj_t *obj = lv_obj_create(parent_obj);
                                                    lv_obj_set_pos(obj, -35, -32);
                                                    lv_obj_set_size(obj, 148, 58);
                                                    lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                    lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                    lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                    lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                    lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                    lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                    lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                    {
                                                        lv_obj_t *parent_obj = obj;
                                                        {
                                                            lv_obj_t *obj = lv_label_create(parent_obj);
                                                            lv_obj_set_pos(obj, 0, 0);
                                                            lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
                                                            lv_label_set_text(obj, "Serial Number");
                                                            lv_obj_set_style_text_font(obj, &ui_font_roboto_16_bold, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                        }
                                                        {
                                                            lv_obj_t *obj = lv_textarea_create(parent_obj);
                                                            lv_obj_set_pos(obj, 0, 18);
                                                            lv_obj_set_size(obj, 147, 35);
                                                            lv_textarea_set_max_length(obj, 20);
                                                            lv_textarea_set_text(obj, "999999");

This is what the screen in question looks like, the widgets that cause the problem are the box with limits, and the model/serial/software panels.

Here is an example of a segfault stack trace when only one of the widgets is gone, seems to be related to a character being drawn on the screen:

(gdb) bt
#0  0xb6cf3d42 in draw_letter (cb=<optimized out>, letter=98, font=<optimized out>, pos=<synthetic pointer>, dsc=0xbeffef50, draw_unit=<optimized out>)
    at /usr/src/debug/lvgl/9.1.0/src/draw/lv_draw_label.c:419
#1  lv_draw_label_iterate_characters (draw_unit=0xb6d30ed8 <work_mem_int+3224>, dsc=0xb6d3bc9c <work_mem_int+47708>, coords=0xb6d3c720 <work_mem_int+50400>, cb=0xb6cfb1a5 <draw_letter_cb>)
    at /usr/src/debug/lvgl/9.1.0/src/draw/lv_draw_label.c:328
#2  0xb6cfb2da in lv_draw_sw_label (draw_unit=draw_unit@entry=0xb6d30ed8 <work_mem_int+3224>, dsc=<optimized out>, coords=coords@entry=0xb6d3c720 <work_mem_int+50400>)
    at /usr/src/debug/lvgl/9.1.0/src/draw/sw/lv_draw_sw_letter.c:57
#3  0xb6cf8408 in execute_drawing (u=0xb6d30ed8 <work_mem_int+3224>) at /usr/src/debug/lvgl/9.1.0/src/draw/sw/lv_draw_sw.c:377
#4  execute_drawing_unit (u=0xb6d30ed8 <work_mem_int+3224>) at /usr/src/debug/lvgl/9.1.0/src/draw/sw/lv_draw_sw.c:245
#5  dispatch (layer=0xb6d3133c <work_mem_int+4348>, draw_unit=0xb6d30ed8 <work_mem_int+3224>) at /usr/src/debug/lvgl/9.1.0/src/draw/sw/lv_draw_sw.c:325
#6  dispatch (draw_unit=0xb6d30ed8 <work_mem_int+3224>, layer=0xb6d3133c <work_mem_int+4348>) at /usr/src/debug/lvgl/9.1.0/src/draw/sw/lv_draw_sw.c:292
#7  0xb6cf1da4 in lv_draw_dispatch_layer (disp=disp@entry=0xb6d31020 <work_mem_int+3552>, layer=layer@entry=0xb6d3133c <work_mem_int+4348>) at /usr/src/debug/lvgl/9.1.0/src/draw/lv_draw.c:255
#8  0xb6cf1edc in lv_draw_dispatch () at /usr/src/debug/lvgl/9.1.0/src/draw/lv_draw.c:161
#9  0xb6cf1f4a in lv_draw_finalize_task_creation (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, t=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/draw/lv_draw.c:138
#10 0xb6cf3652 in lv_draw_label (coords=0xbefff038, dsc=0xbefff068, layer=0xb6d3133c <work_mem_int+4348>) at /usr/src/debug/lvgl/9.1.0/src/draw/lv_draw_label.c:97
#11 0xb6d1e85c in draw_main (e=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/widgets/label/lv_label.c:779
#12 lv_label_event (class_p=<optimized out>, e=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/widgets/label/lv_label.c:712
#13 lv_label_event (class_p=<optimized out>, e=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/widgets/label/lv_label.c:663
#14 0xb6ce9656 in lv_obj_event_base (class_p=class_p@entry=0x0, e=e@entry=0xbefff100) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_event.c:86
#15 0xb6ce96a2 in event_send_core (e=e@entry=0xbefff100) at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_event.c:359
#16 0xb6ce973a in lv_obj_send_event (obj=obj@entry=0xb6d340b4 <work_mem_int+15988>, event_code=event_code@entry=LV_EVENT_DRAW_MAIN, param=param@entry=0xb6d3133c <work_mem_int+4348>)
    at /usr/src/debug/lvgl/9.1.0/src/core/lv_obj_event.c:64
#17 0xb6cef6e2 in lv_obj_redraw (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d340b4 <work_mem_int+15988>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:110
#18 0xb6cef9ca in refr_obj (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d340b4 <work_mem_int+15988>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:892
#19 0xb6cef75c in refr_obj (obj=0xb6d340b4 <work_mem_int+15988>, layer=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:888
#20 lv_obj_redraw (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33ef0 <work_mem_int+15536>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:161
#21 0xb6cef9ca in refr_obj (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33ef0 <work_mem_int+15536>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:892
#22 0xb6cef75c in refr_obj (obj=0xb6d33ef0 <work_mem_int+15536>, layer=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:888
#23 lv_obj_redraw (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33e3c <work_mem_int+15356>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:161
#24 0xb6cef9ca in refr_obj (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33e3c <work_mem_int+15356>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:892
#25 0xb6cef75c in refr_obj (obj=0xb6d33e3c <work_mem_int+15356>, layer=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:888
#26 lv_obj_redraw (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33bb8 <work_mem_int+14712>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:161
#27 0xb6cef9ca in refr_obj (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33bb8 <work_mem_int+14712>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:892
#28 0xb6cef75c in refr_obj (obj=0xb6d33bb8 <work_mem_int+14712>, layer=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:888
#29 lv_obj_redraw (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33aa4 <work_mem_int+14436>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:161
#30 0xb6cef9ca in refr_obj (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33aa4 <work_mem_int+14436>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:892
#31 0xb6cef75c in refr_obj (obj=0xb6d33aa4 <work_mem_int+14436>, layer=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:888
#32 lv_obj_redraw (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d339c4 <work_mem_int+14212>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:161
#33 0xb6cef9ca in refr_obj (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d339c4 <work_mem_int+14212>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:892
#34 0xb6cef75c in refr_obj (obj=0xb6d339c4 <work_mem_int+14212>, layer=<optimized out>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:888
--Type <RET> for more, q to quit, c to continue without paging--bt
#35 lv_obj_redraw (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33350 <work_mem_int+12560>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:161
#36 0xb6cef9ca in refr_obj (layer=layer@entry=0xb6d3133c <work_mem_int+4348>, obj=obj@entry=0xb6d33350 <work_mem_int+12560>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:892
#37 0xb6cefde0 in refr_obj (obj=0xb6d33350 <work_mem_int+12560>, layer=0xb6d3133c <work_mem_int+4348>) at /usr/src/debug/lvgl/9.1.0/src/core/lv_refr.c:826

Show lvconf primary this part

/*=========================
   STDLIB WRAPPER SETTINGS
 *=========================*/

/* Possible values
 * - LV_STDLIB_BUILTIN:     LVGL's built in implementation
 * - LV_STDLIB_CLIB:        Standard C functions, like malloc, strlen, etc
 * - LV_STDLIB_MICROPYTHON: MicroPython implementation
 * - LV_STDLIB_RTTHREAD:    RT-Thread implementation
 * - LV_STDLIB_CUSTOM:      Implement the functions externally
 */
#define LV_USE_STDLIB_MALLOC    LV_STDLIB_BUILTIN
#define LV_USE_STDLIB_STRING    LV_STDLIB_BUILTIN
#define LV_USE_STDLIB_SPRINTF   LV_STDLIB_BUILTIN


#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN
    /*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/
    #define LV_MEM_SIZE (64 * 1024U)          /*[bytes]*/

    /*Size of the memory expand for `lv_malloc()` in bytes*/
    #define LV_MEM_POOL_EXPAND_SIZE 0

    /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
    #define LV_MEM_ADR 0     /*0: unused*/
    /*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/
    #if LV_MEM_ADR == 0
        #undef LV_MEM_POOL_INCLUDE
        #undef LV_MEM_POOL_ALLOC
    #endif
#endif  /*LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN*/

This is the part I had tried modifying the most. I had tried LV_STDLIB_BUILTIN and LV_STDLIB_CLIB, as those are the relevant options for my config.

I have also tried modifying the LV_MEM_SIZE to be much larger, (although 10MB is pretty substantial compared the defaults) and none of those things made a difference.

/*=========================
   STDLIB WRAPPER SETTINGS
 *=========================*/

/* Possible values
 * - LV_STDLIB_BUILTIN:     LVGL's built in implementation
 * - LV_STDLIB_CLIB:        Standard C functions, like malloc, strlen, etc
 * - LV_STDLIB_MICROPYTHON: MicroPython implementation
 * - LV_STDLIB_RTTHREAD:    RT-Thread implementation
 * - LV_STDLIB_CUSTOM:      Implement the functions externally
 */
#define LV_USE_STDLIB_MALLOC    LV_STDLIB_CLIB
#define LV_USE_STDLIB_STRING    LV_STDLIB_CLIB
#define LV_USE_STDLIB_SPRINTF   LV_STDLIB_CLIB


#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN
/*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/
#define LV_MEM_SIZE (1024U * 1024U * 10)

/*Size of the memory expand for `lv_malloc()` in bytes*/
#define LV_MEM_POOL_EXPAND_SIZE 0

/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
#define LV_MEM_ADR 0     /*0: unused*/
/*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/
#if LV_MEM_ADR == 0
#undef LV_MEM_POOL_INCLUDE
#undef LV_MEM_POOL_ALLOC
#endif
#endif  /*LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN*/

CLIB seems ok try add checks for null obj dont created …

Ok, so I have just tried that, but I suspect that it would have failed earlier on if there was a problem with the object. Why would it be failing (in this particular instance) on lv_textarea_set_text() and not earlier if this was a NULL pointer issue.

That is the part that is most confusing about this issue, it seems like if there were an issue with my code, it should be manifesting itself right at the point of failure, not many layers deep in the library code.

lv_obj_t *parent_obj = obj;
                                                        {
                                                            lv_obj_t *obj = lv_label_create(parent_obj);
                                                            if(obj == NULL){
                                                                syslog(LOG_WARNING,"%s,%d: obj is NULL",__func__,__LINE__);
                                                            }
                                                            lv_obj_set_pos(obj, 0, 0);
                                                            lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
                                                            lv_label_set_text(obj, "Serial Number");
                                                            lv_obj_set_style_text_font(obj, &ui_font_roboto_16_bold, LV_PART_MAIN | LV_STATE_DEFAULT);
                                                        }
                                                        {
                                                            lv_obj_t *obj = lv_textarea_create(parent_obj);
                                                            if(obj == NULL){
                                                                syslog(LOG_WARNING,"%s,%d: obj is NULL",__func__,__LINE__);
                                                            }
                                                            lv_obj_set_pos(obj, 0, 18);
                                                            lv_obj_set_size(obj, 147, 35);
                                                            lv_textarea_set_max_length(obj, 20);
                                                            lv_textarea_set_text(obj, "999999");
                                                            lv_textarea_set_one_line(obj, false);
                                                            lv_textarea_set_password_mode(obj, false);

I wound up solving this problem. The issue is that the lv_conf.h file doesn’t actually set a bunch of the memory limits, or the logging or a few other things for the library to work with, these limits are hard coded into the library file at compile time (at least when its built in Yocto).

The solution that worked for me, was to go into a file in meta-openembedded/meta-oe/recipes-graphics/lvgl and modify a file called lv-conf.inc which contains the settings that get injected into the lv_conf.h file during compilation, and set LV_USE_LOG and LV_MEM_SIZE in that file.

I’m sure there is a better way to do this with bitbake overlays, but I just wanted to make sure if anyone else comes across this issue they have a starting point to solve it for themselves!