华为软件编程低级错误:杂项_第1页
华为软件编程低级错误:杂项_第2页
华为软件编程低级错误:杂项_第3页
华为软件编程低级错误:杂项_第4页
华为软件编程低级错误:杂项_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、HUAWEI TECHNOLOGIES CO., LTDHuawei Confidential Security Level: 2022-5-15PSSTPSST系统工程部系统工程部 CC语言软件编程规范工作组语言软件编程规范工作组公司常见软件编程低公司常见软件编程低级错误:杂项级错误:杂项HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 前言l这套材料作为编程规范的辅助材料,帮助大家理解编程规范背后的原理。这套材料作为编程规范的辅助材料,帮助大家理解编程规范背后的原理。lC和和C+语言是我司的主流编程语言,然而语言是我司的主流编程语言,然而C/

2、C+具有很多强大的语言特性,从而具有很多强大的语言特性,从而导致导致C/C+非常复杂,使得代码更容易出现非常复杂,使得代码更容易出现BUG、难以阅读和维护。、难以阅读和维护。l业界知名的编程规范都对业界知名的编程规范都对C/C+容易出现问题的语言特性进行管理。例如容易出现问题的语言特性进行管理。例如MISRA(汽车工业软件可靠性联合会)制定的(汽车工业软件可靠性联合会)制定的1998版的版的MISRAC规范指出,一些在规范指出,一些在C看看来可以接受,却存在隐患的地方有来可以接受,却存在隐患的地方有127处之多。处之多。2004版的版的MISRAC规范将针对规范将针对C语语言的规则增加到了言的

3、规则增加到了141条。条。l对于程序员来说,能工作的代码并不等于对于程序员来说,能工作的代码并不等于“好好” 代码。代码。“好好”代码的指标很多,代码的指标很多,包括可读性、可维护性、可移植性和可靠性等。出现网上问题的代码,大多数包括可读性、可维护性、可移植性和可靠性等。出现网上问题的代码,大多数是不良编程习惯引起的。不遵守编程规范的代码,往往也是最不可靠的代码。是不良编程习惯引起的。不遵守编程规范的代码,往往也是最不可靠的代码。HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 整数溢出:整数上溢(1)【问题描述问题描述】测试人员在测试流的读写时

4、,先写入42949672954294967295长度的数据, 然后写入少量数据.写入成功后,从流中取数据,coredump【问题定位问题定位】问题代码如下:int CBufferedStream:read(TString& v) if(read(nDataLen) != 0) return -1; if (if (nDataLennDataLen + m_currReadPos m_MaxDataSize) + m_currReadPos m_MaxDataSize) /* nDataLen为42949672954294967295,nDataLen + m_ currReadPosnData

5、Len + m_ currReadPos超出整数上限,成为负数,不会超出整数上限,成为负数,不会return -1return -1 */ return -1; v.assign(const Char*)m_pData+m_currReadPos, nDataLen);/* nDataLen为42949672954294967295,内存访问越界*/【纠正措施纠正措施】考虑到代码逻辑中m_currReadPos不可能大于m_MaxDataSize. 所以将加法表达式改成减法表达式,从而避免了上溢:if ( nDataLen m_MaxDataSize - m_currReadPos )if (

6、 nDataLen m_MaxDataSize - m_currReadPos )HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 整数溢出:整数上溢(2)【问题描述问题描述】代码飞检发现如下代码:m_wSerialID+;m_wSerialID+;【问题定位问题定位】当m_wSerialIDm_wSerialID等于WORD类型的最大值6553565535时,m_wSerialID+m_wSerialID+等于0 0,但0 0有特殊含义,正常的序列号不允许为有特殊含义,正常的序列号不允许为0 0。【纠正措施纠正措施】增加最小值检查,修改后代码如

7、下:m_wSerialID+;If ( MIN_SERIAL_ID m_wSerialID ) m_wSerialID = MIN_SERIAL_ID;m_wSerialID = MIN_SERIAL_ID;HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 整数溢出:整数下溢【问题描述问题描述】处理PPP用户的LCP协商报文时系统发生异常【问题定位问题定位】问题代码如下:/* 报文长度减去FSM头的长度 */ulLen -= FSM_HDRLEN ;处理过短报文时,ulLen的长度可能小于FSM_HDRLEN,减法的结果小于0。由于ulLen是无

8、符号数,结果返回了一个很大的ULONG数值。【纠正措施纠正措施】增加长度检查,修改后代码如下:If ( ulLen FSM_HDRLEN ) return VOS_ERROR; ulLen -= FSM_HDRLEN ;HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 整数溢出:使用危险函数atoi【问题描述问题描述】代码飞检发现如下代码:OutArrayParaNum = (UCHAR) OutArrayParaNum = (UCHAR) atoiatoi (const char (const char* *)TmpPara);)TmpPara

9、);return NSERR_CFG_SUCCESS;return NSERR_CFG_SUCCESS;/* 注:在父函数中判断OutArrayParaNum的值是否合法(必须在121范围内) */【问题定位问题定位】atoi函数的源代码如下: int total; /* current total,最后返回转换结果 */ . while (isdigit(c) total = 10 * total + (c - 0); /* accumulate digit */ c = (int)(unsigned char)*nptr+; /* get next char */ 在语句 total =

10、10 * total + (c - 0) 中,没有检测整数的范围,直接计算10 * total,如果输入一个超过int范围的数字,则total整数溢出,可能是任意值。可能正好在合法值范围内可能正好在合法值范围内。【纠正措施纠正措施】使用strtol代替atoi。strtol内部会检测overflow,超出范围时返回INT_MAX,并且设置全局变量errorno。【举一反三举一反三】atoi, atol, atof等函数,都不检测overflow,应该禁止使用这类函数。,应该禁止使用这类函数。HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 函数参

11、数中隐含的类型转换:长度截断【问题描述问题描述】测试PS的流程,程序异常退出; 【问题定位问题定位】在把消息长度作为函数参数函数参数传递时,函数调用过程中进行了两次隐含的类型转换(unsigned int32unsigned int16unsigned int32),导致数据被截断。 【纠正措施纠正措施】修改函数原型定义,消息长度的参数全部为unsigned int32。 HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 函数参数中隐含的类型转换:输出变量未赋值【问题描述问题描述】代码飞检发现如下代码: int iOutParaint iOutP

12、ara iRet = GetOSCCfgPara (, iOutPara, ); iRet = GetOSCCfgPara (, iOutPara, );GetOSCCfgPara的原型定义如下: GetOSCCfgPara (, GetOSCCfgPara (, UCHAR& pucOutPara,) / UCHAR& pucOutPara,) / 输出参数的类型是输出参数的类型是UCHARUCHAR【问题定位问题定位】传入的iOutPara为4个字节,编译器将iOutPara强制转换为UCHAR,在GetOSCCfgPara函数中,仅仅被赋值了1个字节,其它3个字节没有被初始化,是随机值。

13、【纠正措施纠正措施】修改代码为: UCHAR ucTmpOutPara;UCHAR ucTmpOutPara; iRet = GetOSCCfgPara (, iRet = GetOSCCfgPara (, ucTmpOutPara,ucTmpOutPara, ); ); iOutPara = ucTmpOutPara; iOutPara = ucTmpOutPara;【举一反三举一反三】产品的代码经过多年维护,中间有很多调用层次,相互传递的参数大同小异,存在很多类型不一致的参数,应使用临时变量中转一下,不要在调用下层函数时直接进行类型转换。除了消息除了消息解码外,原则上禁止对指针进行类型转换

14、。解码外,原则上禁止对指针进行类型转换。HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 函数返回值中的类型转换:整数上溢或下溢【问题描述问题描述】代码飞检发现如下代码:OutArrayParaNum = (UCHAR) atoi (const char*)TmpPara);return NSERR_CFG_SUCCESS;【问题定位问题定位】atoi的返回值是int类型,返回值可能超过255,或者是负数,不应该转换成UCAHR【纠正措施纠正措施】修改代码为:#include INT iPara = atoi(const char*)TmpPar

15、a);If ( (iPara UCHAR_MAX) | (iPara ulUserAAAID; 命令行模块命令行模块pstAuthenEnableRecord-ulUserAAAID值本来是值本来是0XFFFFFFFF ,强制转换,强制转换成成USHORT后变成后变成FFFF,到,到AAA模块判断无效值是根据模块判断无效值是根据0XFFFFFFFF来判断的,来判断的, FFFF认为是有效的,走入了错误的分支。认为是有效的,走入了错误的分支。【纠正措施纠正措施】去掉强制转换,修改代码为:stAuthenEnableReqMsg.ulCID = pstAuthenEnableRecord-ulUs

16、erAAAID;HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 默认的类型转换:【问题描述问题描述】*品牌用户,出现用户费用不足的情况下,被错误的开机。品牌用户,出现用户费用不足的情况下,被错误的开机。【问题定位问题定位】用户开机处理判断中,需要判断用户账户当前金额是否大于待扣费用。用户开机处理判断中,需要判断用户账户当前金额是否大于待扣费用。如果大于,则会进行开机处理。如果大于,则会进行开机处理。unsigned long ulNeccesaryFee; /待扣费用if (ValidAcctLeft(updBasetab_pps, False

17、) ulNeccesaryFee) 开机处理;ValidAcctLeft()函数返回为int类型数,而ulNeccesaryFee为unsigned long类型。编译器先将 ValidAcctLeft()函数返回值换为unsigned long类型,再与ulNeccesaryFee比较,则负数就变为了正数,从而导致比较错误。【纠正措施纠正措施】修改修改ulNeccesaryFeeulNeccesaryFee变量类型为变量类型为intint类型,如下:类型,如下:int ulNeccesaryFee;if (ValidAcctLeft(updBasetab_pps, False) ulNecc

18、esaryFee) 开机处理;HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 默认的类型转换:不可移植【问题描述问题描述】代码飞检发现很多产品有类似下面的代码:unsigned short usBoardNumber = xxx;long lBoardNum;lBoardNum = usBoardNumber;lBoardNum = usBoardNumber;由于usBoardNumber不可能很大,这样的代码并没有作为飞检发现的问题提出,但其实存在隐患【问题定位问题定位】将unsigned short赋值给long需要经过两次类型转换,AN

19、SI标准中没有规定多次类型转换的顺序。大多数编译器(例如VC)在高位优先填充0,即使用下面的顺序进行转换:lBoardNum = (long) (unsigned long) usBoardNumber;lBoardNum = (long) (unsigned long) usBoardNumber;个别编译器(例如BSD的一些编译器)在高位优先填充1,即使用下面的顺序进行转换:lBoardNum = (long) (signed short) usBoardNumber;lBoardNum = (long) (signed short) usBoardNumber;如果是后一种转换顺序,并且

20、正好usBoardNumber的高位为1,则首先被转换成一个负数的long,接着转换成unsigned long时就成了很大的数。【纠正措施纠正措施】既然BoardBumber永远不可能为负数,没有必要使用signed修饰,修改修改lBoardNumlBoardNum的类的类型为型为unsigned longunsigned long,并更改名字为,并更改名字为ulBoardNumulBoardNum【举一反三举一反三】尽量避免无符号数与有符号数的转换尽量避免无符号数与有符号数的转换,特别是长度不同的数值类型转换。请首先考虑设计上是否需要这种转换。HUAWEI TECHNOLOGIES CO.

21、, LTD.Huawei Confidential 类型定义冲突(1)【问题描述问题描述】研发经验案例库案例: debug-shell中设置全局变量uchar uchar g_ucPrintNeedTimeFlag为1,允许串口打印输出,但是实际上串口没有输出。【问题定位问题定位】经分析发现,g_ucPrintNeedTimeFlag的内存地址为:0 x14889bc,但查看该内存值时,发现设置的内存地址为0 x14889bf,并没有设置到相应的内存地址,相差了3个字节。在代码中搜索该变量,发现symtbl.c中有如下定义:IMPORT int g_ucPrintNeedTimeFlag;sy

22、mtbl.c中定义g_ucPrintNeedTimeFlag为int类型,编译器有时不能检查出这类冲突。【纠正措施纠正措施】修改所有的定义,统一定义为UINT32:_UINT32 g_ulPrintNeedTimeFlag = 0;HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 类型定义冲突(2)【问题描述问题描述】产品的一个新的R版本ST阶段进行补丁功能测试中发现,记录补丁状态的全局变量数组g_ucSIWFBRDPatchState的值总是被偷偷的改变了。【问题定位问题定位】 g_ucSIWFBRDPatchState在V_ADAPT.C中是

23、这样定义的:VOS_UINT8 g_ucSIWFBRDPatchStateSIWF_MAX_SLOT_NUM;该变量在PATCH_COM.C中声明是这样写的:extern VOS_UINT32 g_ucSIWFBRDPatchStateSIWF_MAX_SLOT_NUM;导致内存越界。【纠正措施纠正措施】修改所有的定义,统一定义为UINT8:HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 使用memcpy操作字符串(1)【问题描述问题描述】网上问题案例:char ParaList2MAXPARALEN = “460018884000002”,“

24、46001888400003”char tempMAXPARALEN;iParaLen = strlen(ParaList0);memcpy(temp, ParaList0, iParaLen);iParaLen = strlen(ParaList1);memcpy(temp, ParaList1, iParaLen);【问题定位问题定位】首先将“460018884000002”拷贝到temp缓冲区,这个数据使用完毕后,再将“46001888400003” 拷贝到temp,temp中的值为“460018884000032”。【纠正措施纠正措施】使用temp缓冲区以后,立刻将其数据清空。【举一反

25、三举一反三】memcpy拷贝的是无结构的内存,很多产品在函数之间传递void或char*指针,但并不传递指针长度,也不在缓冲区结尾强制添加0,最终可能使用了缓冲区结尾的垃圾数据。上面的纠正措施其实就是在字符串结尾强制添加0HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 使用memcpy操作字符串(2)【问题描述问题描述】代码飞检发现问题:char pDeviceID MAX_DEVICEID_LEN;memcpy(pDeviceID,pMsg,strlen(pMsg));【问题定位问题定位】memcpy拷贝的是无结构的内存,虽然源地址pMsg确

26、实是字符串,但memcpy不会在目标字符串的结尾添加0,导致以后应用此字符串时可能存在问题。而且拷贝strlen(pMsg))长度的内存可能会内存越界。【纠正措施纠正措施】字符串拷贝使用字符串专用的处理函数,以便维护人员理解缓冲区内存放的是字符串:strncpy ( pDeviceID, pMsg, MAX_DEVICEID_LEN-1);pDeviceID MAX_DEVICEID_LEN-1=0;HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 寄存器赋值时包含垃圾数据【问题描述问题描述】切换通道测试,单板异常复位。【问题定位问题定位】某寄存

27、器的1115位表示通道号,代码如下:#define OFFSET_OF_RX_PORT 11uwRegData = ReadRegFPGA(FPGA_CPU_RX_HDLC_LENGTH);uwRegData = uwRegData | (ucLinkNum OFFSET_OF_RX_PORT);WriteRegFPGA(FPGA_CPU_RX_HDLC_LENGTH, uwRegData );从寄存器读出数据后,低BIT不变,高5BIT写入 (ucLinkNum OFFSET_OF_RX_PORT),但高5BIT中包含了uwRegData以前的数据。【纠正措施纠正措施】清除高5位,修改代码如

28、下:uwRegData = (uwRegData & 0 x7FF)(uwRegData & 0 x7FF) | (ucLinkNum B-C-A环式调用。HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 多线程:没有互斥就访问共享数据(1)【问题描述问题描述】系统测试案例:动态MAC绑定系统测试,端口动态绑定较多MAC时,再关闭全局动态MAC绑定功能,导致主备倒换。 【问题定位问题定位】两个任务(命令行任务和安全特性任务)同时存取数据链表时发生了冲突,内存访问越界。 【纠正措施纠正措施】 增加一个全局信号量,所有任务对DHCP安全特性的绑定数据

29、进行删除/修改/添加操作时,先获取信号量,获取失败则不允许操作【举一反三举一反三】多任务操作链表等数据结构时,一定要加上保护HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 多线程:没有互斥就访问共享数据(2)【问题描述问题描述】系统测试案例:使用脚本连续删除多个BFD实例,系统产生断言【问题定位问题定位】VTY0执行RPC操作删除数据,此时发生任务切换到BFD任务,BFD任务中的定时器访问正在删除的数据结构,产生断言【纠正措施纠正措施】在删除时设置一个标志,删除完成后去掉标志,定时器处理时检查这个标志【举一反三】我司很多产品都设计成不可抢占的任

30、务调度方式,开发人员编程时就不注意存取全局变量的互斥,认为不会发生任务切换,但间接调用系统调用的操作可能导致任务切换,如RPC/IPC/Exec_OutString等。HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 多线程:没有互斥就访问共享数据(3)【问题描述问题描述】打开浏览器多个插件实例时,有些插件实例无法显示窗口【问题定位问题定位】在每一个实例中,创建一个新线程操作窗口,但由于GUI资源是全局的,非线程安全,多线程访问导致冲突。【纠正措施纠正措施】增加互斥操作【举一反三举一反三】 GUI资源是全局变量,非线程安全,线程里面不要直接操作,

31、可以通过信号量进行互斥操作,或者发送消息到一个线程中集中操作GUI资源HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 多线程:预料外的运行次序(1)【问题描述问题描述】某线程结束时,程序随机coredump。【问题定位问题定位】查看coredump产生的core文件,发现在定时器线程中引用了非法指针。某线程创建定时器线程时,将pTimer对象作为参数传入子线程。某线程结束时,删除了pTimer对象,但定时器子线程还在继续使用pTimer对象。【纠正措施纠正措施】某线程先调用pthread_join(TimerThread, ),等待定时器子线程

32、结束后,再删除pTimer对象。【举一反三举一反三】线程结束删除资源时,必须考虑资源是否被其它线程使用。实际环境中经常出现预料外的多线程运行次序,不能想当然,最好使用专门函数同步线程之间的状态。HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 多线程:预料外的运行次序(2)【问题描述问题描述】系统长时间无人操作,突然Coredump。【问题定位问题定位】分析堆栈发现是一个对象的虚函数指针为空造成的。const RWDBBufferFactory& RWDBInserterImp:bufferFactory ( ) const static RWD

33、BGenericBufferFactory genericBufferFactory; return genericBufferFactory;函数内部的static变量只在第一次调用时候才初始化。第一个线程打上标记,然后初始化静态变量,在初始化静态变量完成前切换到第二个线程,第二个线程发现存在这个标记,认为静态变量已经完成初始化,从而引用了未初始化的虚函数表地址。【纠正措施纠正措施】模块加载时,强制初始化这些内部静态变量。【举一反三举一反三】静态对象不能有复杂的初始化操作,这样会导致线程风险剧增HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential

34、多进程:父进程无法彻底释放资源【问题描述问题描述】在运行状态下修改配置的网络监听端口后,新端口可以处于listen状态,但原配置端口没有被关闭,仍处于listen状态。【问题定位问题定位】产品运行一段时间会fork一些子进程,然后使用exec系列函数执行业务进程。但fork的子进程默认继承了父进程打开的文件和socket等描述符,导致修改配置后,主进程无法彻底关闭打开的socket。【纠正措施纠正措施】创建子进程后,子进程立刻关闭父进程的socekt、管道、打开的文件等资源。【举一反三举一反三】子进程如果不需要父进程的资源(打开的文件、socket、管道、数据库连接),必须立刻关闭。HUAWE

35、I TECHNOLOGIES CO., LTD.Huawei Confidential 重复释放内存【问题描述问题描述】在在Diameter项目组开发时,碰到了一个项目组开发时,碰到了一个core的问题,经过的问题,经过gdb跟踪,发现是在执行下面的语句(斜体表示)时出现的跟踪,发现是在执行下面的语句(斜体表示)时出现的core:IDiamTransport *pConnector = NULL;pConnector = m_pIDiamTransportManager-create(ptTCPConnector, tPeerData.connId);CDiamPeerEntity *pPee

36、rEntity = NULL;NEW(pPeerEntity, CDiamPeerEntity);DInt4 nErr = pPeerEntity-initialize(tPeerData, pConnector, this, m_pLogger, pIDiamTimer, m_pIDiamBaseStackInner, bServer); /peerEntity的初始化函数if (DIAM_SUCCESS != nErr) DELETE(pPeerEntity); if (NULL != pConnector) m_pIDiamTransportManager-destroy(pConnec

37、tor); /出现core现象 pConnector = NULL; return DIAM_FAILED;上面m_pIDiamTransportManager-destroy(pConnector)语句,在执行之前判断了pConnector是否为NULL,应该属于正常的内存释放,但这里出现了core现象,实在比较让人费解。HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential 重复释放内存(续一)【问题定位问题定位】在跟踪在跟踪pPeerEntity-initialize(tPeerData,pConnector,this,m_pLogger,pID

38、iamTimer,m_pIDiamBaseStackInner,bServer)函数的实现时,发现了下面的语句:m_pConnector = pConnector;并且CDiamPeerEntity类的析构函数中有下面的语句:if (NULL != m_pPeerManager-getTransportManager() & (NULL != m_pConnector) m_pPeerManager-getTransportManager()-destroy(m_pConnector); m_pConnector = NULL;从上面的程序段可以看到,pConnector被赋值给CDiamPeerEntity的成员变量m_pConnector,并且在CDiamPeerEntity对象被析构时,将成员m_pConnector的内存释放了。这样,就使得pConnector指向的内存空间被释放了两次:第一次:m_pPeerManager-getTrans

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论