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

问题描述 投票:0回答:2

我正在尝试创建基于 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 时,如果我理解得很好的话。 我完全不知道泄漏的位置。 你的建议?

c memory-leaks address-sanitizer
2个回答
0
投票
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
分配的内存永远不会被释放。


0
投票
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);
}
© www.soinside.com 2019 - 2024. All rights reserved.