From 6ecd891f641b0f4818335855fc76147a50dcd548 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 27 Oct 2026 12:52:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(desk):=20=E6=B8=85=E7=A9=BA=E5=85=B1?= =?UTF-8?q?=E4=BA=AB=E5=8C=BA=E6=A7=BD=E8=A1=A8=E5=B9=B6=E6=8C=89=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=8B=92=E7=BB=9D=E6=97=A7=20app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现场:所有窗口消失、任务栏多出若干图标,点击后 explorer 以 [0E] rip=0x4061e8 cr2=0x1207e8fff 缺页退出。 原因:desk_format 只清 DeskHeader,没有清 0x100 起的 WinSlot 表。 DESK_SHM_SIZE 从 8MB 提到 32MB 后,mm.malloc 拿到的内存不再恰好全零 (混入 bootloader/固件遗留数据),随机 used/active 被当成窗口, 合成时按垃圾 fb_off 越界读像素。 - desk_format 先 memset 整个控制区(0x000000 ~ 0x200000) - 分配槽位时整槽清零,避免复用残留 - DESK_VERSION 1 → 2,desk_ready 校验版本: 旧 app 按旧 WinSlot 偏移读写会写坏共享区,现在直接拒绝挂载 - render_window_rows 校验 fb_off 范围,坏槽位只跳过,不再拖崩合成器 --- Apps/Explorer/desk_server.vp | 6 ++++++ vpsdk/desk.vp | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Apps/Explorer/desk_server.vp b/Apps/Explorer/desk_server.vp index 066dda5..7b676a2 100644 --- a/Apps/Explorer/desk_server.vp +++ b/Apps/Explorer/desk_server.vp @@ -459,6 +459,8 @@ class DeskServer: for i in range(desk.DESK_MAX_WIN): s: desk.WinSlot* = self.slot(i) if s.used == 0: + # 槽位复用前整块清零:避免上一任窗口的 pid/几何/缓冲区偏移残留。 + string.memset(s, 0, desk.desk_slot_size()) cap_px: int = w * content_h buf_off: uint32 = desk.desk_arena_alloc(self.shm, uint32(cap_px) * uint32(4)) if buf_off == uint32(0): return -1 @@ -1202,6 +1204,10 @@ class DeskServer: buf: uint32* = uint32*(self.shm + uint64(s.fb_off)) fw: int = int(s.fb_w) fh: int = int(s.fb_h) + # 槽表被写坏时宁可跳过该窗口,也不要按越界 fb_off 读像素把整个合成器带崩。 + need_bytes: uint64 = uint64(fw) * uint64(fh) * uint64(4) + if s.fb_off < uint32(desk.DESK_OFF_ARENA) or uint64(s.fb_off) + need_bytes > uint64(desk.DESK_SHM_SIZE): + return content_y0: int = wy + th + TITLE_GAP r: int = WIN_RADIUS yy: int = y0 diff --git a/vpsdk/desk.vp b/vpsdk/desk.vp index bb0bf15..f9f0e74 100644 --- a/vpsdk/desk.vp +++ b/vpsdk/desk.vp @@ -29,7 +29,7 @@ from stdint import * # 32MB:1920×1080 全屏窗口的内容缓冲约 7.3MB,最大化需要足够 arena。 define DESK_SHM_SIZE = 33554432 define DESK_MAGIC = 0x4B534544 # 'DESK' -define DESK_VERSION = 1 +define DESK_VERSION = 2 # WinSlot 布局变更必须 +1,旧 app 拒绝挂载 define DESK_MAX_WIN = 8 define DESK_TITLE_MAX = 32 @@ -213,6 +213,9 @@ def desk_map(fd: int) -> uint64: def desk_format(base: uint64, fb_w: uint32, fb_h: uint32, fb_pitch: uint32): """explorer 专用:初始化共享区头与各环。""" + # 先清空整个控制区(头 + 窗口槽表 + 各环):共享区来自 mm.malloc,不能假设为 0。 + # 否则槽表里的随机 used/active 会被当成"多出来的窗口",合成器还会按垃圾 fb_off 取像素。 + string.memset(rawptr(base), 0, uint64(DESK_OFF_ARENA)) h: DeskHeader* = DeskHeader*(base + desk_header_off()) string.memset(h, 0, DeskHeader.__sizeof__()) h.magic = uint32(DESK_MAGIC) @@ -236,6 +239,10 @@ def desk_ready(base: uint64) -> int: h: DeskHeader* = DeskHeader*(base + desk_header_off()) if h.magic != uint32(DESK_MAGIC): return 0 + # 共享结构布局变了(WinSlot 增字段)就拒绝挂载:旧 app 按错偏移读写会把 + # 头部/槽表/别人的像素缓冲写坏,比"连不上"危险得多。 + if h.version != uint32(DESK_VERSION): + return 0 return h.ready def desk_arena_alloc(base: uint64, size: uint32) -> uint32: