mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-22 15:24:16 +08:00
fix(draw_sw): ensure buf_h >= 1 to prevent zero-size alloc in rotated image transform (#9776)
Signed-off-by: lijianjun <lijianjun@xiaomi.com>
This commit is contained in:
@@ -412,7 +412,7 @@ static void recolor_only(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_ds
|
||||
buf_stride = 1;
|
||||
}
|
||||
buf_h = MAX_BUF_SIZE / buf_stride;
|
||||
if(buf_h > blend_h) buf_h = blend_h;
|
||||
buf_h = LV_CLAMP(1, buf_h, blend_h);
|
||||
tmp_buf = lv_malloc(buf_stride * buf_h);
|
||||
LV_ASSERT_MALLOC(tmp_buf);
|
||||
if(!tmp_buf) {
|
||||
@@ -501,19 +501,19 @@ static void transform_and_recolor(lv_draw_task_t * t, const lv_draw_image_dsc_t
|
||||
if(cf_final == LV_COLOR_FORMAT_RGB565A8) {
|
||||
uint32_t buf_stride = blend_w * 3;
|
||||
buf_h = MAX_BUF_SIZE / buf_stride;
|
||||
if(buf_h > blend_h) buf_h = blend_h;
|
||||
buf_h = LV_CLAMP(1, buf_h, blend_h);
|
||||
transformed_buf = lv_malloc(buf_stride * buf_h);
|
||||
}
|
||||
else if(cf_final == LV_COLOR_FORMAT_AL88) {
|
||||
uint32_t buf_stride = blend_w;
|
||||
buf_h = MAX_BUF_SIZE / (buf_stride * 2);
|
||||
if(buf_h > blend_h) buf_h = blend_h;
|
||||
buf_h = LV_CLAMP(1, buf_h, blend_h);
|
||||
transformed_buf = lv_malloc(buf_stride * buf_h * 2);
|
||||
}
|
||||
else {
|
||||
uint32_t buf_stride = blend_w * lv_color_format_get_size(cf_final);
|
||||
buf_h = MAX_BUF_SIZE / buf_stride;
|
||||
if(buf_h > blend_h) buf_h = blend_h;
|
||||
buf_h = LV_CLAMP(1, buf_h, blend_h);
|
||||
transformed_buf = lv_malloc(buf_stride * buf_h);
|
||||
}
|
||||
LV_ASSERT_MALLOC(transformed_buf);
|
||||
|
||||
@@ -523,4 +523,60 @@ void test_snapshot_extreme_size_objects(void)
|
||||
lv_obj_delete(small_obj);
|
||||
}
|
||||
|
||||
/* Regression test: rotated image with large bounding box must not
|
||||
* cause heap-buffer-overflow in transform_argb8888.
|
||||
*
|
||||
* The bug: in img_draw_core, buf_h = MAX_BUF_SIZE / buf_stride.
|
||||
* MAX_BUF_SIZE depends on _lv_refr_get_disp_refreshing(). When
|
||||
* the refreshing display is small but the rotated image bounding
|
||||
* box is large, buf_stride > MAX_BUF_SIZE, buf_h = 0, malloc(0),
|
||||
* and OOB write in transform_argb8888.
|
||||
*
|
||||
* We reproduce this by temporarily shrinking the default display
|
||||
* to 10x10 (making MAX_BUF_SIZE tiny), placing a large rotated
|
||||
* image, and taking a snapshot. The snapshot renders into a large
|
||||
* off-screen layer while MAX_BUF_SIZE stays small.
|
||||
* Without fix: buf_h=0 -> infinite loop in img_draw_core.
|
||||
* With fix: buf_h clamped to 1 -> completes normally. */
|
||||
void test_snapshot_rotated_large_bbox_no_overflow(void)
|
||||
{
|
||||
lv_display_t * disp = lv_display_get_default();
|
||||
|
||||
/* Save original resolution and shrink to 10x10.
|
||||
* MAX_BUF_SIZE = 4 * 10 * 4(ARGB8888) = 160 bytes
|
||||
*
|
||||
* A 200x200 image rotated 45° has bounding box ~283px.
|
||||
* buf_stride = 283 * 4 = 1132 >> 160 = MAX_BUF_SIZE
|
||||
* buf_h = 160 / 1132 = 0 (BUG without fix) */
|
||||
int32_t orig_hor = lv_display_get_horizontal_resolution(disp);
|
||||
int32_t orig_ver = lv_display_get_vertical_resolution(disp);
|
||||
lv_display_set_resolution(disp, 10, 10);
|
||||
|
||||
/* Create a 200x200 ARGB8888 draw_buf as image source */
|
||||
lv_draw_buf_t * src_buf = lv_draw_buf_create(200, 200, LV_COLOR_FORMAT_ARGB8888, 0);
|
||||
TEST_ASSERT_NOT_NULL(src_buf);
|
||||
lv_draw_buf_clear(src_buf, NULL);
|
||||
|
||||
/* Place a rotated image on the current screen */
|
||||
lv_obj_t * img = lv_image_create(lv_screen_active());
|
||||
lv_image_set_src(img, src_buf);
|
||||
lv_image_set_rotation(img, 450); /* 45 degrees */
|
||||
lv_obj_center(img);
|
||||
lv_obj_update_layout(img);
|
||||
|
||||
/* Take a snapshot. Internally snapshot sets this display as
|
||||
* refreshing (small MAX_BUF_SIZE), but renders into a layer
|
||||
* sized to the object's bounding box (~283x283).
|
||||
* Without fix: buf_h=0 -> infinite loop.
|
||||
* With fix: buf_h clamped to 1 -> safe. */
|
||||
lv_draw_buf_t * snapshot = lv_snapshot_take(img, LV_COLOR_FORMAT_ARGB8888);
|
||||
TEST_ASSERT_NOT_NULL(snapshot);
|
||||
|
||||
/* Cleanup and restore original resolution */
|
||||
lv_draw_buf_destroy(snapshot);
|
||||
lv_obj_delete(img);
|
||||
lv_draw_buf_destroy(src_buf);
|
||||
lv_display_set_resolution(disp, orig_hor, orig_ver);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user