malloc之后的访问冲突

时间:2015-10-28 14:23:00

标签: c malloc access-violation

有人可以帮我理解以下行为:

我有一小段用于克隆浮动图像的代码。 方法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

6 个答案:

答案 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)

我想如果你检查了范围,widthheight是合理的(所以你不会溢出),最好的做法是尝试使用valgrid。这样你就可以看到在此之前你是否有一些内存错误可能导致malloc行为不端,或者如果你实际上有一个不够大的内存块

答案 3 :(得分:1)

你不能说出你的目标平台是什么,但是这个:

int s = width * height;
如果width * height产生的数字大于MAX_INT

会导致溢出。 C标准只需要签名int即可存储最多+32767。

您的目标平台可能使用更大的整数,特别是如果它是桌面操作系统,但它仍然是不好的做法。

此外,您的函数签名允许将负值作为宽度或高度传递,但您的代码不能处理这种可能性。

编辑:总之,使用更合适的类型。 widthheight 可能unsigned int。如果是,则si应为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。