透過自動化的軟體工具,可以為程式設計者在開發上帶來諸多的好處。自動化的前提是可以被定義的規則及邏輯。這些規則和邏輯都是人定義出來的,但是,倘若透過人力去執行這些規則及邏輯,一來可能會需要耗費大量的人力,二來也會需要可觀的時間,而且,因為利用人力為之,可能會犯錯,無法正確而且完整的執行所有的規則及邏輯。

而自動化的工具,便是基於機器的優勢,透過遠較人類快速的計算能力,來提供快速、而且在既定規則及邏輯下不會犯錯的執行力,協助程式設計者提升開發時的生產力。

在這樣的概念下,有諸多的自動工具被發展出來,而其中有一類的工具,正是幫助程式設計者分析程式碼,藉以找出程式中可能存在的品質問題。

在前一回中,我們提到了程式分析工具可分為兩類── 靜態分析及動態分析。這兩類工具各有其優劣處,也時常被應用在不同領域,解決不同類型的需求。而我們在前一回的重心放在靜態分析工具的作用,從最簡單的程式碼撰寫的排版及命名慣例的規範、到自動的重構、甚至幫你檢查一些潛在的程式臭蟲,這些工具都可以協助程式設計者,在幾乎不花自身力氣、同時在很短的時間內,找到可能危害品質的程式碼。

將影響程式碼品質的因素搬上檯面檢視
程式碼的品質,可以從各種面向上來看,從是否遵守程式碼排版及命名慣例的規範、程式碼中是否具備腐敗的壞味道、到是否暗藏潛在的臭蟲,都可能影響到程式碼的品質。

是否遵守程式碼的排版及命名慣例,影響到團隊是否易於合作開發;程式碼中是否具備腐敗的壞味道,影響到日後是否容易犯錯,或者是否易於修改等等不同的程式碼特性;而程式碼中暗藏的臭蟲,更是直接反映在程式執行時的邏輯錯誤,甚至造成程式執行時損毀。由此可見,自動化的靜態程式碼分析工具,是可以為程式設計者提供不少幫助的。

近來,有不少靜態的程式碼分析工具,將重心放在找出程式碼中可能存在的臭蟲,有一些類型的臭蟲可能是很小的錯誤,判斷規則也不複雜,卻有可能在程式設計者不經意的疏忽之下,把它藏在程式碼之中。如果臭蟲發作的方式顯而易見,那也就算了,畢竟不需要花費太多功夫就能重新複製錯誤,但如果是那種若隱若現、時有時無,甚至在不同機器或運行環境上有著不同結果的臭蟲,若能透過工具,在開發的過程中就加以察覺,那麼,便可以省去大量除錯的時間,自然大大的助益生產力的提升。

有一些類型的臭蟲,像是錯誤的陣列索引值、將區域變數的位址以指標傳回函式之外、使用其值未經初始化的變數、使用已釋放記憶體空間的指標等等,都可以透過對程式碼進行靜態分析找出。

每個程式設計者,都可能在不經意間犯下這些錯誤。有了足以分析這些錯誤的工具,即使不小心犯錯,也能利用工具來彌補一時間的粗心及大意。而每個錯誤,都需要花上數倍,甚至數十倍於撰寫出此錯誤的時間,才能加以修正。

可結合進階的程式碼品質分析能力
早期的程式碼靜態分析工具,只能檢查程式碼是否滿足程式設計規範,以及形式上的檢查,因為它們可能只執行了程式原始碼的字詞分析(lexical analysis),以及語法的分析(syntax parsing)的動作。而更先進一些的靜態分析工具,還會做到更進一步的語意分析(semantics analysis)、程式執行流程(control flow),以及資料流程(dataflow)的分析。

在語意分析的層次上,這類工具會解析程式中各個符號(symbol)的型態,同時檢查其型態。而在程式執行流程的分析上,工具會嘗試分析函式內的可能執行路徑,此分析的結果即為所謂的執行流程圖(control flow graph)。另外,也可以分析函式之間的呼叫關係,所得的產物即為叫用關係圖(call graph)

不論是上述的那些階段及動作,其實都是屬於編譯器技術的範疇。而除了主要的編譯作用之外,編譯器也會利用它們來建立進行最佳化所需的資訊。不過,輔助性質的程式碼靜態分析工具,則是利用這些技術所得到的資訊,建立起程式的抽象模型。接著,再搭配各種不同的分析演算法,找出不同類型的問題。

有愈來愈多不同的分析演算法被發展出來,這使得靜態分析工具愈來愈強大,這使得許多被視為必須利用動態分析工具才能找出來的問題,也能透過靜態分析工具提供參考意見。像是想取Null指標所指向的值、重複釋放記憶體、動態配置的記憶體量不足使用、記憶體洩露、檔案洩露、等等。

有些問題,雖然實際上必須在動態時期才有辦法確認,但是,透過對程式執行流程或叫用關係及資料流的分析,也可以進行推論及研判,進而提供一些參考資訊。雖然可能沒法子找到所有的問題,而做出的建議也有可能是不正確的,但是,因為靜態分析在計算上具有的優勢,所以可以做為初步篩選及過濾的工具。

可應用於程式碼安全性的檢查
程式碼的靜態分析工具,除了在尋找一些臭蟲上可以派上用場之外,也有不少人利用此類的工具來檢查是否存在安全性的漏洞。

像許多利用記憶體緩衝區溢位弱點的攻擊,便可以透過靜態分析工具來協助尋找。此外,像一些使用不安全函式(例如使用strcpy(),而不使用strncpy())之類的情況,更是輕易的便能找出。

任何一個程式,只要其中存在一個安全性的漏洞,就可能造成系統門戶洞開,全面淪陷。而一個團隊中,只要有任一位程式設計者不小心寫下了有安全性問題的程式碼,就會造成這種局面。因此,透過分析工具來自動化的提供最基本的保障,是有相當大幫助的。

能協助評估程式碼的複雜程度
關於程式的品質,除了上述提到的各面向,也有人利用靜態分析工具來分析程式中的複雜度。

要如何定義、評估程式的複雜度,其實本身就是個很複雜的議題。究竟什麼樣的程式,才算是複雜度高的程式?而又是什麼樣的程式,可以算是複雜度低的程式呢?有一些人發展出各種不同的指標,用以從不同的角度來衡量程式的複雜度。

例如,有個名為McCabe Cyclomatic Complexity(又稱MCC)的程式複雜度指標,基本上,這個指標就是衡量特定函式中的獨立執行路徑的個數,來做為衡量程式複雜度的參考。而正如前文所提的,靜態分析工具,有能力分析出函式中的控制流程,找出可能的執行路徑,而這正有助於我們得到像MCC這樣的程式複雜度指標。此外,評估函式或類別相依於其他函式或類別的程度,也可以從叫用或引用的圖中得到資訊。而這也是時常被用來評估程式複雜度的指標。

透過靜態分析工具,我們可以基於各種指標來衡量程式的複雜度,當程式愈複雜,代表程式中存在了不好的品質因素,那麼程式設計者便可以參考工具所提供的資訊來進行改善。

從上述的說明,相信讀者不難明白,自動化的靜態分析工具,可以為程式設計者在程式碼品質提供多面向的幫助。程式碼品質若能改善,也間接可以助益開發生產力的提升。

 

專欄作者

熱門新聞

Advertisement