fix(ncm): 播放页歌词解析栈溢出(SIGSEGV)修复 —— lyric_parse 栈上 227KB 临时数组超 128KB 线程栈

根因(真机 sig=11,RA 落 lyric_parse / pc 在 lib):
app/logic/lyric.c lyric_parse() 在栈上定义
  long ttmp[NCM_LYRIC_LINES=600]; char txt[600][192]; char tl[600][192]
  = ~227KB 栈帧,远超 ncm_thread_create 统一设的 NCM_THREAD_STACK=128KB。
播放页 enter → player_manager_load_lyric → lyric_worker(128KB 线程栈) → lyric_parse → 栈溢出 SIGSEGV。
崩溃仅在「播放页前台 + 拉取歌词成功 + 解析」时触发,故与播放进度无关、autoplay 仅后台起播不崩。

修法:排序临时数组移到堆(按 s_n 计,≤600 行,峰值 ~230KB 瞬态),栈帧回到 KB 级。

复现/定位(/dev 调试 + 真机):
- 真机通过 amd 恢复路径:/tmp/ncm_autoplay 起播缓存曲,app_on_tick 于 UI 线程调 player_play_song
  打开播放页(复现用户点曲路径;autoplay_ui_consume 承接)。原崩溃:pid sig=11 dur=3683ms;
  修复后:连续两次 play:start 无崩溃、60s+ 存活、无 crash_report。
- app.c 增 async-signal-safe SIGSEGV/SIGBUS/SIGILL 处理器(MIPS mcontext_t.pc + gregs ra/sp/fp
  → stderr + crash_report.txt),供 addr2line/链接布局定位。

验证:stream/player_flow/window/search/cache_evict sim 全 PASS;test_ncm_core host + qemu-mipsel
PASS;build_ncm.sh -Wall -Wextra 0 warning;ncm_host NCM_PAGE=player/home 离屏渲染 exit=0。
This commit is contained in:
AskaEth committed 2026-09-02 09:53:34 +08:00
1 parent 54750a63c5
commit bcc016e50e
6 files changed
+101 -18

No files matched your search

+19 -1
View File
@@ -644,6 +644,22 @@ int appstate_current_playing(void)
#define AUTOPLAY_TRIGGER "/tmp/ncm_autoplay"
#define AUTOPLAY_SCAN_PL 3
/* 真机崩溃复现扩展:autoplay 在后台线程起播后,把「打开播放页」动作交给 UI 线程
* (meow_view_page_push/view_enter 非线程安全,UI 栈只能 UI 线程驱动)。worker 写
* g_autoplay_* 标志,app_on_tick 每 tick 用 autoplay_ui_consume() 取走并调 player_play_song,
* 从而完整复现用户「点曲 → 播放页渲染(封面/歌词/动画/进度)」路径。仅 /tmp/ncm_autoplay 存在时激活。 */
static volatile int g_autoplay_goto_player = 0;
static int g_autoplay_play_idx = -1;
int autoplay_ui_consume(void) /* UI 线程取走「已缓存起播」标志,返回曲目 idx(无则 -1) */
{
if (!g_autoplay_goto_player) return -1;
g_autoplay_goto_player = 0;
int i = g_autoplay_play_idx;
g_autoplay_play_idx = -1;
return i;
}
/* 播放单个歌单首页中第一首已缓存曲目。命中播放返回 1,否则 0。 */
static int autoplay_try_playlist(int pl)
{
@@ -666,7 +682,9 @@ static int autoplay_try_playlist(int pl)
g_st.active_playlist = pl;
meow_log(MEOW_LOG_INFO, "autoplay: playlist[%d] song[%d] id=%s cached -> play",
pl, i, s.id);
player_manager_play(i);
/* 交给 UI 线程打开播放页(模拟用户点曲播放),避免后台线程调 UI 栈 */
g_autoplay_play_idx = i;
g_autoplay_goto_player = 1;
return 1;
}
}