2011-07-08 56 views
3

我正在用C寫一個nginx模塊,並且有一些超級怪異的結果。我從我的模塊中提取了一個函數來測試它的輸出以及相關的nginx類型/宏定義。printf()似乎在破壞我的數據

我在我的build_key_hash_pair函數中構建一個結構,然後在main的內容上做一個printf()。當我在printf內部函數中的數據時,main的輸出有效。當我在內部函數中刪除printf時,main會打印一個空字符串。這很讓人困惑,因爲在函數調用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]); 
    } 
} 

這裏是輸出當我做了printf("hello")build_key_hash_pair函數內部:

helloapi_key = 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 
ip = 123.123.123.123 
pair->key = 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8123.123.123.123 
pair->hash = 32509824 

這裏是(奇怪的)輸出,當我不printfbuild_key_hash_pair

api_key = 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 
ip = 123.123.123.123 
pair->key = 
pair->hash = 32509824 

如您所見,pair->key沒有數據。在gdb中,如果我在build_key_hash_pair的main調用後立即斷點,pair->key包含適當的數據。但是在第一次撥打printf後,它被刪除。內存地址保持不變,但數據剛剛消失。任何人都可以告訴我,我做錯了什麼?

+0

也許我錯過了一些東西,但是你的空終止符在哪裏? – KevinDTimm

+0

字符串常量在末尾不需要顯式空字節。這些是由編譯器添加的。 –

回答

7

這條線是一個問題:

ngx_str_set(&h->key, str); 

這裏str是一個局部變量,你把它的指針裏面h->key,將被返回給調用者。在build_key_hash_pair返回後,指針將不再有效。當你沒有調用任何其他函數時,指針碰巧仍然指向相同的值,但這不是你可以依賴的。致電printf覆蓋了該堆棧的一部分。

您需要的是動態分配mallocstrdup的字符串,或者在key_hash_pair結構中放置一個數組來保存密鑰(如果密鑰始終大小相同,則可能)。

+0

確實很好知道,但是爲什麼我在打印函數中使用printf(「hello」)做主打印pair->鍵就好了? – localshred

+0

而我假設解決方案是memcpy'str'到結構中? – localshred

+1

@localshred:我已經編輯了我的答案,在你問他們之前回答這兩個問題:) – interjay

2

build_key_hash_pair使用基於堆棧的陣列str來填充的h密鑰的data字段。當您退出該功能時,該指針不再有效,因爲str超出了範圍。

您的結果可能是從顯然正確的操作到程序故障。功能中的printf將起作用,但如果事後調用則絕對不會。 ngx_str_set需要分配內存並將text字符串複製到其中(當然以後要釋放)。

我會用函數或內聯代碼個人替換所有這些宏。

+0

替換它們將不起作用,因爲它們是我必須在nginx源代碼中使用的。不是我的代碼。 – localshred

+0

啊,我明白了。我不喜歡它們,因爲不可能在宏的特定部分設置斷點。 –

0

問題出在build_key_hash_pair函數中,特別是堆棧變量char str[56];,它通過宏ngx_str_set分配給key_hash_pair

由於包含char str[56];的堆棧框架在函數返回時消失,一旦函數結束,所有投注都將關閉該對數據的值。