目录
背景:
问题分析:
参数异常分析:
分析文件原始值:
分析数据类型转换
代码分析:
结论:
参考资料:
背景:
在Ubuntu环境下进行项目开发时,调试时程序总是进入断言错误,但是在Windows环境下,没有出现该错误。起初以为是不同编译器的容错能力不同,应该是产生断言代码兼容性较差导致,但通过仔细分析,发现之前推论较为武断,不是一个科学的问题定位方法,想当然尔。事情发展总是遵循相同规律,就像海因里希法则所指出的:一个明显错误的背后,总是一系列小的错误导致。
问题分析:
传入参数值为-2147483648,即INT32_MIN。
当参数为INT32_MIN时,进入断言。
参数异常分析:
经过逐层调用分析,发现数据从文件提取时,获取的数值已经异常。
查看从文件中获取的原始值
发现从文件中获取的信号值为:4291895296,与m_LH_Line_First_C2_asl :-2147483648不一致。
分析文件原始值:
文件中原始值为-3072000,与以上值都不匹配。
将-3072000 转化为十六进制数字为:0xFFD12000。将4291895296 转为十六进制为0xFFD12000。由此可得,m_LH_Line_First_C2_asl._0_ 信号值获取地址是正确的,但是符号位转化存在问题。
分析数据类型转换
有图可知,在Ubuntu系统中,uint32数据转化为long类型数据时,由于两种数据类型可表示范围不同,因此,出现了非预期结果。同时,在Windows系统中进行验证,由于long类型数据在Windows下占用4个字节,因此将能够获取期望结果。
浮点数 --> 整数
-
- 首先,忽略前者的小数部分
- 如果忽略后的值可以由后者表示,直接表示即可
- 如果忽略后的值超出了后者所能表示的范围,则是未定义的行为
另外,在为了提高代码的稳定性和健壮性,特别是对快平台数据解析和组装,避免使用数据类型长度不一致数据类型。对于产品代码,使用产品定义数据类型,对于工具代码,建议使用C++ 11标准类型:
代码分析:
原始错误代码
由于long 类型数据长度在不同平台下所表示范围不同,当long类型数据占用8个字节时导致有符号数据被转化为无符号结果
修改后结果:
结论:
程序在ubuntu环境下进入断言,主要由以下几个因素引起:
- 代码解析时,使用long 型变量存储int32_t类型数据,由于long 类型数据长度在不同平台下所表示范围不同,当long类型数据占用8个字节时导致有符号数据被转化为无符号数值。
- 由于int32_t类型 接收到超出范围数据时,直接使用numeric_limits<unsigned int>::min()进行赋值,出现未定义行为。
- 在fabs函数中,进行断言判断时,正好与numeric_limits<unsigned int>::min()进行比较。
以上各种情况组合到一起,从而导致了断言的发生。
因此,在调试过程中出现的问题,我们不能够想当然尔,而是应该静下来仔细分析,找到出现问题的根本原因,这才是对待产品开发应该持有的态度。
参考资料:
安全验证 - 知乎