c - Valgrind:大小 1 的读/写无效

标签 c pointers valgrind dynamic-memory-allocation

我正在尝试使用C构建一个非常基本的网络服务器。我已经解决了 valgrind 报告的所有问题,除了这个问题。这是导致它的相关代码片段。我已将 x>> 添加到 valgrind 建议的行中:

/* Set the response header. */
char *response_header = "HTTP/1.1 404 Not Found\r\n"
        "Content-Type: text/html\r\n"
        "Connection: close\r\n"
        "\r\n";

/* Try to load the 404 message. Return 0 if failed. */
int response_body_size = 0;
char *response_body = read_file(FILE_404, &response_body_size);
if (response_body == NULL) {
    return 0;
}
terminate_string(response_body, response_body_size);

/* Allocate space to merge the header and body and merge them. Return 0 if failed. */
1>> char *response = (char *) malloc(sizeof(char) * (strlen(response_header) + strlen(response_body)));
if (response == NULL) {
    return 0;
}
strcpy(response, response_header);
2,3>> strcat(response, response_body);

/* Return the response. */
4>> write(connection_fd, response, strlen(response));

terminate_string():

/* Adds the terminating character to the specified string. */
void terminate_string(char *str, int length) {
5>> str[length] = '\0';
}

read_file():

/* Reads the specified file and returns its contents. Will return NULL if could not read. */
/* Assumes the filename starts with a / character! */
void* read_file(char *filename, int *file_size) {
    /* Open the file in binary read mode. Return NULL if failed. */
    FILE *file = fopen(filename + 1, "rb");
    if (file == NULL) {
        return NULL;
    }

    /* Get the size of the file. Return NULL if failed.*/
    struct stat fs;
    if (fstat(fileno(file), &fs) == -1) {
        return NULL;
    }

    *file_size = fs.st_size;

    /* Read the contents to a string. */
    void* result = NULL;
6>> result = (void *) malloc (fs.st_size);
    /* Return NULL if malloc failed. */
    if (result == NULL) {
        return NULL;
    }
    fread(result, 1, *file_size, file);

    /* Close the file. */
    fclose(file);

    return result;
}

Valgrind 报告:

1: Invalid read of size 1 [PID: 3896]
2: Invalid read of size 1 [PID:3896]
3: Invalid write of size 1 [PID:3896]
4: Invalid read of size 1 [PID:3896]
5: Invalid write of size 1 [PID:3896]
6: Address 0x541bbb4 is 0 bytes after a block of size 4 alloc'd [PID: 3896]

由于某种原因,read_file() 函数返回 2 个额外字符。这似乎可以通过 terminate_string() 解决,但显然 valgrind 知道一些我不知道的事情。在过去的 3 个小时里,我一直在查看这段代码,同时阅读我在网上找到的所有可能的解决方案,但我没能弄清楚。我对 C 中的动态内存分配非常陌生,因此对于有经验的人来说这可能是非常明显的。

这里有什么问题以及如何解决它?

此外,为什么 read_file() 返回的字节数比文件包含的字节数多 2 个字节?

最佳答案

首先,使用 valgrind 做得很好。

在第 6 点,您会:

result = (void *) malloc (fs.st_size);

我建议你这样做:

size_t sz = fs.st_size;
result = malloc (sz+1); /* no need to cast return of malloc() */
((char *)result)[sz] = 0; /* zero terminate it */

由于您遇到的问题是您为文件和正文提供了malloc完全足够的空间,但没有为终止NUL.

你的terminate_string想法被打破了,因为它写到了response_body的末尾。如果响应正文以零结尾,则您不需要它,因此可以将其删除。

出于类似的原因,您想要:

char *response = malloc(sizeof(char) *
                 (strlen(response_header) + strlen(response_body) + 1));

+1 代表 NUL

但是,还有一个更大的问题:HTTP 文档本身可以包含 \0,即零字节,在这种情况下您无法 strlen() 它们。因此,更好的解决方法是写入响应 header ,然后写入响应正文,并简单地将正文的大小保留为整数。我已经解释了上面的问题,因为您知道这一点很重要。

关于c - Valgrind:大小 1 的读/写无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22126188/

相关文章:

android - 为 Android 构建 Valgrind

c - 进程返回 -1073741819 (0xC0000005)

c - token 之前的预期标识符(

c - 字符串中的 `% a` 读取为内存中的一个点

c - 如何获取 *chars 并返回非整数?

C++ - const 与非 const 成员函数 - 带有函数指针的模板

c++ - STL_algo.h 中的错误,比较指针

c - 将 2D 数组传递给采用指针的函数

c - 全局结构内存错误

c++ - 何时调用 QApplication 析构函数