2009年7月1日 星期三

小心移除 GList 裡的 Node

Standard
最近忙著開發新的 LXNM(Lightweight Network Manager),但在開發的過程中碰到了一個 Critical Bug,該 Bug 會讓 LXNM Daemon Crashes。難過的是,已經費盡心思卻仍然找不出問題所在,以致浪費好多時間在 debug。最後多虧了 Paulliu 的協助,終於找出了程式中臭蟲,令人想不到的是,問題居然是出在 GList 的操作。

這問題出在於移除 GList 裡的 Node 之後,再讀取下一個 Node 時會 Crash,這有一個簡化後的錯誤範例:
GList *node;

for (node=mylist;node;node=g_list_next(node)) {
mylist = g_list_delete_link(mylist, node);
}

這樣表面看起來或許沒有錯誤,但以 Link-list 的基礎觀點來看,卻馬上可以發現到問題所在。該程式中,當迴圈進行到第二輪時,會因為 g_list_next() 無法取得下一個 Node 而死在那裡,因為供參考的 Node 已經在第一輪迴圈就被刪除,我們無法取得其 Node->next,當然就會發生錯誤。因此,需要稍微修改,以避免掉這樣的問題:
GList *node;
GList *next_node;

for (node=mylist;node;node=next_node) {
next_node = g_list_next(node);
mylist = g_list_delete_link(mylist, node);
}

GLib 提供的 API 包裝,讓懶惰的我們可以很輕鬆的建立和操作 Link-list,當然難免就會不小心寫出像這樣有問題的 Code 來。因此,對程式開發者而言,就算 GLib 再方便好用,資料結構和各種演算法的理論還是無法完全拋棄。