华为软件编程规范培训实例与练习.pdf

上传人:紫竹语嫣 文档编号:5518583 上传时间:2020-05-28 格式:PDF 页数:70 大小:217.14KB
返回 下载 相关 举报
华为软件编程规范培训实例与练习.pdf_第1页
第1页 / 共70页
华为软件编程规范培训实例与练习.pdf_第2页
第2页 / 共70页
华为软件编程规范培训实例与练习.pdf_第3页
第3页 / 共70页
华为软件编程规范培训实例与练习.pdf_第4页
第4页 / 共70页
华为软件编程规范培训实例与练习.pdf_第5页
第5页 / 共70页
点击查看更多>>
资源描述

《华为软件编程规范培训实例与练习.pdf》由会员分享,可在线阅读,更多相关《华为软件编程规范培训实例与练习.pdf(70页珍藏版)》请在三一文库上搜索。

1、华为软件编程规范培训实例与练习 问题分类 1 逻辑类问题( A类)指设计、编码中出现的计算正确性和一致性、程 序逻辑控制等方面出现的问题,在系统中起关键作用, 将导致软件死机、 功能正 常实现等严重问题; 接口类问题( B类)指设计、编码中出现的函数和环境、其他函数、全 局/局部变量或数据变量之间的数据/控制传输不匹配的问题,在系统中起重要作 用,将导致模块间配合失效等严重问题; 维护类问题( C类)指设计、编码中出现的对软件系统的维护方便程度 造成影响的问题, 在系统中不起关键作用, 但对系统后期维护造成不便或导致维 护费用上升; 可测试性问题( D类)指设计、编码中因考虑不周而导致后期系统

2、可测 试性差的问题。 处罚办法 问题发生率: P=D/S D=D A+0.5DB+0.25DC 其中: P 问题发生率 D 1个季度内错误总数 DA 1个季度内A类错误总数 DB 1个季度内B类错误总数 DC 1个季度内C 类错误总数 S 1个季度内收到问题报告单总数 1)当D 3时,如果P3,将进行警告处理,并予以公告; 2)当D 5时,如果P5,将进行罚款处理,并予以公告。 目录 一、逻辑类代码问题 第5页 1、变量 /指针在使用前就必须初始化 第5页 【案例 1.1.1】 第5页 2、防止指针 /数组操作越界 第5页 【案例 1.2.1】 第5页 【案例 1.2.2】 第6页 【案例 1

3、.2.3】 第7页 【案例 1.2.4】 第8页 3、避免指针的非法引用 第9页 【案例 1.3.1】 第9页 4、变量类型定义错误 第10页 【案例 1.4.1】 第10页 5、正确使用逻辑与 . . Get_Config_Table( AMP_CPM_CARD_CONFIG_TABLE, . . b_middle_data_ok = generate_trans_middle_data_from_original_data( puc_card_config_tab, Ul_card_config_num) . 其中红色部分巧妙的利用指向指针的指针为指针puc_card_config_tab

4、 赋值,而 在兰色部分使用该指针。 但在Get_Config_Table函数中有可能失败返回而不给 该指针赋值。因此,以后使用的可能是一个非法指针。 指针的使用是非常灵活的,同时也存在危险性,必须小心使用。指针使用的 危险性举世共知。 在新的编程思想中, 指针基本上被禁止使用 (JAVA 中就是 这样),至少也是被限制使用。而在我们交换机的程序中大量使用指针,并 且有增无减。 2、防止指针 /数组操作越界 【案例 1.2.1】 在香港项目测试中,发现ISDN话机拨新业务号码时,若一位一位的拨 至18位,不会有问题。但若先拨完号码再成组发送,会导致MPU死机。 处理过程: 查错过程很简单,按呼叫

5、处理的过程检查代码, 发现某一处的判断有误, 本应为小于 18的判断,写成了小于等于18。 结论: 代码编写有误。 思考与启示: 1、极限测试必须注意,测试前应对某项设计的极限做好充分测试规划。 2、测试极限时还要注意多种业务接入点,本例为ISDN。对于交换机 来说,任何一种业务都要分别在模拟话机、ISDN话机、 V5话机、多种形式的话 务台上做测试。对于中继的业务,则要充分考虑各种信令:TUP、ISUP、PRA、 NO1、V5等等。 【案例 1.2.2】 对某交换类进行计费测试,字冠011对应1号路由、 1号子路由,有 4个中继群 11,12,13,14(都属于 1#模块),前后两个群分别构

6、成自环。其中11,13群向为出中 继,12,14群向为入中继,对这四个群分别进行计费设置,对出入中继都计费。电 话60640001拨打01160010001两次,使四个群都有机会被计费,取话单后浏览话 单发现对 11群计费计次表话单出中继群号不正确,其它群的计次表中出中继群号 正常。 处理过程: 与开发人员在测试组环境多次重复以上步骤,发现11群的计次表话单有时正 常,有时其出中继群号就为一个随机值,发生异常的频率比较高。 为什么其它群 的话单正常, 唯独11群不正常呢? 11群是四个群中最小的群, 其中继计次表位于 缓冲区的首位, 打完电话后查询内存发现出中继群号在内存中是正确的,取完话 单

7、后再查就不正确了。 结论: 话单池的一个备份指针 Pool_head_1 和中继计次表的头指针重合, 影响到第一 个中继计次表的计费。 思考与启示: 随机值的背后往往隐藏着指针问题,两块内存缓冲区的交界处比较容易出现 问题,在编程时是应该注意的地方。 【案例 1.2.3】 【正文】 在接入网产品 A测试中,在内存数据库正常的情况下的各种数据库方 面的操作都是正常的。 为了进行数据库异常测试, 于是将数据库内容人为地破坏 了。发现在对数据库进行比较操作时,出现程序跑死了现象。 经过跟踪调试发现问题出现在如下一段代码中: 1 for(i=0; idbf_count; i+) 2 3 pDBFat

8、= (_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 10 if(strlen(dbf-dbf_name) != 0 13 filesize = pDBFat-dbf_fsize; 14 break; 15 16 在测试时发现程序死在循环之中,得到的错误记录是“Bus Error“(总线 出错),由此可以说明出现了内存操作异常。 经过跟踪变量值发现循环

9、变量i的阀值 pSysHead-dbf_count 的数值为 0xFFFFFFFF, 该值是从被破坏的内存数据库中获取的,正常情况下该值小于 127。 而pDBFat是数据库的起始地址,如果pSysHead-dbf_count值异常过大,将导致 pDBFat值超过最大内存地址值,随后进行的内存操作将导致内存操作越界错误, 因而在测试过程中数据库破坏后就出现了主机死机的现象。 上面的问题解决起来很容易,只需在第一行代码中增加一个判断条件即可, 如下: for(i=0; idbf_coun 但由于得到 index后,没有任何判断,导致若MNT/MLT 端口没有做半永久, 端口激活后,执行此部分函数

10、,(PortTable+index)-spcNo有可能为NULL_WORD, 于是,运算后,pSpcCB 可能为非法值。此时主机在取进行判断,就不知会导致 什么后果了。 其实,改起来很简单,只要在这两句前增加一个判断就行了。于是,修改 代码为: if ( (PortTable+index)-spcNo != NULL_WORD) pSpcCB = SpcCB + (PortTable+index)-spcNo; if ( SPC_STATE_OK = pSpcCB-bySpcState ) 。 修改后,问题不再重现。 经过分析可以发现, 编译环境是有很大的容许空间的,若主机没有做充分 的保护,

11、很可能会有极严重的随即故障出现。所以编程时一定要考虑各种可能情 况;而测试中遇到此类死机问题, 则要耐心的定位到具体是执行哪句代码时出现 的,再进行分析。因为问题很隐蔽,直接分析海一样的代码是很难发现的。 4、变量类型定义错误 【案例 1.4.1】 【正文】 在FRI板上建几条 FRPVC,其DLCI 类型分别为: 10Bit/2bytes、 10bit/3bytes、16bit/3bytes、17bit/4bytes、23bit/4bytes。相应的 DLCI 值为: 16、 234、991、126975、1234567,然后保存,重起 MUX ,观察 PVC的恢复情况,结 果DLCI 值为

12、16、234和991的PVC正确恢复,而 DLCI=126975的PVC恢复的数据 错误为 61439,而DLCI=1234567的PVC完全没有恢复。 对于17/4类型,DLCI=126975的PVC在恢复时变成 61439,根据这条线 索,查找原因,发现 126975-61439=65535 ,转化二进制就是 10000000000000000 , 也就是说在数据恢复或保存时把原数据的第一个1给忽略了。此时第一个想法是: 在程序处理中,把无符号长整型变量当作短整型变量处理了,为了证实这个判断, 针对17bit/4bytes类型又重新设计测试用例:(1) 先建PVC,DLCI=65535 ,

13、然 后保存,重起 MUX ,观察 PVC的恢复情况,发现 PVC能够正确恢复; (2)再建 PVC,DLCI=65536,然后保存,重起 MUX ,观察 PVC的恢复情况, 此时PVC不能正确恢复。 至此基本可以断定原因就是出在这里。带着这个目的查看原代码, 发现在以下代 码中有问题: int _GetFrDlci( DWORD* dwDlci, char* str, DWORD dwDlciType, DWORD dwPortType, DWORD dwSlotID, DWORD dwPortID) DWORD tempDlci; char szArg80; 1 char szLine80;

14、 ID LowPVCEP; DWORD dwDlciVal52 = 16,1007, 16,1007, 1024,64511, 2048,129023, 131072,4194303 ; typedef struct tagFrPppIntIWF WORD wHdlcPort; WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort; SFrPppIntIWFData; DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint ) BYTE bSlotID, bPeerSlotID; DWORD

15、dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci, wPeerIci, wPeerHdlcPort ; WORD wCount; DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint ) BYTE bSlotID; DWORD dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci ; WORD wCount; unSevData.FrNetExtIWFwCount.bSlotID = bSlotID; unSevData.FrNetExtIWFwCou

16、nt.wHdlcPort = wHdlcPort; unSevData.FrNetExtIWFwCount.wHdlcDlci = gFrPVCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI; unSevData.FrNetExtIWFwCount.wOldAtmPort = wAtmPort; unSevData.FrNetExtIWFwCount.wAtmDlci = gFrPVCEP bSlotID gFrPVCCbSlotIDdwCCID.dwHiPVCEP .dwDLCI; unSevData.FrNetExtIWFwCount.dw

17、MapMode = gFrPVCCbSlotIDdwCCID.dwMapMode; DWORD RestoreFrNetExtIWFData ( WORD wSlotID, BYTE *pReadPoint ) WORD wCount, wTotalNetIWF; BYTE bSlotID, bHdlcDlciType, bAtmDlciType; WORD wOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORD dwMapMode, dwCIR, dwBe; DWORD dwCCID, dwResult, dwAtmPort; wTotalNet

18、IWF = g_MuxData.SevDataSize.wFrNetExtIWFNum; DWORD RestoreFrHdlcIntIWFData ( WORD wSlotID, BYTE *pReadPoint ) WORD wCount, wTotalHdlcIWF; DWORD dwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort; DWORD dwResult; BYTE bSlotID, bPeerSlotID; WORD wHdlcPort, wOldAtmPort, wCIR; WORD wPeerHdlcPort, wPeerOldAtmP

19、ort; 其中涉及 DLCI 值的变量都为 WORD(即无符号短整型)类型,在程序 的处理时,出现 WORD和DWORD(无符号长整型)类型在一句中同时存在的情 况,至此可以判断问题出在这里。由于DLCI 值在不同类型时的取值范围不同, 前三种类型的取值范围为16991,第四种取值范围为 2048126975,第五种取值 范围为 1310724194303 ,所以当采用前三种 DLCI 类型时,采用 WORD类型最大 值为65535,已经完全够用了;而对于第四种类型时,其取值在超过65535时,获 取DLCI 值的函数 _GetFrDlci()采用 DWORD类型,而负责保存和恢复的两个函 数

20、SaveFrNetExtIWFData()和 RestoreFrNetExtIWFData(),都把 DLCI的值当 作WORD类型进行处理,因此导致 DLCI 取值越界,于是程序把原本为长整型的 DLCI强制转换成整型,从而导致DLCI值在恢复时,比原数据小65536。而在程 序运行过程中,这些数据保存在DRAM 中,程序运行直接从 DRAM 中获取数据, 程序不会出错;当 FRI板复位或插拔后,需要从 FLASH中读取数据,此时恢复函 数的错误就表现出来。 另一个问题是为什么 23/4类型的 DLCI 数据不能恢复?这是由于对于23/4 类型的 PVC,其DLCI 的取值范围为: 1310

21、724194303 ,而程序强制转换并恢复 的数据最大只能是 65535,所以这条 PVC不能恢复。 至此, DLCI 数据恢复出错的原因完全找到,解决的方法是将DLCI 的类 型改为DWORD类型。从这个案例可以看出,在程序开发中一个很低级的错误, 将在实际工作中造成很严重的后果。 【案例 1.4.2】 【正文】 在FRI板上建几条 FRPVC,其DLCI 类型分别为: 10Bit/2bytes、 10bit/3bytes、16bit/3bytes、17bit/4bytes、23bit/4bytes。相应的 DLCI 值为: 16、 234、991、126975、1234567,然后保存,重

22、起 MUX ,观察 PVC的恢复情况,结 果DLCI 值为16、234和991的PVC正确恢复,而 DLCI=126975的PVC恢复的数据 错误为 61439,而DLCI=1234567的PVC完全没有恢复。 对于17/4类型,DLCI=126975的PVC在恢复时变成 61439,根据这条线 索,查找原因,发现 126975-61439=65535 ,转化二进制就是 10000000000000000 , 也就是说在数据恢复或保存时把原数据的第一个1给忽略了。此时第一个想法是: 在程序处理中,把无符号长整型变量当作短整型变量处理了,为了证实这个判断, 针对17bit/4bytes类型又重新

23、设计测试用例:(1) 先建PVC,DLCI=65535 ,然 后保存,重起 MUX ,观察 PVC的恢复情况,发现 PVC能够正确恢复; (2)再建 PVC,DLCI=65536,然后保存,重起 MUX ,观察 PVC的恢复情况, 此时PVC不能正确恢复。 至此基本可以断定原因就是出在这里。带着这个目的查看原代码, 发现在以下代 码中有问题: int _GetFrDlci( DWORD* dwDlci, char* str, DWORD dwDlciType, DWORD dwPortType, DWORD dwSlotID, DWORD dwPortID) DWORD tempDlci; c

24、har szArg80; char szLine80; ID LowPVCEP; DWORD dwDlciVal52 = 16,1007, 16,1007, 1024,64511, 2048,129023, 131072,4194303 ; typedef struct tagFrPppIntIWF WORD wHdlcPort; WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort; SFrPppIntIWFData; DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint ) BYTE b

25、SlotID, bPeerSlotID; DWORD dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci, wPeerIci, wPeerHdlcPort ; WORD wCount; DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint ) BYTE bSlotID; DWORD dwCCID, dwPeerCCID; WORD wHdlcPort, wAtmPort, wIci ; WORD wCount; unSevData.FrNetExtIWFwCount.bSlotID = bSlotID

26、; unSevData.FrNetExtIWFwCount.wHdlcPort = wHdlcPort; unSevData.FrNetExtIWFwCount.wHdlcDlci = gFrPVCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI; unSevData.FrNetExtIWFwCount.wOldAtmPort = wAtmPort; unSevData.FrNetExtIWFwCount.wAtmDlci = gFrPVCEP bSlotID gFrPVCCbSlotIDdwCCID.dwHiPVCEP .dwDLCI; unS

27、evData.FrNetExtIWFwCount.dwMapMode = gFrPVCCbSlotIDdwCCID.dwMapMode; DWORD RestoreFrNetExtIWFData ( WORD wSlotID, BYTE *pReadPoint ) WORD wCount, wTotalNetIWF; BYTE bSlotID, bHdlcDlciType, bAtmDlciType; WORD wOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORD dwMapMode, dwCIR, dwBe; DWORD dwCCID, dwR

28、esult, dwAtmPort; wTotalNetIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum; DWORD RestoreFrHdlcIntIWFData ( WORD wSlotID, BYTE *pReadPoint ) WORD wCount, wTotalHdlcIWF; DWORD dwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort; DWORD dwResult; BYTE bSlotID, bPeerSlotID; WORD wHdlcPort, wOldAtmPort, wCIR; WORD

29、wPeerHdlcPort, wPeerOldAtmPort; 其中涉及 DLCI 值的变量都为 WORD(即无符号短整型)类型,在程序 的处理时,出现 WORD和DWORD(无符号长整型)类型在一句中同时存在的情 况,至此可以判断问题出在这里。由于DLCI 值在不同类型时的取值范围不同, 前三种类型的取值范围为16991,第四种取值范围为 2048126975,第五种取值 范围为 1310724194303 ,所以当采用前三种 DLCI 类型时,采用 WORD类型最大 值为65535,已经完全够用了;而对于第四种类型时,其取值在超过65535时,获 取DLCI 值的函数 _GetFrDlci

30、()采用 DWORD类型,而负责保存和恢复的两个函 数SaveFrNetExtIWFData()和 RestoreFrNetExtIWFData(),都把 DLCI的值当 作WORD类型进行处理,因此导致 DLCI 取值越界,于是程序把原本为长整型的 DLCI强制转换成整型,从而导致DLCI值在恢复时,比原数据小65536。而在程 序运行过程中,这些数据保存在DRAM 中,程序运行直接从 DRAM 中获取数据, 程序不会出错;当 FRI板复位或插拔后,需要从 FLASH中读取数据,此时恢复函 数的错误就表现出来。 另一个问题是为什么 23/4类型的 DLCI 数据不能恢复?这是由于对于23/4

31、 类型的 PVC,其DLCI 的取值范围为: 1310724194303 ,而程序强制转换并恢复 的数据最大只能是 65535,所以这条 PVC不能恢复。 至此, DLCI 数据恢复出错的原因完全找到,解决的方法是将DLCI 的类 型改为 DWORD类型。从这个案例可以看出,在程序开发中一个很低级的错误, 将在实际工作中造成很严重的后果。 5、正确使用逻辑与 这里当 head=126时,SendWin.head = 0 ,这将造成发送窗口指针和队列窗口指针 错位,造成链路复位 ; 另外,在重发函数 void INVOKE_RETRANSMISSION(_US logic_link,_US n_

32、r)中, 有如下语句: retran_num = (LinkStatelogic_link.Vs + MOD128 - (_UC)n_r) % MOD128 ; w_head = (LinkStatelogic_link.SendWin.head + W_MOD - retran_num) % W_MOD ; 第一个语句求欲重发的消息包个数,第二个语句求重发的起始位置,当Vs小于 n_r时,将造成实际重发数小于欲重发数,同时造成实际起始重发位置和欲重发 起始位置错开,从而引起链路复位。上面三个语句应该做如下改动: linkstate_ptr-SendWin.head = (head + 1)

33、retran_num = (LinkStatelogic_link.Vs + MOD128 + 1 - (_UC)n_r) w_head = (LinkStatelogic_link.SendWin.head + W_MOD + 1 - retran_num) 【结论】:由于链路通信对系统效率要求很高,算法采用效率最高的,但位与 ( char型强制转换成 WORD型。B7就变成了 FFB7,十进制就是 65463。由 于char是有符号型, B7的第8位为1,所以转换后为 FFB7,而不是代码作者希望 的00B7,如果第 8位是0,或该变量是 BYTE 型,转换就不会有问题了。 2、函数形参和

34、实参不一致,实际上和第一种情况本质上是一样的,只是 表现的形式不太一样,这种情况也是代码中经常出现的问题,下面例子是测试中 曾经发现的一个小问题: 【例二】在file01 中的INT DebugMsgProc(char byMsg0, char byMsg1) 函 数,两个形参都是char型, 而实际传入的参数都是BYTE 型, 结果函数中的如下语 句: PrintfE(PID_RED,“ %d ticks time out!“,byMsg1); 在byMsg1 大于127时,输出错误的结果。 二、不同数据类型之间的比较操作 在循环终止条件的判断中, 不同类型变量的比较操作是容易造成死循环错

35、误的地方, 同时也是开发人员容易忽视的地方,值得测试人员多加留意。 下面两 个例子是该类错误的两种典型情况: 【例三】 file02文件中某函数中如下代码,可能造成死循环: int i; WORD *pCheck =(WORD*)p; WORD wCheckSum=*pCheck; pCheck+; for(i=1;i= g_wASL32StartPSN ) if ( ( bsn % 16 ) = 7 | ( bsn % 16 ) = 8 ) return TRUE; return FALSE; 作者的本意是如果是 32路用户板(蓝色字体判断),就看端口号是否是第15 和16路,如果是,就是反

36、极性端口,返回TRUE,否则就不是,应该返回 FALSE。 但代码表达的意思是: 如果是 32路用户板并且端口号是 15或16就返回真值, 否则 还要执行下边语句。 当端口在 32路用户板上,但端口号不是15或16时,不同的 32路端口的起始地 址g_wASL32StartPSN,会导致不同的非 15、16端口被误认为是反极性端口。举 个例子,当 g_wASL32StartPSN的值为 3000时,端口号为 3000 (第一块板上的第 0 个端口)就被认为是反极性端口,这与作者的意图完全相悖。 可以将代码修改如下: if ( ( bsn = g_wASL32StartPSN ) if ( (

37、( bsn - g_wASL32StartPSN ) % 32 ) = 15 | ( ( bsn - g_wASL32StartPSN ) % 32 = 16 ) ) ) return TRUE; else if ( ( bsn % 16 ) = 7 | ( bsn % 16 ) = 8 ) return TRUE; return FALSE; 通过这个例子,我觉得在代码审查时应该留意在判断条件较多的情况下,每 个输入是否都能正确输出, 在单元测试、 集成测试、系统测试时要针对边界值设 计相应的测试用例。 判断条件较多时开发人员也应该适当分开写,既使代码更易读,又不容易出 错。 8、条件分支处

38、理是否有遗漏 【案例 1.8.1】 【现象】 在接入网主机程序的代码审查中,发现dbquery.c的DBQ_Init_ANType 函数中如下代码段缺少应有的条件分支,在数据异常的情况下, 会产生较严重的 问题。 【处理过程】 该错误比较隐蔽,现在说明如下: Max2B1QStatTime 最大统计时间 Max2B1QStatPortNum最大统计端口数 MAX_2B1Q_STAT_PSN 最大统计内存分配数量 其中: Max2B1QStatTime(最大统计时间)和 Max2B1QStatPortNum (最大统计端口数)的乘积不能大于MAX_2B1Q_STAT_PSN 程序如下: /查询数

39、据库,获得 Max2B1QStatTime的值 directQueryCond.tupleNo = 10; error_code = DB_Query( RID_OTHERS_PARA_INFO, 1, (LPDBCondition) /查询数据库成功 if( error_code = DB_SUCCESS ) /tempstruct0.data是数据库中为 Max2B1QStatTime配置的值 if ( tempstruct0.data MAX_2B1Q_STAT_PSN ) Max2B1QStatTime = MAX_2B1Q_STAT_PSN; else if ( tempstruct

40、0.data != 0 ) Max2B1QStatTime = tempstruct0.data; /查询数据库,获得 Max2B1QStatPortNum的值 directQueryCond.tupleNo = 11; error_code = DB_Query( RID_OTHERS_PARA_INFO, 1, (LPDBCondition) /查询数据库成功 if( error_code = DB_SUCCESS ) /tempstruct0.data 为数据库中为 Max2B1QStatPortNum配置的值,如果其缺 省值和Max2B1QStatTime乘积值大于 MAX_2B1Q_

41、STAT_PSN 的话: if ( (tempstruct0.data * Max2B1QStatTime) MAX_2B1Q_STAT_PSN ) Max2B1QStatPortNum = MAX_2B1Q_STAT_PSN / Max2B1QStatTime; /如果在合理范围内且不为 0的话: else if ( tempstruct0.data != 0 ) Max2B1QStatPortNum = tempstruct0.data; 此处if-else if 分支没有判断值为0的情况,即数据库为 Max2B1QStatPortNum配置的值为 0: tempstruct0.data

42、= 0 ,则 Max2B1QStatPortNum就为缺省值 32。 【结论】 由于内存限制, Max2B1QStatTime(最大统计时间)和 Max2B1QStatPortNum(最大统计端口数)的乘积不能大于 MAX_2B1Q_STAT_PSN , 如果从数据库中得到 Max2B1QStatTime为MAX_2B1Q_STAT_PSN ,而 数据库中最大统计端口数恰好为0,由于上述代码没有对 tempstruct0.data = 0 的 情况进行判断, Max2B1QStatPortNum为缺省值 32,这样 Max2B1QStatTime和 Max2B1QStatPortNum乘积已经

43、是 32倍MAX_2B1Q_STAT_PSN 了, 远远超过了设 计内存的限制。 造成这种错误的原因是判断语句对条件判断不完整。 【思考与启示】 在代码审查时, 应该十分注意条件判断的的完备性。好多问题就是因为 条件判断不完全造成的。 9、引用已释放的资源 【案例 1.9.1】 【正文】 在计费测试的过程中,用呼叫器进行大话务量呼叫测试。30路话路通过 TUP 自环呼叫另外 30路话路,计费数据的设定是这样的: 通过计费情况索引对主叫计 费,得到详细话单。首先保证计费数据设定的正确性,打了几次自环电话后,查 看话单正常,则开始呼叫。 呼叫几万次后停止呼叫, 取话单进行观察。 发现这 30路每次

44、呼叫总会出现一张告 警话单,其余话单正常,该告警话单相对于话路来说是随机出现的。 通知开发人员后,首先我们再次对计费数据进行了确认。某个用户在某次呼 叫产生了告警话单, 其上一次和下一次呼叫的计费情况都正常,两次呼叫之间的 时间间隔只有几秒钟, 排除了人为修改数据的可能。 开发人员认为是 CCB的问题, 后来一查果然如此。 当中继选线发生了同抢需要重新选线时,CCB的 reset_CCB_for_reseatch_called_location() 就会把有关的呼叫信息清掉, 造成计费情 况分析失败,产生计费费用为0的告警话单。 更正reset_CCB_for_reseatch_called_

45、location() 中清除被叫信息的代码, 重选中 继时不清除被叫用户这部分属性。 思考与启示: 1、在计费测试过程中,对话单的观察很重要,不应该放过任何一个细小的 疑点; 2、计费测试仅仅打几次电话往往达不到效果,越接近用户实际使用的情况 越可能发现问题。 【案例 1.9.2】 【案例描述】 在进行 128模块V5用户CENTREX新业务测试时, 偶然遇到一个怪现象: 对群内一个 V5ST用户只开放 MCT权限,在进行恶意呼叫追查时,有一次报恶意 呼叫追查成功音只报了一半, 当正要报出恶意呼叫的号码时, 业务中断重新回到 通话态,随即重新追查一次,报“已申请其它新业务,本次申请不成功”。恶

46、意 呼叫追查与任何新业务都不会冲突,而且此用户也只有恶意呼叫追查有权,可以 肯定此时程序出问题了。为了重现,再次挂机,重新呼叫,应用此新业务,但这 个现象一直没有出现。 大约反复操作 20遍,又出现了一次这样的情况, 显然程序 中可能存在某种问题。 【处理过程】 出现这个问题后,及时与开发人员A取得了联系,并一起试图重现这个 问题,通过许多次的反复操作,又出现了一次这种情况。确认问题后,A表现出 高度的责任心,马上驾调试环境,反复调测,终于在当天就逮住了狐狸尾巴: 1、当用户接听恶意呼叫者的电话, 并启动恶意呼叫追查业务后, 在 V5_CR_VOICETONE 状态下 , 只要听 MCT音的用

47、户用脉冲方式拨任意一个数字, 则立即停止送 MCT音, 而将用户切换回与恶意呼叫者的通话. 但是程序中没有 对拨号类型作判断 , 导致用户若用音频拨号也会作同样的处理。 2、除了取消此次 MCT服务, 将用户切换回与恶意呼叫者的通话外, 如 果不释放 MCT_HANDLE, 由于每个模块只有一个这样的资源, 则下一次使用 MCT业务的用户不能成功 , 因为会在申请 MCT_HANDLE 时失败 , V5模块和 ST模 块在这个地方处理都有问题, 没有将 MCT_HANDLE 释放掉 , 对于V5用户会听 新业务失败音 , 对于ST用户会听音乐。 当不停的拨测 V5用户的 MCT业务时 , 有时

48、在听音时 , 可能由于网板有 杂音等原因 (或用户碰了话机的按键 ), 导致DTR收到一位号 , 则会立即停止此 次MCT服务, 用户会听到 MCT送音突然中断 , 然后恢复了与恶意呼叫者的通话. 而下次再用 MCT时, 由于上面所述的原因 , 会听到新业务失败音 , 此次失败后 , 无论MCT_HANDLE 分配成功与否 , 该用户的 MCT标志都被置为 1, 所以在用户 挂机时 , 会将该模块唯一的 MCT_HANDLE 资源释放掉 . 则以后该功能又可以正 常实现。 在追查这个问题时,开发人员A又发现了一个可能导致死机的严重问 题: 在用户启动 MCT服务, 正在听报追查号码的 MCT音时, 若恶意用户此时挂机 , CCB的处理中 , 只针对 ST用户送 DISCONNECT, 而对V5ST用户送的是 RELEASE消息, 这导致 V5X收到此消息后 , 将该V5ST用户的 cr2清除掉 , V5_USER_TALBE . cr2变为0xFFFF, 这样在 V5_CR_VOICETONE 超时后 , 程序中会检查 cr2的状态是否为 HOLD, 当取cr2的内容时 , 由于cr2已被清除 , 会 发生指针越界的 GP错误。 【结论】 通过调测发现、定位并解决问题。 【思考与启示】 我们平

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/环境 > 建筑资料


经营许可证编号:宁ICP备18001539号-1