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:
1 parent
54750a63c5
commit
bcc016e50e
6 files changed
+101
-18
No files matched your search
@@ -119,27 +119,33 @@ int lyric_parse(const char *lrc, const char *tlrc)
|
||||
{
|
||||
pthread_mutex_lock(&g_lyric_mu);
|
||||
lyric_clear_nolock();
|
||||
int *idx = NULL;
|
||||
int result = 0;
|
||||
lrc_parse(lrc, 0);
|
||||
lrc_parse(tlrc, 1);
|
||||
/* 按时间排序(用索引数组) */
|
||||
idx = (int *)malloc(sizeof(int) * (size_t)(s_n ? s_n : 1));
|
||||
if (idx) {
|
||||
for (int i = 0; i < s_n; i++) idx[i] = i;
|
||||
qsort(idx, (size_t)s_n, sizeof(int), cmp_lines);
|
||||
long ttmp[NCM_LYRIC_LINES];
|
||||
char txt[NCM_LYRIC_LINES][LRC_MAX_TEXT];
|
||||
char tl[NCM_LYRIC_LINES][LRC_MAX_TEXT];
|
||||
memcpy(ttmp, s_t, sizeof(s_t));
|
||||
memcpy(txt, s_txt, sizeof(s_txt));
|
||||
memcpy(tl, s_tl, sizeof(s_tl));
|
||||
for (int i = 0; i < s_n; i++) {
|
||||
s_t[i] = ttmp[idx[i]];
|
||||
memcpy(s_txt[i], txt[idx[i]], LRC_MAX_TEXT);
|
||||
memcpy(s_tl[i], tl[idx[i]], LRC_MAX_TEXT);
|
||||
/* 按时间排序(用索引数组)。临时数组放**堆**上:`char [600][192]`×2 + `long[600]`
|
||||
* 若放栈会占 ~227KB,超过任何线程的 128KB 栈(ncm_thread_create NCM_THREAD_STACK)
|
||||
* → lyric_worker 起播解析时栈溢出 SIGSEGV(真机 sig=11,RA 落在 lyric_parse)。
|
||||
* 堆上按 s_n 计(≤600 行),峰值 ~230KB 瞬态、用后即 free。 */
|
||||
if (s_n > 0) {
|
||||
int *idx = (int *)malloc(sizeof(int) * (size_t)s_n);
|
||||
long *ttmp = (long *)malloc(sizeof(long) * (size_t)s_n);
|
||||
char (*txt)[LRC_MAX_TEXT] =
|
||||
(char (*)[LRC_MAX_TEXT])malloc((size_t)LRC_MAX_TEXT * (size_t)s_n);
|
||||
char (*tl)[LRC_MAX_TEXT] =
|
||||
(char (*)[LRC_MAX_TEXT])malloc((size_t)LRC_MAX_TEXT * (size_t)s_n);
|
||||
if (idx && ttmp && txt && tl) {
|
||||
for (int i = 0; i < s_n; i++) idx[i] = i;
|
||||
qsort(idx, (size_t)s_n, sizeof(int), cmp_lines);
|
||||
memcpy(ttmp, s_t, sizeof(long) * (size_t)s_n);
|
||||
memcpy(txt, s_txt, (size_t)LRC_MAX_TEXT * (size_t)s_n);
|
||||
memcpy(tl, s_tl, (size_t)LRC_MAX_TEXT * (size_t)s_n);
|
||||
for (int i = 0; i < s_n; i++) {
|
||||
s_t[i] = ttmp[idx[i]];
|
||||
memcpy(s_txt[i], txt[idx[i]], LRC_MAX_TEXT);
|
||||
memcpy(s_tl[i], tl[idx[i]], LRC_MAX_TEXT);
|
||||
}
|
||||
}
|
||||
free(idx);
|
||||
free(idx); free(ttmp); free(txt); free(tl); /* 任一 malloc 失败:保留未排序(不崩) */
|
||||
}
|
||||
result = s_n;
|
||||
pthread_mutex_unlock(&g_lyric_mu);
|
||||
|
||||
Reference in new issue
Block a user