2011-07-08 5 views
3

私はC言語でnginxモジュールを書いていますが、奇妙な結果があります。関連するnginxの型/マクロ定義だけでなく、その出力をテストするために私のモジュールから関数を抽出しました。printf()が私のデータを破壊しているようです

私のbuild_key_hash_pair関数で構造体を構築していて、という内容のprintf()を実行しています。 printf内部関数内のデータがmainの出力に有効です。内側の関数の中のprintfを削除すると、mainは空文字列を出力します。これは、build_key_hash_pairへの関数呼び出しの後で、データを表示する以外は操作していないため、混乱します。ここでは、コードです:私はbuild_key_hash_pair関数内printf("hello")を行うときにここで

#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をしていないとき

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

そして、ここでは(奇妙な)出力されます。

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

ご覧のとおり、pair->keyにはデータがありません。 gdbでは、メインの呼び出しの直後にブレークポイントをbuild_key_hash_pairにすると、pair->keyに適切なデータが含まれています。しかし、printfへの最初の呼び出しの後、それは消去されます。メモリアドレスは同じですが、データは消えてしまいました。誰でも私が間違っている世界の何を教えてもらえますか?

+0

多分私は何かが欠落していますが、これらの文字列のヌルターミネータはどこにありますか? – KevinDTimm

+0

文字列定数は、最後に明示的なヌルバイトを必要としません。これらはコンパイラによって追加されます。 –

答えて

7

この行は問題である:ここではstr

ngx_str_set(&h->key, str); 

がローカル変数であり、あなたは、呼び出し元に返されますh->key、内部のそれへのポインタを入れています。 build_key_hash_pairが返された後、ポインタはもはや有効ではなくなります。あなたが他の関数を呼び出さなかったとき、ポインタはまだ同じ値を指していましたが、これはあなたが信頼できるものではありません。 printfへの呼び出しは、そのスタックの一部を上書きしました。

は何が必要のいずれかを動的にmallocまたはstrdupで文字列を割り当てるか、(キーが常に同じサイズであれば可能)キーを保持するためにkey_hash_pair構造体の内部の配列を置くことです。

+0

確かに知っておきたいことですが、なぜビルド関数でprintf( "hello")を実行すれば、メインプリントペア - >キーだけでいいのですか? – localshred

+0

私は、構造体にmemcpyの 'str'があると仮定していますか? – localshred

+1

@localshred:私はすでにこれらの質問に答える前に私の答えを編集しました:) – interjay

2

build_key_hash_pairは、dataフィールドにキーhを入力するためにスタックベースの配列strを使用します。関数を終了すると、strが範囲外になるため、そのポインタは無効になります。

あなたの結果は、明らかに正しく動作してからプログラムが失敗するまでの何かになる可能性があります。関数内のprintfは機能しますが、後で呼び出された場合は間違いありません。 ngx_str_setはメモリを割り当て、textの文字列をコピーする必要があります(後で解放されます)。

これらのマクロはすべて関数またはインラインコードで置き換えます。

+0

それらを置き換えることは、彼らがnginxソースで作業しなければならないように機能しません。私のコードではありません。 – localshred

+0

ああ、そうだ。マクロの特定の部分にブレークポイントを設定することは不可能なので、私はそれらを嫌いです。 –

0

この問題は関数、具体的にはスタック変数char str[56];で、ngx_str_setを介してkey_hash_pairに割り当てられています。

関数が戻るときにchar str[56];を含むスタックフレームが消えるため、関数が終了するとペアのデータの値に対してすべてのベットがオフになります。

関連する問題