我正在尝试使用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/