C++11中3个及以上整数乘法溢出规避问题咨询
关于C++11代码中整数溢出检查的分析与优化
嘿,我来帮你捋捋这段用CodeSonar测试的C++11代码里的整数溢出检查问题——先把你的代码和宏片段清晰呈现,再一步步拆解潜在问题和优化方向:
你的代码片段
int weights_size = c * n * size * size; int weights_memory_size = weights_size * sizeof(float); if (IS_OVERFLOW_6(weights_memory_size, c, n, size, size, (int)sizeof(float))) { overflow_error(); } l.weights = (float*) calloc(weights_size, sizeof(float));
你的整数溢出检查宏(片段)
#define IS_OVERFLOW_6(multipliedVal, val1, val2, val3, val4, val5) \ (((val1) > 0) && ((val2) > 0) &&...
现有实现的几个潜在问题
- 检查时机太滞后:你先计算了
weights_size和weights_memory_size,再调用溢出检查宏,但这两个变量的计算过程已经可能触发整数溢出了——而C++里整数溢出属于未定义行为,这意味着错误的计算结果已经产生,甚至会被CodeSonar标记为高危告警。 - 类型匹配有隐患:你把
sizeof(float)强制转成int,虽然大部分平台上sizeof(float)是4没问题,但特殊平台下可能出问题;另外,如果c、n、size是size_t这类更大的整数类型,宏里的int检查逻辑会直接失效。 - 宏的逻辑不完整:从你给出的片段看,宏只做了正数检查,但完全没验证相乘过程中是否会溢出——正确的溢出检查应该在每一步相乘前就验证,而不是等结果算出来再事后诸葛亮。
优化建议
- 提前分步检查,规避未定义行为
不要先算结果再检查,而是每一步相乘前都验证是否会溢出,同时把变量换成size_t(更适合内存相关计算,避免int的范围限制):
size_t weights_size = 1; // 分步验证每一步相乘的溢出 if (static_cast<size_t>(c) > SIZE_MAX / static_cast<size_t>(n)) { overflow_error(); } weights_size *= static_cast<size_t>(c); weights_size *= static_cast<size_t>(n); if (weights_size > SIZE_MAX / static_cast<size_t>(size)) { overflow_error(); } weights_size *= static_cast<size_t>(size); if (weights_size > SIZE_MAX / static_cast<size_t>(size)) { overflow_error(); } weights_size *= static_cast<size_t>(size); // 再检查内存总大小的溢出 size_t weights_memory_size = weights_size; if (weights_memory_size > SIZE_MAX / sizeof(float)) { overflow_error(); } weights_memory_size *= sizeof(float); // 分配内存时用static_cast替代C风格转换 l.weights = static_cast<float*>(calloc(weights_size, sizeof(float)));
- 把宏换成类型安全的模板函数
宏没有类型检查,很容易踩坑,建议用模板函数实现通用的乘法溢出检查:
#include <limits> template<typename T> bool is_multiplication_overflow(T a, T b, T& result) { if (b != 0 && a > std::numeric_limits<T>::max() / b) { return true; } result = a * b; return false; } // 调用示例 size_t temp, weights_size; if (is_multiplication_overflow(static_cast<size_t>(c), static_cast<size_t>(n), temp) || is_multiplication_overflow(temp, static_cast<size_t>(size), temp) || is_multiplication_overflow(temp, static_cast<size_t>(size), weights_size)) { overflow_error(); }
- 如果能升级到C++20,直接用标准库工具
C++20引入了std::numeric_limits的安全算术支持,或者std::checked_arithmetic,可以彻底避免手动写检查逻辑,比如:
#include <utility> try { size_t weights_size = std::multiplies<size_t>{}( std::multiplies<size_t>{}(static_cast<size_t>(c), static_cast<size_t>(n)), std::multiplies<size_t>{}(static_cast<size_t>(size), static_cast<size_t>(size)) ); // 内存大小检查同理 } catch (const std::overflow_error& e) { overflow_error(); }
- 统一内存相关变量的类型
calloc的两个参数都是size_t,所以把weights_size定义为size_t更合理,避免int到size_t的隐式转换可能带来的截断或溢出问题。
内容的提问来源于stack exchange,提问作者frozenca
相关产品推荐
相关产品推荐

