我在C编写一个nginx模块,并有一些超级离奇的结果。 我从我的模块中提取了一个函数来testing它的输出以及相关的nginxtypes/macros定义。
我在我的build_key_hash_pair
函数中构build一个结构,然后在printf()
的内容上执行printf()
。 当我printf
内部printf
的数据时, main
的输出是有效的。 当我在内部函数中删除printf
, main
打印一个空string。 这是令人困惑的,因为在函数调用build_key_hash_pair
我不对数据进行操作,除了显示它。 这里是代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct ngx_str_t { size_t len; char *data; } ngx_str_t; typedef uintptr_t ngx_uint_t; typedef struct key_hash_pair { ngx_uint_t hash; ngx_str_t key; } key_hash_pair; #define ngx_string(str) { sizeof(str) - 1, (char *) str } #define ngx_str_set(str, text) \ (str)->len = sizeof(text) - 1; (str)->data = (char *) text #define ngx_hash(key, c) ((ngx_uint_t) key * 31 + c) #define ngx_str_null(str) (str)->len = 0; (str)->data = NULL void build_key_hash_pair(key_hash_pair *h, ngx_str_t api_key, ngx_str_t ip); int main (int argc, char const *argv[]) { ngx_str_t api_key = ngx_string("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"); ngx_str_t ip = ngx_string("123.123.123.123"); key_hash_pair *pair; pair = malloc(sizeof(key_hash_pair)); build_key_hash_pair(pair, api_key, ip); printf("api_key = %s\n", api_key.data); printf("ip = %s\n", ip.data); printf("pair->key = %s\n", pair->key.data); printf("pair->hash = %u\n", (unsigned int)pair->hash); return 0; } void build_key_hash_pair(key_hash_pair *h, ngx_str_t api_key, ngx_str_t ip) { ngx_str_null(&h->key); char str[56]; memset(str, 0, sizeof(str)); strcat(str, api_key.data); strcat(str, ip.data); ngx_str_set(&h->key, str); ngx_uint_t i; for (i = 0; i < 56; i++) { h->hash = ngx_hash(&h->hash, h->key.data[i]); } }
下面是我在build_key_hash_pair
函数中执行printf("hello")
时的输出:
helloapi_key = 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 ip = 123.123.123.123 pair->key = 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8123.123.123.123 pair->hash = 32509824
这里是(不寻常的)输出,当我不printf
里面build_key_hash_pair
:
api_key = 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 ip = 123.123.123.123 pair->key = pair->hash = 32509824
正如你所看到的, pair->key
没有数据。 在gdb中,如果我在main中调用build_key_hash_pair
之后立即断点, build_key_hash_pair
pair->key
包含适当的数据。 但是在第一次调用printf
,它是空白的。 内存地址保持不变,但数据刚刚消失。 谁能告诉我,我在做什么错了?
这条线是一个问题:
ngx_str_set(&h->key, str);
这里的str
是一个局部变量,你在h->key
里面放一个指针,这个指针会返回给调用者。 build_key_hash_pair
返回后,指针将不再有效。 当你没有调用任何其他函数时,指针碰巧仍然指向相同的值,但这不是你可以依赖的。 printf
的调用覆盖了堆栈的一部分。
你需要的是用malloc
或strdup
动态分配字符串,或者在key_hash_pair
结构中放置一个数组来保存键值(如果键值总是相同的话)。
build_key_hash_pair
使用基于堆栈的数组str
来填充h
键中的data
字段。 从函数中退出时,由于str
超出范围,该指针不再有效。
你的结果可能是从明显正确的操作到程序故障。 在printf
中的printf
将起作用,但如果事后调用,则肯定不会。 ngx_str_set
需要分配内存并复制text
字符串(当然后来释放)。
我会用函数或内联代码来替换所有这些宏。
问题出在build_key_hash_pair
函数中,具体来说就是堆栈变量char str[56];
通过宏ngx_str_set
分配给key_hash_pair
。
由于堆栈框架包含char str[56];
函数返回时消失,一旦函数结束,所有的赌注都将关闭。