1 现象:问题描述
2006年5月24日 21:07:16 A局点的 HTTP 进程异常退出,Monitor进程发现后拉起。业务中断三秒钟。
2006年5月25日 A局点的 HTTP 进程异常退出四次,每次业务中断3秒钟。
2 关键过程:根本原因分析
目前发现所有异常退出时,均有用户访问网站,该网站内部连接数过多,超过100个,而且都是相对URL.程序内部要相对URL转换为绝对URL,在进行内存申请时,默认最大URL个数是60,这样导致申请的内存过小,在进行内存拷贝时越界引发Core。
经走读程序文件发现如下代码行:
memcpy((char*)tmpOutRspHolder.pcData+tmpOutRspHolder.iDataSize, absuri, strlen(absuri));
注:下文将(char*)tmpOutRspHolder.pcData+tmpOutRspHolder.iDataSize视为字符串a,将absuri视为字符串b。
将上述的mempcy函数抽象为如下形式:
memcpy(a, b, strlen(b));
在字符串b超过字符串a的长度情况下,导致b拷贝给a后系统内存越界写操作,破坏了系统内存中的正常数据,并最终导致HTTP进程发生Core。
3 结论:解决方案及效果
抽象的memcpy原型如下:
void *memcpy( void *a, const void *b, sizeof(b));
在进行memcpy前要比较目的地址空间与拷贝空间大小的比较,如果目的空间的地址小于要拷贝的空间,则不进行拷贝,直接返回,表示不需要进行URL转换。
修改memcpy函数的调用为如下方式:
if (strlen(b) <= strlen(a))
{
memcpy(a,b,strlen(b));
}
else
{
return;
}
4 经验总结:预防措施和规范建议
? 编码过程中,正确使用Memcpy函数,增加对字符串的长度的判断。
? 编码环节引入错误,可以通过严格执行编程规范和代码Review有效阻止。
5 备注
6 考核点
对内存写操作
7 试题
在Linux操作系统下,以下写法安全的是:D
A:const char szTmp[] = { 'a', 'b', 'c' };
std::string sValue = szTmp;
说明:因为std::string重载的赋值操作,是从一个指定的首地址复制一段内存到自己内部,以遇到'\0'字符为结束。题中数组szTmp中不包含'\0'字符,所以从数组首地址开始读取,一定会读越界。
B:const char* const g_pszCode = "\x0D\x0A";
char* pBuffer = new char[strlen(g_pszCode)];
memcpy(pBuffer, g_pszCode, sizeof(g_pszCode));
说明:题中strlen(g_pszCode)的值是2,而sizeof(g_pszCode)的值,在32位机上是4(因为g_pszCode是指针,在32位机上,指针类型所占空间都是4个字节),将4字节的数据塞进2字节的空间,一定会写越界。
C:const char* const g_pszInfo = "Have fun!";
char szTmp[5];
strncpy(szTmp, g_pszInfo, sizeof(szTmp));
printf(szTmp);
说明:strncpy函数的原型是:
char* strncpy(char* str1, const char* str2, size_t count);
如果str2所指的字符串中的字符数大于count,str1所指的结果字符串将不以null结束。
D:const char* const g_pszInfo = "Have fun!";
char szTmp[5];
snprintf(szTmp, sizeof(szTmp), "%s\n", g_pszInfo);
printf(szTmp);
阅读(444) | 评论(0) | 转发(0) |