fix(stubmerger): 依赖 worklist 去重,修复 64KB 溢出(app_deps 与 BFS 展开均无去重,公共模块重复累积导致溢出;三处逐模块词边界去重,溢出检查保留作防线)

This commit is contained in:
TermiNexus committed 2026-08-20 03:11:48 +08:00
1 parent b08a0aff48
commit b68ae16639
2 files changed
+98 -24

No files matched your search

+31 -7
View File
@@ -587,14 +587,38 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)。
# 依赖在翻译早期已填充,即使 _deps_pending 也收集。
if tr_a._imported_modules is not None and app_deps_buf is not None:
# 逐模块去重拼接:多个 App 文件 import 同一模块(builtins/
# _list/_dict/stdlib/t/c 等公共依赖)会让 app_deps 无去重
# 膨胀到接近 64KB,_BuildReachableSha1Set 的初始 worklist
# 即满 → BFS 展开必报"依赖 worklist 溢出"。
im_len_a: t.CSizeT = string.strlen(tr_a._imported_modules)
if im_len_a > 0 and app_deps_len + im_len_a + 1 < APP_DEPS_BUF_SIZE:
if app_deps_len > 0:
app_deps_buf[app_deps_len] = ' '
app_deps_len = app_deps_len + 1
string.strcpy(app_deps_buf + app_deps_len, tr_a._imported_modules)
app_deps_len = app_deps_len + im_len_a
app_deps_buf[app_deps_len] = '\0'
im_pos_a: t.CSizeT = 0
while im_pos_a < im_len_a:
im_start_a: t.CSizeT = im_pos_a
while im_pos_a < im_len_a and tr_a._imported_modules[im_pos_a] != ' ':
im_pos_a += 1
im_mod_len: t.CSizeT = im_pos_a - im_start_a
if im_pos_a < im_len_a:
im_pos_a += 1
if im_mod_len == 0:
continue
im_mod_buf: bytes = stdlib.malloc(im_mod_len + 1)
if im_mod_buf is None:
continue
string.strncpy(im_mod_buf, tr_a._imported_modules + im_start_a, im_mod_len)
im_mod_buf[im_mod_len] = '\0'
# 已在 app_deps 中则跳过(词边界精确匹配)
if app_deps_len > 0 and HandlesImports.is_module_imported(app_deps_buf, im_mod_buf) != 0:
stdlib.free(im_mod_buf)
continue
if app_deps_len + im_mod_len + 2 < APP_DEPS_BUF_SIZE:
if app_deps_len > 0:
app_deps_buf[app_deps_len] = ' '
app_deps_len = app_deps_len + 1
string.strcpy(app_deps_buf + app_deps_len, im_mod_buf)
app_deps_len = app_deps_len + im_mod_len
app_deps_buf[app_deps_len] = '\0'
stdlib.free(im_mod_buf)
if tr_a._deps_pending != 0:
# 依赖模块 text.ll 未生成(同项目文件顺序),不写盘,下遍重试
fb_dp: str = VLogger.fmt_buf()
+67 -17
View File
@@ -538,13 +538,36 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
tr._inject_auto_container_visibility(mb, tree)
# 获取 _imported_modules
if tr._imported_modules is not None:
# 逐模块去重追加(同 app_deps 拼接,防 worklist 膨胀溢出)
im_len: t.CSizeT = string.strlen(tr._imported_modules)
if im_len > 0 and wl_len + im_len + 1 < REACH_WORKLIST_BUF:
string.strcpy(worklist + wl_len, tr._imported_modules)
wl_len += im_len
worklist[wl_len] = ' '
wl_len += 1
worklist[wl_len] = '\0'
im_pos: t.CSizeT = 0
while im_pos < im_len:
im_start: t.CSizeT = im_pos
while im_pos < im_len and tr._imported_modules[im_pos] != ' ':
im_pos += 1
im_mod_len: t.CSizeT = im_pos - im_start
if im_pos < im_len:
im_pos += 1
if im_mod_len == 0:
continue
im_buf: bytes = stdlib.malloc(im_mod_len + 1)
if im_buf is None:
continue
string.strncpy(im_buf, tr._imported_modules + im_start, im_mod_len)
im_buf[im_mod_len] = '\0'
if wl_len > 0 and HandlesImports.is_module_imported(worklist, im_buf) != 0:
stdlib.free(im_buf)
continue
if wl_len + im_mod_len + 2 < REACH_WORKLIST_BUF:
if wl_len > 0:
worklist[wl_len] = ' '
wl_len += 1
string.strcpy(worklist + wl_len, im_buf)
wl_len += im_mod_len
worklist[wl_len] = ' '
wl_len += 1
worklist[wl_len] = '\0'
stdlib.free(im_buf)
# 计算 App 源文件 SHA1,填充依赖到内存存储器
# worklist 遍历时,LookupIncludesDeps 能找到 App 源文件的依赖
if e_r.Sha1 is not None:
@@ -662,17 +685,44 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
if deps_str is not None:
dl: t.CSizeT = string.strlen(deps_str)
if dl > 0:
if wl_len + dl + 2 < REACH_WORKLIST_BUF:
if wl_len > 0 and worklist[wl_len - 1] != ' ':
worklist[wl_len] = ' '
wl_len = wl_len + 1
string.strcpy(worklist + wl_len, deps_str)
wl_len = wl_len + dl
worklist[wl_len] = ' '
wl_len = wl_len + 1
worklist[wl_len] = '\0'
else:
VLogger.error("依赖 worklist 溢出", "StubMerger")
# 逐模块追加 + 去重:worklist 初始已含全部 App 直接依赖,
# deps_str 中的模块若已在 worklist/processed 不重复追加,
# 否则 BFS 沿共享依赖(builtins/stdlib 等)反复累积到
# 64KB 溢出("依赖 worklist 溢出"根因)。
dpos: t.CSizeT = 0
while dpos < dl:
dstart: t.CSizeT = dpos
while dpos < dl and deps_str[dpos] != ' ':
dpos += 1
dlen: t.CSizeT = dpos - dstart
if dpos < dl:
dpos += 1
if dlen == 0:
continue
dmod: bytes = stdlib.malloc(dlen + 1)
if dmod is None:
continue
string.strncpy(dmod, deps_str + dstart, dlen)
dmod[dlen] = '\0'
in_wl: int = 0
if HandlesImports.is_module_imported(worklist, dmod) != 0:
in_wl = 1
if in_wl == 0 and processed is not None:
if HandlesImports.is_module_imported(processed, dmod) != 0:
in_wl = 1
if in_wl == 0:
if wl_len + dlen + 2 < REACH_WORKLIST_BUF:
if wl_len > 0 and worklist[wl_len - 1] != ' ':
worklist[wl_len] = ' '
wl_len = wl_len + 1
string.strcpy(worklist + wl_len, dmod)
wl_len = wl_len + dlen
worklist[wl_len] = ' '
wl_len = wl_len + 1
worklist[wl_len] = '\0'
else:
VLogger.error("依赖 worklist 溢出", "StubMerger")
stdlib.free(dmod)
# deps_str 为空字符串视为无依赖(合法情况,如叶子模块)
else:
# 依赖未在内存中找到