C语言 在我的代码中是否有“释放后堆使用”?

lb3vh1jj  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(112)

我在C中有一个结构体,它模仿哈希表,除了它是一个链表数组。
数组的长度由hash_length预先确定,并设置为2^hash_length
我的函数在这里应该释放所有由其各自的ht_create函数分配的内存。通过循环链表数组,释放其所有节点,然后释放数组,然后释放哈希表本身。
然而,通过运行这段代码,我遇到了一个免费后堆使用。我相信问题在于我写函数本身的方式,但我似乎无法查明错误。我不确定这是否是足够的信息来确定一个问题,让我知道如果需要进一步澄清。

void ht_destroy(struct hashtable *ht) {
    for(int i = 0; i < my_exp(2,ht->hash_length); ++i) {
        struct llist *lst = &ht->list[i];
        struct llnode *curnode = lst->front;
        struct llnode *nextnode = NULL;
        while (curnode) {
            nextnode = curnode->next;
            free(curnode->str);
            free(curnode);
            curnode = nextnode;
        }
        free(&ht->list[i]);
    }
    free(ht->list);
    free(ht);
}

这应该是一个最小的可重复示例,它只是使用ht_create创建一个哈希表,然后使用ht_destroy释放内存

// my_exp(a,b): raises a to the bth power.
// Requires: b >= 0
int my_exp(int a, int b) {
  if (b == 0) {
    return 1;
  }
  int tot = a;
  for (int i = 1; i < b; ++i) {
    tot *= a;
  }

  return tot;
}

struct llnode {
  char *str;
  struct llnode *next;
};

struct llist {
  struct llnode *front;
};

struct hashtable {
  int hash_length;
  struct llist *list;
};

struct hashtable *ht_create(int hash_length) {

  struct hashtable *ht = malloc(sizeof(struct hashtable));

  ht->list = malloc(my_exp(2,hash_length) * sizeof(struct llist));
  ht->hash_length = hash_length;

  for(int i = 0; i < my_exp(2,hash_length); ++i ){
    (ht->list)[i].front = NULL;
  }
  return ht;
}

void ht_destroy(struct hashtable *ht) {
  for(int i = 0; i < my_exp(2,ht->hash_length); ++i) {
      struct llist *lst = &ht->list[i];
      struct llnode *curnode = lst->front;
      struct llnode *nextnode = NULL;
      while (curnode) {
        nextnode = curnode->next;
        free(curnode->str);
        free(curnode);
        curnode = nextnode;
      }
  free(&ht->list[i]);
  }
free(ht->list);
free(ht);
}

int main(void) {
struct hashtable *ht = ht_create(2);
ht_destroy(ht);
}
68bkxrlz

68bkxrlz1#

这一行导致了未定义的行为:

free(&ht->list[i]);

ht->list[i]是一个数组元素。数组ht->list是动态分配的,但它的各个元素的地址不是,所以你不能释放它们。动态分配的元素在从ht->list[i].head到达的链表中,你在while循环中释放了它们。
“use after free”是因为&ht->list[0]等价于ht->list,所以for循环的第一次迭代释放了整个数组,然后后续的迭代尝试使用该释放数组的元素。然后你再尝试使用free(ht->list)释放它。
删除上面的行。

相关问题