contributed by < afcidk
>
後續改進:
作業系統:Linux elementaryOS 4.16.9-041609-generic
gcc 版本:8.1.0
gcc 版本應該升級到 7.2+, 否則後續有些實驗 (如 LTO) 會無效
我們需要以 linked list 實作 queue,並且支援 LIFO 和 FIFO。
因為我們是在基礎的程式碼再加上自己實作的函式,因此事先了解整個檔案目錄的結構是很重要的。
首先,我們觀察一下有哪些檔案,並為他們下上對應的註解
malloc
和 free
,增加額外的檢查driver.py
:一個協助我們進行單元測試的腳本*.cmd
:單元測試的測試檔案,共有 15 個queue.h
裡頭定義了我們需要實作的函式,分別是
另外,原本提供的資料結構
也許沒辦法提供一個有效率 ( ) 的方式做出 q_insert_tail
以及 q_size
,因此需要做適當的修改。
在 harness.h
裡頭,我們可以發現兩行巨集,由此可得知 free()
和 malloc()
這兩個函式都被對應到自己實作的 test_free()
以及 test_malloc()
其實整個 harness.h
最外層是被一層 macro 包裝起來了
可以看到當 INTERNAL
沒有被定義時,我們的 free/malloc
才會被 hook 成 test_free/test_malloc
。
接下來再找找看哪些檔案有引入 harness.h
,發現如下3個檔案
由此可知我們實作的時候,使用的 free/malloc
都會被 hook 成已經寫好的 test_free/test_malloc
,這樣做的用意是提供多一層的檢查,讓程式在出錯(e.g. double free)時不會直接 crash 而是印出錯誤訊息。
然而,這樣做也有一些缺點,像是我們沒有辦法使用有呼叫 malloc
/ free
的其他標準函式,例如 strdup()
。
可以比照 test_malloc/test_free,去封裝 strdup
一類的函式嗎?若可,提交對應的 pull request
pull request: https://github.com/sysprog21/lab0-c/pull/6
這部份會初始化我們的 queue,需要注意判斷 malloc
有沒有成功。
只需要使用到一個指標就可以了[1],一直刪掉 head 直到整個 queue 清空。
要記得每次 malloc 過後都要確認是不是有成功,如果沒有成功的化要把先前 malloc 過的東西都 free 回去。
另外因為 queue 的資料結構多了 tail,所以我們需要判斷如果 queue 長度是 1 的化,tail 的值也要改動,雖然這邊是 insert_head。
注意到如果要刪除第一個元素,除了 queue 要存在,queue 裏面也要有至少一個元素。
還有另外一個命令 (rh
) 不需要紀錄刪除的字串,這時候 bufsize
是 0,也需要特別判斷。
為了達到 的時間複雜度,所以我直接修改 queue 的結構,增加了 size
,在每次操作時都會更改到 size
。
根據 dudect 工具以及提出的對應論文 Dude, is my code constant time?,我們得知了一種以實驗而非理論驗證時間複雜度的方法。
他透過 timing attack (精確一點只算是 leakage,因為洩漏的資訊太少不足以完成一項攻擊) 來檢測。
一種 leakage detection 的方式是 fix-vs-random test。這個方式透過餵給程式固定以及隨機的資料,再比較執行時間的差異。
dudect 使用的方法便是這種 fix-vs-random test。在得到執行時間後,利用 t-test 檢查兩種測試資料是否差異。
最後我取 dudect 中計算 t-test 的部份,修改後放到 qtest 中。執行 qtest -t
可以測試 q_insert_tail
和 q_size
是否可能非常數時間複雜度。
不過我還沒有把 fix-vs-random test 理解得很透澈,看完之後再來補上
qtest -t
相關的程式碼在這個 commit push 上去了,不小心逛到這裡的同學可以把他 clone 下來,再把 queue 替換成自己的實作試試看~
執行後可能會有類似這樣的輸出