一、静态代码分析
静态代码分析是一种通过检查代码而不是执行程序来发现源代码中错误的手段。通常可以帮助我们发现常见的编码错误,例如:
-
语法错误
-
违反制定的标准编码
-
未定义的变量
-
安全性问题
静态代码分析可以通过评估编写的代码来提高代码质量;可以稳定的运行且可以轻松自动化;增加了在源代码中发现漏洞的可能性,从而提高应用安全;由于是针对源码扫描可以在离线的开发环境中完成。但是静态代码分析并不能完全保证编写的代码没有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代码扫描工具,主要介绍大体编写代码的逻辑流程。
文章来自我的公众号,大家如果有兴趣可以关注,具体扫描关注下图。