【问题标题】:malloc memory corruption, fopenmalloc 内存损坏,fopen
【发布时间】:2023-03-16 17:39:01
【问题描述】:

我尝试过使用 GDB 和 Valgrind,但我似乎无法确定问题所在。 有趣的是,程序在正常执行和 GDB 期间会崩溃,但 Valgrid 不会。

为了帮助您跟随代码,以下是程序的基本点: 通过套接字和 UDP 与服务器通信以传输文件,并处理一些基本的数据包丢失。

我不会分享服务器的代码,因为我知道问题不存在。 可能会让一些人感到困惑的一点是,我自己正在使用数字生成器来实现数据包丢失。现在它实际上并没有做任何事情,除了让程序使用另一个recvfrom。

为了引导您完成程序输出,客户端告诉服务器它想要什么文件,服务器告诉客户端它要发送的文件有多大,然后以块的形式发送(一次 10 个字符) .

输出显示发送了什么块,接收了多少个字符,以及连接的字符串是什么。

据我所知,文件传输成功了,只是我用来编写接收到的文件的 fopen 调用给我带来了麻烦。不确定这是否与我的 malloc 调用有关。

这里是源代码:

pastebin.com/Z79hvw6L

以下是 CLI 执行和 Valgrind 的输出(GDB 似乎没有提供更多信息):

注意 CLI 给出了 malloc 内存损坏错误,而 Valgrind 没有。

CLI:http://pastebin.com/qdTKMCD2

VALGRIND:http://pastebin.com/8inRygnU

感谢您的帮助!

添加了 GDB 回溯结果

======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x6b961)[0x19a961]
/lib/i386-linux-gnu/libc.so.6(+0x6e15d)[0x19d15d]
/lib/i386-linux-gnu/libc.so.6(__libc_malloc+0x63)[0x19ef53]
/lib/i386-linux-gnu/libc.so.6(+0x5c2b8)[0x18b2b8]
/lib/i386-linux-gnu/libc.so.6(fopen+0x2c)[0x18b38c]
/home/---/client[0x8048dc2]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x145e37]
/home/---/client[0x8048871]

也许这可以让某人了解错误在程序的哪个部分?

【问题讨论】:

  • 一般来说,如果您不能在帖子的上下文中发布相关的来源子集,您将不会收到很多回复。
  • 你为什么不发布它在 valgrind 中崩溃的回溯?我敢打赌,如果你得到那个回溯,然后在损坏的内存(崩溃点)上设置一个内存观察点,它会导致你遇到问题。
  • 乔是什么意思?我认为问题出在哪个区域?
  • @dbeer,除非我误解了 valgrind 输出,否则它在 valgrind 中根本不会崩溃?
  • 添加了回溯。我一直在观察我的绳子,它容纳了所有的块,结果似乎很好。它就在 fopen 崩溃。

标签: c sockets udp malloc fopen


【解决方案1】:
char chunk[10];
chunk[10] = '\0';

错了,chunk[10] 是数组的后一个。

一般来说,这样做要小心

char filename[25];
scanf("%s",filename);

如果你输入一个长文件名,你会浪费内存。使用 fgets() 会更好。您至少还想检查 scanf 是否成功,否则文件名上的以下 strlen() 无效。

第 93 行,buf[strlen(buf)-1]='\0'; 很危险,如果缓冲区还没有被 nul 终止,则不能使用 strlen,如果 buf 是空字符串,则在索引 buf[-1] 时会丢弃内存。

编辑。 您的另一个问题是 strcat(fullstring,chunk); ,如果您碰巧收到的数据超出了它可以容纳的数量,您无法控制循环停止附加到该字符串。大小也可能减一,因为您需要最后一个 nul 终止符的空间。至少让它char * fullstring = malloc(sizeof(char)*filesize + 1 ); 但是你的循环确实需要检查它是否没有超过缓冲区的末尾。

至于在 buf 中添加一个 nul 终止符,recv 调用会返回您已读取的字节数,因此如果您检查了 recv 是否有错误,请执行 buf[numbytes] = 0 ,但这也会减一,因为您已经为 buf 分配了 10 个字节,并且您也尝试将 10 个字节读入其中 - 但在 C 中,字符串也需要为 nul 终止符留出空间。使 buf 11 个字节大。或者 recv() 只有 9 个字节。

事实上,你已经偏离了很多地方,所以开始计算你需要多少字节,以及你是否在其中放入了东西。请记住,在 C 中,数组从索引 0 开始,而 10 的数组只能通过索引 0 到 9 进行索引。

【讨论】:

  • 更改了 chunk[10] 位,但没有结果。我将文件名保留原样,一旦工作正常,我将进行错误检查。如果我知道 buf 不会被空终止,我如何在没有 strlen 的情况下向它添加空终止符?
  • 谢谢,答案是我在整个字符串和块上越界了。我不得不像你建议的那样增加完整的字符串,并且正确地终止每个块。我会研究解决其他问题。
【解决方案2】:

这(第 93 行)是可疑的:

buf[strlen(buf)-1]='\0';

更新这(第 99,100 行)也是错误的:

char chunk[10];
chunk[10] = '\0';

UPDATE2:缓冲区太小

char * fullstring = malloc(sizeof(char)*filesize); // line 103
...
strcat(fullstring,chunk); // line 124

更新3: UDP不可靠。数据包的传输可能会失败(数据包可能会在发送方和接收方之间的任何地方丢弃),并且接收数据包的顺序可能与您发送它们的顺序不同。

【讨论】:

    【解决方案3】:

    好吧,这在现代操作系统上应该不是问题:es 但您不会检查 malloc() 的返回值是否为 NULL。它在哪条线路上崩溃以及使用什么信号?

    【讨论】:

    • 它在 fopen 上崩溃了,我怎么知道它崩溃的信号是什么?它说 Malloc - 内存损坏,如果这就是你的意思。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 2011-06-04
    • 1970-01-01
    相关资源
    最近更新 更多