From 0bf96cba10f62ee08063cce5178e4cf5f92437b8 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sat, 21 Mar 2026 06:53:54 +0100 Subject: [PATCH] fix(grid): fix segfault when row/column screen descriptor is missing (#9790) --- src/layouts/grid/lv_grid.c | 72 ++++++++++++++++++++++++++++---- tests/src/test_cases/test_grid.c | 55 ++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 8 deletions(-) diff --git a/src/layouts/grid/lv_grid.c b/src/layouts/grid/lv_grid.c index e4115ca0bf..ca8366709b 100644 --- a/src/layouts/grid/lv_grid.c +++ b/src/layouts/grid/lv_grid.c @@ -192,7 +192,10 @@ static void grid_update(lv_obj_t * cont, void * user_data) lv_grid_calc_t c; lv_result_t res = calc(cont, &c); - if(res != LV_RESULT_OK) return; + if(res != LV_RESULT_OK) { + calc_free(&c); + return; + } item_repos_hint_t hint; lv_memzero(&hint, sizeof(hint)); @@ -230,8 +233,8 @@ static void grid_update(lv_obj_t * cont, void * user_data) */ static lv_result_t calc(lv_obj_t * cont, lv_grid_calc_t * calc_out) { + lv_memzero(calc_out, sizeof(lv_grid_calc_t)); if(lv_obj_get_child(cont, 0) == NULL) { - lv_memzero(calc_out, sizeof(lv_grid_calc_t)); return LV_RESULT_INVALID; } @@ -282,12 +285,19 @@ static lv_result_t calc_cols(lv_obj_t * cont, lv_grid_calc_t * c) const int32_t * col_templ; col_templ = get_col_dsc(cont); + + /*If there is no descriptor check if it's a subgrid*/ bool subgrid = false; if(col_templ == NULL) { lv_obj_t * parent = lv_obj_get_parent(cont); + if(parent == NULL) { + LV_LOG_WARN("No column descriptor, and there is no parent for a screen to process subgrid"); + return LV_RESULT_INVALID; + } + col_templ = get_col_dsc(parent); if(col_templ == NULL) { - LV_LOG_WARN("No col descriptor found even on the parent"); + LV_LOG_WARN("No column descriptor found even on the parent"); return LV_RESULT_INVALID; } @@ -375,9 +385,16 @@ static lv_result_t calc_rows(lv_obj_t * cont, lv_grid_calc_t * c) { const int32_t * row_templ; row_templ = get_row_dsc(cont); + + /*If there is no descriptor check if it's a subgrid*/ bool subgrid = false; if(row_templ == NULL) { lv_obj_t * parent = lv_obj_get_parent(cont); + if(parent == NULL) { + LV_LOG_WARN("No row descriptor, and there is no parent for a screen to process subgrid"); + return LV_RESULT_INVALID; + } + row_templ = get_row_dsc(parent); if(row_templ == NULL) { LV_LOG_WARN("No row descriptor found even on the parent"); @@ -471,14 +488,53 @@ static lv_result_t calc_rows(lv_obj_t * cont, lv_grid_calc_t * c) static void item_repos(lv_obj_t * item, lv_grid_calc_t * c, item_repos_hint_t * hint) { if(lv_obj_has_flag_any(item, LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) return; - uint32_t col_span = get_col_span(item); - uint32_t row_span = get_row_span(item); - if(row_span == 0 || col_span == 0) return; + + int32_t col_span = get_col_span(item); + if(col_span <= 0) { + LV_LOG_WARN("Column span was %" LV_PRId32 ", setting it to 1", col_span); + col_span = 1; + } + + int32_t row_span = get_row_span(item); + if(row_span <= 0) { + LV_LOG_WARN("Row span was %" LV_PRId32 ", setting it to 1", row_span); + row_span = 1; + } bool rev = lv_obj_get_style_base_dir(lv_obj_get_parent(item), LV_PART_MAIN) == LV_BASE_DIR_RTL; - uint32_t col_pos = get_col_pos(item); - uint32_t row_pos = get_row_pos(item); + int32_t col_pos = get_col_pos(item); + if(col_pos < 0) { + LV_LOG_WARN("Column position was %" LV_PRId32 ", setting it to 0", col_pos); + col_pos = 0; + } + + if(col_pos >= (int32_t)c->col_num) { + LV_LOG_WARN("Column position was %" LV_PRId32 ", setting to %" LV_PRId32, col_pos, c->col_num - 1); + col_pos = c->col_num - 1; + } + + int32_t row_pos = get_row_pos(item); + if(row_pos < 0) { + LV_LOG_WARN("Row position was %" LV_PRId32 ", setting it to 0", row_pos); + row_pos = 0; + } + + if(row_pos >= (int32_t)c->row_num) { + LV_LOG_WARN("Row position was %" LV_PRId32 ", setting to %" LV_PRId32, row_pos, c->row_num - 1); + row_pos = c->row_num - 1; + } + + if(col_pos + col_span > (int32_t)c->col_num) { + col_span = c->col_num - col_pos; + LV_LOG_WARN("Column span is too large, limiting it to %" LV_PRId32, col_span); + } + + if(row_pos + row_span > (int32_t)c->row_num) { + row_span = c->row_num - row_pos; + LV_LOG_WARN("Row span is too large, limiting it to %" LV_PRId32, row_span); + } + lv_grid_align_t col_align = get_cell_col_align(item); lv_grid_align_t row_align = get_cell_row_align(item); diff --git a/tests/src/test_cases/test_grid.c b/tests/src/test_cases/test_grid.c index a6dca0c818..e3ad37910b 100644 --- a/tests/src/test_cases/test_grid.c +++ b/tests/src/test_cases/test_grid.c @@ -122,4 +122,59 @@ void test_grid_rtl(void) TEST_ASSERT_EQUAL_SCREENSHOT("grid_rtl.png"); } + +void test_grid_no_crash_on_invalid_settings(void) +{ + /*Should't crash because of these*/ + + /*No col/row descriptors on screen*/ + lv_obj_t * scr = lv_obj_create(NULL); + lv_screen_load(scr); + lv_obj_set_style_layout(scr, LV_LAYOUT_GRID, 0); + lv_refr_now(NULL); + + /*No col/row descriptors on a widget*/ + lv_obj_t * cont = lv_obj_create(scr); + lv_obj_set_style_layout(cont, LV_LAYOUT_GRID, 0); + lv_refr_now(NULL); + + /*Set a cell without having row/col descriptor on the parent*/ + lv_obj_set_grid_cell(cont, LV_GRID_ALIGN_CENTER, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1); + lv_refr_now(NULL); + + /*Add grid descriptors*/ + const int32_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; + const int32_t row_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST}; + lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc); + lv_refr_now(NULL); + + lv_obj_t * label = lv_label_create(cont); + + /*Zero span*/ + lv_obj_set_grid_cell(label, LV_GRID_ALIGN_CENTER, 0, 0, LV_GRID_ALIGN_CENTER, 0, 0); + lv_refr_now(NULL); + + /*Too large span*/ + lv_obj_set_grid_cell(label, LV_GRID_ALIGN_CENTER, 0, 20, LV_GRID_ALIGN_CENTER, 0, 30); + lv_refr_now(NULL); + + /*Negative span*/ + lv_obj_set_grid_cell(label, LV_GRID_ALIGN_CENTER, 0, -50, LV_GRID_ALIGN_CENTER, 0, -20); + lv_refr_now(NULL); + + /*Too large position*/ + lv_obj_set_grid_cell(label, LV_GRID_ALIGN_CENTER, 30, 1, LV_GRID_ALIGN_CENTER, 20, 1); + lv_refr_now(NULL); + + /*Negative position*/ + lv_obj_set_grid_cell(label, LV_GRID_ALIGN_CENTER, -100, 1, LV_GRID_ALIGN_CENTER, -20, 1); + lv_refr_now(NULL); + + /*Valid settings*/ + lv_obj_set_grid_cell(label, LV_GRID_ALIGN_CENTER, 1, 2, LV_GRID_ALIGN_CENTER, 0, 1); + lv_refr_now(NULL); + TEST_PASS(); +} + + #endif