2017-05-19 9 views
1

私が長いこと前に書いたライブラリを使用しようとしていたとき、私は奇妙な動作を見つけました。主な問題は、プログラムがFedora 25で実行され、LD_PRELOADを使用して自分のライブラリにリンクされていると、セグメンテーションフォルトが発生することです。私は問題を簡単に理解するために私の古い図書館の小さなサンプルを作った。Fedora 25でLD_PRELOADを使用するとセグメンテーションフォールトが発生する

#include <stdio.h> 
#include <stdlib.h> 
#include <malloc.h> 

extern void *__libc_malloc(size_t size); 

void *malloc(size_t size) 
{ 
    void *ptr = __libc_malloc(size); 
    fprintf(stdout, "Malloc(%d)->(%p)\n", (int) size, ptr); 
    return ptr; 
} 

このコードは、これらのパラメータを使用してコンパイルされた:

gcc -c -fPIC -O3 -Wall -o libtest.o libtest.c 
gcc -shared -o libtest.so libtest.o 

次のようにプログラムが実行された:

LD_PRELOAD=./libtest.so ./progtest 

私が "関数fprintf" 行が引き起こしたことが判明Segfaultの問題"stdout"ファイル記述子を "stderr"に変更しましたが、問題はなくなりました。

それから私は、CentOSの7を実行している別のマシン上で「 fprintfの」のための出力として「STDOUT」ファイルディスクリプタを使用して同じコードをテストし、それが「標準出力」を使用して、両方のケースで罰金働いて、 "stderr"。

これらの結果を観察することで、私は何が欠けているのか、なぜこれが起こっているのだろうかと思います。 Fedoraの25にインストール

のglibcとGCCバージョン:

GNUのLDバージョン2.26.1-1.fc25

GCC(GCC)6.3.1 20161221(6.3.1-1レッドハット)

のCentOS 7にインストール

のglibcとGCCバージョン:

GNUのLDバージョン2.25.1-22.base.el7

GCC(GCC)4.8.5 20150623(レッドハット4.8.5-11)

答えて

2

fprintf自体は、いくつかの状況下でmallocを使用する必要があるかもしれません。考えられる理由の1つは、stderrはバッファされず、stdoutはバッファされていることです。 fprintf(stdout)にすでにバッファがあるか、または割り当てようとしている可能性があります。mallocを呼び出すと、再びfprintfが呼び出されますが、同じFILE*には再入可能ではありません。出力文字列への書き込みを()ローカルバッファへのsnprintfを使用する代わりに、

#include <stdbool.h> 
#include <threads.h> 
thread_local bool inside_malloc = false; 
void *malloc(size_t size) { 
    void *ptr = __libc_malloc(size); 
    if (!inside_malloc) { 
     inside_malloc = true; 
     fprintf(stdout, "Malloc(%zd)->(%p)\n", size, ptr); 
     inside_malloc = false; 
    } 
    return ptr; 
} 
+0

別のアプローチは、関数fprintfを使用して捨てることであり、呼び出し:

あなたは、このような(C11)としてフラグをリエントラントを防止することができますsnprintfによって作成されました – nos

+0

@nosそれはうまくいく可能性がありますが、私は 'snprintf'が割り振りを伴うかもしれないことにはまだ注意が必要です。 – ephemient

関連する問題