作者: 苏鹏 、朴星海、戈峰、张雁
一 内存越界检查
1 字符串操作越界:strcpy( )和 sprintf (fullName, "%s%s", dir, fileName),检查是否长度会超过缓冲区,建议采用strncpy。
2 字符串操作越界: 检查String对象substring(int beginIndex, int endIndex)函数beginindex和endindex是否会越界(JAVA)。请适当增加一些防御性代码。
3 数据下标检查:数组下标为变量或者函数返回值,请检查该变量取值或者函数返回值是否会为导致数组访问越界。例如:tasks[i], tasks[function()]。
二 函数检查(针对每个函数)
1 返回值检查:检查被调用函数各种返回值是否都被处理。重点检查是否会返回NULL或者null。容易出问题的情况是该函数调用不是单独的一行。
建议: java或者c#等语言中,将arrayList等集合对象初始化成为长度为0的对象,而不是null对象。这边避免在函数返回时返回null对象。
2 异常处理检查:检查被调用函数是否会抛出异常,如果抛出异常,请检查是否捕获了异常并进行了处理。
3 输入参数检查:检查被调用函数是否对输入参数有要求,确保对输入参数合法性检查,要么在调用者保证合法性,要么由被调用者进行检查。
4 返回出口检查:针对有多个出口的函数(例如try{} catch),请检查(1)返回值是否符合预先设计。(2)本函数申请的资源是否都被释放了。
如果被调用函数是自己编写,请查看被调用函数说明;如果被调用函数是类库调用,请仔细查看该类库官方帮助文档(例如:java类库调用,必须查看官方java类库帮助文档)。
三 同步互斥检查
1 检查每个类,检查该类所对应对象会被多个线程访问的类,针对该对象每个成员属性,通过检查该类所有public方法来确保所有成员属性访问被互斥保护。
难点是:要能知道某个类实例被多个线程调用,特别是ICE内置线程。因此关键点要对程序中所启动的线程 心里做到有数。
2 检查并确保同步保护代码区域中没有操作耗时代码,例如访问数据库,读写文件等。
建议1: 减少同步保护区域中的代码,只把必须的控制逻辑放在被保护区域中。
建议2:有时为了避免出现上述情况,可以采用内存复制的方式来解决上述问题。例如线程A会向某个队列ListA增加元素,而线程B会读ListA并把ListA中元素取出并利用网络写入另外一个程序。此时B线程可以在同步保护下,将ListA中元素转移到一个本地ListB对象,然后立刻释放ListA,最后线程B访问ListB来发送数据
3 如果采用第三方类库,请阅读官方说明,是否为线程安全。如果不是请不要多线程使用一个对象。
4 检查是否存在因为异常短路或者程序出现多分支导致锁没有被释放。
5 检查是否存在多重锁情况(建议不要在私有函数中进行加锁,只在public函数中加锁)。
6 对于两个程序通过文件进行信息交换,检查是否采用基于文件名rename方法实现文件读写互斥,避免一个程序还在写一个文件时,另外一个程序就开始读该文件。
四 资源管理类检查
1 对C/C++, 针对每个new 操作,请检查是否有对应的delete操作,并重点检查是否存在因为异常短路或者new操作之后处理代码出现分支导致只在部分分支调用delete,导致资源泄露。
2 对JAVA、c#等非托管资源(主要包括 数据库连接、文件句柄),检查每个open等资源获取操作,是否有对应close等资源释放操作,并重点检查是否存在因为异常短路或者open操作之后处理代码出现分支导致只在部分分支调用close,导致资源泄露。
建议:
(1) 资源申请和资源释放尽量成对出现在比较靠近地方,并且尽量出现在同一个层次代码。
(2) 如果是C/C++程序,对资源管理建议采用RAII方式;
(3) 如果是java、C#程序,请使用try{}catch{}finally{}.在finally{}中进行资源释放;