-
-
Save holishing/a4ee1582947d0adea7e29c8ba01c6ecc to your computer and use it in GitHub Desktop.
Maple3 BRH crash
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
作者 lantw44 ([#################]) 看板 lantw44 | |
標題 Re: [測試] 轉得過去嗎? | |
時間 2018/02/12 Mon 23:30:38 | |
> 作者: lantw44 ([#################]) 看板: lantw44 | |
> 標題: Re: [測試] 轉得過去嗎? | |
> 時間: 2018/02/11 Sun 17:26:35 | |
> | |
> 於是我先把 SIGBUS 和 SIGSEGV 的 signal handler 拿掉了,總覺得把這種 signal 抓 | |
> 下來實在很沒意義,只是造成 debug 困難而已,不知道當初為什麼會這樣寫。 | |
於是看來 signal handler 存在的目的是呼叫 u_exit 讓已經當掉的使用者不會繼續出現 | |
在使用者名單上。不過我想這功能實際上只對站務帳號有用,因為普通使用者登入的時候 | |
會提示是否踢掉重覆登入,我想大部分的人應該都會選「是」吧。 | |
儘管如此我依然不認為一個普通程式可以對 SIGBUS 和 SIGSEGV 這種代表程式錯誤的訊 | |
號設定 signal handler。程式本身都已經發生嚴重錯誤了,還能叫 u_exit? | |
> r2 推:有印象又叫回 abort_bbs 這個部分@@ 超奇怪的@@ 0211 20:39 | |
> lantw44 推:再來登入一下收集 core dump 吧…… 0211 21:19 | |
> r2 推:ok @@ 0211 23:32 | |
> lantw44 推:我把 setrlimit(RLIMIT_DATA, &limit) 這行註解掉了 0212 00:54 | |
> lantw44 說:再來試試看吧,總覺得這類資源限制還蠻容易造成問題的 0212 00:56 | |
> r2 推:有再測試了, 進去 (B)oards (F)avorite 或 s 過去 lantw44 板 0212 02:14 | |
> r2 說:還是都會斷線@@ 0212 02:15 | |
一開始會猜 setrlimit 是因為 dmesg 曾經有出現過類似訊息,但既然還是會斷線,那就 | |
代表不是這個的問題了。BBS 本身記憶體用量就不高,而 glibc 的 malloc 實作也只有 | |
在配置小量空間時才會用 sbrk,大量空間用 mmap 應該是不受 RLIMIT_DATA 限制。 | |
------------------------------------------------------------------------------ | |
前篇訊息的回覆就到這裡,先說結論: | |
你的帳號的 .BRH 檔案爛掉了 | |
以下是一些 debug 的過程和細節,有興趣就看看吧,至於 .BRH 如何處理結尾再說。 | |
------------------------------------------------------------------------------ | |
$ gdb ~bbs/bin/bbsd 'core.!home!bbs!bin!bbsd.signal-11.pid-26147' | |
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git | |
...... | |
Reading symbols from /home/bbs/bin/bbsd...done. | |
[New LWP 26147] | |
Core was generated by `bbsd -i'. | |
Program terminated with signal SIGSEGV, Segmentation fault. | |
#0 0xf7582f06 in _IO_vfscanf_internal (s=0xff6f5470, format=0xf7692108 | |
"%hu%n:%hu%n:%hu%n", argptr=0xff6f5548 | |
"vUo\377|Uo\377xUo\377|Uo\377zUo\377|Uo\377", errp=0x0) | |
at vfscanf.c:279 | |
首先這個什麼 scanf 的我想完全不重要,stack overflow 以後整個程式就不知道在跑 | |
什麼東西了,之後看 backtrace 我也是直接忽略這段。 | |
(gdb) set height unlimited | |
(gdb) bt | |
...... | |
#56604 0x565abcbe in abort_bbs () at bbsd.c:178 | |
#56605 0x565b1215 in brh_alloc (tail=0xc1fb3af8, size=1887295246) at | |
board.c:97 | |
#56606 0x565b208f in brh_save () at board.c:668 | |
#56607 0x565abb2f in u_exit (mode=0x565e2e50 "AXXED") at bbsd.c:121 | |
#56608 0x565abcbe in abort_bbs () at bbsd.c:178 | |
#56609 0x565b1215 in brh_alloc (tail=0xc1fb3af8, size=1887295246) at | |
board.c:97 | |
#56610 0x565b208f in brh_save () at board.c:668 | |
#56611 0x565abb2f in u_exit (mode=0x565e2e50 "AXXED") at bbsd.c:121 | |
#56612 0x565abcbe in abort_bbs () at bbsd.c:178 | |
#56613 0x565b1215 in brh_alloc (tail=0xc1fb3af8, size=1887295246) at | |
board.c:97 | |
#56614 0x565b208f in brh_save () at board.c:668 | |
#56615 0x565abb2f in u_exit (mode=0x565e5da2 "EXIT ") at bbsd.c:121 | |
#56616 0x565c384a in goodbye () at menu.c:213 | |
#56617 0x565c4359 in menu () at menu.c:1137 | |
#56618 0x565adc5d in tn_main () at bbsd.c:1201 | |
#56619 0x565ae600 in main (argc=2, argv=0xffef3194) at bbsd.c:1657 | |
總之可以看到第一次 u_exit 是使用者自己從選單按離站而呼叫的,之後的每一次都是 | |
由 brh_alloc 透過 abort_bbs 叫的。這裡並沒有 signal handler 介入,所以前一篇 | |
文章所說一直重複收到 signal 而進入 abort_bbs 的假設應該是錯誤的,應該是每次只 | |
要走到 brh_alloc 它就會呼叫 abort_bbs,而 abort_bbs 又會叫回 brh_alloc,如此 | |
重複遞迴呼叫直到 stack overflow 收 SIGSEGV 被系統砍掉。 | |
於是我們先來看看 brh_alloc 為什麼會去叫 abort_bbs。 | |
(gdb) up 56613 | |
#56613 0x565b1215 in brh_alloc (tail=0xc1fb3af8, size=1887295246) at | |
board.c:97 | |
97 abort_bbs(); | |
這附近的程式長得像是這樣: | |
base = (int *) realloc((char *) base, size); | |
if (base == NULL) | |
abort_bbs(); | |
很明顯是 realloc 失敗了才會叫到 abort_bbs,但是為什麼會失敗? | |
(gdb) p size | |
$1 = 1887295246 | |
所以說大小出錯了,那會是錯在什麼地方? | |
base = brh_base; | |
n = (char *) tail - (char *) base; | |
size += n; | |
其中 size 是參數,由 brh_save 傳入,而 brh_save 傳入的 size 是個常數,因此 | |
問題應該是出在後面的 n。 | |
(gdb) p n | |
$2 = 1776274024 | |
(gdb) p tail | |
$3 = (int *) 0xc1fb3af8 | |
base 因為已經被 realloc 的回傳值蓋掉了,所以我們從全域的 brh_base 來看。 | |
(gdb) p brh_base | |
$4 = (int *) 0x581b7090 | |
(gdb) p brh_tail | |
$5 = (int *) 0x581b71d4 | |
由此可見 brh_base 和 brh_tail 的值都正常,是 brh_save 傳入的 tail 不知道為什麼 | |
大的這麼離譜,才造成 n 的值大到 realloc 不可能成功。 | |
回到上層的 brh_save 看看出了什麼事。 | |
(gdb) up | |
#56614 0x565b208f in brh_save () at board.c:668 | |
668 tail = brh_alloc(base, sizeof(time_t) * MAXBOARD); | |
這附近的程式長得像是這樣: | |
/* Thor.980830: lkchu patch: 還沒 load 就不用 save */ | |
if (!(base = brh_base)) | |
return; | |
brh_put(); | |
/* save history of un-zapped boards */ | |
bits = brd_bits; | |
head = base; | |
tail = brh_tail; | |
while (head < tail) | |
{ | |
bhno = bstamp2bno(*head); | |
size = head[2] * sizeof(time_t) + sizeof(BRH); | |
if (bhno >= 0 && !(bits[bhno] & BRD_Z_BIT)) | |
{ | |
if (base != head) | |
memcpy(base, head, size); | |
base = (int *) ((char *) base + size); | |
} | |
head = (int *) ((char *) head + size); | |
} | |
/* save zap record */ | |
tail = brh_alloc(base, sizeof(time_t) * MAXBOARD); | |
brh_alloc 中爛掉的 tail 值來自 brh_save 中爛掉的 base 值。而 base 的初始值來自 | |
brh_base 全域變數。brh_base 變數的值看起來並沒有爛掉,所以一定是這個迴圈的某個 | |
地方把它改爛了。而會動到 base 的只有一行: | |
base = (int *) ((char *) base + size); | |
由此可推知 size 也爛掉了,而動到 size 的也只有一行: | |
size = head[2] * sizeof(time_t) + sizeof(BRH); | |
head 指向從檔案裡面讀出來的內容,所以說就是 .BRH 檔案爛掉了。 | |
(gdb) p base | |
$6 = (int *) 0xc1fb3af8 | |
(gdb) p size | |
$7 = 1776273804 | |
brh_save 的 base 確實和 brh_alloc 的 tail 相符,而這個 size 很明顯有問題。 | |
所以說我就把 ~bbs/usr/r/r2/.BRH 打開來看了。 | |
------------------------------------------------------------------------------ | |
以下是 ~bbs/usr/r/r2/.BRH 的檔案內容。為了避免洩漏隱私資料,不重要的部份這裡都 | |
用 xx 來代替。 | |
00000000 - xx xx xx 59 - xx xx xx 5a - 00 00 00 00 - xx xx xx 3b | |
00000010 - xx xx xx 5a - 01 00 00 00 - xx xx xx d9 - xx xx xx 3b | |
00000020 - xx xx xx 5a - 00 00 00 00 - xx xx xx 35 - xx xx xx 5a | |
00000030 - 00 00 00 00 - xx xx xx 3b - xx xx xx 5a - 20 00 00 00 應有 32 個 | |
00000040 - xx xx xx 5a - xx xx xx 5a - xx xx xx 5a - xx xx xx 59 2 個區間 | |
00000050 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 6 個區間 | |
00000060 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 10 個區間 | |
00000070 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 14 個區間 | |
00000080 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 18 個區間 | |
00000090 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 22 個區間 | |
000000a0 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 26 個區間 | |
000000b0 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 30 個區間 | |
000000c0 - xx xx xx 3b - xx xx xx 5a - 01 00 00 00 - xx xx xx da | |
000000d0 - xx xx xx 3b - xx xx xx 5a - 00 00 00 00 - xx xx xx 3b | |
000000e0 - xx xx xx 5a - 00 00 00 00 - xx xx xx da - xx xx xx 59 | |
000000f0 - xx xx xx 5a - 14 00 00 00 - 60 f2 77 5a - xx xx xx 5a 應有 20 個 | |
00000100 - xx xx xx 5a - xx xx xx 5a - xx xx xx 5a - xx xx xx 5a 3 個區間 | |
00000110 - xx xx xx da - xx xx xx 5a - xx xx xx 5a - xx xx xx da 6 個區間 | |
00000120 - xx xx xx da - xx xx xx da - xx xx xx d9 - xx xx xx d9 10 個區間 | |
00000130 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 - xx xx xx d9 14 個區間 | |
00000140 - xx xx xx d9 - xx xx xx d9 16 個區間 | |
檔案格式可以參考之前的文章。所有資料都對齊 4 bytes 的邊界,淺藍色代表一筆看板 | |
資料的開頭,綠色代表正確的長度欄位,紅色代表錯誤的長度欄位。 | |
其實這個檔案還算容易看,因為只有長度欄位的上面幾個 byte 會是 0,其他欄位因為 | |
都是代表時間而不可能是 0,由此可以很容易地找出每筆看板資料的位置。 | |
上面已經標示,第一個紅字的地方缺了 2 個區間,第二個紅字的地方缺了 4 個區間。 | |
那前面的 1776273804 是怎麼來的呢? | |
size = head[2] * sizeof(time_t) + sizeof(BRH); | |
^^^^^^^^^^^^^^ ^^^^^^^^^^^ | |
4 12 | |
而如果我們把標示成黃色的地方的數值代入 head[2]: | |
0x5a77f260 * 4 + 12 = 6071241100 = 0x169dfc98c | |
捨棄超過 32-bit 的部份可以得到: | |
0x69dfc98c = 1776273804 | |
------------------------------------------------------------------------------ | |
於是我想就兩種解法: | |
1. 把那兩個紅字的地方改回正確數值。 | |
2. 直接把 .BRH 砍掉。 | |
我個人偏好第一種,你有什麼想法呢? | |
雖然說我也不知道為什麼 .BRH 檔案會爛掉…… | |
-- | |
┼─╮ ╭───────╮ | |
│ │台南一中.索尼小站∣sony.TFcis.org│ │ | |
╰─────────╯ ╰─┼ | |
by lantw44 from 172.20.7.2 (tinc: lantw44) | |
→ r2 推:同意第一種… 覺得神秘@@ 0213 18:08 | |
→ lantw44 推:我改好了,再試試看吧 0214 14:41 | |
→ r2 推:發現夢大也會發生這個問題...@@ 0215 12:23 | |
→ lantw44 推:你說 .BRH 不知道為什麼自己壞掉嗎? 0215 14:56 | |
→ r2 推:對...@@ 0216 01:00 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment