华为软件编程规范培训案例和练习.doc

上传人:帮**** 文档编号:1841759 上传时间:2019-10-27 格式:DOC 页数:69 大小:334KB
返回 下载 相关 举报
华为软件编程规范培训案例和练习.doc_第1页
第1页 / 共69页
华为软件编程规范培训案例和练习.doc_第2页
第2页 / 共69页
点击查看更多>>
资源描述

《华为软件编程规范培训案例和练习.doc》由会员分享,可在线阅读,更多相关《华为软件编程规范培训案例和练习.doc(69页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、软件编程规范培训软件编程规范培训 实例与练习实例与练习第一版深圳市华为技术有限公司深圳市华为技术有限公司说明本文分为两部分,第一部分为中研关于规范开发人员设计编码行为、提高软件质量的通知文件,其中包含来自测试人员总结的大量的包括逻辑类、接口类、维护类和可测试类四个方面的生动实例,是典型的软件编程规范培训实例,亦可供我司员工自学;第二部分是一个练习,作为软件编程规范教学使用。案例与练习案例与练习 第一部分第一部分深圳市华为技术有限公司深圳市华为技术有限公司 研发管理办公室文件研发管理办公室文件关于规范开发人员设计编码行为、提高软件质量的通知关于规范开发人员设计编码行为、提高软件质量的通知为更有效

2、地贯彻执行软件编码规范总则,强化开发人员规范意识,进一步规范开发人员的设计、编码习惯(至少“犯过的错误,不能再犯”),为流程下游部门(如测试部)提供高质量的输出,使下游部门避免低效、重复劳动,特此通知,请各开发部门遵照执行。以下问题由测试部的问题单、案例分类汇总而成,将常见设计、编码问题分为四类:逻辑类、接口类、维护类和可测试性,问题级别为:逻辑类 接口类 维护类 可测试性。本通知中罗列问题如再次出现,将进行通报批评并记入干部部关键事件库。问题分类逻辑类问题(A类)指设计、编码中出现的计算正确性和一致性、程序逻辑控制等方面出现的问题,在系统中起关键作用,将导致软件死机、功能正常实现等严重问题;

3、接口类问题(B类)指设计、编码中出现的函数和环境、其他函数、全局/局部变量或数据变量之间的数据/控制传输不匹配的问题,在系统中起重要作用,将导致模块间配合失效等严重问题;维护类问题(C类)指设计、编码中出现的对软件系统的维护方便程度造成影响的问题,在系统中不起关键作用,但对系统后期维护造成不便或导致维护费用上升;可测试性问题(D类)指设计、编码中因考虑不周而导致后期系统可测试性差的问题。处罚办法问题发生率:P=D/SD=DA+0.5DB+0.25DC其中:P 问题发生率D 1个季度内错误总数DA 1个季度内A类错误总数DB 1个季度内B类错误总数DC 1个季度内C类错误总数S 1个季度内收到问

4、题报告单总数1)当D3时,如果P3,将进行警告处理,并予以公告;2)当D5时,如果P5,将进行罚款处理,并予以公告。目目 录录一、逻辑类代码问题一、逻辑类代码问题第第5页页1、变量、变量/指针在使用前就必须初始化指针在使用前就必须初始化第第5页页【案例案例1.1.1】第第5页页2、防止指针、防止指针/数组操作越界数组操作越界第第5页页【案例案例1.2.1】第第5页页【案例案例1.2.2】第第6页页【案例案例1.2.3】第第7页页【案例案例1.2.4】第第8页页3、避免指针的非法引用、避免指针的非法引用第第9页页【案例案例1.3.1】第第9页页4、变量类型定义错误、变量类型定义错误第第10页页【

5、案例案例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赋值,而在兰色部分使用该指针。但在Get_Config_Table函数中有可能失败返回而不给该指针赋值。因此,以后使用的可能是一个非法指

6、针。指针的使用是非常灵活的,同时也存在危险性,必须小心使用。指针使用的危险性举世共知。在新的编程思想中,指针基本上被禁止使用(JAVA中就是这样),至少也是被限制使用。而在我们交换机的程序中大量使用指针,并且有增无减。2、防止指针/数组操作越界【案例案例1.2.1】1 在香港项目测试中,发现ISDN话机拨新业务号码时,若一位一位的拨至18位,不会有问题。但若先拨完号码再成组发送,会导致MPU死机。 处理过程:查错过程很简单,按呼叫处理的过程检查代码,发现某一处的判断有误,本应为小于18的判断,写成了小于等于18。 结 论:代码编写有误。思考与启示:1、极限测试必须注意,测试前应对某项设计的极限

7、做好充分测试规划。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两次,使四个群都有机会被计费,取话单后浏览话

8、单发现对11群计费计次表话单出中继群号不正确,其它群的计次表中出中继群号正常。处理过程:与开发人员在测试组环境多次重复以上步骤,发现11群的计次表话单有时正常,有时其出中继群号就为一个随机值,发生异常的频率比较高。为什么其它群的话单正常,唯独11群不正常呢?11群是四个群中最小的群,其中继计次表位于缓冲区的首位,打完电话后查询内存发现出中继群号在内存中是正确的,取完话单后再查就不正确了。结 论:话单池的一个备份指针Pool_head_1和中继计次表的头指针重合,影响到第一个中继计次表的计费。思考与启示:随机值的背后往往隐藏着指针问题,两块内存缓冲区的交界处比较容易出现问题,在编程时是应该注意的

9、地方。【案例案例1.2.3】【正 文】在接入网产品A测试中,在内存数据库正常的情况下的各种数据库方面的操作都是正常的。为了进行数据库异常测试,于是将数据库内容人为地破坏了。发现在对数据库进行比较操作时,出现程序跑死了现象。经过跟踪调试发现问题出现在如下一段代码中: 1for(i=0; idbf_count; i+)23 pDBFat = (_NM_DBFAT_STRUC *)(NVDB_BASE + DBFAT_OFFSET + i*DBFAT_LEN);4if(fat_check(pDBFat) != 0) 56 pSysHead-system_flag = 0;7 head_sum();8

10、 continue;9 10 if(strlen(dbf-dbf_name) != 0 13 filesize = pDBFat-dbf_fsize;14 break;15 16 在测试时发现程序死在循环之中,得到的错误记录是“Bus Error“(总线出错),由此可以说明出现了内存操作异常。经过跟踪变量值发现循环变量i的阀值pSysHead-dbf_count的数值为0xFFFFFFFF,该值是从被破坏的内存数据库中获取的,正常情况下该值小于127。而pDBFat是数据库的起始地址,如果pSysHead-dbf_count值异常过大,将导致pDBFat值超过最大内存地址值,随后进行的内存操作

11、将导致内存操作越界错误,因而在测试过程中数据库破坏后就出现了主机死机的现象。上面的问题解决起来很容易,只需在第一行代码中增加一个判断条件即可,如下:for(i=0; idbf_coun 但由于得到 index 后,没有任何判断,导致若MNT/MLT端口没有做半永久,端口激活后,执行此部分函数,(PortTable+index)-spcNo 有可能为NULL_WORD,于是,运算后,pSpcCB 可能为非法值。此时主机在取进行判断,就不知会导致什么后果了。其实,改起来很简单,只要在这两句前增加一个判断就行了。于是,修改代码为:if ( (PortTable+index)-spcNo != NUL

12、L_WORD)pSpcCB = SpcCB + (PortTable+index)-spcNo;if ( SPC_STATE_OK = pSpcCB-bySpcState )。修改后,问题不再重现。经过分析可以发现,编译环境是有很大的容许空间的,若主机没有做充分的保护,很可能会有极严重的随即故障出现。所以编程时一定要考虑各种可能情况;而测试中遇到此类死机问题,则要耐心的定位到具体是执行哪句代码时出现的,再进行分析。因为问题很隐蔽,直接分析海一样的代码是很难发现的。4、变量类型定义错误【案例案例1.4.1】【正 文】在FRI板上建几条FRPVC,其DLCI类型分别为:10Bit/2bytes、1

13、0bit/3bytes、16bit/3bytes、17bit/4bytes、23bit/4bytes。相应的DLCI值为:16、234、991、126975、1234567,然后保存,重起MUX,观察PVC的恢复情况,结果DLCI值为16、234和991的PVC正确恢复,而DLCI=126975的PVC恢复的数据错误为61439,而DLCI=1234567的PVC完全没有恢复。对于17/4类型,DLCI=126975的PVC在恢复时变成61439,根据这条线索,查找原因,发现126975-61439=65535,转化二进制就是10000000000000000,也就是说在数据恢复或保存时把原数

14、据的第一个1给忽略了。此时第一个想法是:在程序处理中,把无符号长整型变量当作短整型变量处理了,为了证实这个判断,针对17bit/4bytes类型又重新设计测试用例:(1) 先建PVC,DLCI=65535,然后保存,重起MUX,观察PVC的恢复情况,发现PVC能够正确恢复;(2)再建PVC,DLCI=65536,然后保存,重起MUX,观察PVC的恢复情况,此时PVC不能正确恢复。至此基本可以断定原因就是出在这里。带着这个目的查看原代码,发现在以下代码中有问题:int _GetFrDlci( DWORD* dwDlci, char* str, DWORD dwDlciType, DWORD dw

15、PortType, DWORD dwSlotID, DWORD dwPortID) DWORD tempDlci;charszArg80;1charszLine80;ID LowPVCEP;DWORD dwDlciVal52 = 16,1007, 16,1007, 1024,64511,2048,129023, 131072,4194303 ;typedef struct tagFrPppIntIWFWORD wHdlcPort;WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort;SFrPppIntIWFData;DWORD Sav

16、eFrNetIntIWFData ( DWORD *pdwWritePoint )BYTEbSlotID, bPeerSlotID;DWORDdwCCID, dwPeerCCID;WORD wHdlcPort, wAtmPort, wIci, wPeerIci, wPeerHdlcPort ;WORD wCount;DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint )BYTEbSlotID;DWORDdwCCID, dwPeerCCID;WORD wHdlcPort, wAtmPort, wIci ;WORD wCount;unSevData.F

17、rNetExtIWFwCount.bSlotID = bSlotID;unSevData.FrNetExtIWFwCount.wHdlcPort= wHdlcPort;unSevData.FrNetExtIWFwCount.wHdlcDlci= gFrPVCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.wOldAtmPort= wAtmPort;unSevData.FrNetExtIWFwCount.wAtmDlci= gFrPVCEP bSlotID gFrPVCCbSlotIDdwC

18、CID.dwHiPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.dwMapMode = gFrPVCCbSlotIDdwCCID.dwMapMode;DWORD RestoreFrNetExtIWFData ( WORD wSlotID, BYTE *pReadPoint )WORDwCount, wTotalNetIWF;BYTE bSlotID, bHdlcDlciType, bAtmDlciType;WORDwOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORDdwMapMode, dwCIR, dwBe;

19、DWORDdwCCID, dwResult, dwAtmPort;wTotalNetIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum;DWORD RestoreFrHdlcIntIWFData ( WORD wSlotID, BYTE *pReadPoint )WORD wCount, wTotalHdlcIWF;DWORDdwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort;DWORDdwResult;BYTEbSlotID, bPeerSlotID;WORD wHdlcPort, wOldAtmPort, wCIR;

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

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

22、序强制转换并恢复的数据最大只能是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,然后保存,重起MUX,观察PVC的恢复情况,结果DLCI值为16、234和99

23、1的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,然后保存,重起MUX,观察PVC的恢复情况,发

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

25、1007, 1024,64511,2048,129023, 131072,4194303 ;typedef struct tagFrPppIntIWFWORD wHdlcPort;WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort;SFrPppIntIWFData;DWORD SaveFrNetIntIWFData ( DWORD *pdwWritePoint )BYTEbSlotID, bPeerSlotID;DWORDdwCCID, dwPeerCCID;WORD wHdlcPort, wAtmPort, wIci, wPeer

26、Ici, wPeerHdlcPort ;WORD wCount;DWORD SaveFrNetExtIWFData ( DWORD *pdwWritePoint )BYTEbSlotID;DWORDdwCCID, dwPeerCCID;WORD wHdlcPort, wAtmPort, wIci ;WORD wCount;unSevData.FrNetExtIWFwCount.bSlotID = bSlotID;unSevData.FrNetExtIWFwCount.wHdlcPort= wHdlcPort;unSevData.FrNetExtIWFwCount.wHdlcDlci= gFrP

27、VCEPbSlotID gFrPVCCbSlotIDdwCCID.dwLoPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.wOldAtmPort= wAtmPort;unSevData.FrNetExtIWFwCount.wAtmDlci= gFrPVCEP bSlotID gFrPVCCbSlotIDdwCCID.dwHiPVCEP .dwDLCI;unSevData.FrNetExtIWFwCount.dwMapMode = gFrPVCCbSlotIDdwCCID.dwMapMode;DWORD RestoreFrNetExtIWFData ( WOR

28、D wSlotID, BYTE *pReadPoint )WORDwCount, wTotalNetIWF;BYTE bSlotID, bHdlcDlciType, bAtmDlciType;WORDwOldAtmPort, wAtmDlci, wHdlcPort, wHdlcDlci; DWORDdwMapMode, dwCIR, dwBe;DWORDdwCCID, dwResult, dwAtmPort;wTotalNetIWF = g_MuxData.SevDataSize.wFrNetExtIWFNum;DWORD RestoreFrHdlcIntIWFData ( WORD wSlo

29、tID, BYTE *pReadPoint )WORD wCount, wTotalHdlcIWF;DWORDdwCCID, dwPeerCCID, dwAtmPort, dwPeerAtmPort;DWORDdwResult;BYTEbSlotID, bPeerSlotID;WORD wHdlcPort, wOldAtmPort, wCIR;WORD wPeerHdlcPort, wPeerOldAtmPort;其中涉及DLCI值的变量都为WORD(即无符号短整型)类型,在程序的处理时,出现WORD和DWORD(无符号长整型)类型在一句中同时存在的情况,至此可以判断问题出在这里。由于DLCI

30、值在不同类型时的取值范围不同,前三种类型的取值范围为16991,第四种取值范围为2048126975,第五种取值范围为1310724194303,所以当采用前三种DLCI类型时,采用WORD类型最大值为65535,已经完全够用了;而对于第四种类型时,其取值在超过65535时,获取DLCI值的函数_GetFrDlci()采用DWORD类型,而负责保存和恢复的两个函数SaveFrNetExtIWFData()和RestoreFrNetExtIWFData(),都把DLCI的值当作WORD类型进行处理,因此导致DLCI取值越界,于是程序把原本为长整型的DLCI强制转换成整型,从而导致DLCI值在恢复

31、时,比原数据小65536。而在程序运行过程中,这些数据保存在DRAM中,程序运行直接从DRAM中获取数据,程序不会出错;当FRI板复位或插拔后,需要从FLASH中读取数据,此时恢复函数的错误就表现出来。另一个问题是为什么23/4类型的DLCI数据不能恢复?这是由于对于23/4类型的PVC,其DLCI的取值范围为:1310724194303,而程序强制转换并恢复的数据最大只能是65535,所以这条PVC不能恢复。至此,DLCI数据恢复出错的原因完全找到,解决的方法是将DLCI的类型改为DWORD类型。从这个案例可以看出,在程序开发中一个很低级的错误,将在实际工作中造成很严重的后果。5、正确使用逻

32、辑与这里当head=126时,SendWin.head = 0,这将造成发送窗口指针和队列窗口指针错位,造成链路复位;另外,在重发函数void INVOKE_RETRANSMISSION(_US logic_link,_US n_r)中,有如下语句:retran_num = (LinkStatelogic_link.Vs + MOD128 - (_UC)n_r) % MOD128 ;w_head = (LinkStatelogic_link.SendWin.head + W_MOD - retran_num) % W_MOD ;第一个语句求欲重发的消息包个数,第二个语句求重发的起始位置,当Vs

33、小于n_r时,将造成实际重发数小于欲重发数,同时造成实际起始重发位置和欲重发起始位置错开,从而引起链路复位。上面三个语句应该做如下改动:linkstate_ptr-SendWin.head = (head + 1) retran_num = (LinkStatelogic_link.Vs + MOD128 + 1 - (_UC)n_r) w_head = (LinkStatelogic_link.SendWin.head + W_MOD + 1 - retran_num) 【结 论】:由于链路通信对系统效率要求很高,算法采用效率最高的,但位与(char型强制转换成WORD型。B7就变成了FFB

34、7,十进制就是65463。由于char是有符号型,B7的第8位为1,所以转换后为FFB7,而不是代码作者希望的00B7,如果第8位是0,或该变量是BYTE型,转换就不会有问题了。2、函数形参和实参不一致,实际上和第一种情况本质上是一样的,只是表现的形式不太一样,这种情况也是代码中经常出现的问题,下面例子是测试中曾经发现的一个小问题:【例二】在file01中的INT DebugMsgProc(char byMsg0, char byMsg1)函数,两个形参都是char型,而实际传入的参数都是BYTE型,结果函数中的如下语句:PrintfE(PID_RED,“ %d ticks time out!

35、“,byMsg1);在byMsg1大于127时,输出错误的结果。二、不同数据类型之间的比较操作在循环终止条件的判断中,不同类型变量的比较操作是容易造成死循环错误的地方,同时也是开发人员容易忽视的地方,值得测试人员多加留意。下面两个例子是该类错误的两种典型情况:【例三】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

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

37、码修改如下: if ( ( bsn = g_wASL32StartPSN ) if ( ( ( bsn - g_wASL32StartPSN ) % 32 ) = 15 | ( ( bsn - g_wASL32StartPSN ) % 32 = 16 ) ) )return TRUE;elseif ( ( bsn % 16 ) = 7 | ( bsn % 16 ) = 8 )return TRUE; return FALSE;通过这个例子,我觉得在代码审查时应该留意在判断条件较多的情况下,每个输入是否都能正确输出,在单元测试、集成测试、系统测试时要针对边界值设计相应的测试用例。判断条件较多时开

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

39、B1Q_STAT_PSN程序如下:/查询数据库,获得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 (

40、tempstruct0.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_STA

41、T_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 = 0,则Max2B

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

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

44、们再次对计费数据进行了确认。某个用户在某次呼叫产生了告警话单,其上一次和下一次呼叫的计费情况都正常,两次呼叫之间的时间间隔只有几秒钟,排除了人为修改数据的可能。开发人员认为是CCB的问题,后来一查果然如此。当中继选线发生了同抢需要重新选线时,CCB的reset_CCB_for_reseatch_called_location()就会把有关的呼叫信息清掉,造成计费情况分析失败,产生计费费用为0的告警话单。更正reset_CCB_for_reseatch_called_location()中清除被叫信息的代码,重选中继时不清除被叫用户这部分属性。思考与启示:1、在计费测试过程中,对话单的观察很重要

45、,不应该放过任何一个细小的疑点;2、计费测试仅仅打几次电话往往达不到效果,越接近用户实际使用的情况越可能发现问题。【案例1.9.2】【案例描述】在进行128模块V5用户CENTREX新业务测试时,偶然遇到一个怪现象:对群内一个V5ST用户只开放MCT权限,在进行恶意呼叫追查时,有一次报恶意呼叫追查成功音只报了一半,当正要报出恶意呼叫的号码时,业务中断重新回到通话态,随即重新追查一次,报“已申请其它新业务,本次申请不成功”。恶意呼叫追查与任何新业务都不会冲突,而且此用户也只有恶意呼叫追查有权,可以肯定此时程序出问题了。为了重现,再次挂机,重新呼叫,应用此新业务,但这个现象一直没有出现。大约反复操

46、作20遍,又出现了一次这样的情况,显然程序中可能存在某种问题。 【处理过程】出现这个问题后,及时与开发人员A取得了联系,并一起试图重现这个问题,通过许多次的反复操作,又出现了一次这种情况。确认问题后,A表现出高度的责任心,马上驾调试环境,反复调测,终于在当天就逮住了狐狸尾巴:1、当用户接听恶意呼叫者的电话, 并启动恶意呼叫追查业务后, 在V5_CR_VOICETONE状态下, 只要听MCT音的用户用脉冲方式拨任意一个数字, 则立即停止送MCT音, 而将用户切换回与恶意呼叫者的通话. 但是程序中没有对拨号类型作判断, 导致用户若用音频拨号也会作同样的处理。2、除了取消此次MCT服务, 将用户切换

47、回与恶意呼叫者的通话外, 如果不释放MCT_HANDLE, 由于每个模块只有一个这样的资源, 则下一次使用MCT业务的用户不能成功, 因为会在申请MCT_HANDLE时失败, V5模块和ST模块在这个地方处理都有问题, 没有将MCT_HANDLE释放掉, 对于V5用户会听新业务失败音, 对于ST用户会听音乐。当不停的拨测V5用户的MCT业务时, 有时在听音时, 可能由于网板有杂音等原因(或用户碰了话机的按键), 导致DTR收到一位号, 则会立即停止此次MCT服务, 用户会听到MCT送音突然中断, 然后恢复了与恶意呼叫者的通话. 而下次再用MCT时, 由于上面所述的原因, 会听到新业务失败音,

48、此次失败后, 无论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的状

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 大学资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com