【问题标题】:C memory management error?C内存管理错误?
【发布时间】:2010-11-25 04:41:23
【问题描述】:

这是我的 C 程序:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define FALSE 0
#define TRUE 1

typedef struct _Frag
{
  struct _Frag *next;
  char *seq;
  int x1;
  int length;
} Frag;

typedef struct _Fragment
{
  int type;
  Frag *frag_list;
} Fragment;

static void
free_frags (Fragment * frags, int len)
{
  int i;
  for (i = 0; i < len; i++)
    {
      Fragment *fragment = &frags[i];
      Frag *current = fragment->frag_list;

      while (current != NULL)
    {
      free (current->seq);
      fragment->frag_list = current->next;
      free (current);
      current = fragment->frag_list;
    }

      /* to do : free fragment */
      free (fragment);
      fragment = NULL;
    }
  free (frags);
}

int
main ()
{
  Fragment *frags = (Fragment *) malloc (10 * sizeof (Fragment));
  int i, j;
  for (i = 0; i < 10; i++)
    {
      Fragment *fragment = &frags[i];
      fragment->frag_list = (Frag *) malloc (1 * sizeof (Frag));
      Frag *frag = fragment->frag_list;
      frag->seq = malloc (6 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next = (Frag *) malloc (1 * sizeof (Frag));
      frag = frag->next;
      frag->seq = malloc (6 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next=NULL;
    }
  free_frags (frags, 10);
  return 0;
}

当我用 gdb 调试它时,错误消息是:

(gdb) run a.out 
..........................
..........................
09574000-09595000 rwxp 00000000 00:00 0          [heap]
b7e00000-b7e21000 rwxp 00000000 00:00 0 
b7e21000-b7f00000 ---p 00000000 00:00 0 
b7f2e000-b7f4b000 r-xp 00000000 08:08 298454     /usr/lib/libgcc_s.so.1
b7f4b000-b7f4c000 rwxp 0001c000 08:08 298454     /usr/lib/libgcc_s.so.1
b7f4c000-b7f4d000 rwxp 00000000 00:00 0 
b7f4d000-b808d000 r-xp 00000000 08:08 67152259   /lib/libc-2.10.1.so
b808d000-b808f000 r-xp 0013f000 08:08 67152259   /lib/libc-2.10.1.so
b808f000-b8090000 rwxp 00141000 08:08 67152259   /lib/libc-2.10.1.so
b8090000-b8094000 rwxp 00000000 00:00 0 
b80ae000-b80af000 r-xp 00000000 00:00 0          [vdso]
b80af000-b80cb000 r-xp 00000000 08:08 67152744   /lib/ld-2.10.1.so
b80cb000-b80cc000 r-xp 0001b000 08:08 67152744   /lib/ld-2.10.1.so
b80cc000-b80cd000 rwxp 0001c000 08:08 67152744   /lib/ld-2.10.1.so
bfc0f000-bfc24000 rw-p 00000000 00:00 0          [stack]

Program received signal SIGABRT, Aborted.
0xb80ae424 in __kernel_vsyscall ()
(gdb) where
#0  0xb80ae424 in __kernel_vsyscall ()
#1  0xb7f77411 in raise () from /lib/libc.so.6
#2  0xb7f78c12 in abort () from /lib/libc.so.6
#3  0xb7fb271d in __libc_message () from /lib/libc.so.6
#4  0xb7fb8581 in malloc_printerr () from /lib/libc.so.6
#5  0xb7fb9c82 in _int_free () from /lib/libc.so.6
#6  0xb7fbcd4d in free () from /lib/libc.so.6
#7  0x08048488 in free_frags (frags=0x9574008, len=10) at main.c:41
#8  0x080485b3 in main () at main.c:65
(gdb) 

valgrind 消息如下:

==2832== Memcheck, a memory error detector.
==2832== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==2832== Using LibVEX rev 1884, a library for dynamic binary translation.
==2832== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==2832== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==2832== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==2832== For more details, rerun with: -v
==2832== 
==2832== Invalid read of size 4
==2832==    at 0x8048442: free_frags (main.c:31)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b034 is 12 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid write of size 4
==2832==    at 0x8048460: free_frags (main.c:36)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b034 is 12 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid read of size 4
==2832==    at 0x8048471: free_frags (main.c:38)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b034 is 12 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid free() / delete / delete[]
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b030 is 8 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== Invalid free() / delete / delete[]
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x80484A5: free_frags (main.c:45)
==2832==    by 0x80485B2: main (main.c:66)
==2832==  Address 0x418b028 is 0 bytes inside a block of size 80 free'd
==2832==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==2832==    by 0x8048487: free_frags (main.c:42)
==2832==    by 0x80485B2: main (main.c:66)
==2832== 
==2832== ERROR SUMMARY: 55 errors from 5 contexts (suppressed: 13 from 1)
==2832== malloc/free: in use at exit: 0 bytes in 0 blocks.
==2832== malloc/free: 41 allocs, 51 frees, 520 bytes allocated.
==2832== For counts of detected errors, rerun with: -v
==2832== All heap blocks were freed -- no leaks are possible.

请帮我修复它们,谢谢。

【问题讨论】:

  • 尝试使用 Valgrind 的 Memcheck - 它会告诉你失败的地方。
  • 注意:如果你要对它们进行类型定义,那么命名你的结构绝对没有意义。它只是用一个毫无意义的名字来混淆代码,让任何人读到代码都会“嗯......我想知道这个名字是用来做什么的?”然后在找不到名字时感到困惑。是的,我在预测,但这并不意味着我错了。
  • @unwind:你错了。如果您需要在结构本身的主体中使用结构定义,那么您需要一个名称和一个 typedef。这正是他对 _Frag/Frag 结构所做的事情。
  • @unwind - 第一个结构是一个链表,所以他必须给它命名才能引用它自己。第二个,没那么多。
  • 所以 Valgrind 在你的代码中发现了很多内存错误,告诉你问题发生的确切位置。我认为您现在可以结束您的问题并开始修复您的代码。不要指望其他人会为您解决问题 - 这是您的决定。

标签: c memory-management free


【解决方案1】:

你有多个问题。

在这里,您为 5 个字符分配空间,但复制 6 个(字符串末尾的 nul 终止符也需要一个空格):

  frag->seq = malloc (5 * sizeof (char));
  strcpy (frag->seq, "55555");

同时,您从未在分配的第二个frag 中设置frag-&gt;next。您需要将其设置为NULL,以便free_frag 例程中的while 循环不会跑到杂草中。

第三个问题来了:

  /* to do : free fragment */
  free (fragment);

你释放了fragment,但它不是从malloc 收到的整个块 - 它只是你一次性分配的 10 个片段的单个块之一。后来的free(frags) 正确释放了该块,因此您只需删除该错误行。

【讨论】:

  • +1,这将其他所有人的答案合二为一。我相信它涵盖了您需要的一切。
  • 为了热爱所有神圣的事物,请使用 strdup() 来制作动态分配的字符串副本 - 这样您的第一个错误就不会再发生了。请参阅此处了解更多信息:stackoverflow.com/questions/482375/c-strdup-function
【解决方案2】:

您正在尝试释放数组的中间部分。

Fragment *fragment = &frags[i];
...
...
/* to do : free fragment */
free (fragment);
fragment = NULL;

【讨论】:

  • 顺便说一句,为什么要取指针解引用的地址?为什么不直接使用指针算术?我认为frags + i&amp;frags[i] 更清晰一点,但这只是我的观点。
  • 嗯,我个人认为&amp;frags[i]frags + i 更清晰,因为第一个显然是一个指向数组元素的指针,只需查看它即可。如果不检查其他代码行,frags + i 可能只是一个算术表达式。在我看来,理解一个表达式所需的上下文越少越好。 (想想提问者的同事,他刚刚被告知,“今天下午去修复那个错误。”)
【解决方案3】:

这些行似乎有一个Bufferoverflow

  frag->seq = malloc (5 * sizeof (char));
  strcpy (frag->seq, "55555");

因为字符串55555 还将包含一个终止零字符,该字符也会写入分配的 5 个字节之外的内存中。

您可以使用strdup() 来分配和复制字符串

  frag->seq = strdup("55555");

【讨论】:

  • 这不是他的问题(直接或间接),但确实很危险。
  • strdup() 是非标准的(除非 POSIX 对您来说足够好),但如果您的操作系统不提供,您也可以自己编写。
【解决方案4】:

您将frag_list 视为Frag 指针的链接列表,但您在创建列表时没有放入终止符。

试试这个:

int
main ()
{
  Fragment *frags = (Fragment *) malloc (10 * sizeof (Fragment));
  int i, j;
  for (i = 0; i < 10; i++)
    {
      Fragment *fragment = &frags[i];
      fragment->frag_list = (Frag *) malloc (1 * sizeof (Frag));
      Frag *frag = fragment->frag_list;
      frag->seq = malloc (5 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next = (Frag *) malloc (1 * sizeof (Frag));
      frag = frag->next;
      frag->seq = malloc (5 * sizeof (char));
      strcpy (frag->seq, "55555");
      frag->next = NULL; // <--------------------- This is what you need to do
    }
  free_frags (frags, 10);
  return 0;
}

问题是当你malloc() 一个新的内存块时,编译器和/或操作系统可能为你清空它,但更有可能它只会给你垃圾。当你尝试free() 那个垃圾时,你会崩溃。

【讨论】:

  • 我按照你说的改了,但是还是有一些错误。但你的建议是对的,我忘记了。还是谢谢你们。
【解决方案5】:

如果您打算使用 Frag.next 指针作为标记(在 free_frags() 中),那么您需要在代码中的某处将其设置为 NULL。

另外,请注意 - 您正在使用 malloc() 为 Frag.seq 分配 5 个字符,并且在该空间中复制了一个非 NULL 终止的字符串。

【讨论】:

    【解决方案6】:

    您正在引用不属于您的内存地址。这发生在 free_frags() 函数中,特别是在第 41 行,free (fragment); .

    【讨论】:

      猜你喜欢
      • 2016-04-22
      • 1970-01-01
      • 1970-01-01
      • 2011-12-20
      • 1970-01-01
      • 2010-09-06
      • 2018-12-17
      相关资源
      最近更新 更多