我有此函数,返回一个如下所示的parsed_url结构
typedef struct url_parser_url {
char *protocol;
char *host;
int port;
char *path;
char *query_string;
int host_exists;
} url_parser_url_t;
url_parser_url_t *parsed_url;
parsed_url = (url_parser_url_t *) malloc(sizeof(url_parser_url_t));
parse_url(address, true, parsed_url);
printf("parsed_url->path = %s\n", parsed_url->path);
parse_url函数看起来像
int parse_url(char *url, bool verify_host, url_parser_url_t *parsed_url) {
char *local_url = (char *) malloc(sizeof(char) * (strlen(url) + 1));
char *token;
char *token_host;
char *host_port;
char *token_ptr;
char *host_token_ptr;
char *path = NULL;
strcpy(local_url, url);
token = strtok_r(local_url, ":", &token_ptr);
parsed_url->protocol = (char *) malloc(sizeof(char) * strlen(token) + 1);
strcpy(parsed_url->protocol, token);
token = strtok_r(NULL, "/", &token_ptr);
if (token) {
host_port = (char *) malloc(sizeof(char) * (strlen(token) + 1));
strcpy(host_port, token);
} else {
host_port = (char *) malloc(sizeof(char) * 1);
strcpy(host_port, "");
}
token_host = strtok_r(host_port, ":", &host_token_ptr);
if (token_host) {
parsed_url->host = (char *) malloc(
sizeof(char) * strlen(token_host) + 1);
strcpy(parsed_url->host, token_host);
if (verify_host) {
struct hostent *host;
host = gethostbyname(parsed_url->host);
if (host != NULL) {
parsed_url->host_exists = 1;
} else {
parsed_url->host_exists = 0;
}
} else {
parsed_url->host_exists = -1;
}
} else {
parsed_url->host_exists = -1;
parsed_url->host = NULL;
}
token_host = strtok_r(NULL, ":", &host_token_ptr);
if (token_host)
parsed_url->port = atoi(token_host);
else
parsed_url->port = 0;
token_host = strtok_r(NULL, ":", &host_token_ptr);
assert(token_host == NULL);
token = strtok_r(NULL, "?", &token_ptr);
parsed_url->path = NULL;
if (token) {
path = (char *) realloc(path, sizeof(char) * (strlen(token) + 2));
strcpy(path, "/");
strcat(path, token);
parsed_url->path = (char *) malloc(sizeof(char) * strlen(path) + 1);
strncpy(parsed_url->path, path, strlen(path));
free(path);
} else {
parsed_url->path = (char *) malloc(sizeof(char) * 2);
strcpy(parsed_url->path, "/");
}
token = strtok_r(NULL, "?", &token_ptr);
if (token) {
parsed_url->query_string = (char *) malloc(
sizeof(char) * (strlen(token) + 1));
strncpy(parsed_url->query_string, token, strlen(token));
} else {
parsed_url->query_string = NULL;
}
token = strtok_r(NULL, "?", &token_ptr);
assert(token == NULL);
free(local_url);
free(host_port);
return 0;
}
问题是当我调用函数parse_url,然后我使用parsed_url-> path成员时,它引发了这种分段错误
==16647== Conditional jump or move depends on uninitialised value(s)
谁能解释我发生了什么事,为什么?谢谢
最佳答案
在那里。尽管它被认为是strcpy()
的更安全替代品,但strncpy()
有疣。该标准说:
strncpy函数从s2指向的数组复制到s1指向的数组最多复制n个字符(不复制跟随空字符的字符)。
(C2011 7.24.2.4/2),并且注释308阐明了
因此,如果s2指向的数组的前n个字符中没有空字符,则结果将不会以空字符结尾。
最终引起您特定的valgrind投诉的代码是:
strncpy(parsed_url->path, path, strlen(path));
由于根据定义,在
strlen(path)
的前path
个字符中不能有空字符,因此该strncpy()
可靠地不能确保副本以空字符结尾。您的代码中至少还有一个相同问题的其他实例。由于您似乎已经足够小心以确保有足够的可用空间,因此一种解决方案是将
strncpy()
切换为strcpy()
。这样也将更加有效,因为您可以避免重复调用strlen()
。但是,正如我在评论中指出的那样,如果您愿意依赖POSIX的
strdup()
,则它比strlen()
+ malloc()
+ str[n]cpy()
干净,并且具有相同的语义(您负责释放内存)分配给副本)。如果您以这种方式制作副本,您甚至没有机会犯这些错误。关于c - 条件跳转或移动取决于C中的未初始化值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43079929/