Crash when using message box

Description

Crash when using message box with button matrix.

What MCU/Processor/Board and compiler are you using?

PlatformIO simulator on Linux

What LVGL version are you using?

7.9.1

What do you want to achieve?

I want to use a message box with buttons.

What have you tried so far?

I’m running this code in the simulator on Linux platform using my SDL based encoder driver.

When I click the “Yes” button:
lv_msgbox_get_active_btn function returns id 0, that is correct, but lv_msgbox_get_active_btn_text() returns NULL, because ext->btn_id_act = 0xFFFF (lv_btnmatrix.c:504)

When I click the “Cancel” button everything works as expected.

If I add a dummy button at the beginning, like

static const char *exitMsgButtons[] = {"dummy", "Yes", "Cancel", ""};

“Yes” and “Cancel” work as expected, but “dummy” fails, because of the wrong ID.

Code to reproduce

// Global array of button labels.
static const char *exitMsgButtons[] = {"Yes", "Cancel", ""};

// Message box event handler.
static void exit_msgbox_event_handler(lv_obj_t *obj, lv_event_t event)
{
  if (LV_EVENT_VALUE_CHANGED == event) {
    uint16_t id = lv_msgbox_get_active_btn(obj);
    const char *btext = lv_msgbox_get_active_btn_text(obj);

    if (0 == strcmp(exitMsgButtons[0], btext)) {
      lv_obj_clean(lv_scr_act());
      printf("Simulator Power OFF\n");
    } else if (0 == strcmp(exitMsgButtons[1], btext)) {
      printf("Simulator exit cancelled\n");
    } else {
      ;
    }

    lv_obj_del(obj);
  }
}

// Function that creates the message box.
void SensorioConfirmExit(void)
{
  lv_obj_t *mbox = lv_msgbox_create(lv_scr_act(), NULL);
  lv_msgbox_set_text(mbox, "Do you want to exit?");
  lv_msgbox_add_btns(mbox, exitMsgButtons);
  lv_obj_set_width(mbox, 200);
  lv_obj_set_event_cb(mbox, exit_msgbox_event_handler);
  lv_obj_align(mbox, lv_scr_act(), LV_ALIGN_CENTER, 0, 0);

  lv_group_remove_all_objs(encgroup);
  lv_group_add_obj(encgroup, mbox);
}

Since I’m totally new to LVGL, I might be doing something wrong. Could you help me which direction to go on?

Thanks a lot!
Zoltan

Update:
The text pointer is wrong only for the first reading. If I inactivate the logic in the event callback and prevent crashing, it can read the correct string for the second time:

id:0 btext:0
id:1 btext:1449263116
id:0 btext:1449263112
id:1 btext:1449263116
id:0 btext:1449263112
id:1 btext:1449263116
id:0 btext:1449263112
id:1 btext:1449263116

If I check for the button ID rather than the text itself, it works now, but I’d like to know the reason for this issue.

Regards,
Zoli

Sounds like a bug to me. Can you try adding ext->btn_id_act = ext->btn_id_focused; below this line in lv_btnmatrix.c? I notice that it sets the act variable for touch devices but not for keypads.

(cc @kisvegabor)

Hi @embeddedt,

thanks for your reply. First, I was wrong in my previous comment, it seemed to me that it fails for the first time only, but actually it fails randomly and only for button ID 0. (At least what I experienced.)

Back to your suggestion, no, it didn’t solve the problem.

Thanks for the report!

I’ll check it tomorrow.

I suppose the message box is also on the act_scr (otherwise you couldn’t click on it).

But if the first button is pressed act_scr is clean by this lines:

 if (0 == strcmp(exitMsgButtons[0], btext)) {
      lv_obj_clean(lv_scr_act());

It also deletes the message box itself and makes lv_obj_t * obj invalid (pointing to a deleted object).

Therefore the last lv_obj_del(obj) is called on an already deleted object.

To put it simple: you have deleted an object twice.

Hi @kisvegabor,

that’s true, thanks for pointing this out, but the crash happens in strcmp, because btext is NULL.

I checked the code, and I don’t understand the difference here:

  • lv_msgbox_get_active_btn() returns the ID of the focused button
  • lv_msgbox_get_active_btn_text() returns the text of the active button

The ID of the active button is always LV_BTNMATRIX_BTN_NONE, this explains, what I experience.

Shouldn’t the active and the focused button refer to the same? Why do they differ?

I have just found, that if I focus “Cancel” first, than back to “Yes” and I hit enter, it always works, btext is always correct. On the other hand, if I click “Yes” without changing focus first, btext is always NULL.

Isn’t it an initialization issue of the active ID?

@zmolnar
Hm, that’s strange. I can’t reproduce the issue. This code prints “dummy”, “Yes” and “Cancel” normally for me:

// Global array of button labels.
static const char *exitMsgButtons[] = {"Yes", "Cancel", ""};

static void event_handler(lv_obj_t * obj, lv_event_t event)
{
    if (LV_EVENT_VALUE_CHANGED == event) {
        const char *btext = lv_msgbox_get_active_btn_text(obj);
        printf("%s\n", btext);
    }
}

void lv_ex_msgbox_1(void)
{

    lv_obj_t * mbox1 = lv_msgbox_create(lv_scr_act(), NULL);
    lv_msgbox_set_text(mbox1, "A message box with two buttons.");
    lv_msgbox_add_btns(mbox1, exitMsgButtons);
    lv_obj_set_width(mbox1, 200);
    lv_obj_set_event_cb(mbox1, event_handler);
    lv_obj_align(mbox1, NULL, LV_ALIGN_CENTER, 0, 0); /*Align to the corner*/
}

Does the exact same code work for you?

Thanks @kisvegabor I will check it in the evening, I’ll be back with the result.

(Just to make sure, please note, that I’m using an encoder, simulated on keyboard, if it makes sense. I guess it does.)

Ahh, I missed that you are using an encoder, sorry.

Now I see the issue. Please update this function like this:

void lv_btnmatrix_set_focused_btn(lv_obj_t * btnm, uint16_t id)
{
    LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);

    lv_btnmatrix_ext_t * ext = lv_obj_get_ext_attr(btnm);

    if(id >= ext->btn_cnt && id != LV_BTNMATRIX_BTN_NONE) return;

    if(id == ext->btn_id_focused) return;

    ext->btn_id_focused = id;
    
    //Add this line
    if(ext->btn_id_act == LV_BTNMATRIX_BTN_NONE) ext->btn_id_act = id; 
    
lv_obj_invalidate(btnm);
}

@kisvegabor it solved the issue, now it works fine. Thanks for the fix.

Should I open a bug, or will you handle it?

Thanks for testing.

I’ve just pushed the fix to master.