- 论坛徽章:
- 0
|
本帖最后由 大众推荐 于 2014-12-03 14:48 编辑
话说。。。。2年前开始写的一个服务器程序,一年前上线,跑了一整年,没有挂过,前段时间刚小得意了一下。。。
结果,3周前,悲剧了。。
在过去3周里,挂了8,9次!!!!!!
由于是跑在公网上正处于服务期的,加上很久没怎么看过那份代码。。。再加上自己近来比较忙,也懒。。。。。种种原因。。。。
反正断断续续的跟了3,4天,根本不知道是怎么回事。。。。。
而且自己记得最近没怎么改这份代码。。。
从3天前开始,实在是无法容忍了,于是乎gdb,strace什么的都用上了,虽然coredump大致定位了位置并提示是访问了非法内存,
但仔细看了该部分的代码还是没有找到具体的问题。。。。
可以肯定的是,出现问题的哪行代码是很久没改过了。。。
反复阅读了这部分代码,实在是没问题。。。而且这部分代码跑了1整年了,都没有CRASH过。。。
这不科学啊!!!!!
仔细回想,大概在1个多月前,曾经尝试优化一下HASH TABLE。。。。
于是,看了一下这部分代码,也对比了一下之前的版本。。。。还是没有发现代码有问题。。。。
不过aaaaa.c 有类似这样的一个地方:
struct A* a (void)
{
#if XXX
return aa();
#else
return bb();
#endif
}
其中,之前代码只有 aa(),其他函数也只是直接调用 aa();
而 bb()是为了测试某一样东西加而加的,
而为了这个测试,a()也是后来加的。
由于之前吃过一次亏,所以赶紧找aaaaa.h来看,果然是没有声明a(void)!!!!!
-----------------------------------------------------
背景交代完毕,
A.由于a()返回的是一个malloc()出来的内存指针。
B.我没有在头文件中声明函数的返回类型(一般不会出现这种不声明返回类型的情况,除非是。。。有时候太HIGH了,根本就不记得了。。,而自己又不是每次都会清空编译时候的WARNING)。
C.C返回的默认指针,是只有32BIT的。前面的32BIT会自动CUT掉。
D.跑的服务器是64BIT的。
于是乎,当某个时刻malloc()出来的内存地址,其前面的32BIT不全为0的时候,而系统已经CUT掉了前面的32BIT,那么剩下了的地址就肯定不是我们想要的。。。。
或者说,在linux(UBUNTU AMD 64)中,调用隐式声明的API,返回默认是一个32位的INT,而接收这个返回值的时候,会转换这个返回值为指针,并自动补齐高32BIT的值
(貌似是,如果返回值的最高位是1,则全部补0XFFFFFFFF,如果返回值的最高位为0,则全部补0)
所以,当返回的地址第31-63 BIT(不是第32BIT开始,而包括31)不全为0的时候,自动补齐得出的地址,就肯定不对。。。这个时候去访问,就挂了。。。
-----------------------------------------------------
告诫各位新人,以后写代码,千万不要偷懒。。。
1.不可不声明全局函数。特别地,当返回值是一个指针的时候,+你跑的是64位的系统的时候。。。。。
2.不可放过编译时候的任何一个warning.当然,-Wall是必须的。
|
|