应用程序初始化失败怎么办 程序初始化失败解决方法

应用程序初始化失败怎么办 程序初始化失败解决方法

最近连续遇到两个由于变量未初始化引起的软件异常问题,本文详细讲述一下这两个问题的详细排查过程,通过这两个案例来说明变量初始化的重要性,希望大家能引起足够的重视。

1、BOOL 型变量未初始化导致的软件运行行为不一致的问题

最近在按照新需求开发新功能,在调试某个功能时,出现一个诡异的现象:在运行通过 release 安装包安装的 exe程序时,某功能始终是有问题的,但是直接在 VS2017 中调试运行 release 程序,发现该功能居然是正常的!

两种场景下,exe 程序都是 release 版本,并且底层 dll 库都是一样的,两个版本表现居然截然不同,这太奇怪了!

软件代码中肯定是有 bug 的,于是继续进行排查。想到这个问题在之前稳定版本是没有的,应该是最近开发新功能添加的代码引起的,于是用 svn 查看了最近的代码提交记录,找到相关代码模块仔细进行排查。

结果发现是一个 BOOL 变量影响了代码的控制执行逻辑:

在程序运行的开始阶段,该变量应该是 FALSE 的,出问题的版本居然走到该控制变量为 TRUE 的分支中,导致代码的控制逻辑出了问题!继续看,该 BOOL 型控制变量竟然没有初始化,这就是问题所在了!

在变量没有初始化时,我们用的

微软 Visual Studio 编译器在 debug 下为了方便调试,会对堆内存和栈内存自动进行初始化,比如 debug 下的栈内存会初始化为 0xCCCCCCCC,debug 下的堆内存会被初始化为 0xCDCDCDCD

,如下图所示:

编译器在 release 下是不会自动进行初始化。release 下变量如果没有初始化,变量的值将会是一个随机值,那这个随机值和什么有关呢?是给该变量分配内存时内存中残存的值,所以是随机值,一旦出现了随机值,程序运行时会出现不可预知的结果。

本例中,直接运行安装包安装的 exe 版本与 release 调试运行,因为未初始化的控制变量会得到随机值,所以导致两种情况下的不同表现!

另外,有点迷惑人的地方是,几乎每次直接运行安装包安装的 exe 版本时,该 BOOL 变量的随机值都是 TRUE,但在 release 下调试运行时该变量的值一直是 FALSE,这也许和两种情况的启动运行机制差异有关系吧!反正是变量没有初始化引起的!

2、回调函数指针变量未初始化导致程序“跑飞”,胡乱崩溃的问题

主程序在调用一个 dll 库时,会调用 dll 接口 SetConfigCallBackFunc 给 dll 设置了一个回调函数(地址),dll 内部会将该回调函数的地址保存到一个成员变量(保存回调函数地址的指针变量)m_CallBackFunc 中。

在当前主程序的代码中,在调用 SetConfigCallBackFunc 接口之前,调用了该 dll 的另一个接口(在该接口调用之后,再去调用 SetConfigCallBackFunc 接口给 dll 设置回调函数地址):

触发了 dll 代码运行到执行回调函数的地方:

而此时还没调用 SetConfigCallBackFunc 给该 dll 设置回调函数,导致 dll 中的存放回调函数地址的 m_CallBackFunc 指针中的值还不是一个有效值,虽然做了指针是否为 NULL 的判断,但是因为 m_CallBackFunc 中是个随机值!

然后

以 m_CallBackFunc 内存中的非有效值作为代码段函数地址,直接 call 过去,这是非法的函数调用跳转,即我们经常说的代码“跑飞了”!跳转到的代码处的内存没有准备好,这种非法跳转基本都会发指内存访问违例导致软件崩溃!从现象上看,代码崩溃在一个逻辑上讲不通的地方,甚至是和当前代码的上下文完全没有关系的地方!

后来查下来发现是 m_CallBackFunc 没有初始化引起的,应该初始化为 NULL,代码跑飞了,程序运行过程中出现了不可预料的结果,代码可能就会出现胡乱崩溃的问题了,比如本例中崩溃:

这个未初始化的问题,比上面讲的第一个问题还要严重,直接导致了崩溃。

本例中有两个地方是有问题的,一是在调用 dll 其他接口之前,应该先调用 SetConfigCallBackFunc 接口将回调函数设置进去;二是保存回调函数地址的成员变量 m_CallBackFunc 要初始化。

3、代码静态检测工具 PC-Lint 和 TScanCode

能否通过一些工具提前分析出软件中存在的潜在问题呢?答案是肯定的!

有两个 C/C++静态分析工具比较常用,一个是 GIMPEL SOFTWARE 公司开发的 C/C++软件代码静态分析工具 PC-Lint,一个是腾讯静态分析团队开发的一款开源免费的 C/C++静态分析工具 TScanCode。

利用这些静态分析工具可以发现代码中很多潜在的错误,比如变量没有初始化,数组越界,空指针等问题。

这些工具使用通用的规则去分析代码中可能存在的缺陷,会出现很多的误判,我们在使用这些工具时要加以甄别!

以前比较抗拒这些静态检测工具,会产生一堆误报,比较烦人,但这些工具确实能帮我们提前发现一些问题。因为开发团队中成员的水平层次不齐,特别是缺乏经验的新人,难免会出现一些错误或者考虑不周全的地方!

4、总结

以前我们在开发团队中一再强调变量要初始化,但还是有人说,变量并不需要一上来就初始化,只要控制好自己的代码逻辑就好了,我表示很不赞同!你水平比较高,也许可以控制好代码不出问题,但是后续的维护人员能保证不出问题吗?也许只有经历过问题的人,才会有深刻体会吧!