Valgrind:大小为1的读/写无效

时间:2014-03-02 10:02:30

标签: c pointers valgrind dynamic-memory-allocation

我正在尝试使用C构建一个非常基本的Web服务器。除了这个问题,我已经解决了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个字节?

1 个答案:

答案 0 :(得分:3)

首先,使用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'd 确切文件和正文的足够空间,而不是终止NUL

您的terminate_string想法被打破,因为它超出了response_body的结尾。如果响应主体为零终止,则不需要它,因此可以将其删除。

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

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

+1代表NUL

然而,存在一个更大的问题:HTTP文档本身可以包含\0,即零字节,在这种情况下,您不能strlen()它们。因此,更好的解决方案是write响应头,然后是write响应主体,并简单地将主体的大小保持为整数。我已经解释了上面的问题,因为重要的是你知道。