动态内存分配错误,文件打开函数fopen

3
我已经尝试使用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]

也许这能帮助有人了解程序中出错的部分?

3
一般来说,如果您在发帖时不能在上下文中发布相关的来源子集,那么您将得不到太多回复。 - Joe
为什么不在valgrind中发布它崩溃的回溯信息呢?我敢打赌,如果你得到了那个回溯信息,然后在受损内存上设置一个内存监视点(即崩溃点),它会帮助你找出问题所在。 - dbeer
你是什么意思,乔?我认为问题出在哪个区域? - user974703
除非我误解了valgrind的输出,否则@dbeer,在valgrind中根本没有崩溃? - user974703
回溯中有用的部分应该是libc之外的部分,这样人们可以看到传入libc的内容,以便确定其崩溃原因。此外,请问您是用带有调试符号的编译选项(在gcc中为-g)进行编译的吗?您的回溯看起来很像没有使用调试符号。 - dbeer
显示剩余2条评论
3个回答

4
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);,在循环中,如果您接收到的数据超过了它所能容纳的数据,就无法控制追加到此字符串中的字符数。size也可能不正确,因为您还需要为最后的nul终止符留出空间。至少要这样写:char * fullstring = malloc(sizeof(char)*filesize + 1 );但是您的循环确实需要检查是否已经超过了该缓冲区的末尾。
至于将nul终止符添加到buf中,recv调用返回您已经读取了多少字节,所以如果您已经检查了recv是否有错误,请执行buf[numbytes] = 0,但这也会有一个偏差,因为您为buf分配了10个字节,并尝试将10个字节读入其中 - 但在C中,字符串还需要为nul终止符预留空间。将buf扩大到11个字节,或者只接收9个字节。
实际上,您很多地方都有偏差,所以开始计算您需要多少字节,并且在哪里将它们放入。请记住,在C中,数组从索引0开始,一个大小为10的数组只能由索引0到9进行索引。

更改了chunk[10]的位,但没有结果。我会保留文件名,一旦我让它正常工作,就会进行错误检查。如果我知道buf不会以null结尾,那么我该如何在没有strlen的情况下添加null结尾? - user974703
谢谢,答案是我在完整字符串和块上越界了。我必须像你建议的那样增加fullstring,并正确地对每个块进行空终止。我会研究如何解决其他问题。 - user974703

2

这一行(第93行)有问题:

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

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

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

更新2: 缓冲区太小

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

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


1

嗯,在现代操作系统上应该不会有问题,但您没有检查malloc()返回的NULL值。它在哪一行崩溃并带有什么信号?


它在fopen上崩溃了,我怎么知道它崩溃的信号是什么?如果你指的是它说的Malloc-内存损坏,那就是了。 - user974703

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接