版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
軟件編程規(guī)范培訓
實例與練習第一版深圳市華為技術(shù)有限公司闡明本文分為兩某些,第一某些為中研《關(guān)于規(guī)范開發(fā)人員設(shè)計編碼行為、提高軟件質(zhì)量告知》文獻,其中包括來自測試人員總結(jié)大量涉及邏輯類、接口類、維護類和可測試類四個方面生動實例,是典型軟件編程規(guī)范培訓實例,亦可供我司員工自學;第二某些是一種練習,作為軟件編程規(guī)范教學使用。
案例與練習第一某些
深圳市華為技術(shù)有限公司研發(fā)管理辦公室文獻關(guān)于規(guī)范開發(fā)人員設(shè)計編碼行為、提高軟件質(zhì)量告知 為更有效地貫徹執(zhí)行《軟件編碼規(guī)范總則》,強化開發(fā)人員規(guī)范意識,進一步規(guī)范開發(fā)人員設(shè)計、編碼習慣(至少“犯過錯誤,不能再犯”),為流程下游部門(如測試部)提供高質(zhì)量輸出,使下游部門避免低效、重復(fù)勞動,特此告知,請各開發(fā)部門遵循執(zhí)行。如下問題由測試部問題單、案例分類匯總而成,將常用設(shè)計、編碼問題分為四類:邏輯類、接口類、維護類和可測試性,問題級別為:邏輯類>接口類>維護類>可測試性。本告知中羅列問題如再次浮現(xiàn),將進行通報批評并記入干部部核心事件庫。問題分類邏輯類問題(A類)-指設(shè)計、編碼中浮現(xiàn)計算對的性和一致性、程序邏輯控制等方面浮現(xiàn)問題,在系統(tǒng)中起核心作用,將導致軟件死機、功能正常實現(xiàn)等嚴重問題;接口類問題(B類)-指設(shè)計、編碼中浮現(xiàn)函數(shù)和環(huán)境、其她函數(shù)、全局/局部變量或數(shù)據(jù)變量之間數(shù)據(jù)/控制傳播不匹配問題,在系統(tǒng)中起重要作用,將導致模塊間配合失效等嚴重問題;維護類問題(C類)-指設(shè)計、編碼中浮現(xiàn)對軟件系統(tǒng)維護以便限度導致影響問題,在系統(tǒng)中不起核心作用,但對系統(tǒng)后期維護導致不便或?qū)е戮S護費用上升;可測試性問題(D類)-指設(shè)計、編碼中因考慮不周而導致后期系統(tǒng)可測試性差問題。懲罰辦法問題發(fā)生率:P=D/SD=DA+0.5DB+0.25DC其中:P-問題發(fā)生率D-1個季度內(nèi)錯誤總數(shù)DA-1個季度內(nèi)A類錯誤總數(shù)DB-1個季度內(nèi)B類錯誤總數(shù)DC-1個季度內(nèi)C類錯誤總數(shù)S-1個季度內(nèi)收到問題報告單總數(shù)1)當D≥3時,如果P≥3%,將進行警告解決,并予以公示;2)當D≥5時,如果P≥5%,將進行罰款解決,并予以公示。
目錄一、邏輯類代碼問題第5頁1、變量/指針在使用前就必要初始化第5頁【案例1.1.1】第5頁2、防止指針/數(shù)組操作越界第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頁【案例1.4.1】第10頁5、對的使用邏輯與&&、屏蔽&操作符第17頁【案例1.5.1】第17頁6、注意數(shù)據(jù)類型匹配第18頁【案例1.6.1】第18頁【案例1.6.2】第18頁7、用于控制條件轉(zhuǎn)移表達式及取值范疇與否書寫對的第20頁【案例1.7.1】第20頁【案例1.7.2】第21頁【案例1.7.3】第22頁8、條件分支解決與否有漏掉第24頁【案例1.8.1】第24頁9、引用已釋放資源第26頁【案例1.9.1】第26頁10、分派資源與否已對的釋放第28頁【案例1.10.1】第28頁【案例1.10.2】第29頁【案例1.10.3】第30頁【案例1.10.4】第32頁【案例1.10.5】第33頁【案例1.10.6】第35頁【案例1.10.7】第38頁11、防止資源重復(fù)釋放第39頁【案例1.11.1】第39頁12、公共資源互斥性和競用性第40頁【案例1.12.1】第40頁【案例1.12.2】第40頁二、接口類代碼問題第43頁1、對函數(shù)參數(shù)進行有效性檢查第43頁【案例2.1.1】第43頁【案例2.1.2】第43頁【案例2.1.3】第44頁【案例2.1.4】第46頁【案例2.1.5】第47頁【案例2.1.6】第48頁2、注意多余口函數(shù)解決第49頁【案例2.2.1】第49頁三、維護類代碼問題第51頁1、統(tǒng)一枚舉類型使用第51頁【案例3.1.1】第51頁2、注釋量至少占代碼總量20%第51頁【案例3.2.1】對XXX產(chǎn)品BAM某版本某些代碼注釋量記錄第51頁四、產(chǎn)品兼容性問題第52頁1、系統(tǒng)配備、命令方式第52頁【案例4.1.1】第52頁【案例4.1.2】第53頁2、設(shè)備對接第54頁【案例4.2.1】第54頁3、其她第55頁【案例4.3.1】第55頁五、版本控制問題第58頁1、新老代碼中同一全局變量不一致第58頁【案例5.1.1】第58頁六、可測試性代碼問題第59頁1、調(diào)試信息/打印信息對的性第59頁【案例6.1.1】第59頁
一、邏輯類代碼問題1、變量/指針在使用前就必要初始化【案例1.1.1】 C語言中最大特色就是指針。指針使用品有很強技巧性和靈活性,但同步也帶來了很大危險性。在XXX代碼中有如下一端對指針靈活使用:......_UC*puc_card_config_tab;......Get_Config_Table(AMP_CPM_CARD_CONFIG_TABLE,&ul_card_config_num,&puc_card_config_tab,use_which_data_area);......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函數(shù)中有也許失敗返回而不給該指針賦值。因而,后來使用也許是一種非法指針。指針使用是非常靈活,同步也存在危險性,必要小心使用。指針使用危險性舉世共知。在新編程思想中,指針基本上被禁止使用(JAVA中就是這樣),至少也是被限制使用。而在咱們互換機程序中大量使用指針,并且有增無減。2、防止指針/數(shù)組操作越界【案例1.2.1】1在香港項目測試中,發(fā)現(xiàn)ISDN話機撥新業(yè)務(wù)號碼時,若一位一位撥至18位,不會有問題。但若先撥完號碼再成組發(fā)送,會導致MPU死機。解決過程:查錯過程很簡樸,按呼喊解決過程檢查代碼,發(fā)現(xiàn)某一處判斷有誤,本應(yīng)為不大于18判斷,寫成了不大于等于18。結(jié)論:代碼編寫有誤。思考與啟示: 1、極限測試必要注意,測試前應(yīng)對某項設(shè)計極限做好充分測試規(guī)劃。2、測試極限時還要注意各種業(yè)務(wù)接入點,本例為ISDN。對于互換機來說,任何一種業(yè)務(wù)都要分別在模仿話機、ISDN話機、V5話機、各種形式話務(wù)臺上做測試。對于中繼業(yè)務(wù),則要充分考慮各種信令:TUP、ISUP、PRA、NO1、V5等等?!景咐?.2.2】 對某互換類進行計費測試,字冠011相應(yīng)1號路由、1號子路由,有4個中繼群11,12,13,14(都屬于1#模塊),先后兩個群分別構(gòu)成自環(huán)。其中11,13群向為出中繼,12,14群向為入中繼,對這四個群分別進行計費設(shè)立,對出入中繼都計費。電話60640001撥打兩次,使四個群均有機會被計費,取話單后瀏覽話單發(fā)現(xiàn)對11群計費計次表話單出中繼群號不對的,其他群計次表中出中繼群號正常。解決過程: 與開發(fā)人員在測試組環(huán)境多次重復(fù)以上環(huán)節(jié),發(fā)現(xiàn)11群計次表話單有時正常,有時其出中繼群號就為一種隨機值,發(fā)生異常頻率比較高。為什么其他群話單正常,唯獨11群不正常呢?11群是四個群中最小群,其中繼計次表位于緩沖區(qū)首位,打完電話后查詢內(nèi)存發(fā)現(xiàn)出中繼群號在內(nèi)存中是對的,取完話單后再查就不對的了。結(jié)論: 話單池一種備份指針Pool_head_1和中繼計次表頭指針重疊,影響到第一種中繼計次表計費。思考與啟示: 隨機值背后往往隱藏著指針問題,兩塊內(nèi)存緩沖區(qū)交界處比較容易浮現(xiàn)問題,在編程時是應(yīng)當注意地方?!景咐?.2.3】【正文】在接入網(wǎng)產(chǎn)品A測試中,在內(nèi)存數(shù)據(jù)庫正常狀況下各種數(shù)據(jù)庫方面操作都是正常。為了進行數(shù)據(jù)庫異常測試,于是將數(shù)據(jù)庫內(nèi)容人為地破壞了。發(fā)當前對數(shù)據(jù)庫進行比較操作時,浮現(xiàn)程序跑死了現(xiàn)象。 通過跟蹤調(diào)試發(fā)現(xiàn)問題出當前如下一段代碼中: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 }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 }在測試時發(fā)現(xiàn)程序死在循環(huán)之中,得到錯誤記錄是"BusError"(總線出錯),由此可以闡明浮現(xiàn)了內(nèi)存操作異常。 通過跟蹤變量值發(fā)現(xiàn)循環(huán)變量i閥值pSysHead->dbf_count數(shù)值為0xFFFFFFFF,該值是從被破壞內(nèi)存數(shù)據(jù)庫中獲取,正常狀況下該值不大于127。而pDBFat是數(shù)據(jù)庫起始地址,如果pSysHead->dbf_count值異常過大,將導致pDBFat值超過最大內(nèi)存地址值,隨后進行內(nèi)存操作將導致內(nèi)存操作越界錯誤,因而在測試過程中數(shù)據(jù)庫破壞后就浮現(xiàn)了主機死機現(xiàn)象。 上面問題解決起來很容易,只需在第一行代碼中增長一種判斷條件即可,如下:for(i=0;i<pSysHead->dbf_coun&&i<MAX_DB_NUM;i++)//MAX_DB_NUM=127 這樣就保證了循環(huán)變量i值在正常范疇內(nèi),從而避免了對指針pDBFat進行內(nèi)存越界操作。從上面測試過程中,咱們可以看到:如此嚴重問題,僅僅是一種簡樸錯誤引起。事實上,系統(tǒng)不穩(wěn)定往往是由這些看似很簡樸小錯誤導致。這個問題給咱們教訓是:在直接對內(nèi)存地址進行操作時,一定要保證其值合法性,否則容易引起內(nèi)存操作越界,給系統(tǒng)穩(wěn)定性帶來潛在威脅。 【案例1.2.4】 近日在CDB并行測試中發(fā)現(xiàn)一種問題:咱們需要社區(qū)負荷話統(tǒng)成果總是為零,開始還覺得社區(qū)負荷太小,于是加大短消息下發(fā)數(shù)量,但還為零,于是在程序中加入測試代碼,把收到數(shù)據(jù)在BAM上打印出來, 成果打印出來數(shù)據(jù)正常,不也許為零,仔細查看有關(guān)代碼,問題只也許在指針移位上有問題,果然在函數(shù)中發(fā)現(xiàn)一處比較隱蔽錯誤。/*功能:一種BM模塊內(nèi)所有社區(qū)CDB側(cè)廣播消息忙閑狀況*//*************************************************************/voidCell_CBCH_Load_Static(structMsgCBFAR*pMsg){ 。。。 memcpy((_UC*)&tmp_msg,pMsg,sizeof(tmp_msg)); pMsg=pMsg+sizeof(tmp_msg);//sizeof(tmp_msg)=10;本意是想移動10個字節(jié),可是事實上指針移動了10*sizeof(structMsgCB)個字節(jié); CellNum=tmp_msg.usCellNum; 。。。}因此構(gòu)造指針傳入函數(shù)后,如要進行指針移動操作,最佳先將其轉(zhuǎn)化為_UC型再說??傊羔槻僮饕⌒臑樯?。3、避免指針非法引用【案例1.3.1】【正文】在一次測試中,并沒有記得做了什么操作,發(fā)現(xiàn)HONET系統(tǒng)主機復(fù)位了,之后,系統(tǒng)又工作正常了。由于沒有打開后臺跟蹤窗口,當時查了半天沒有眉目。過了半天,現(xiàn)象又浮現(xiàn)了,并且這次是主機在重復(fù)復(fù)位,系統(tǒng)主線無法正常工作了。我憑記憶,判斷應(yīng)當是與當時正在測試DSL板端口配備關(guān)于。于是將板上所有端口配備為普通2B+D端口,重新加載在主機數(shù)據(jù),現(xiàn)象消失。于是初步定位為主機在DSL端口解決過程中有重大錯誤。我在新數(shù)據(jù)上努力恢復(fù)原出問題現(xiàn)象,卻始終沒有重現(xiàn),于是恢復(fù)原數(shù)據(jù),加載后及時重現(xiàn)。并注意到,當DSL端口激活時,主機復(fù)位。仔細比較兩種數(shù)據(jù)差別,發(fā)現(xiàn)浮現(xiàn)主機復(fù)位問題數(shù)據(jù)中DSL板配備了MNT/MLT端口,但是沒有做DSL端口之間半永久數(shù)據(jù)。于是在程序中不斷加打印語句,通過后臺DBWIN調(diào)試程序跟蹤,最后終于定位為:每當執(zhí)行到portdsl.cDeviceDslMsgProc()函數(shù)中解決U口透傳if(SPC_STATE_OK==pSpcCB->bySpcState)語句時,主機復(fù)位。但是該語句似乎并無不當。再分析整個函數(shù),pSpcCB在函數(shù)前某些已經(jīng)被賦值,pSpcCB=SpcCB+(PortTable+index)->spcNo;但由于得到index后,沒有任何判斷,導致若MNT/MLT端口沒有做半永久,端口激活后,執(zhí)行此某些函數(shù),(PortTable+index)->spcNo有也許為NULL_WORD,于是,運算后,pSpcCB也許為非法值。此時主機在取進行判斷,就不知會導致什么后果了。其實,改起來很簡樸,只要在這兩句前增長一種判斷就行了。于是,修改代碼為:if((PortTable+index)->spcNo!=NULL_WORD){ pSpcCB=SpcCB+(PortTable+index)->spcNo; if(SPC_STATE_OK==pSpcCB->bySpcState) {。。。}} 修改后,問題不再重現(xiàn)。通過度析可以發(fā)現(xiàn),編譯環(huán)境是有很大容許空間,若主機沒有做充分保護,很也許會有極嚴重隨后故障浮現(xiàn)。因此編程時一定要考慮各種也許狀況;而測試中遇到此類死機問題,則要耐心定位到詳細是執(zhí)行哪句代碼時浮現(xiàn),再進行分析。由于問題很隱蔽,直接分析海同樣代碼是很難發(fā)現(xiàn)。4、變量類型定義錯誤【案例1.4.1】【正文】在FRI板上建幾條FRPVC,其DLCI類型分別為:10Bit/2bytes、10bit/3bytes、16bit/3bytes、17bit/4bytes、23bit/4bytes。相應(yīng)DLCI值為:16、234、991、126975、1234567,然后保存,重起MUX,觀測PVC恢復(fù)狀況,成果DLCI值為16、234和991PVC對的恢復(fù),而DLCI=126975PVC恢復(fù)數(shù)據(jù)錯誤為61439,而DLCI=1234567PVC完全沒有恢復(fù)。對于17/4類型,DLCI=126975PVC在恢復(fù)時變成61439,依照這條線索,查找因素,發(fā)現(xiàn)126975-61439=65535,轉(zhuǎn)化二進制就是00000,也就是說在數(shù)據(jù)恢復(fù)或保存時把原數(shù)據(jù)第一種1給忽視了。此時第一種想法是:在程序解決中,把無符號長整型變量當作短整型變量解決了,為了證明這個判斷,針對17bit/4bytes類型又重新設(shè)計測試用例:(1)先建PVC,DLCI=65535,然后保存,重起MUX,觀測PVC恢復(fù)狀況,發(fā)現(xiàn)PVC可以對的恢復(fù);(2)再建PVC,DLCI=65536,然后保存,重起MUX,觀測PVC恢復(fù)狀況,此時PVC不能對的恢復(fù)。至此基本可以斷定因素就是出在這里。帶著這個目查看原代碼,發(fā)當前如下代碼中有問題:int _GetFrDlci(DWORD*dwDlci,char*str,DWORDdwDlciType,DWORDdwPortType,DWORDdwSlotID,DWORDdwPortID){DWORDtempDlci; char szArg[80];1 char szLine[80]; ID LowPVCEP;DWORD dwDlciVal[5][2]= {{16,1007},{16,1007},{1024,64511}, {2048,129023},{131072,4194303}};...}typedefstructtagFrPppIntIWF{ ... WORD wHdlcPort; WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort; ... } SFrPppIntIWFData;DWORD SaveFrNetIntIWFData(DWORD*pdwWritePoint){ BYTE bSlotID,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.FrNetExtIWF[wCount].bSlotID =bSlotID; unSevData.FrNetExtIWF[wCount].wHdlcPort =wHdlcPort; unSevData.FrNetExtIWF[wCount].wHdlcDlci =gFrPVCEP[bSlotID][gFrPVCC[bSlotID][dwCCID].dwLoPVCEP].dwDLCI; unSevData.FrNetExtIWF[wCount].wOldAtmPort =wAtmPort; unSevData.FrNetExtIWF[wCount].wAtmDlci =gFrPVCEP[bSlotID][gFrPVCC[bSlotID][dwCCID].dwHiPVCEP].dwDLCI; unSevData.FrNetExtIWF[wCount].dwMapMode=gFrPVCC[bSlotID][dwCCID].dwMapMode;...}DWORDRestoreFrNetExtIWFData(WORDwSlotID,BYTE*pReadPoint){ WORD wCount,wTotalNetIWF; BYTE bSlotID,bHdlcDlciType,bAtmDlciType; WORD wOldAtmPort,wAtmDlci,wHdlcPort,wHdlcDlci; DWORD dwMapMode,dwCIR,dwBe; DWORD dwCCID,dwResult,dwAtmPort; wTotalNetIWF=g_MuxData.SevDataSize.wFrNetExtIWFNum; ...}DWORDRestoreFrHdlcIntIWFData(WORDwSlotID,BYTE*pReadPoint){ WORD wCount,wTotalHdlcIWF; DWORD dwCCID,dwPeerCCID,dwAtmPort,dwPeerAtmPort; DWORD dwResult; BYTE bSlotID,bPeerSlotID; WORD wHdlcPort,wOldAtmPort,wCIR; WORD wPeerHdlcPort,wPeerOldAtmPort;...}其中涉及DLCI值變量都為WORD(即無符號短整型)類型,在程序解決時,浮現(xiàn)WORD和DWORD(無符號長整型)類型在一句中同步存在狀況,至此可以判斷問題出在這里。由于DLCI值在不同類型時取值范疇不同,前三種類型取值范疇為16~991,第四種取值范疇為2048~126975,第五種取值范疇為131072~4194303,因此當采用前三種DLCI類型時,采用WORD類型最大值為65535,已經(jīng)完全夠用了;而對于第四種類型時,其取值在超過65535時,獲取DLCI值函數(shù)_GetFrDlci()采用DWORD類型,而負責保存和恢復(fù)兩個函數(shù)SaveFrNetExtIWFData()和RestoreFrNetExtIWFData(),都把DLCI值當作WORD類型進行解決,因而導致DLCI取值越界,于是程序把原本為長整型DLCI強制轉(zhuǎn)換成整型,從而導致DLCI值在恢復(fù)時,比原數(shù)據(jù)小65536。而在程序運營過程中,這些數(shù)據(jù)保存在DRAM中,程序運營直接從DRAM中獲取數(shù)據(jù),程序不會出錯;當FRI板復(fù)位或插拔后,需要從FLASH中讀取數(shù)據(jù),此時恢復(fù)函數(shù)錯誤就體現(xiàn)出來。另一種問題是為什么23/4類型DLCI數(shù)據(jù)不能恢復(fù)?這是由于對于23/4類型PVC,其DLCI取值范疇為:131072~4194303,而程序強制轉(zhuǎn)換并恢復(fù)數(shù)據(jù)最大只能是65535,因此這條PVC不能恢復(fù)。至此,DLCI數(shù)據(jù)恢復(fù)出錯因素完全找到,解決辦法是將DLCI類型改為DWORD類型。從這個案例可以看出,在程序開發(fā)中一種很低檔錯誤,將在實際工作中導致很嚴重后果。【案例1.4.2】【正文】在FRI板上建幾條FRPVC,其DLCI類型分別為:10Bit/2bytes、10bit/3bytes、16bit/3bytes、17bit/4bytes、23bit/4bytes。相應(yīng)DLCI值為:16、234、991、126975、1234567,然后保存,重起MUX,觀測PVC恢復(fù)狀況,成果DLCI值為16、234和991PVC對的恢復(fù),而DLCI=126975PVC恢復(fù)數(shù)據(jù)錯誤為61439,而DLCI=1234567PVC完全沒有恢復(fù)。對于17/4類型,DLCI=126975PVC在恢復(fù)時變成61439,依照這條線索,查找因素,發(fā)現(xiàn)126975-61439=65535,轉(zhuǎn)化二進制就是00000,也就是說在數(shù)據(jù)恢復(fù)或保存時把原數(shù)據(jù)第一種1給忽視了。此時第一種想法是:在程序解決中,把無符號長整型變量當作短整型變量解決了,為了證明這個判斷,針對17bit/4bytes類型又重新設(shè)計測試用例:(1)先建PVC,DLCI=65535,然后保存,重起MUX,觀測PVC恢復(fù)狀況,發(fā)現(xiàn)PVC可以對的恢復(fù);(2)再建PVC,DLCI=65536,然后保存,重起MUX,觀測PVC恢復(fù)狀況,此時PVC不能對的恢復(fù)。至此基本可以斷定因素就是出在這里。帶著這個目查看原代碼,發(fā)當前如下代碼中有問題:int _GetFrDlci(DWORD*dwDlci,char*str,DWORDdwDlciType,DWORDdwPortType,DWORDdwSlotID,DWORDdwPortID){DWORDtempDlci; char szArg[80]; char szLine[80]; ID LowPVCEP;DWORD dwDlciVal[5][2]= {{16,1007},{16,1007},{1024,64511}, {2048,129023},{131072,4194303}};...}typedefstructtagFrPppIntIWF{ ... WORD wHdlcPort; WORD wHdlcDlci; WORD wPeerHdlcDlci; WORD wPeerOldAtmPort; ... } SFrPppIntIWFData;DWORD SaveFrNetIntIWFData(DWORD*pdwWritePoint){ BYTE bSlotID,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.FrNetExtIWF[wCount].bSlotID =bSlotID; unSevData.FrNetExtIWF[wCount].wHdlcPort =wHdlcPort; unSevData.FrNetExtIWF[wCount].wHdlcDlci =gFrPVCEP[bSlotID][gFrPVCC[bSlotID][dwCCID].dwLoPVCEP].dwDLCI; unSevData.FrNetExtIWF[wCount].wOldAtmPort =wAtmPort; unSevData.FrNetExtIWF[wCount].wAtmDlci =gFrPVCEP[bSlotID][gFrPVCC[bSlotID][dwCCID].dwHiPVCEP].dwDLCI; unSevData.FrNetExtIWF[wCount].dwMapMode=gFrPVCC[bSlotID][dwCCID].dwMapMode;...}DWORDRestoreFrNetExtIWFData(WORDwSlotID,BYTE*pReadPoint){ WORD wCount,wTotalNetIWF; BYTE bSlotID,bHdlcDlciType,bAtmDlciType; WORD wOldAtmPort,wAtmDlci,wHdlcPort,wHdlcDlci; DWORD dwMapMode,dwCIR,dwBe; DWORD dwCCID,dwResult,dwAtmPort; wTotalNetIWF=g_MuxData.SevDataSize.wFrNetExtIWFNum; ...}DWORDRestoreFrHdlcIntIWFData(WORDwSlotID,BYTE*pReadPoint){ WORD wCount,wTotalHdlcIWF; DWORD dwCCID,dwPeerCCID,dwAtmPort,dwPeerAtmPort; DWORD dwResult; BYTE bSlotID,bPeerSlotID; WORD wHdlcPort,wOldAtmPort,wCIR; WORD wPeerHdlcPort,wPeerOldAtmPort;...}其中涉及DLCI值變量都為WORD(即無符號短整型)類型,在程序解決時,浮現(xiàn)WORD和DWORD(無符號長整型)類型在一句中同步存在狀況,至此可以判斷問題出在這里。由于DLCI值在不同類型時取值范疇不同,前三種類型取值范疇為16~991,第四種取值范疇為2048~126975,第五種取值范疇為131072~4194303,因此當采用前三種DLCI類型時,采用WORD類型最大值為65535,已經(jīng)完全夠用了;而對于第四種類型時,其取值在超過65535時,獲取DLCI值函數(shù)_GetFrDlci()采用DWORD類型,而負責保存和恢復(fù)兩個函數(shù)SaveFrNetExtIWFData()和RestoreFrNetExtIWFData(),都把DLCI值當作WORD類型進行解決,因而導致DLCI取值越界,于是程序把原本為長整型DLCI強制轉(zhuǎn)換成整型,從而導致DLCI值在恢復(fù)時,比原數(shù)據(jù)小65536。而在程序運營過程中,這些數(shù)據(jù)保存在DRAM中,程序運營直接從DRAM中獲取數(shù)據(jù),程序不會出錯;當FRI板復(fù)位或插拔后,需要從FLASH中讀取數(shù)據(jù),此時恢復(fù)函數(shù)錯誤就體現(xiàn)出來。另一種問題是為什么23/4類型DLCI數(shù)據(jù)不能恢復(fù)?這是由于對于23/4類型PVC,其DLCI取值范疇為:131072~4194303,而程序強制轉(zhuǎn)換并恢復(fù)數(shù)據(jù)最大只能是65535,因此這條PVC不能恢復(fù)。至此,DLCI數(shù)據(jù)恢復(fù)出錯因素完全找到,解決辦法是將DLCI類型改為DWORD類型。從這個案例可以看出,在程序開發(fā)中一種很低檔錯誤,將在實際工作中導致很嚴重后果。5、對的使用邏輯與&&、屏蔽&操作符【案例1.5.1】【案例描述】:由于C語言中位與比求模效率高,因而系統(tǒng)設(shè)計時,對于模128地方都改為與127,系統(tǒng)定義宏為#defineMOD128127和#defineW_MOD127(定義宏名字易引起誤解),但實際程序中還是采用求模,從而引起發(fā)送窗口欲重發(fā)和實際重發(fā)不一致,最后導致鏈路復(fù)位此類嚴重問題,曾在定位此問題時花了不少時間?!窘鉀Q過程】:解決過程如下:#defineMOD128127//隊列長128,當隊頭到128時,上其返回。#defineW_MOD127//發(fā)送窗口隊列,意義同上。在函數(shù)L2_TO_L1()中,有如下語句:linkstate_ptr->SendWin.head=(head+1)%W_MOD;這里當head=126時,SendWin.head=0,這將導致發(fā)送窗口指針和隊列窗口指針錯位,導致鏈路復(fù)位;此外,在重發(fā)函數(shù)voidINVOKE_RETRANSMISSION(_USlogic_link,_USn_r)中,有如下語句:retran_num=(LinkState[logic_link].Vs+MOD128-(_UC)n_r)%MOD128;w_head=(LinkState[logic_link].SendWin.head+W_MOD-retran_num)%W_MOD;第一種語句求欲重發(fā)消息包個數(shù),第二個語句求重發(fā)起始位置,當Vs不大于n_r時,將導致實際重發(fā)數(shù)不大于欲重發(fā)數(shù),同步導致實際起始重發(fā)位置和欲重發(fā)起始位置錯開,從而引起鏈路復(fù)位。上面三個語句應(yīng)當做如下改動:linkstate_ptr->SendWin.head=(head+1)&W_MOD;retran_num=(LinkState[logic_link].Vs+MOD128+1-(_UC)n_r)&MOD128;w_head=(LinkState[logic_link].SendWin.head+W_MOD+1-retran_num)&W_MOD;【結(jié)論】:由于鏈路通信對系統(tǒng)效率規(guī)定很高,算法采用效率最高,但位與(&)和求模(%)這小社區(qū)別,導致竟是鏈路復(fù)位這種嚴重錯誤?!舅伎寂c啟示】:對此類問題,人們在閱讀代碼或代碼審查時一定要注意,仔細一點往往能發(fā)現(xiàn)問題,但在測試中來定位這種問題,耗費時間往往更長。6、注意數(shù)據(jù)類型匹配【案例1.6.1】【案例描述】 下面通過測試中一種例子來闡明這個問題:命令DSPN7C是用來顯示NO7電路狀態(tài),其參數(shù)設(shè)備類型DID支持TUP和ISUP,參數(shù)信道號BSN支持多值輸入(最多支持32路查詢),正常狀況下該命令沒有問題。但試了非正常狀況下,問題就出來了。 1、一方面試BSN參數(shù)越界狀況,即參數(shù)BSN超過32路查詢,選了幾種數(shù)據(jù)段,問題就出來了。對于0&&300和0&&256,該命令返回成果不一致,對前者以為參數(shù)越界,對后者返回執(zhí)行成功。 2、對于參數(shù)DID,選定一種設(shè)備類型(TUP或ISUP),讓參數(shù)BSN所包括32路電路跨越TUP和ISUP,兩次成果是不一致。【解決過程】 反饋到開發(fā)人員那里,第一種問題是BAM問題,第二個問題是SM問題?!窘Y(jié)論】 1、為數(shù)據(jù)超過范疇溢出導致,int值賦值給BYTE,導致數(shù)據(jù)丟失。 2、問題產(chǎn)生是由于查詢第一種信道是TUP電路,但是卻按ISUP電路查詢。ISUP維護解決函數(shù)判斷第一種信道不是ISUP信道,以為整個PCM不是ISUP類型PCM,返回所有電路狀態(tài)為未安裝。消息解決不合理。TUP也會產(chǎn)生如此錯誤。【思考與啟示】 咱們MML命令并不是無懈可擊,許多表面上小問題,往往隱藏著代碼缺陷和錯誤。【案例1.6.2】【正文】當咱們使用PC-LINT檢查代碼時,會發(fā)現(xiàn)大量數(shù)據(jù)類型不匹配告警,大某些狀況下,這種代碼上存在問題并不會引起程序功能實現(xiàn)上錯誤,但有些狀況下,也許會產(chǎn)生嚴重問題:一、不同數(shù)據(jù)類型變量之間賦值引起問題,事實上,該類問題也可以分為幾種狀況:1、直接賦值,例如,把一種WORD型變量賦給一種INT型變量,如果WORD型變量不不大于32767,INT型變量得到就是一種負值了。【例一】一次測試過程中發(fā)現(xiàn),SDH送告警在BAM調(diào)試窗口打印出紅色提示:File(XXX),Line(XXX):Invalidalarmid,from:7,AlarmId:65463通過檢查數(shù)據(jù)發(fā)現(xiàn),并沒有ID為65463告警,分析上報數(shù)據(jù)幀,發(fā)現(xiàn)上報告警ID為B7,本來代碼中有一處強制類型轉(zhuǎn)換:sdhAlmStru.AlarmId=(WORD)RecvBuffer[iTmpLen+5];char型強制轉(zhuǎn)換成WORD型。B7就變成了FFB7,十進制就是65463。由于char是有符號型,B7第8位為1,因此轉(zhuǎn)換后為FFB7,而不是代碼作者但愿00B7,如果第8位是0,或該變量是BYTE型,轉(zhuǎn)換就不會有問題了。2、函數(shù)形參和實參不一致,事實上和第一種狀況本質(zhì)上是同樣,只是體現(xiàn)形式不太同樣,這種狀況也是代碼中經(jīng)常浮現(xiàn)問題,下面例子是測試中曾經(jīng)發(fā)現(xiàn)一種小問題:【例二】在file01中INTDebugMsgProc(charbyMsg0,charbyMsg1)函數(shù),兩個形參都是char型,而實際傳入?yún)?shù)都是BYTE型,成果函數(shù)中如下語句:PrintfE(PID_RED,"%dtickstimeout!",byMsg1);在byMsg1不不大于127時,輸出錯誤成果。二、不同數(shù)據(jù)類型之間比較操作在循環(huán)終結(jié)條件判斷中,不同類型變量比較操作是容易導致死循環(huán)錯誤地方,同步也是開發(fā)人員容易忽視地方,值得測試人員多加留意。下面兩個例子是該類錯誤兩種典型狀況:【例三】file02文獻中某函數(shù)中如下代碼,也許導致死循環(huán):......inti; WORD*pCheck=(WORD*)p; WORDwCheckSum=*pCheck; pCheck++; for(i=1;i<dwLen/2;i++) { wCheckSum^=(*pCheck); pCheck++; } //binlenhadalreadywordalignment return(wCheckSum); ......該段代碼是在DOS環(huán)境下用BC編譯,由于循環(huán)變量i是int型(2個字節(jié)),而dwLen是DWORD型(4個字節(jié)),如果dwLen不不大于65536,那么該函數(shù)就是死循環(huán)了。上面例子是不同類型變量之間直接比較操作,尚有一種狀況是函數(shù)返回值與另一不同類型變量比較,見下面例子:【例四】file03.c文獻中某函數(shù)中如下代碼, while(ftell(fp)<Part[3]) {.....} ftell返回long型,而Part是DWORD型,有符號變量和無符號變量比較,也許導致死循環(huán)。類似例子尚有諸多,類型不匹配問題尚有許各種狀況,都是代碼中隱患,有時會導致嚴重后果,需要引起足夠注重。對于該類問題,咱們可以運用PC-LINT工具對代碼進行細致檢查。7、用于控制條件轉(zhuǎn)移表達式及取值范疇與否書寫對的【案例1.7.1】【案例描述】: 在測試主機MPU板倒換功能時,如果MPU備份充分,倒換先后對處在激活狀態(tài)電路應(yīng)無影響,即不影響通話。但近期測試發(fā)現(xiàn),如果兩局通過DT板進行一號對接,MPU備份倒換卻發(fā)生斷話。詳細現(xiàn)象為:如果DT板第1個PCM系統(tǒng)電路為故障,則MPU倒換時復(fù)位該DT板,如果DT板第2個PCM系統(tǒng)電路為故障,則MPU倒換時復(fù)位下一塊DT?!窘鉀Q過程】: 據(jù)查,MPU倒換時會自動復(fù)位處在“故障”態(tài)電路,但由于計算錯誤(多加了32),錯復(fù)位了下一種PCM系統(tǒng)32路電路。【結(jié)論】: 如此嚴重問題為什么到今天才發(fā)現(xiàn)?由于咱們在實驗室中普通采用同一單板2個PCM系統(tǒng)自環(huán)進行測試,則不會在某單板上有故障和空閑電路共存,自環(huán)屏蔽了錯誤?!舅伎寂c啟示】: 自環(huán)是在測試環(huán)境下慣用一種提高效率手段,但一旦條件容許,咱們測試工作應(yīng)盡量模仿網(wǎng)上實際環(huán)境進行?!景咐?.7.2】 平時對計費功能進行測試時候,瀏覽詳細話單都是比較注意話單自身對的性,并沒有注意該命令對系統(tǒng)影響。因此當瀏覽少量話單時候,并沒有發(fā)現(xiàn)該命令異常。但是當時間跨度較大時,詳細話單數(shù)量較多,問題就浮現(xiàn)了。執(zhí)行如下命令: LSTAMA:TP=NRM,SD=1999&7&1,SA=YES; 當瀏覽了大概10萬張詳細話單后,終端與BAM連接關(guān)閉。重建連接后,發(fā)現(xiàn)話單臺命令不能執(zhí)行。觀測BAM性能,發(fā)現(xiàn)話單臺仍占有CPU50%以上運用率,闡明本來任務(wù)仍在執(zhí)行。需要關(guān)一下話單臺才干恢復(fù)正常。 重復(fù)上述環(huán)節(jié),當終端與BAM連接尚未關(guān)閉時積極斷開本次連接,成果同上。 反饋到開發(fā)人員那里,發(fā)現(xiàn)該現(xiàn)象與設(shè)計初衷是相違背。本來話單臺控制最多輸出200張話單,這是為了防止過多話單輸出顯示會增長BAM開銷,從而減少BAM性能。查看一下源代碼,問題就發(fā)現(xiàn)了。 話單臺控制最多輸出200張話單程序如下while(timeCur<=timeEnd){ timeCur+=tsOneDay;//加一天 while(fileBill.Read(&rpt,sizeof(CBillReport))== sizeof(CBillReport)) {..................... //只輸出滿足條件前200張話單 if(++wBillCount==200) { break; } }//一種文獻查詢結(jié)束}//所有文獻查詢結(jié)束 在話單輸出200張之后,程序只退出一層循環(huán),依然會從下一天話單繼續(xù)輸出,導致向MML發(fā)幀過多,導致MML和話單臺都被堵死。 修改ProcessQueryBill()函數(shù)//只輸出滿足條件前200張話單if(++wBillCount==200){ timeCur=timeEnd+tsOneDay;//退出第二層循環(huán), while(timeCur<=timeEnd) break;} 作上述修改后問題就不再浮現(xiàn)了。 某些MML命令從完畢功能來講也許是沒什么問題,但其執(zhí)行對系統(tǒng)性能影響咱們在測試時時往往給忽視了。在咱們當前BAM方案中,存在著各種終端協(xié)同工作,如果某個終端發(fā)出命令在BAM中長時間獨占著大某些系統(tǒng)資源,導致后果是嚴重。這是在設(shè)計時要避免,在測試中要注意問題?!景咐?.7.3】【正文】 在判斷模仿顧客端口與否反極性時有這樣一段程序: if((bsn>=g_wASL32StartPSN)&&(((bsn-g_wASL32StartPSN)%32)==15||((bsn-g_wASL32StartPSN)%32==16))) returnTRUE; if((bsn%16)==7||(bsn%16)==8) returnTRUE; returnFALSE; 作者本意是如果是32路顧客板(藍色字體判斷),就看端標語與否是第15和16路,如果是,就是反極性端口,返回TRUE,否則就不是,應(yīng)當返回FALSE。但代碼表達意思是:如果是32路顧客板并且端標語是15或16就返回真值,否則還要執(zhí)行下邊語句。 當端口在32路顧客板上,但端標語不是15或16時,不同32路端口起始地址g_wASL32StartPSN,會導致不同非15、16端口被誤以為是反極性端口。舉個例子,當g_wASL32StartPSN值為3000時,端標語為3000(第一塊板上第0個端口)就被以為是反極性端口,這與作者意圖完全相悖。 可以將代碼修改如下: if((bsn>=g_wASL32StartPSN) { if(((bsn-g_wASL32StartPSN)%32)==15||((bsn-g_wASL32StartPSN)%32==16))) returnTRUE; } else if((bsn%16)==7||(bsn%16)==8) returnTRUE; returnFALSE; 通過這個例子,我覺得在代碼審查時應(yīng)當留旨在判斷條件較多狀況下,每個輸入與否都能對的輸出,在單元測試、集成測試、系統(tǒng)測試時要針對邊界值設(shè)計相應(yīng)測試用例。 判斷條件較多時開發(fā)人員也應(yīng)當恰當分開寫,既使代碼更易讀,又不容易出錯。8、條件分支解決與否有漏掉【案例1.8.1】【現(xiàn)象】在接入網(wǎng)主機程序代碼審查中,發(fā)現(xiàn)dbquery.cDBQ_Init_ANType函數(shù)中如下代碼段缺少應(yīng)有條件分支,在數(shù)據(jù)異常狀況下,會產(chǎn)生較嚴重問題?!窘鉀Q過程】該錯誤比較隱蔽,當前闡明如下:Max2B1QStatTime最大記錄時間Max2B1QStatPortNum最大記錄端口數(shù)MAX_2B1Q_STAT_PSN最大記錄內(nèi)存分派數(shù)量其中:Max2B1QStatTime(最大記錄時間)和Max2B1QStatPortNum(最大記錄端口數(shù))乘積不能不不大于MAX_2B1Q_STAT_PSN程序如下://查詢數(shù)據(jù)庫,獲得Max2B1QStatTime值 directQueryCond.tupleNo=10; error_code=DB_Query(RID_OTHERS_PARA_INFO,1, (LPDBCondition)&directQueryCond, (BYTEFAR*)&tempstruct0); //查詢數(shù)據(jù)庫成功 if(error_code==DB_SUCCESS) { //tempstruct0.data是數(shù)據(jù)庫中為Max2B1QStatTime配備值 if(tempstruct0.data>MAX_2B1Q_STAT_PSN) Max2B1QStatTime=MAX_2B1Q_STAT_PSN; elseif(tempstruct0.data!=0) Max2B1QStatTime=tempstruct0.data; }//查詢數(shù)據(jù)庫,獲得Max2B1QStatPortNum值 directQueryCond.tupleNo=11; error_code=DB_Query(RID_OTHERS_PARA_INFO,1, (LPDBCondition)&directQueryCond, (BYTEFAR*)&tempstruct0); //查詢數(shù)據(jù)庫成功 if(error_code==DB_SUCCESS) { //tempstruct0.data為數(shù)據(jù)庫中為Max2B1QStatPortNum配備值,如果其缺省值和Max2B1QStatTime乘積值不不大于MAX_2B1Q_STAT_PSN話: if((tempstruct0.data*Max2B1QStatTime)>MAX_2B1Q_STAT_PSN) Max2B1QStatPortNum=MAX_2B1Q_STAT_PSN/Max2B1QStatTime;//如果在合理范疇內(nèi)且不為0話:elseif(tempstruct0.data!=0) Max2B1QStatPortNum=tempstruct0.data; }此處if-elseif分支沒有判斷值為0狀況,即數(shù)據(jù)庫為Max2B1QStatPortNum配備值為0:tempstruct0.data==0,則Max2B1QStatPortNum就為缺省值32。【結(jié)論】由于內(nèi)存限制,Max2B1QStatTime(最大記錄時間)和Max2B1QStatPortNum(最大記錄端口數(shù))乘積不能不不大于MAX_2B1Q_STAT_PSN,如果從數(shù)據(jù)庫中得到Max2B1QStatTime為MAX_2B1Q_STAT_PSN,而數(shù)據(jù)庫中最大記錄端口數(shù)正好為0,由于上述代碼沒有對tempstruct0.data==0狀況進行判斷,Max2B1QStatPortNum為缺省值32,這樣Max2B1QStatTime和Max2B1QStatPortNum乘積已經(jīng)是32倍MAX_2B1Q_STAT_PSN了,遠遠超過了設(shè)計內(nèi)存限制。導致這種錯誤因素是判斷語句對條件判斷不完整?!舅伎寂c啟示】在代碼審查時,應(yīng)當十分注意條件判斷完備性。好多問題就是由于條件判斷不完全導致。9、引用已釋放資源【案例1.9.1】【正文】 在計費測試過程中,用呼喊器進行大話務(wù)量呼喊測試。30路話路通過TUP自環(huán)呼喊此外30路話路,計費數(shù)據(jù)設(shè)定是這樣:通過計費狀況索引對主叫計費,得到詳細話單。一方面保證計費數(shù)據(jù)設(shè)定對的性,打了幾次自環(huán)電話后,查看話單正常,則開始呼喊。呼喊幾萬次后停止呼喊,取話單進行觀測。發(fā)現(xiàn)這30路每次呼喊總會浮現(xiàn)一張告警話單,別的話單正常,該告警話單相對于話路來說是隨機浮現(xiàn)。 告知開發(fā)人員后,一方面咱們再次對計費數(shù)據(jù)進行了確認。某個顧客在某次呼喊產(chǎn)生了告警話單,其上一次和下一次呼喊計費狀況都正常,兩次呼喊之間時間間隔只有幾秒鐘,排除了人為修改數(shù)據(jù)也許。開發(fā)人員以為是CCB問題,日后一查果然如此。 當中繼選線發(fā)生了同搶需要重新選線時,CCBreset_CCB_for_reseatch_called_location()就會把關(guān)于呼喊信息清掉,導致計費狀況分析失敗,產(chǎn)生計費費用為0告警話單。 改正reset_CCB_for_reseatch_called_location()中清除被叫信息代碼,重選中繼時不清除被叫顧客這某些屬性。 思考與啟示: 1、在計費測試過程中,對話單觀測很重要,不應(yīng)當放過任何一種細小疑點; 2、計費測試僅僅打幾次電話往往達不到效果,越接近顧客實際使用狀況越也許發(fā)現(xiàn)問題?!景咐?.9.2】【案例描述】在進行128模塊V5顧客CENTREX新業(yè)務(wù)測試時,偶爾遇到一種怪現(xiàn)象:對群內(nèi)一種V5ST顧客只開放MCT權(quán)限,在進行惡意呼喊追查時,有一次報惡意呼喊追查成功音只報了一半,當正要報出惡意呼喊號碼時,業(yè)務(wù)中斷重新回到通話態(tài),隨后重新追查一次,報“已申請其他新業(yè)務(wù),本次申請不成功”。惡意呼喊追查與任何新業(yè)務(wù)都不會沖突,并且此顧客也只有惡意呼喊追查有權(quán),可以必定此時程序出問題了。為了重現(xiàn),再次掛機,重新呼喊,應(yīng)用此新業(yè)務(wù),但這個現(xiàn)象始終沒有浮現(xiàn)。大概重復(fù)操作20遍,又浮現(xiàn)了一次這樣狀況,顯然程序中也許存在某種問題?!窘鉀Q過程】浮現(xiàn)這個問題后,及時與開發(fā)人員A獲得了聯(lián)系,并一起試圖重現(xiàn)這個問題,通過許多次重復(fù)操作,又浮現(xiàn)了一次這種狀況。確認問題后,A體現(xiàn)出高度責任心,立即駕調(diào)試環(huán)境,重復(fù)調(diào)測,終于在當天就逮住了狐貍尾巴:1、當顧客接聽惡意呼喊者電話,并啟動惡意呼喊追查業(yè)務(wù)后,在V5_CR_VOICETONE狀態(tài)下,只要聽MCT音顧客用脈沖方式撥任意一種數(shù)字,則及時停止送MCT音,而將顧客切換回與惡意呼喊者通話.但是程序中沒有對撥號類型作判斷,導致顧客若用音頻撥號也會作同樣解決。2、除了取消本次MCT服務(wù),將顧客切換回與惡意呼喊者通話外,如果不釋放MCT_HANDLE,由于每個模塊只有一種這樣資源,則下一次使用MCT業(yè)務(wù)顧客不能成功,由于會在申請MCT_HANDLE時失敗,V5模塊和ST模塊在這個地方解決均有問題,沒有將MCT_HANDLE釋放掉,對于V5顧客會聽新業(yè)務(wù)失敗音,對于ST顧客會聽音樂。當不斷撥測V5顧客MCT業(yè)務(wù)時,有時在聽音時,也許由于網(wǎng)板有雜音等因素(或顧客碰了話機按鍵),導致DTR收到一位號,則會及時停止本次MCT服務(wù),顧客會聽到MCT送音突然中斷,然后恢復(fù)了與惡意呼喊者通話.而下次再用MCT時,由于上面所述因素,會聽到新業(yè)務(wù)失敗音,本次失敗后,無論MCT_HANDLE分派成功與否,該顧客MCT標志都被置為1,因此在顧客掛機時,會將該模塊唯一MCT_HANDLE資源釋放掉.則后來該功能又可以正常實現(xiàn)。在追查這個問題時,開發(fā)人員A又發(fā)現(xiàn)了一種也許導致死機嚴重問題:在顧客啟動MCT服務(wù),正在聽報追查號碼MCT音時,若惡意顧客此時掛機,CCB解決中,只針對ST顧客送DISCONNECT,而對V5ST顧客送是RELEASE消息,這導致V5X收到此消息后,將該V5ST顧客cr2清除掉,V5_USER_TALBE[].cr2變?yōu)?xFFFF,這樣在V5_CR_VOICETONE超時后,程序中會檢查cr2狀態(tài)與否為HOLD,當取cr2內(nèi)容時,由于cr2已被清除,會發(fā)生指針越界GP錯誤?!窘Y(jié)論】通過調(diào)測發(fā)現(xiàn)、定位并解決問題?!舅伎寂c啟示】咱們尋常某些熟視無睹業(yè)務(wù)或按正常流程操作沒有問題業(yè)務(wù),不能保證它就一定沒有問題,要善于抓住一絲一毫異常現(xiàn)象。對于很難重現(xiàn)問題千萬不要容易放過,咱們網(wǎng)上設(shè)備所出問題諸多都是某些在實驗室難以浮現(xiàn)或很難重現(xiàn)某些問題,某些顯而易見問題普通都可消滅在實驗室,難就難在消滅某些隱藏很深問題。說誠實話,咱們產(chǎn)品尚有許多問題,需要咱們扎夯實實鍥而不舍工作。10、分派資源與否已對的釋放【案例1.10.1】【正文】在對接入網(wǎng)A產(chǎn)品網(wǎng)管軟件測試中,發(fā)現(xiàn)了一種WINDSOWS資源損耗問題:當網(wǎng)管軟件運營幾天后,WINDOWS總會浮現(xiàn)“資源不夠”告警提示。如果網(wǎng)管軟件不關(guān)掉再重新啟動話,就會浮現(xiàn)WINDOWS資源完全耗盡現(xiàn)象,最后網(wǎng)管系統(tǒng)反映很慢,無法正常工作。 從現(xiàn)象上可以判斷出,網(wǎng)管軟件存在隱蔽內(nèi)存泄露或資源不釋放問題,并且這種資源耗盡是一種緩慢過程。如何定位這個問題呢? 定位這種問題可以運用WINDOWS中一種系統(tǒng)資源監(jiān)視工具。打開Windows“附件/系統(tǒng)工具/資源狀況”,這是一種系統(tǒng)資源、顧客資源、和GDI資源實時監(jiān)視工具。 工具備了,那么如何發(fā)現(xiàn)導致不斷消耗資源特定操作呢? 一方面和開發(fā)人員共同探討,列出幾種最也許消耗資源操作和某些操作組合,這樣就縮小了監(jiān)視范疇,避免沒有范疇碰運氣,否則如大海撈針。 監(jiān)視前,一方面重新啟動WINDOWS,最佳不運營其她程序,打開“系統(tǒng)狀況”這個監(jiān)視工具,然后運營網(wǎng)管軟件,記下此時資源狀況數(shù)據(jù)。 然后針對一種可疑操作,迅速大量地重復(fù)進行。這種重復(fù)性操作可以運用QArun測試工具執(zhí)行,QArun可以記錄操作者一次操作環(huán)節(jié),然后按照設(shè)定次數(shù)重復(fù)操作。操作后,觀測此時資源狀況,并記下此時數(shù)據(jù),與操作前數(shù)據(jù)比較,如果操作先后數(shù)據(jù)數(shù)據(jù)沒有變化或變化很小,可排除此項操作,否則就可斷定此項操作會引起資源耗盡。 對其他可疑操作和操作組合重復(fù)以上過程。 通過以上環(huán)節(jié),終于找出引起資源耗盡罪魁禍首。分析相應(yīng)某些代碼,發(fā)現(xiàn)引起資源耗盡因素有:內(nèi)存泄露,畫筆和畫刷資源用完后未釋放等。【案例1.10.2】【正文】某產(chǎn)品后臺軟件版本,是用C++寫,程序員在寫代碼時,經(jīng)常在構(gòu)造函數(shù)中申請一塊內(nèi)存,而不釋放,在程序其她代碼中也經(jīng)常只管申請,不論釋放。例如:voidWarnSvr::SaveWarnData(){...... for(intm=0;m<RecordsInBuffer[EVENT_ALARM];m++) { HISTORY_FILTER_INDEX*item=
newHISTORY_FILTER_INDEX; item->Csn=Buffer[EVENT_ALARM][m].Csn;
item->Position=m
+(RecordsInHistoryFile-RecordsInBuffer[EVENT_ALARM]); //IfawarnwithacertainCsnisnotinEventFilterIndex //itisnotnecessarytobeaddedtoHistoryFilterIndex intitem_total=EventFilterIndex.GetItemsInContainer(); BOOLfind_flag=false; for(intk=0;k<item_total;k++) if(EventFilterIndex[k]->Csn==item->Csn) { find_flag=true; break; } if(find_flag) { HistoryFilterIndex.Add(item); if(HistoryFilterIndex.IsFull()) ClearIndexEntry(); }//建議在此處加上://else//deleteitem;}。有程序員以為,后臺運營環(huán)境有大量內(nèi)存,幾種字節(jié)揮霍不會導致死機等重大事故。然而,長時間合計起來,必然會導致資源緊張而浮現(xiàn)故障。事實上,這種思想是導致咱們產(chǎn)品不穩(wěn)定因素之一。咱們主機在網(wǎng)上能運營幾種月幾年,人們對內(nèi)存分派釋放較敏感,而咱們后臺產(chǎn)品往往只能正常運營幾天。這個地方不注意也是因素之一吧?!景咐?.10.3】【正文】 在進行代碼審查過程中,導致內(nèi)存泄漏代碼比較多。下面舉幾種常用內(nèi)存泄漏錯誤,供測試人員在代碼審查中參照: 1.函數(shù)有各種出口時,沒有在每個出口處對動態(tài)申請內(nèi)存進行釋放。普通在異常解決時容易浮現(xiàn)這種錯誤。下面代碼段就是這樣例子:.....pRecord=newchar[pTable->GetRecordLength()]; assert(pRecord!=NULL); if(pTable->GoTop(FALSE)!=DBIERR_NONE) return;//如果從這里返回,pRecord將得不到釋放.....pTable->Close();1 delete[]pRecord;} 2.給指針賦值時,沒有檢查指針與否為空,如果指針不為空,那么指針本來指向內(nèi)存將丟失。請看如下代碼段:.... structFileInfo*pdbffile=newstructFileInfo; pdbffile->pfileinfo=newstructffblk; pdbffile->srcname=srcRootPath; pdbffile->desname=desRootPath; pdbffile->prev=NULL; pfile=pdbffile;//賦值之前沒有檢查一下pfile與否為空,如果不為空,會導致pfile指向內(nèi)存丟失。 dbf_start_needed=FALSE; dbf_Finish=FALSE; flag_begined=TRUE; if(FALSE==Copy(TRUE)) { dbf_start_needed=TRUE; WarnMsgOut("Erroroccurswhilecopyingfilesindirectory<dbf>,tryingagain."); }} 3.持續(xù)二次內(nèi)存動態(tài)分派,在第二次分派失敗時,忘掉釋放第一次已經(jīng)申請到內(nèi)存。 .... pMsgDB_DEV=(PDBDevMsg)GetBuff(sizeof(DBDevMsg),__LINE__); if(pMsgDB_DEV==NULL) return; pMsgDBApp_To_Logic=(LPDBSelfMsg)GetBuff(sizeof(DBSelfMsg),__LINE__); if(pMsgDBApp_To_Logic==NULL) return;//此處返回導致pMsgDB_DEV指向內(nèi)存丟失 .... 4.代碼中缺少應(yīng)有條件分支解決,導致程序未執(zhí)行任何操作而退出時,也也許沒有釋放應(yīng)釋放內(nèi)存,這種狀況普通是缺少應(yīng)有else分支,或switch語句default分支沒有應(yīng)有解決。staticvoidOncePowerCmdHandle(structHT_Appmsg*msg){ ...... pPower_test_answer=(struct_oncepower_test_answer*)GetBuff(sizeof(struct_oncepower_test_answer),__LINE__); if(pPower_test_answer==NULL_PTR) return; ...... if(TSS_State[testpsn].state==TEST_DEV_BUSY|| TSS_State[testpsn].state==TEST_DEV_ERROR) {... } elseif(TSS_State[testpsn].state==TEST_DEV_IDLE) {... } //缺少else分支,也許導致pPower_test_answer得不到釋放}導致內(nèi)存泄漏狀況諸多,以上是幾種典型狀況。雖然內(nèi)存泄露普通出當前異常狀況下,畢竟給系統(tǒng)導致很大隱患,使系統(tǒng)健壯性減少。測試人員在作代碼審查時,對上述幾種狀況要特別注意。【案例1.10.4】【正文】在進行SARPDU包發(fā)收測試過程中要同步考慮幾種邊界值,即發(fā)送包大小范疇[0-Nmax],SARPDU包接受最大值Kmax,MBUF塊大小M.在實測中,將SARPDU包接受最大值設(shè)為(Kmax=B),MBUF塊長設(shè)為512(M=512B),則發(fā)送包大小對的分支取值為下限0,上限Nmax=,然后在0與之間隨機取若干值,再考慮MBUF塊長,還可增長M倍數(shù)若干選值及其附近值.以上是測試普通思路,但由于很偶爾機會選取包長,及Kmax=B,才發(fā)現(xiàn)問題.因素如下:MBUF塊長512,但塊中實際存儲數(shù)據(jù)只有500(MBUF頭上有2個長字,尾部有1個長字共12B只用于塊控制),而發(fā)送包長正好是500整數(shù)倍4,由于是整數(shù)倍,因此SAR(BT8230)從FREE鏈上摘成5個MBUF(因素從略),而SAR驅(qū)動只懂得有4個MBUF,這樣到上層顧客時,只釋放4個MBUF,從而漏掉1個MBUF,通過很短一段時間后,內(nèi)存即被耗盡.(此問題非常嚴重,由于在實際運用中,是500整數(shù)倍PDU包概率較小,但一旦浮現(xiàn)就會發(fā)生一次內(nèi)存泄漏,這樣通過若干天或若干月運營后會使系統(tǒng)崩潰)此前未發(fā)現(xiàn)此問題因素是由于本來使用緩沖塊長為2048,減去12B控制信息,實際存儲數(shù)據(jù)長度為2036.由于只考慮了2048這個值,忽視了2036,因此在選用上下限中若干值時,選用包長度是2036倍數(shù)概率就非常小,因而未發(fā)現(xiàn)該問題.由于測試中普通很難將取值范疇中所有值覆蓋全,因此在選用上下限中若干取值時要格外仔細,考慮方面盡量全,由于很有也許其中某些值就是測試邊界值.凡是涉及數(shù)字盡量選用,象該例中對的分支測試邊界為0,,512及其整數(shù)倍,500及其整數(shù)倍,12及其整數(shù)倍等值,它們是必測邊界值,而非可測可不測隨機選用所謂若干選值.【案例1.10.5】【正文】ABIS.CPP中函數(shù)rel_ABIS_CCB_conn()中,在進行消息鏈表Msg_Queue[ces]拆鏈操作時,對于相應(yīng)CCB只進行了一次拆鏈操作,即只拆除了一種節(jié)點,如果浮現(xiàn)該CCB相應(yīng)消息節(jié)點不止一種狀況就會浮現(xiàn)大量節(jié)點不能釋放問題。if(Msg_Queue[ces].msghead!=NULL_PTR)//messagebuffernotempty{//getfirstmessagerecordpMsgRecord=Msg_Queue[ces].msghead;//releasebuffer-messagesconcerningwithccb_nofor(index=0;index<MSGBUFFERNUM;index++){//這里要對pMsgRecord值進行判斷if((pMsgRecord!=
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工程施工合同補充協(xié)議模板
- 2024保險合同解除的原因
- 2024年度某玩具公司向某國外買家出口玩具產(chǎn)品的合同
- 五方土地買賣合同
- 2024裝修裝飾合同范本
- 攝影設(shè)備購買合同樣本
- 產(chǎn)品眾籌合作意向書
- 2024花生買賣合同范文
- 2024【溫室大棚建造】溫室大棚建造合同范本2
- 2024展會布置合同
- 《專利及專利申請》課件
- 中國兒童注意缺陷多動障礙(ADHD)防治指南
- 城市燃氣安全管理技術(shù)
- 兩癌的健康知識講座
- 中西方創(chuàng)世神話文化的比較
- 幼兒園戶外游戲活動設(shè)計課件精
- 2023燃氣工程分包合同正規(guī)版
- 陜西師范大學學位英語試題
- 【基于嵌入式的人體健康智能檢測系統(tǒng)設(shè)計與實現(xiàn)14000字(論文)】
- 基礎(chǔ)管理風險分級管控清單(雙體系)
- 醫(yī)學課件:臨床決策分析
評論
0/150
提交評論