【Lua篇】靜態代碼掃描分析(一)初步介紹

一、靜態代碼分析

        靜態代碼分析是一種通過檢查代碼而不是執行程序來發現源代碼中錯誤的手段。通常可以幫助我們發現常見的編碼錯誤,例如:

  • 語法錯誤 

  • 違反制定的標準編碼 

  • 未定義的變量

  • 安全性問題

        靜態代碼分析可以通過評估編寫的代碼來提高代碼質量;可以穩定的運行且可以輕鬆自動化;增加了在源代碼中發現漏洞的可能性,從而提高應用安全;由於是針對源碼掃描可以在離線的開發環境中完成。但是靜態代碼分析並不能完全保證編寫的代碼沒有Bug,它也有一些缺點,例如:

  • 誤報問題,發現了一個不是錯誤的錯誤。

  • 靜態分析的規則需要特定維護,並非總是適用。

  • 系統和第三方庫可能無法分析。

     

二、為何需對Lua代碼進行靜態分析 

        Lua腳本語言在性能方面非常出色、語法簡單且容易上手。目前有相當多的遊戲服務器和客戶端程序都是使用它來開發功能業務。Lua屬於解釋性語言,編寫的邏輯代碼只有在程序運行的過程才會發現邏輯錯誤,而一些較隱藏的分支可能要經過很長時間的運行才能觸發錯誤。未發現的錯誤如果在正式環境中觸發將會產生不可預估的損失。

        如何發現更多的錯誤,除了通過更加詳細的測試外,還可以利用工具來彌補,下面列舉了一些平時常見的錯誤問題,如果使用靜態掃描分析工具是很容易發現的。

    1. 變量的作用域問題[1],定義的變量在超出了作用域外使用。

1 function demo(param)
2     if param then
3         local var = param.smobj:get_var()
4         -- do_something()
5     end
6     -- 聲明的`var`變量在超出作用域後訪問
7     local new_var = var + 3 
8 end

    2. 變量的作用域問題[2],超出作用域變量作為條件判斷

 1 function demo(param)
 2     if param then
 3         local var = param.smobj:get_var()
 4         -- do_something()
 5     end
 6     if var then
 7         -- 永遠無法執行到,但不會報錯
 8         local new_var = var + 10    
 9         -- do_something()
10     end
11 end

    3. 參數未定義,經常出現在代碼複製-粘貼的時候,未修改完全

 1 function Player:set_world_pos(x, y) 
 2     do_something(x,y)
 3     if condition_false then
 4         log("set_world_pos x:%s, y:%s", x, y)
 5     end
 6 end
 7 function Player:set_pos(cx, cy) 
 8     do_something(cx, cy)
 9     if condition_false then
10         -- 這裡是從上面拷貝,但是傳參沒有修改
11         -- 代碼不會報錯但行為已經錯了。
12         log("set_pos  x:%s , y:%s", x, y)   
13     end
14 end

    4. 變量拼寫錯誤,很常見但不易察覺。

1 -- 由於拼寫錯誤,這個只有在重載文件或者熱更文件出現
2 -- 出現就會導致數據丟失,所謂一個粗心導致的大錯
3 g_player_mng = g_plater_mng or {}
4 -- do_something

    5. 判空邏輯問題[1],先使用變量,後進行空值判斷

1 function demo() 
2     local var = self:get_value()
3     local count = #var
4     -- 先拿變量進行了操作,然後才判斷空值情況
5     if var then     
6         self:do_something()
7     end
8 end 

    6. 判空邏輯問題[2],判空的覆蓋不全,後面繼續使用了空值變量。

 1 function demo() 
 2     local var = self:get_value()
 3     if var then
 4         count = #var
 5     end
 6     local r, b = self:get_data()
 7     if b then
 8         -- 雖然前面對var判空了
 9         -- 但是沒有進行處理,這裡就繼續使用了。
10         table.insert(var, r)   
11     end
12 end

    7. 類成員方法聲明寫錯,「.」「:」 經常寫錯。

1 -- 寫類的成員方法的時候漏寫了self 或者 :寫成了.
2 function Player.set_hp(var)
3     if self.mHp > var then
4         self.mHp = var
5     end
6 end 

    8. 方法調用時,「.」「:」 寫錯。

1 function Player:demo2(param)
2     -- 少傳了參數self
3     self.demo()  
4     -- 多傳入了參數self.dos
5     self.dos:demoe(self.dos)  
6 end

        上面這些錯誤來自平時項目中血與淚的教訓,如果能夠通過靜態代碼掃描工具提前發現這些錯誤,那對提高代碼的質量是非常有幫助和有價值的事情。目前市面上可以使用騰訊的TscanCode來對代碼掃描,支持的語言也挺多的。

        我也嘗試花幾篇文章來介紹一下如何編寫一個簡單的Lua代碼掃描工具,主要介紹大體編寫代碼的邏輯流程。

   文章來自我的公眾號,大家如果有興趣可以關注,具體掃描關注下圖。