【问题标题】:C freeing array and elements fails with double freeC释放数组和元素失败,双释放
【发布时间】:2015-12-14 19:19:13
【问题描述】:

我是 C 新手,正在尝试使用正则表达式库。到目前为止,我已经成功构建了一个正则表达式匹配数组(字符串数组),并且我正在尝试释放这样做时使用的内存。代码在这里:

    #include "basic_curl.h"

//returns an array of strings
//the free_regex_memory should be called when regex results are no longer
//needed
char **regexme(char *_string, const char *reg_to_match, int reg_limit) {

    regex_t preg;
    size_t nmatch = 1;
    regmatch_t pmatch[1];
    int comp_ret;
    int match;
    int start;
    int end = 0;
    int match_len;
    int i;
    int string_offset = 0;

    char **matches = (char **) malloc(sizeof(char *) * reg_limit);

    for (i=0; i < reg_limit; i++) {

    comp_ret = regcomp(&preg, reg_to_match, REG_ICASE|REG_EXTENDED);
    match = regexec(&preg, &_string[string_offset], nmatch, pmatch, 0);

    if (match == 1) {
        puts("No more matches found, rest of the loop will be filled with NULLs");
        break;
    }

    else if (match == 0 ) {
        start = pmatch[0].rm_so;
        end = pmatch[0].rm_eo;

        string_offset += end;
        match_len = end - start;
        printf("%.*s\n", match_len, &_string[string_offset - match_len]);

        //use malloc to find the length and use that instead of limiting array initially
        //http://stackoverflow.com/questions/33003196/cant-copy-string-to-an-array-of-strings-in-c
        matches[i] = malloc(sizeof(char) * (match_len + 1));
        sprintf(matches[i], "%.*s" , match_len, &_string[string_offset - match_len]);

    }
    }

    return matches;
}

int free_regex_memory(char **matches_array) {

    int i = 0;
    while (matches_array[i] != NULL) {
        free(&matches_array[i]);
    }

    //why can't I do this after the above?
    //I get a crash from the below line trying to free the array itself:
    /*
       *** Error in `/home/punk/ClionProjects/curl-ex/src/regmatch': double free or corruption (fasttop): 0x0000000000603010 ***

      Program received signal SIGABRT, Aborted.
      0x00007ffff7a4af79 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
    */
    free(matches_array);

    return 0;

}

int main() {

    char **matches;
    int i =0;

    matches = regexme("0fff 1fc<a href=\"https://www.blahblahblah.com/whatever.php?xxx=r\" keaw 2eafa", 
              "(http|https)://[%/0-9a-zA-Z\\.\?=&#@:]*",
              10);

    //puts(matches[1]);

    while (matches[i] != NULL) {
        puts(matches[i]);
        i++;
    }

    free_regex_memory(matches);

    return 0;
}

基本上,上面的 regexme 函数从字符串中提取正则表达式并将它们存储到一个动态分配的字符串数组中,称为“matches”,然后从函数中返回它。这很好用。

我的问题是我现在想释放与字符串数组关联的内存,这就是 free_regex_memory() 函数的用武之地。我循环遍历数组,并释放与字符串中的每个元素关联的内存匹配数组,然后我尝试释放数组本身。我可以做一个或另一个,要么释放数组,要么释放它的元素。但是,尝试同时执行这两种操作(如上面的代码)会给我“双重释放或损坏”错误(如上面代码中的 cmets 所示)。

那是什么?我看到的所有其他 SO 问题都提到需要释放分配的数组和元素以正确释放内存,但我似乎不能这样做。我错过了什么?

顺便说一句,我是 C 的新手,我在这段代码中做了什么非常愚蠢或低效的事情吗?


编辑:这是我基于 cmets 和答案的新代码

#include "basic_curl.h"

//returns an array of strings
//the free_regex_memory should be called when regex results are no longer
//needed
char **regexme(char *_string, const char *reg_to_match, int reg_limit) {

    regex_t preg;
    size_t nmatch = 1;
    regmatch_t pmatch[1];
    int comp_ret;
    int match;
    int start;
    int end = 0;
    int match_len;
    int i;
    int string_offset = 0;

    //char **matches = (char **) malloc(sizeof(char *) * reg_limit);

    void **matches = malloc(sizeof(char *) * reg_limit);

    for (i=0; i < reg_limit; i++) {

    comp_ret = regcomp(&preg, reg_to_match, REG_ICASE|REG_EXTENDED);
    match = regexec(&preg, &_string[string_offset], nmatch, pmatch, 0);

    if (match == 1) {
        puts("No more matches found, rest of the loop will be filled with NULLs");
        break;
    }

    else if (match == 0 ) {
        start = pmatch[0].rm_so;
        end = pmatch[0].rm_eo;

        string_offset += end;
        match_len = end - start;
        printf("%.*s\n", match_len, &_string[string_offset - match_len]);

        //use malloc to find the length and use that instead of limiting array initially
        //http://stackoverflow.com/questions/33003196/cant-copy-string-to-an-array-of-strings-in-c
        matches[i] = malloc(sizeof(char) * (match_len + 1));
        sprintf(matches[i], "%.*s" , match_len, &_string[string_offset - match_len]);

    }
    }

    return matches;
}

int free_regex_memory(char **matches_array) {

    int i = 0;
    //fixed so that i'm no longer dereferencing the array element addresses and incrementing the pointer
    while (matches_array[i] != NULL) {
        free(matches_array[i]);
         i++;
    }

    //this works now
    free(matches_array);

    return 0;

}

int main() {

    char **matches;
    int i =0;

    matches = regexme("0fff 1fc<a href=\"https://www.blahblahblah.com/whatever.php?xxx=r\" keaw 2eafa", 
              "(http|https)://[%/0-9a-zA-Z\\.\?=&#@:]*",
              10);

    //puts(matches[1]);

    while (matches[i] != NULL) {
        puts(matches[i]);
        i++;
    }

    free_regex_memory(matches);

    return 0;
}

哦,这里是 basic_curl.h,以防有人想编译它:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <curl/curl.h>
#include <regex.h>
#include <sys/types.h>

struct MemWriteData {

    size_t size;
    char *memory;
};

static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userp);
char **regexme(char *_string, const char *reg_to_match, int reg_limit);
int free_regex_memory(char **matches_array);

【问题讨论】:

  • 不应该 free(&amp;matches_array[i]);free(matches_array[i]); 吗?当您使用 i == 0 执行此操作时,您正在执行您使用 free(matches_array) 尝试的操作 — 库标识的双重免费。
  • 1) 一般规则:除非您真的知道自己在做什么,否则不要施放(有时施放,有时不施放,说明您不知道)。 2)不要在C中转换malloc和朋友的结果。你没有数组,而是指向指针的指针。 4) 指针不是数组。
  • 同意matches_array[0]matches_array 是两个不同的地址,但这无关紧要,因为您将&amp;matches_array[0]matches_array 传递给free(),它们是同一个地址。您真的不希望在对free 的调用中使用&amp;。我不得不不同意接受的答案,尽管我承认我没有正式编译和运行代码(部分原因是我没有 basic_curl.h 使其可编译)。
  • 哦;我明白了——公认的答案是指出什么是错的,而不是显示什么是对的。那我就同意了。
  • @acnutch 请注意,在 C 中您应该始终检查您的返回值。但是,您的代码中似乎没有。特别是,对malloc() 的调用可能会因返回NULL 而失败。如果发生这种情况并且您继续使用返回的 NULL 指针,您可能会发现 未定义的行为 包括从“工作”到“奇怪的错误”到它只是崩溃(在 任何点)。我强烈建议您考虑一些最小的错误处理。我对 curl API 不太熟悉,但我想您也没有处理它可能出现的错误。

标签: c arrays regex memory-management memory-leaks


【解决方案1】:

你有:

int i = 0;
while (matches_array[i] != NULL) {
    free(&matches_array[i]);
}
  • 您正在释放matches_array[i] 的地址。我不相信这是故意的。
  • 你永远不会增加i

您需要与此等效的代码(使用for 循环是一个选项):

int i = 0;
while (matches_array[i] != NULL) {
    free(matches_array[i++]);
}

【讨论】:

  • 谢谢,两者都绝对正确。这解决了这个问题。我现在就去打自己的脸。
  • 好的,现在我明白你只是引用OP的代码。 Colud 你最好把它标记为引用?我拿了这个给你更正。也许您应该添加正确的代码:free(matches_array[i]) 以使您的意图更加清晰。
  • 如何将其标记为引文? 更新我相信我已经为你修好了
【解决方案2】:

更多建议 -

来自维基百科:

malloc 预留的内存未初始化,可能包含杂物:以前使用和丢弃的数据的残余

使用malloc()时,分配后清除内存块:

char **matches = (char **) malloc(sizeof(char *) * reg_limit);
memset( (char *)matches, 0, sizeof(char *) * reg_limit );

不要依赖于 matches_array 指针的硬端,使用您分配的限制:

void free_regex_memory( char **matches_array, int reg_limit )
{
    int i = 0;
    for (i = 0; i < reg_limit; i++)
    {
        if ( matches_array[i] != NULL )
           free( matches_array[i] );   // initial problem
    }
    free(matches_array);
}

Main 调用:

int main()
{
    char **matches;
    int i =0;

    /////////////////

    free_regex_memory( matches, reg_limit );
    return 0;
}

【讨论】:

  • 不要在 C 中转换 void *
  • 你在哪里看到void *
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-26
  • 1970-01-01
  • 2017-09-05
  • 1970-01-01
  • 2014-11-10
相关资源
最近更新 更多