我从 hp fortify 中收到了缓冲区溢出:格式化字符串警告。请问您能否告诉我一个 double 值的最大长度是多少?在以下示例中,dCode
是一个存储在 pszPref
中的双精度浮点数值。
代码:
TCHAR pszPref[64];
_stprintf(pszPref, "%f", dCode);
我想确认dCode的最大长度,无论是否带小数。
由于十进制基数通常不是浮点数的最自然表示方式,因此没有最大字符串长度:显示精确浮点数可能需要无限数量的十进制数字。
幸运的是,对于IEEE754浮点双精度,15个有效数字就足够了。如果您使用该精度编写并读回一个浮点双精度,则会得到与开始时相同的数字。(使用"%.15E"
作为printf
-样式格式化程序。)尽管C++标准不坚持double
是那种类型,但它最常见,并且对于MFC是目标的系统,它可能是。
您可以通过检查std::numeric_limits<double>::is_iec559
来进行(几乎)确定。
由于您没有为格式提供精度参数,printf
及其相关函数默认使用6位小数。
iee 754双精度浮点数的最小值为-1.7976931348623157E+308
要以6位小数的精度打印该数字,您需要一个字符用于符号,一个字符用于小数点,308个字符用于整数部分和6个小数位,总共316个字符。不要忘记为空终止符分配额外的字符。因此,一个317个字符的数组应该足够,但只有在使用iee 754时才能保证,这在c++标准中是不保证的。
hp fortify可能不知道这一点,而且不能安全地假设iee 754,因此无论您使用多大的数组,都可能无法摆脱警告。为确保不会发生溢出,请使用snprintf
或类似函数,允许传递缓冲区大小。
无论目标缓冲区实际有多大,只要使用未限定的 CRT 字符串输出方法(sprintf
、strcpy
、strcat
等),Fortify 就会产生警告。近年来,Microsoft 已经为所有这些方法制作了“安全”版本,这些版本具有 _s
扩展名,例如 _stprintf_s
。
与截断版本(snprintf
等)相比,这些方法改进了在溢出发生时调用 error handler 的方式。截断方法不会溢出缓冲区,但它们理论上可以用于制作一些无效的缓冲区内容,从而导致连锁错误,可能被黑客用作攻击向量。
因此,为了保护您的代码并消除 Fortify 的警告:
使用回调方法处理溢出错误,调用 _set_invalid_parameter_handler
(stdlib.h
)。
使用 _stprintf_s(pszPref, sizeof(pszPref)/sizeof(pszPref[0]), "%f", dCode)
。
_stprintf_s
函数期望缓冲区大小以字符数为单位,而不是字节数。由于 Windows 使用 UTF-16(并且项目通常定义了 UNICODE
),因此您创建了您试图解决的缓冲区溢出问题。相反,使用函数模板,可以推断出缓冲区大小:_stprintf_s(pszPref, _T("%f"), dCode);
。 - IInspectablestd::string strPref = std::to_string(dCode);
snprintf
来避免任何缓冲区溢出的可能性。 - M.M