内存泄漏读取文件到C中的链接列表

时间:2016-08-27 12:46:42

标签: c memory-leaks valgrind

学习如何使用链接列表,我在将文件读入一个文件时遇到内存泄漏问题。

我的代码如下:

const struct dhcp_ops dhcp_exec;

struct dhcp_list {
  char mac[18];
  char ip[20];
  char name[255];
  struct dhcp_list *next;
}*conductor;

struct dhcp_ops {
  void (*clients)(struct dhcp_list **);
};

void get_clients(struct dhcp_list **buf)
{
  FILE *fp;
  char line[128];

  struct dhcp_list *ptr;
  ptr = (struct dhcp_list*)malloc(sizeof(struct dhcp_list));

  ptr->next = NULL;
  conductor = ptr;

  fp = fopen(DHCP_LEASES, "r");
  if(NULL == fp)
    return;

  char created[10];
  char mask[5];

  while(fgets(line, sizeof(line), fp) != NULL){
    ptr->next = malloc(sizeof(struct dhcp_list));
    if (ptr->next == NULL) break;

    sscanf(line, "%s %s %s %s %s\n",
        created,
        ptr->mac,
        ptr->ip,
        ptr->name,
        mask);

    ptr = ptr->next;
    ptr->next = NULL;
  }
  fclose(fp);

  *buf = conductor;
}

调用/格式化为JSON的块,用于演示。

void format_dhcp(json_object *jdhcp_array)
  {

    const struct dhcp_ops *dhcp;

    struct dhcp_list *clients = (struct dhcp_list*)malloc(sizeof(struct dhcp_list));

    dhcp = &dhcp_exec;
    dhcp->clients(&clients);

    while (clients->next != NULL) {
      printf("MAC ADDRESS: %s\n", clients->mac);

      json_object *jdhcp = json_object_new_object();

      json_object *jmac = json_object_new_string(tmp->mac);
      json_object_object_add(jdhcp, "mac", jmac);

      clients = clients->next;
    }

    struct dhcp_list *freeMe = clients;
    struct dhcp_list *holdMe = NULL;
    while(freeMe->next != NULL) {
      holdMe = freeMe->next;
      free(freeMe);
      freeMe = holdMe;
    }
    // free(clients);
 }

 const struct dhcp_ops dhcp_exec = {
   .clients       = get_clients,
 };

当我使用valgrind运行时,我收到以下错误:

==2925== HEAP SUMMARY:
==2925==     in use at exit: 2,128 bytes in 7 blocks
==2925==   total heap usage: 1,756 allocs, 1,749 frees, 357,725 bytes allocated
==2925==
==2925== 304 bytes in 1 blocks are definitely lost in loss record 2 of 3
==2925==    at 0x4C27C0F: malloc (vg_replace_malloc.c:299)
==2925==    by 0x405176: format_dhcp (collector.c:479)
==2925==    by 0x4056DF: collect_data (collector.c:637)
==2925==    by 0x4057DB: collect_and_send_data (collector.c:669)
==2925==    by 0x405E35: monitor (monitor.c:165)
==2925==    by 0x40AA05: run_collector (boot.c:115)
==2925==    by 0x40AB10: boot (boot.c:152)
==2925==    by 0x409DE1: main (socketman.c:242)
==2925==
==2925== LEAK SUMMARY:
==2925==    definitely lost: 304 bytes in 1 blocks
==2925==    indirectly lost: 0 bytes in 0 blocks
==2925==      possibly lost: 0 bytes in 0 blocks
==2925==    still reachable: 1,824 bytes in 6 blocks
==2925==         suppressed: 0 bytes in 0 blocks
==2925== Reachable blocks (those to which a pointer was found) are not shown.
==2925== To see them, rerun with: --leak-check=full --show-leak-kinds=all

我通过移动'空闲区块来测试'进入读取文件的主函数。这完美运行,没有泄漏。显然,我没有得到输出。

有人可以建议我出错的地方/我需要做些什么才能正确清理内存。

------------ EDIT已解决----------------------

根据评论和答案,我实施了更改。之后,我摆脱了丢失的字节。但是,我还有1800+可以访问。

==10669== LEAK SUMMARY:
==10669==    definitely lost: 0 bytes in 0 blocks
==10669==    indirectly lost: 0 bytes in 0 blocks
==10669==      possibly lost: 0 bytes in 0 blocks
==10669==    still reachable: 1,824 bytes in 6 blocks
==10669==         suppressed: 0 bytes in 0 blocks
==10669== Reachable blocks (those to which a pointer was found) are not shown.
==10669== To see them, rerun with: --leak-check=full --show-leak-kinds=all

事实证明,客户端总是在第一个循环之后。所以,我将freeMe结构移动到修复问题的第一个循环之上:

  void format_dhcp(json_object *jdhcp_array)
  {

    const struct dhcp_ops *dhcp;
    struct dhcp_list *clients = NULL;

    dhcp = &dhcp_exec;
    dhcp->clients(&clients);

    struct dhcp_list *freeMe = clients;

    while (clients->next != NULL) {
      printf("MAC ADDRESS: %s\n", clients->mac);

      json_object *jdhcp = json_object_new_object();

      json_object *jmac = json_object_new_string(clients->mac);
      json_object_object_add(jdhcp, "mac", jmac);

      json_object *jip = json_object_new_string(clients->ip);
      json_object_object_add(jdhcp, "ip", jip);

      json_object *jname = json_object_new_string(clients->name);
      json_object_object_add(jdhcp, "name", jname);

      json_object_array_add(jdhcp_array, jdhcp);

      clients = clients->next;
    }

    struct dhcp_list *holdMe = NULL;
    while(freeMe != NULL) {
      debug("Should be freed");
      holdMe = freeMe->next;
      free(freeMe);
      freeMe = holdMe;
    }
}

2 个答案:

答案 0 :(得分:2)

条件为freeMe->next != NULL时,不会释放最后一个元素。

18 + 20 + 255 = 293,因此“丢失的”304个字节应该是一个struct dhcp_list。 (左边11个字节应该是一个指针+填充)

请尝试使用freeMe != NULL

另请注意,他们说you shouldn't cast the result of malloc() in C

这是另一个内存泄漏:

你在行

中分配了一些内存
struct dhcp_list *clients = (struct dhcp_list*)malloc(sizeof(struct dhcp_list));

但你在dhcp->clients get_clients完全没有使用地址时抛弃了地址,struct dhcp_list *clients; 。 停止分配这样一个浪费的内存,只需进行变量声明,如

dhcp->clients

或为了使NULL无法正常工作更安全,请将其初始化为NULL并在调用函数后检查其值是否仍为{{1}}。

答案 1 :(得分:1)

问题出在format_dhcp

struct dhcp_list *clients = (struct dhcp_list*)malloc(sizeof(struct dhcp_list));
                  ^^^^^^^ here you allocate memory for clients
dhcp = &dhcp_exec;
dhcp->clients(&clients);
      ^^^^^^ here you call get_clients

get_clients你做:

ptr = (struct dhcp_list*)malloc(sizeof(struct dhcp_list));

ptr->next = NULL;
conductor = ptr;
....
*buf = conductor;
^^^^^
Now the original clients is lost and you have a leak

你永远不会在clients内使用分配给format_dhcp的内存,而是覆盖导致泄漏的get_clients中的指针。

所以结论是:不要在malloc中执行format_dhcp - 你不需要它。