前不久将已有c++代码从红帽5移植到ubuntu 12.4上,当修改配置文件时,发现key=value对中value左右两侧有空格时,对value的业务校验总是失败。最后时间紧迫,把所有能去掉的value左右两侧的空格都去掉,就不报错了。
今天有时间了,用valgrind检测了下可执行程序。检测出如下问题:
==8744== by 0x407534: TrimLeftRight(char*) (sdp_log.cpp:1050)
==8744== by 0x404C16: InitLog(tagSdpLog*, int, char const*) (sdp_log.cpp:95)
==8744== by 0x4076F7: main (sdp_pmf_con.cpp:48)
问题代码如下:
char *TrimLeftRight(char *szTrim) { /* 局部变量区 */ int nLen; char *pStr = NULL; /* 代码区 */ //参数检查 if(NULL == szTrim) { return NULL; } pStr = szTrim; //去掉字符串的右空格和制表符'\t'和'\n' nLen = strlen(szTrim); if(nLen <= 0) { return szTrim; } while(nLen && (' ' == szTrim[nLen - 1] || '\t' == szTrim[nLen - 1] || '\n' == szTrim[nLen - 1])) { nLen--; } szTrim[nLen] = '\0'; //去掉字符串的左空格 while(' ' == *szTrim || '\t' == *szTrim || '\n' == *szTrim) { szTrim++; } nLen = strlen(szTrim); strncpy(pStr, szTrim, nLen); pStr[nLen]= '\0'; return pStr; }
原因是目标地址的头和源地址的尾重叠了。这会破坏源地址的内容。结果很严重:
http://www.aquaphoenix.com/ref/gnu_c_library/libc_61.html
Most of these functions do not work properly if the source and destination arrays overlap. For example, if the beginning of the destination array overlaps the end of the source array, the original contents of that part of the source array may get overwritten before it is copied. Even worse, in the case of the string functions, the null character marking the end of the string may be lost, and the copy function might get stuck in a loop trashing all the memory allocated to your program.
修改下,用临时数据解决:
char *TrimLeftRight(char *szTrim) { /* 局部变量区 */ int nLen; //char *pStr = NULL; char sz_buf[2048]; /* 代码区 */ //参数检查 if(NULL == szTrim) { return NULL; } memset(sz_buf,0,sizeof(sz_buf)); strcpy(sz_buf,szTrim); char *pStr = sz_buf; //pStr = szTrim; //去掉字符串的右空格和制表符'\t'和'\n' nLen = strlen(pStr); if(nLen <= 0) { return szTrim; } while(nLen && (' ' == pStr[nLen - 1] || '\t' == pStr[nLen - 1] || '\n' == pStr[nLen - 1])) { nLen--; } pStr[nLen] = '\0'; //去掉字符串的左空格 while(' ' == *pStr || '\t' == *pStr || '\n' == *pStr) { pStr++; } //nLen = strlen(szTrim); //strncpy(pStr, szTrim, nLen); //pStr[nLen]= '\0'; strcpy(szTrim,pStr); return szTrim; }
最后用vargrind测试一切正常:
==15789== Memcheck, a memory error detector
==15789== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==15789== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==15789== Command: ./pmfc
==15789==
sdp_log.cpp:107:配置项 #日志文件的基本名,可以不配置配置错误!
命令无效,正确使用方法如下:
./pmfc -s n: 启动子进程,n表示进程序号
./pmfc -q n: 停止子进程,n表示进程序号
./pmfc -c a: 查看所有子进程状态
./pmfc -c n: 查看指定子进程状态,n表示进程序号
==15789==
==15789== HEAP SUMMARY:
==15789== in use at exit: 0 bytes in 0 blocks
==15789== total heap usage: 1 allocs, 1 frees, 568 bytes allocated
==15789==
==15789== All heap blocks were freed -- no leaks are possible
==15789==
==15789== For counts of detected and suppressed errors, rerun with: -v
==15789== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
最后一点:写完代码用内存使用检测软件测试下,会发现一些致命问题。有些linux系统会掩盖一些问题,但是健壮的程序一定需要这样的内存检测工具进行检测,把这些隐蔽的错误修正过来。工具如:valgrind