有人可以帮我理解以下行为:
我有一小段用于克隆浮动图像的代码。
方法Clone
将指向另一个图像的指针及其尺寸作为参数。
一切都按预期工作,但有时此行clone[i] = color;
会导致访问冲突。异常的发生既不是可预测的也不是可预测的。在崩溃时检查变量表明Color color = source[i];
始终设置且有效。
malloc
如何返回错误的指针?
代码:
typedef struct
{
float r;
float g;
float b;
float a;
} Color;
Color* Clone(Color* source, int width, int height)
{
int s = width * height;
Color *clone;
clone = (Color *)malloc(s * sizeof(Color));
if (clone)
{
for (int i = 0; i < s; i++)
{
Color color = source[i];
// Sometimes app crash here: Access violation
clone[i] = color;
}
}
return clone;
}
非常感谢任何帮助。
更新
平台:Windows 64位
崩溃时变量的值:
width = 256
height = 256
s = 655536
i = 0
答案 0 :(得分:2)
此
int s = width * height;
容易出现乘法整数溢出。如果发生这种情况,您将调用未定义的行为(因为未定义有符号整数的溢出行为);通常malloc会将缓冲区分配得太短。
编辑:如果宽度或高度中的任何一个都是负数,也会发生这种未定义的溢出。
为避免这种情况,您必须检查乘法溢出。唯一可行的方法是使用无符号算法(定义了溢出行为)。
if( 0 > width
|| 0 > height
){
return ERROR_INVALID_VALUE;
}
size_t const sz_width = width;
size_t const sz_height = height;
/* ((size_t)x) != x makes use of arithmetic conversion
* rules to check for truncation by the cast */
if( sz_width != width
|| sz_height != height
){
return ERROR_TRUNCATION;
}
/* now check if the multiplication overflows */
/* size_t is unsigned, so overflow is well behaved */
size_t const sz = sz_width * sz_height;
if( (sz / sz_width) != sz_height ) {
return ERROR_OVERFLOW;
}
答案 1 :(得分:2)
我认为这段代码没有什么特别的错误。但是,如果堆之前已经损坏,malloc
确实可以返回垃圾。实际上malloc
通常是h
,当一个人发现出现了问题并且你得到了一个明确的&#34;堆腐败&#34;错误信息。
我的建议是,如果可能的话,在valgrind下运行程序,希望抓住破坏堆数据结构的真正坏人......在调用这个克隆函数之前发生的事情。
答案 2 :(得分:1)
我想如果你检查了范围,width
和height
是合理的(所以你不会溢出),最好的做法是尝试使用valgrid。这样你就可以看到在此之前你是否有一些内存错误可能导致malloc
行为不端,或者如果你实际上有一个不够大的内存块
答案 3 :(得分:1)
你不能说出你的目标平台是什么,但是这个:
int s = width * height;
如果width * height
产生的数字大于MAX_INT
,会导致溢出。 C标准只需要签名int
即可存储最多+32767。
您的目标平台可能使用更大的整数,特别是如果它是桌面操作系统,但它仍然是不好的做法。
此外,您的函数签名允许将负值作为宽度或高度传递,但您的代码不能处理这种可能性。
编辑:总之,使用更合适的类型。 width
和height
可能为unsigned int
。如果是,则s
和i
应为unsigned long
。
答案 4 :(得分:0)
malloc调用可能不是你的问题(正如@KarolyHorvath所说,尺寸不是很大)。最可能的问题是传入的source
为空或空;在尝试引用source[i]
之前,您应该检查一下。
答案 5 :(得分:0)
当您在 Visual Studio 中编译不包含 stdlib.h 的 .c 源代码(其中 malloc 定义为返回 void*)并且 Visual Studio 使用其自己的定义时,malloc 返回 int。
Visual Studio 打印:
<块引用>警告 C4013:'malloc' 未定义;假设 extern 返回 int
因此您的指针被截断为 4 个字节而不是 8 个字节。似乎只有在 .c 文件中以 x64 模式编译时才会出现此问题。
所以,解决方案是 - 只包含 stdlib.h。