一个C语言的惨痛教训
来源:互联网 发布:网络连接配置存在问题 编辑:程序博客网 时间:2024/04/29 09:53
一个c语言动态库开发的惨痛教训,作为警示,希望大家不要碰到这类问题。
背景
交代下背景,最近的一个项目,apache module开发,使用的是c语言。这个其实比较无奈,apache mod_dav.h中声明的dav_error结构体,其中一个字段就是const char *namespace,这不是鄙视C++吗?
虽然有方法可以绕过,搞成C++的,最后还是决定用c语言开发。
悲剧
悲剧就是这样发生的。
调试发现模块crash频繁,用gdb调试,结果让人迷惑,在pool上分配的地址竟然out of bound,诸如如下面的代码。
ptr = apr_psprintf(r->pool, "<lp%d:href>%s</lp%d:href>", ns, ptr, ns);
resp = apr_pcalloc(pool, sizeof(*resp));
resp->href = apr_pstrdup(pool, uri);
...
而且有时候程序crash时,发现函数的入栈参数明显有问题,参数错位。折腾了两天也没查出是什么原因。怀疑是pool被程序破坏了,但该pool上分配的其他地址都很正常,检查n+1编程序也没发现什么问题。搞的相当于郁闷。本来感到apr的内存分配系统还是挺不错的,不过现在想想,pool要是真的不小心被程序破坏了,那也是相当难以查出来的。
发现原因
按照pool破坏的思路折腾了几天,实在是没找到头绪。这个问题原因的发现还是听偶然的,就是仔细检查编译警告时,发现编译器对于apr_xxx的string系列操作函数发出警告:
warning: assignment makes pointer from integer without a cast
我算是比较粗心的,对编译错误一般不仔细看,发现这个警告要归功于我的一位可爱的同事。
当时我看到这个警告就怀疑,是不是这个原因引起的crash。阴霍的天空无疑透出了一丝光亮。
相关.h文件没有包含导致编译器不认识这些库函数,如同编译warning所显示的那样:于是c语言就会把指针cast为int。由于编译机器是64位linux,如果把分配的地址空间cast到32位的int型数据,那么对于超过4G的地址空间来讲,这个结果就是一场灾难。
通常情况,如果函数没有定义,本来在运行时会报链接错误。但是这些是库函数,所以能够正常链接。
添加头文件,重新编译运行。程序不再crash。
十年被蛇咬。马上动手把所有的编译warning都修复掉。怕了...
教训
不要忽略编译warning
编译条件要严,像函数没有声明这种情况,应该设置为error,而非warning。我们的编译框架不够严格。
- 一个C语言的惨痛教训
- jQuery的惨痛教训
- 惨痛的教训
- 使用ConcurrentLinkedQueue惨痛的教训
- 惨痛的教训改用SVN
- 代码编写的惨痛教训
- flask 404 惨痛的教训
- 使用ConcurrentLinkedQueue惨痛的教训
- 惨痛的wordpress调试教训
- 惨痛教训
- 惨痛教训
- 惨痛教训
- 惨痛教训
- 自大的cocos2dx程序员惨痛的教训
- 记录一次惨痛的升级glibc 教训
- Linux下的惨痛教训=>LTS
- [原]使用ConcurrentLinkedQueue惨痛的教训
- >/dev/null 2>&1 & 的惨痛教训
- C# 中 MongoDB 更新操作
- You have new mail in /var/spool/mail/loganalysis
- MS SQL 注入总结
- 大数问题:用字符串解决大数相加和相乘。【转】
- ASCII码表
- 一个C语言的惨痛教训
- 如何和外国人流利对话:出国英语900句 (301-600)
- Hibernate关于Session管理的openSession和getCurrentSession的理解
- iPhone开发学习笔记_剪切板的使用
- 构建Spring环境(基于spring-framework-2.5.6开发)
- IT公司的加班文化
- 如何和外国人流利对话:出国英语900句 (601-900)
- 笔试问题 一
- 使用Django的Feed生成RSS