内存越界的灾难
Tag C语言, 内存, 越界, on by view 3439

今天为了修复一个bug折腾了将近一天的时间,原本是计划在沙箱子项目里面添加命令行指定配置文件路径功能,结果被我发现之前留下的一个坑,但是整个发现过程花了一整下午的时间。

调试过程中发现明明传入到函数中的路径printf是正确的,可是当执行到fopen时却直接异常退出,于是gdb跟踪调试

filename_interrupt.png

调试显示传入的文件名是正常的,但是当执行到#93步时文件名很明显被截断了,这是一件非常奇怪的事情,我甚至怀疑fopen函数是不是对传入文件名长度有限制,可事实上不是这样的。因为我后来专门写了个测试代码,同样的文件名路径,fopen却是正常的。我又怀疑是不是因为文件名字符串是malloc分配的原因,测试后却也是正常的。

非常纠结,之后决定采用大段大段的砍掉无关代码的方法来更清晰的定位错误可能的位置,因为代码带多确实看着眼花缭乱。当我砍到只剩下调用config_read的时候,惊奇的发现上面内存初始化是这样的:

// alloc memory for path string    
executable = (char*)malloc(sizeof(EXE_LEN));    
memset(executable, 0, sizeof(EXE_LEN));

shit! 这儿的EXE_LEN是int型指定文件名长度的啊,也就是说sizeof(EXE_LEN)是4byte,坑爹啊。但是我后面给这个内存strncpy了73个字符组成的字符串,嗯,编译器没给我报错,然后这内存几经传递传到了fopen里面,却被莫名的修改了,呵呵,修改了活该啊,谁让我把剩下的69个字符强行放入了它不该放的地方呢。其实应该是这个字符串越界到了fopen函数所使用的内存去,被修改也是太正常不过了。

C语言编程确实需要小心谨慎,因为编译器给你的提示实在是太少,逻辑错了就会按照错的运行,结果便会是谬之千里。