我正在尝试使用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个字节?
答案 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
响应主体,并简单地将主体的大小保持为整数。我已经解释了上面的问题,因为重要的是你知道。