2、防止指针/数组操作越界 【案例121】 在香港项目测试中,发现ISDN话机拨新业务号码时,若一位一位的拨 至18位,不会有问题。但若先拨完号码再成组发送,会导致MPU死机。 处理过程: 査错过程很简单,按呼叫处理的过程检查代码,发现某一处的判断有误 本应为小于18的判断,写成了小于等于18。 结论 代码编写有误。 思考与启 1、极限测试必须注意,测试前应对某项设计的极限做好充分测试规划。 2、测试极限时还要注意多种业务接入点,本例为ISDN。对于交换机 来说,任何一种业务都要分别在模拟话机、ISDN话机、V5话机、多种形式的话 务台上做测试。对于中继的业务,则要充分考虑各种信令:TUP、ISUP、PRA NO1、V5等等。 【案例122】 对某交换类进行计费测试,字冠011对应1号路由、1号子路由,有4个中继群 1112,13,14(都属于1#模块,前后两个群分别构成自环。其中11,13群向为出中 继,12,14群向为入中继,对这四个群分别进行计费设置,对出入中继都计费。电 话60640001拨打01160010001两次,使四个群都有机会被计费,取话单后浏览话 单发现对11群计费计次表话单出中继群号不正确,其它群的计次表中出中继群号 正常。 处理过程 与开发人员在测试组环境多次重复以上步骤,发现11群的计次表话单有时正
2、防止指针/数组操作越界 【案例1.2.1】 在香港项目测试中,发现ISDN话机拨新业务号码时,若一位一位的拨 至18位,不会有问题。但若先拨完号码再成组发送,会导致MPU死机。 处理过程: 查错过程很简单,按呼叫处理的过程检查代码,发现某一处的判断有误, 本应为小于18的判断,写成了小于等于18。 结 论: 代码编写有误。 思考与启示: 1、极限测试必须注意,测试前应对某项设计的极限做好充分测试规划。 2、测试极限时还要注意多种业务接入点,本例为ISDN。对于交换机 来说,任何一种业务都要分别在模拟话机、ISDN话机、V5话机、多种形式的话 务台上做测试。对于中继的业务,则要充分考虑各种信令:TUP、ISUP、PRA、 NO1、V5等等。 【案例1.2.2】 对某交换类进行计费测试,字冠011对应1号路由、1号子路由,有4个中继群 11,12,13,14(都属于1#模块),前后两个群分别构成自环。其中11,13群向为出中 继,12,14群向为入中继,对这四个群分别进行计费设置,对出入中继都计费。电 话60640001拨打01160010001两次,使四个群都有机会被计费,取话单后浏览话 单发现对11群计费计次表话单出中继群号不正确,其它群的计次表中出中继群号 正常。 处理过程: 与开发人员在测试组环境多次重复以上步骤,发现11群的计次表话单有时正
常,有时其出中继群号就为一个随机值,发生异常的频率比较高。为什么其它群 的话单正常,唯独11群不正常呢?11群是四个群中最小的群,其中继计次表位于 缓冲区的首位,打完电话后查询内存发现出中继群号在内存中是正确的,取完话 单后再查就不正确了 结论: 话单池的一个备份指针 Pool head1和中继计次表的头指针重合,影响到第 个中继计次表的计费。 思考与启示: 随机值的背后往往隐藏着指针问题,两块内存缓冲区的交界处比较容易出现 问题,在编程时是应该注意的地方 【案例123】 【正 文】 在接入网产品A测试中,在内存数据库正常的情况下的各种数据库方 面的操作都是正常的。为了进行数据库异常测试,于是将数据库内容人为地破坏 了。发现在对数据库进行比较操作时,出现程序跑死了现象 经过跟踪调试发现问题出现在如下一段代码中 I for(F0; KpSysHead->dbf count; 1++) pDBFat=( NM DBFAT STRUC *(NVDB BASE+ DBFAT OFFSET+1 DBFAT LEN) if(fat check(pDBFat)I=O) 456789 pSysHead->system flag =0; head sumo continue:
常,有时其出中继群号就为一个随机值,发生异常的频率比较高。为什么其它群 的话单正常,唯独11群不正常呢?11群是四个群中最小的群,其中继计次表位于 缓冲区的首位,打完电话后查询内存发现出中继群号在内存中是正确的,取完话 单后再查就不正确了。 结 论: 话单池的一个备份指针Pool_head_1和中继计次表的头指针重合,影响到第一 个中继计次表的计费。 思考与启示: 随机值的背后往往隐藏着指针问题,两块内存缓冲区的交界处比较容易出现 问题,在编程时是应该注意的地方。 【案例1.2.3】 【正 文】 在接入网产品A测试中,在内存数据库正常的情况下的各种数据库方 面的操作都是正常的。为了进行数据库异常测试,于是将数据库内容人为地破坏 了。发现在对数据库进行比较操作时,出现程序跑死了现象。 经过跟踪调试发现问题出现在如下一段代码中: 1 for(i=0; i<pSysHead->dbf_count; i++) 2 { 3 pDBFat = (_NM_DBFAT_STRUC *)(NVDB_BASE + DBFAT_OFFSET + i*DBFAT_LEN); 4 if(fat_check(pDBFat) != 0) 5 { 6 pSysHead->system_flag = 0; 7 head_sum(); 8 continue; 9 }
if(strlen(dbf->dbf name)!=0 & strncmp(dbf->dbf name, pDBFat->dbf name, strlen(dbf->dbf name)==0) 123456 dbf ptrI=( UC *)pDB Fat->dbf head filesize=pDB Fat->dbf fsize, 在测试时发现程序死在循环之中,得到的错误记录是" Bus error"(总线 出错),由此可以说明出现了内存操作异常。 经过跟踪变量值发现循环变量i阀值 pSysHead-> dbf count的数值为 0 XFFFFFFFF,该值是从被破坏的内存数据库中获取的,正常情况下该值小于127。 而 pDBFat是数据库的起始地址,如果 pSysHead-> dbf count值异常过大,将导致 pDBFat1值超过最大内存地址值,随后进行的内存操作将导致内存操作越界错误, 因而在测试过程中数据库破坏后就出现了主机死机的现象。 上面的问题解决起来很容易,只需在第一行代码中增加一个判断条件即可, 如下 for(i=0; ipSysHead->dbf coun & i< MAX DB NUM: i++) ∥ MAX DB NUM=127 这样就保证了循环变量i的值在正常范围内,从而避免了对指针 pDBFat进行 内存越界的操作 从上面的测试过程中,我们可以看到:如此严重的问题,仅仅是一个简单的 错误引起的。实际上,系统的不稳定往往是由这些看似很简单的小错误导致的。 这个问题给我们教训的是:在直接对内存地址进行操作时,一定要保证其值的合 法性,否则容易引起内存操作越界,给系统的稳定性带来潜在的威胁 【案例124】
10 if(strlen(dbf->dbf_name) != 0 && strncmp(dbf->dbf_name, pDBFat->dbf_name, strlen(dbf->dbf_name)) == 0) 11 { 12 dbf_ptr1 = (_UC *)pDBFat->dbf_head; 13 filesize = pDBFat->dbf_fsize; 14 break; 15 } 16 } 在测试时发现程序死在循环之中,得到的错误记录是"Bus Error"(总线 出错),由此可以说明出现了内存操作异常。 经过跟踪变量值发现循环变量i的阀值pSysHead->dbf_count的数值为 0xFFFFFFFF,该值是从被破坏的内存数据库中获取的,正常情况下该值小于127。 而pDBFat是数据库的起始地址,如果pSysHead->dbf_count值异常过大,将导致 pDBFat值超过最大内存地址值,随后进行的内存操作将导致内存操作越界错误, 因而在测试过程中数据库破坏后就出现了主机死机的现象。 上面的问题解决起来很容易,只需在第一行代码中增加一个判断条件即可, 如下: for(i=0; i<pSysHead->dbf_coun && i < MAX_DB_NUM; i++) // MAX_DB_NUM=127 这样就保证了循环变量i的值在正常范围内,从而避免了对指针pDBFat进行 内存越界的操作。 从上面的测试过程中,我们可以看到:如此严重的问题,仅仅是一个简单的 错误引起的。实际上,系统的不稳定往往是由这些看似很简单的小错误导致的。 这个问题给我们教训的是:在直接对内存地址进行操作时,一定要保证其值的合 法性,否则容易引起内存操作越界,给系统的稳定性带来潜在的威胁。 【案例1.2.4】
近日在CDB并行测试中发现一个问题:我们需要的小区负荷话统结果总是为 零,开始还以为小区负荷太小,于是加大短消息下发数量,但还为零,于是在程 序中加入测试代码,把收到的数据在BAM上打印出来, 结果打印出来的数据正常不可能为零仔细查看相关代码,问题只可能在指针 移位上有问题,果然在函数中发现一处比较隐蔽的错误 *功能:一个BM模块内所有小区CDB侧广播消息忙闲情况* /*************************************************/ void Cell CBCH Load Static(struct Msg CB FAR pMsg memcpy(( UC *)&tmp msg, pMsg, sizeof(tmp msg); pMsg=pMsg+ - sizeof( tmp msg)/ sizeof(tmp msg=10本意是想移动10个字 节,可是实际上指针移动了10* sizeof(struct MscE)个字节; CelINum=tmp msg. usCelNum 所以结构指针传入函数后,如要进行指针移动操作,最好先将其转化为 UC型再说。总之指针操作要小心为上 3、避免指针的非法引用 【案例131】 【正 文】 在一次测试中,并没有记得做了什么操作,发现 HONET系统的主机复位 了,之后,系统又工作正常了。由于没有打开后台的跟踪窗口,当时查了半天没 有眉目。过了半天,现象又出现了,而且这次是主机在反复复位,系统根本无法
近日在CDB并行测试中发现一个问题:我们需要的小区负荷话统结果总是为 零,开始还以为小区负荷太小,于是加大短消息下发数量,但还为零,于是在程 序中加入测试代码,把收到的数据在BAM上打印出来, 结果打印出来的数据正常,不可能为零,仔细查看相关代码,问题只可能在指针 移位上有问题,果然在函数中发现一处比较隐蔽的错误。 /* 功能:一个BM模块内所有小区CDB侧广播消息忙闲情况 */ /*************************************************************/ void Cell_CBCH_Load_Static(struct MsgCB FAR *pMsg) { 。。。 memcpy((_UC *)&tmp_msg,pMsg,sizeof(tmp_msg)); pMsg=pMsg+sizeof(tmp_msg);//sizeof(tmp_msg)=10;本意是想移动10个字 节,可是实际上指针移动了10*sizeof(struct MsgCB)个字节; CellNum=tmp_msg.usCellNum; 。。。 } 1 所以结构指针传入函数后,如要进行指针移动操作,最好先将其转化为 _UC型再说。总之指针操作要小心为上。 3、避免指针的非法引用 【案例1.3.1】 【正 文】 在一次测试中,并没有记得做了什么操作,发现HONET系统的主机复位 了,之后,系统又工作正常了。由于没有打开后台的跟踪窗口,当时查了半天没 有眉目。过了半天,现象又出现了,而且这次是主机在反复复位,系统根本无法
正常工作了 我凭记忆,判断应该是与当时正在测试的DSL板的端口配置有关。于是将 板上所有端口配置为普通2B+D端口,重新加载在主机数据,现象消失。于是初 步定位为主机在DSL端口处理过程中有重大错误。 我在新的数据上努力恢复原出问题的现象,却一直没有重现,于是恢复原 数据,加载后立即重现。并注意到,当DSL端口激活时,主机复位。仔细比较两 种数据的差别,发现出现主机复位问题的数据中DSL板配置了 MNTMLT端口, 但是没有做DSL端口之间的半永久数据 于是在程序中不断加打印语句,通过后台的 DBWIN调试程序跟踪,最后 终于定位为:每当执行到 portal. c的 Devicedslmsgproo(O函数中处理U口透传的 if( SPC STATE OK = pSpcCB->bySpcState 语句时,主机复位。但是该语句似乎并无不妥 再分析整个函数, pSpcCB在函数前部分已经被赋值 pSpcCB= SpcCB+(PortTable+index)->spcNo 但由于得到 index后,没有任何判断,导致若 MNTMLT端口没有做半永久, 端口激活后,执行此部分函数,( PortAble+ index)-> spaNo有可能为NUL_WORD, 于是,运算后, pSpcCB可能为非法值。此时主机在取进行判断,就不知会导致 什么后果了。 其实,改起来很简单,只要在这两句前增加一个判断就行了。于是,修改 代码为: if((PortTable+index)-spc No NULL WORD pSpcCB SpcCB+( PortTable+index)->spcNo if( SPC STATE OK = pSpcCB->bySpcState 修改后,问题不再重现 经过分析可以发现,编译环境是有很大的容许空间的,若主机没有做充分 的保护,很可能会有极严重的随即故障出现。所以编程时一定要考虑各种可能情
正常工作了。 我凭记忆,判断应该是与当时正在测试的DSL板的端口配置有关。于是将 板上所有端口配置为普通2B+D端口,重新加载在主机数据,现象消失。于是初 步定位为主机在DSL端口处理过程中有重大错误。 我在新的数据上努力恢复原出问题的现象,却一直没有重现,于是恢复原 数据,加载后立即重现。并注意到,当DSL端口激活时,主机复位。仔细比较两 种数据的差别,发现出现主机复位问题的数据中DSL板配置了MNT/MLT端口, 但是没有做DSL端口之间的半永久数据。 于是在程序中不断加打印语句,通过后台的DBWIN调试程序跟踪,最后 终于定位为:每当执行到portdsl.c的DeviceDslMsgProc()函数中处理U口透传的 if ( SPC_STATE_OK == pSpcCB->bySpcState ) 语句时,主机复位。但是该语句似乎并无不妥。 再分析整个函数,pSpcCB在函数前部分已经被赋值, pSpcCB = SpcCB + (PortTable+index)->spcNo; 但由于得到 index 后,没有任何判断,导致若MNT/MLT端口没有做半永久, 端口激活后,执行此部分函数,(PortTable+index)->spcNo 有可能为NULL_WORD, 于是,运算后,pSpcCB 可能为非法值。此时主机在取进行判断,就不知会导致 什么后果了。 其实,改起来很简单,只要在这两句前增加一个判断就行了。于是,修改 代码为: if ( (PortTable+index)->spcNo != NULL_WORD) { pSpcCB = SpcCB + (PortTable+index)->spcNo; if ( SPC_STATE_OK == pSpcCB->bySpcState ) {。。。} } 修改后,问题不再重现。 经过分析可以发现,编译环境是有很大的容许空间的,若主机没有做充分 的保护,很可能会有极严重的随即故障出现。所以编程时一定要考虑各种可能情