修复 I1 绘制缓冲缺 8 字节 palette 头导致的越界写与整帧错位,补存储维护文档
This commit is contained in:
+15
-10
@@ -15,15 +15,18 @@
|
||||
/* 160x160 1bpp 帧 = 3200 字节 */
|
||||
static uint8_t g_ui_fbuf[UI_FB_SIZE];
|
||||
|
||||
/* LVGL 绘制缓冲(整屏渲染)。LVGL 9.3.0 对 I1 格式的整帧渲染,会在其自身算出的
|
||||
* stride*h(=3200) 之后再越界多写 1 个字节(实测台架金丝雀命中 draw_buf[3200]=0xFF)。
|
||||
* 若紧邻其后的 .bss(本例 ui_menu_view.o 的 s_frame_box)恰有指针,其最低字节被
|
||||
* 打成 0xFF → 野指针 → HardFault(PC=lv_obj_get_scroll_y,2026-09-20 存储套件实证,
|
||||
* SRAM/CCM 两种堆布局下同一签名、与 CCM 无关)。物理多留 UI_DRAW_BUF_GUARD 字节
|
||||
* 吸收该越界写;逻辑尺寸仍按 UI_FB_SIZE 上报 LVGL(渲染数学 stride*h 不变)。
|
||||
* Lib/LVGL 为第三方库,不改其源码,越界容纳放在本移植层。 */
|
||||
/* LVGL 9.3 索引色(I1)绘制缓冲的真实布局 = [palette 8B][pixel data stride*h]:
|
||||
* - lv_draw_buf_create() 按 stride*h + palette 分配;
|
||||
* - lv_draw.c:497 → lv_draw_buf_goto_xy() 取绘制指针时先 += palette;
|
||||
* - lv_refr.c get_max_row() 也从 data_size 里扣掉 palette 才当可用像素。
|
||||
* 但 lv_display_set_buffers()/lv_draw_buf_init() 的容量校验只看 stride*h(不含 palette),
|
||||
* 所以"只给 stride*h 字节"会被静默接受 → 末 8 个像素字节写到缓冲之外
|
||||
* (2026-09-21 金丝雀实测:越界 n=8,且 flush 回调收到的首地址前 8 字节是 palette)。
|
||||
* 本端口据此按 stride*h + palette 提供缓冲,flush 时跳过 palette 取真实像素。
|
||||
* UI_DRAW_BUF_GUARD 只给后续 LVGL 版本差异留余量,不再依赖它吸收越界。 */
|
||||
#define UI_DRAW_BUF_PALETTE ((uint32_t)LV_COLOR_INDEXED_PALETTE_SIZE(LV_COLOR_FORMAT_I1) * 4u)
|
||||
#define UI_DRAW_BUF_GUARD 32
|
||||
static uint8_t g_ui_draw_buf[UI_FB_SIZE + UI_DRAW_BUF_GUARD];
|
||||
static uint8_t g_ui_draw_buf[UI_FB_SIZE + UI_DRAW_BUF_PALETTE + UI_DRAW_BUF_GUARD];
|
||||
|
||||
/* 单键缓冲:菜单无需多键队列,仅保存最近一次待处理键 */
|
||||
static volatile uint8_t g_pending_key = 0;
|
||||
@@ -83,7 +86,8 @@ static void ui_keypad_read(lv_indev_t * indev, lv_indev_data_t * data) {
|
||||
static void ui_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p) {
|
||||
(void)disp;
|
||||
(void)area;
|
||||
memcpy(g_ui_fbuf, color_p, UI_FB_SIZE);
|
||||
/* color_p = 绘制缓冲首地址(含 palette 头)→ 跳过 palette 取真实像素 */
|
||||
memcpy(g_ui_fbuf, color_p + UI_DRAW_BUF_PALETTE, UI_FB_SIZE);
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
@@ -105,7 +109,8 @@ int ui_port_init(void) {
|
||||
return -1;
|
||||
}
|
||||
lv_display_set_color_format(disp, LV_COLOR_FORMAT_I1);
|
||||
lv_display_set_buffers(disp, g_ui_draw_buf, NULL, UI_FB_SIZE,
|
||||
lv_display_set_buffers(disp, g_ui_draw_buf, NULL,
|
||||
UI_FB_SIZE + UI_DRAW_BUF_PALETTE,
|
||||
LV_DISPLAY_RENDER_MODE_FULL);
|
||||
lv_display_set_flush_cb(disp, ui_flush_cb);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user