記一個(gè)十分詭異的bug:結(jié)構(gòu)體的內(nèi)容會莫名其妙的變化。

本文節(jié)選自我的實(shí)驗(yàn)報(bào)告。
北航的操作系統(tǒng)課程會在學(xué)期末布置若干個(gè)"挑戰(zhàn)性任務(wù)",任務(wù)要求是在本學(xué)期完成的系統(tǒng)內(nèi)核中增添新的功能。我選擇的挑戰(zhàn)性任務(wù)是實(shí)現(xiàn)進(jìn)程間通信的信號機(jī)制,下文記錄了我在傳輸信號結(jié)構(gòu)體時(shí)遇到的一個(gè)bug。解決這個(gè)bug的過程加深了我對系統(tǒng)編程的理解,特此記錄。
s
是指向struct signal
結(jié)構(gòu)體的指針。

明明沒有修改s->signum
的值,為什么輸出結(jié)果會發(fā)生變化呢?難道是sigx
自減時(shí)修改了它的值?還是說printk
修改了它的值?這都不可能啊。
單看這一段代碼,我實(shí)在是摸不著頭腦。
抓耳撓腮了很久,我終于找到了問題所在,在新建信號結(jié)構(gòu)體時(shí),我是在一個(gè)函數(shù)內(nèi)部新建了一個(gè)struct signal
結(jié)構(gòu)體,再將鏈表里的指針指向這個(gè)結(jié)構(gòu)體。代碼如下:
?int sys_sendsig(u_int envid, int sig) {
? ...
? struct signal s = {.signum = sig};
? TAILQ_INSERT_HEAD(&e->sig_pending, &s, sig_link);
? ...
?}
?
我在用java寫oo作業(yè)時(shí),經(jīng)常會寫出這樣的業(yè)務(wù)邏輯,并且不會出現(xiàn)bug。這種寫法很直觀,很容易理解,就是新建一個(gè)東西再放到鏈表里嘛。
但是在系統(tǒng)內(nèi)核里就不能這么寫,這么寫就會出bug。
問題就出在"在一個(gè)函數(shù)內(nèi)部新建結(jié)構(gòu)體",這只是在棧上申請了一個(gè)局部變量,當(dāng)這段空間釋放后被重新使用時(shí),這段空間原有的內(nèi)容就會被覆蓋。
為了解決這個(gè)問題,我聯(lián)想到了Env
結(jié)構(gòu)體的組織方式:先使用全局變量申請固定的空間,這樣結(jié)構(gòu)體的內(nèi)容就不會被更改了。每次需要申請信號結(jié)構(gòu)體時(shí),只需要取出一份來用就可以了。代碼如下:
?// lab4-challenge
?struct signal sigs[SIG_BUFFER] __attribute__((aligned(BY2PG)));
解決這個(gè)bug的經(jīng)歷,是我這次挑戰(zhàn)性任務(wù)收獲最大的部分。