如何避免当前代码中的内存泄漏(C)

omvjsjqw  于 2023-04-11  发布在  其他
关注(0)|答案(2)|浏览(139)

我正在尝试创建基于C的HTML客户端。我对C内存泄漏调试很陌生,所以请参阅HTML响应解析器的(简化)代码:

//=============
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int str_index_of(const char *a, char *b) {
    char *offset = (char *) strstr(a, b);
    return offset - a;
}

char *get_until(char *haystack, char *until) {
    int offset = str_index_of(haystack, until);
    return strndup(haystack, offset);
}
char *str_replace(const char *search, const char *replace, const char *subject) {
    size_t search_size = strlen(search);
    size_t replace_size = strlen(replace);
    size_t subject_size = strlen(subject);

    // Count the number of occurrences of search in subject
    size_t count = 0;
    const char *p = subject;
    while ((p = strstr(p, search)) != NULL) {
        count++;
        p += search_size;
    }

    // Allocate memory for the new string
    size_t new_size = subject_size + count * (replace_size - search_size);
    char *new_subject = (char *) calloc(new_size + 1, sizeof(char));

    // Replace search with replace in subject
    const char *old = subject;
    char *new_p = new_subject;
    while ((p = strstr(old, search)) != NULL) {
        size_t old_size = p - old;
        memcpy(new_p, old, old_size);
        new_p += old_size;
        memcpy(new_p, replace, replace_size);
        new_p += replace_size;
        old = p + search_size;
    }
    strcpy(new_p, old);

    return new_subject;
}

void getStatusCode(char *response, char *status_code) {
    char *status_line = get_until(response, "\r\n");
    status_line = str_replace("HTTP/1.1 ", "", status_line);
    char *code = strndup(status_line, 4);
    code = str_replace(" ", "", code);
    status_code = strcpy(status_code, code);

    free(code);
    free(status_line);
}

void mockRequest(char *status_code) {
    char *res = "HTTP/1.1 200 OK\n"
                "Server: nginx\n"
                "Date: Fri, 07 Apr 2023 18:44:22 GMT\n"
                "Content-Type: application/json; charset=utf-8\n"
                "Connection: close\n"
                "Access-Control-Allow-Origin: *\n"
                "\n"
                "73\n"
                "some-body-content-here\n"
                "0";
    char *status_line = NULL;
    getStatusCode(res, status_code);
    free(status_line);
}


int main() {
    char status_code[4];
    mockRequest(status_code);
    printf("STATUS: %s", status_code);
    return 0;
}

//=============

我用地址消毒器。消毒器报告:

==8055==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 190 byte(s) in 1 object(s) allocated from:
    #0 0x7f31ccabc808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x7f31cca25243 in __interceptor_strndup ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:379
    #2 0x55d0abad935c in get_until /home/user/CLionProjects/untitled/main.c:12
    #3 0x55d0abad94e0 in getStatusCode /home/user/CLionProjects/untitled/main.c:48
    #4 0x55d0abad959d in mockRequest /home/user/CLionProjects/untitled/main.c:70
    #5 0x55d0abad963f in main /home/user/CLionProjects/untitled/main.c:78
    #6 0x7f31cc7e1082 in __libc_start_main ../csu/libc-start.c:308

Direct leak of 5 byte(s) in 1 object(s) allocated from:
    #0 0x7f31ccabc808 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
    #1 0x7f31cca25243 in __interceptor_strndup ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:379
    #2 0x55d0abad9513 in getStatusCode /home/user/CLionProjects/untitled/main.c:50
    #3 0x55d0abad959d in mockRequest /home/user/CLionProjects/untitled/main.c:70
    #4 0x55d0abad963f in main /home/user/CLionProjects/untitled/main.c:78
    #5 0x7f31cc7e1082 in __libc_start_main ../csu/libc-start.c:308

SUMMARY: AddressSanitizer: 195 byte(s) leaked in 2 allocation(s).

泄漏是在调用strndup时,如果我理解得很好。我完全不知道泄漏可能位于何处。您的建议?

ni65a41a

ni65a41a1#

void getStatusCode(char *response, char *status_code) {
    char *status_line = get_until(response, "\r\n");
    status_line = str_replace("HTTP/1.1 ", "", status_line);
    char *code = strndup(status_line, 4);
    code = str_replace(" ", "", code);
    status_code = strcpy(status_code, code);

    free(code);
    free(status_line);
}

注意,变量code存储strndup的结果,但在下一行code被重新分配给str_replace的结果。strndup分配的内存永远不会释放,也不能释放,因为不再有指向它的指针。
status_line也存在同样的问题。
为了避免将来发生这种情况,请确保每个内存分配都维护一个指向它的指针,该指针可以被释放。

char *a = memory_allocating_function();
char *b = other_memory_allocating_function(a);

// ...

free(a);
free(b);
ny6fqffe

ny6fqffe2#

status_line = str_replace("HTTP/1.1 ", "", status_line);

泄漏原始status_line,因为str_replace()为替换的副本分配了新的内存。您需要将结果分配给一个新变量,以便释放原始变量。

void getStatusCode(char *response, char *status_code) {
    char *status_line = get_until(response, "\r\n");
    char *clean_status_line = str_replace("HTTP/1.1 ", "", status_line);
    free(status_line);

    char *code = strndup(clean_status_line, 4);
    free(clean_status_line);

    char *clean_code = str_replace(" ", "", code);
    free(code);

    strcpy(status_code, clean_code);
    free(clean_code);
}

相关问题