【问题标题】:*** glibc detected *** free(): invalid next size (normal): 0x0a03c978 *** [duplicate]*** 检测到 glibc *** free():下一个大小无效(正常):0x0a03c978 *** [重复]
【发布时间】:2011-06-26 05:39:13
【问题描述】:

我正在编写一个套接字程序来下载图像。问题是当我在像 gif 这样的小图片上测试我的代码时,它工作正常。但是当我使用 JPG 图片(比 GIF 大)运行它时,我收到了错误消息:

*** glibc detected *** /home/ubuntu/NetBeansProjects/myDownloader/dist/Debug/GNU-Linux-x86/mydownloader: free(): invalid next size (normal): 0x0a03c978 ***

请查看代码,我将提供有关错误的更多信息。

FILE* pFile;
long lSize;
unsigned char* buffer;
size_t result;
FILE* combinedFile = fopen("mypic.jpg", "wb+");

for(i = 1; i <= numberOfPartitions; i++)
{
    sprintf(filename, "part%d", i);
    pFile = fopen(filename, "rb");

    //obtain file size
    fseek(pFile , 0 , SEEK_END);
    lSize = ftell(pFile);
    rewind(pFile);

    // allocate memory to contain the whole file:
    buffer = (unsigned char*) malloc(sizeof(unsigned char) * (lSize + 1));

    if(buffer == NULL)
    {
        fputs("Memory error", stderr);
        exit(2);
    }

    // copy the file into the buffer:
    result = fread(buffer, 1, lSize, pFile);

    if(result != lSize)
    {
        fputs("Reading error", stderr);
        exit(3);
    }
    else
    {
        unsigned char* temp = strstr(buffer, "\r\n\r\n");

        temp = temp + 4;
        int len = lSize - (temp - buffer);

        //printf("i :  %d len is : %d plen is %f\n",i,len,pLen);
        if(i != numberOfPartitions)
            fwrite(temp, 1, len - 1, combinedFile);
        else
            fwrite(temp, 1, len, combinedFile);
    }

    fclose(pFile);
    printf("crash here\n");
    free(buffer);

}

fclose(combinedFile);

我从这部分得到了错误,正如我所说的,当图像尺寸很小时它可以正常工作。但是更大的尺寸它坏了! P.S:程序将图片分成几个文件,然后重新组合,所以组合部分是导致错误的部分。

任何帮助将不胜感激,因为我已经被这个错误困住超过 3 天了!

【问题讨论】:

  • 唯一让我兴奋的是strstr(buffer,"\r\n\r\n");。为什么要在二进制文件中搜索(Windows 风格的)返回字符?
  • 确定通过套接字响应的标头的结尾。这是丢弃此标头并开始复制二进制数据的唯一方法。
  • 当有多个“分区”时,这些“分区”是否都包含"\r\n\r\n"序列?
  • 您好,实际上每个分区都是通过执行不同的 GET 请求生成的。因此,它们中的每一个都包含“\r\n\r\n”。当循环到达空闲(缓冲区)时完成第一次迭代时会发生问题!
  • 仅供参考,Valgrind,可能在您的发行版的包管理器中可用,是帮助处理此类事情的好工具。

标签: c linux sockets gcc


【解决方案1】:

您没有验证fopen() 调用是否全部成功;这是麻烦的秘诀。

您没有检查ftell() 是否为您在lSize 中提供了一个合理的值。

您没有验证strstr() 操作是否确实找到了标记字符串。如果不是,它将返回 NULL 并且以下长度操作是虚假的。但该错误表明您的代码写入越界,而不仅仅是读取数据越界。

您可以将前四个变量声明到循环体中,而不是在循环外。

你没有显示变量filename的声明;那可能是一个没有分配空间的char指针吗?还是一个足够大的数组?

这是一个赔率的赌注,即某些已分配空间的末尾已写入某些内容。这段代码有什么问题并不是很明显,但问题可能出在其他地方,但正是这段代码受到了其他地方违规的影响。这在内存问题中很常见;发现问题的代码不是导致问题的代码。

当您分配零字节时,您机器上的malloc() 是否返回空指针或非空指针?两者都是合法的回应。

如果ftell() 返回-1,则malloc() 将分配一个0 字节的缓冲区,但fread() 将尝试读取最多4 GB 的数据,这可能会溢出空间。 OTOH,如果ftell() 失败,fread() 很可能也会失败。

您打印出文件的大小了吗?是第二个崩溃的部分文件,还是后来的文件?


我已经获取了您提供的代码,将其包装为main() 函数,提供了缺失的变量和标头,并在 valgrind 下运行它。 (MacOS X 10.6.6, GCC 4.5.2, Valgrind 3.6.0) 显示没有问题。因此,您的问题很可能不在此代码本身;程序中较早的其他内容超出了分配的内存范围并导致此操作失败。我使用脚本生成了 4 部分文件:

{ echo "Header:control-Vcontrol-Mreturncontrol-Vcontrol-M"; dd if=/dev/random bs=1k count=4; } >part1

所以每个文件有 4107 字节长。

工作代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char filename[32];
    FILE* pFile;
    long lSize;
    char *buffer;
    ssize_t result;
    FILE* combinedFile = fopen("mypic.jpg", "wb+");
    int numberOfPartitions = 4;
    int i;

    for(i = 1; i <= numberOfPartitions; i++)
    {
        sprintf(filename, "part%d", i);
        pFile = fopen(filename, "rb");

        fseek(pFile , 0 , SEEK_END);
        lSize = ftell(pFile);
        rewind(pFile);
        printf("size(%d) = %ld\n", i, lSize);

        buffer = (char*) malloc(sizeof(char) * (lSize + 1));

        if (buffer == NULL)
        {
            fputs("Memory error", stderr);
            exit(2);
        }

        result = fread(buffer, 1, lSize, pFile);

        if (result != lSize)
        {
            fputs("Reading error", stderr);
            exit(3);
        }
        else
        {
            char* temp = strstr(buffer, "\r\n\r\n");    
            temp = temp + 4;
            int len = lSize - (temp - buffer);
            if(i != numberOfPartitions)
                fwrite(temp, 1, len - 1, combinedFile);
            else
                fwrite(temp, 1, len, combinedFile);
        }

        fclose(pFile);
        printf("crash here\n");
        free(buffer);    
    }

    fclose(combinedFile);
    return 0;
}

如果它是我自己的程序,我没有插入所有的错误检查。

我的方案中的输出文件是 16381 字节长;即短 3 个字节。那里的问题是fwrite() 电话。 fread() 代码告诉你它读取了多少字节;您减去了标头的字节,然后再减去了一个。因此,if/else 代码简化为 else 中的 fwrite()

【讨论】:

  • 嗨,所有分区的数据大小都大于 1。当我将空闲(缓冲区)移出循环时它可以工作,但在大约 17 次迭代后崩溃。当 malloc 分配零字节时,我的机器返回 null .感谢您的建议。
  • 您好,感谢您帮助修复此错误。很抱歉打扰您,但我已向您的 gmail 帐户发送了一封包含完整程序的电子邮件,以了解我的代码的其他部分是否会导致此问题。再次非常感谢您的帮助。
  • 问题不在显示的代码中;它在代码中为通过 Internet 发送的消息分配空间。将分配大小的“-6”更改为“+32”治愈了“写越界”,其他一切都神奇地工作。它泄漏了很多内存。
【解决方案2】:

实际上,我在上面的代码中找不到任何明显的内存或文件处理问题,free() 上的崩溃可能只是代码中写入 malloc() 的个人空间中的某些内容的症状。 .

您可以使用 Valgrind 等内存检查器或 gdb 等调试器来仔细查看。

唯一可能想到的错误是 buffer 不一定是 NUL 终止的,因此 strstr() 搜索可以愉快地遍历它, buffer[lSize] = '\0';在 malloc-NULL-check 之后应该解决这个问题。还要确定的是,检查 strstr() 是否确实找到了它正在寻找的内容(如果没有,则返回 NULL)。您可能还想检查所有 fopen() 调用是否实际成功(返回不为 NULL)。 如果这些都没有帮助,在 fwrite() 调用之前打印输出 len、lSize、temp 和 buffer 的值会很有帮助。

【讨论】:

  • 我试过 buffer[lSize]='\0' 但没有任何改变!!!当我将 free(buffer) 移出循环时,它工作正常,直到 20 次中的第 17 次迭代,然后它崩溃了!这意味着整个问题都在于内存分配,你不这么认为吗?
猜你喜欢
  • 1970-01-01
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 2011-04-12
  • 2016-06-16
相关资源
最近更新 更多