一个类型转换引起的Bug
2013-03-27 17:52
441 查看
最近有个bug实在让人抓狂,仅仅是由于一个简单的类型强转导致的,这里给大家讲讲。
这是pwrite系统调用的接口说明,我们关注最后一个参数:
运行环境是CentOS x86_64,off_t的实际类型是long,8字节。程序在跑了很长一段时间后,遇到pwrite返回了-1,errno为(22: Invalid argument)。有经验的同学可能已经看出了问题:
当两个int类型相乘(即代码中的unit * length)发生溢出时,最后的结果已经产生,并截断为int类型保存在某处。这样这个被截断的错误值就赋给了offset,两者的相乘行为完全无视左值offset的类型。怎么处理好呢?只需要对其中任何一个相乘的变量做一个强转,即:
offset = (off_t)unit * length 或者 offset = unit * (off_t)length 或者 offset = (off_t)unit * (off_t)length
不过之前的代码pwrite就没有报错(但不一定就是正确):
offset = uint * sizeof(struct xxx);
因为sizeof的返回值是size_t,它的真面目是unsigned int,这里相当于换成了int * unsigned int,运算的结果被看做是一个unsigned int类型,碰巧没有越界罢了。
所以这里告诫大家,在程序里面涉及很多不同类型的参数之间转换的时候,一点要谨慎,小心。最好的建议就是别整那么多类型!
这是pwrite系统调用的接口说明,我们关注最后一个参数:
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);我们有个接口实现是:
int storage_write_meta_info(int fd, void *data, int unit) { ... off_t offset; int length; ssize_t n; lenght = sizeof(struct xxx); offset = unit * length; n = pwrite(fd, data, length, offset); ... }
运行环境是CentOS x86_64,off_t的实际类型是long,8字节。程序在跑了很长一段时间后,遇到pwrite返回了-1,errno为(22: Invalid argument)。有经验的同学可能已经看出了问题:
当两个int类型相乘(即代码中的unit * length)发生溢出时,最后的结果已经产生,并截断为int类型保存在某处。这样这个被截断的错误值就赋给了offset,两者的相乘行为完全无视左值offset的类型。怎么处理好呢?只需要对其中任何一个相乘的变量做一个强转,即:
offset = (off_t)unit * length 或者 offset = unit * (off_t)length 或者 offset = (off_t)unit * (off_t)length
不过之前的代码pwrite就没有报错(但不一定就是正确):
offset = uint * sizeof(struct xxx);
因为sizeof的返回值是size_t,它的真面目是unsigned int,这里相当于换成了int * unsigned int,运算的结果被看做是一个unsigned int类型,碰巧没有越界罢了。
所以这里告诫大家,在程序里面涉及很多不同类型的参数之间转换的时候,一点要谨慎,小心。最好的建议就是别整那么多类型!
相关文章推荐
- 一个类型转换的bug
- 一个隐式类型转换引起的重载函数二义性错误
- 一个隐式类型转换引起的重载函数二义性错误
- 一个类型转换而引起的三级事件的一些思考
- 关于NBearMapping中枚举类型转换的一个Bug
- 一个类型转换而引起的三级事件的一些思考 数据检查
- javascript入门·脚本执行的时间的四种类型(赠送一个转换的小例题)
- 更新数据库所有表的某一个指定字段 ,附加对‘将 varchar 值转换为数据类型为 int 的列时发生语法错误’处理方法
- MVC 无法将类型“System.Collections.Generic.List<AnonymousType#1>”隐式转换为“System.Collections.Generic.IList<Mvc3Modeltest.Models.Movie>”。存在一个显式转换(是否缺少强制转换?))
- 【IE6的疯狂之十二】一个display:none引起的3像素的BUG
- 一个比较愚蠢的办法,解决excel表,关于导出时间类型转换成QString的问题
- Delphi XE2 里面string 与 ansistring 转换导致kbmMW 的一个bug
- 在javascript中,如何将一个日期字符串转换成日期类型(跨浏览器)
- 创建一个Pager实现类在基于maven的ssh项目中出现无法install的解决方案(不兼容的类型: capture#1, 共 ?无法转换为long))
- 得到一个Unicode串时,可以用下列几种方法之一将它转换成char类型串
- Python-一个因浅复制和深复制引起的bug
- 一个笔试题目(实现大小端的相互转换,只针对32位的int类型)
- memcpy引起的一个bug
- javascript入门·脚本执行的时间的四种类型(赠送一个转换的小例题)
- struts2中的类型转换,从web页面传来的离散的值在后台封装成一个user对象