6

私の前の質問に関連して

私はうまく介入しましたが、もっと問題mallocがあるようです。calloc

これは特定のホストで発生し、内部呼び出しcallocの可能性がある無限ループでスタックします。ただし、基本的なテストホストはこの動作を示しませんが、私のシステムの「ls」コマンドは示しています。callocdlsym

これが私のコードです:

// build with: g++ -O2 -Wall -fPIC -ldl -o libnano.so -shared Main.cc
#include <stdio.h>
#include <dlfcn.h>

bool gNanoUp = false;// global

// Function types
typedef void* (*MallocFn)(size_t size);
typedef void* (*CallocFn)(size_t elements, size_t size);

struct MemoryFunctions {
    MallocFn   mMalloc;
    CallocFn   mCalloc;
};

MemoryFunctions orgMemFuncs;

// Save original methods.
void __attribute__((constructor)) __nano_init(void) {
    fprintf(stderr, "NANO: init()\n");

    // Get address of original functions
    orgMemFuncs.mMalloc = (MallocFn)dlsym(RTLD_NEXT, "malloc");
    orgMemFuncs.mCalloc = (CallocFn)dlsym(RTLD_NEXT, "calloc");

    fprintf(stderr, "NANO: malloc() found @%p\n", orgMemFuncs.mMalloc);
    fprintf(stderr, "NANO: calloc() found @%p\n", orgMemFuncs.mCalloc);

    gNanoUp = true;
}

// replacement functions
extern "C" {
    void *malloc(size_t size) {
        if (!gNanoUp) __nano_init();
        return orgMemFuncs.mMalloc(size);
    }

    void* calloc(size_t elements, size_t size) {
        if (!gNanoUp) __nano_init();
        return orgMemFuncs.mCalloc(elements, size);
    }
}

さて、次のことを行うと、無限ループに続いてセグメンテーション違反が発生します。例:

% setenv LD_PRELOAD "./libnano.so"
% ls
...
NANO: init()
NANO: init()
NANO: init()
Segmentation fault (core dumped)

ただし、インターポーザーをコメントアウトすると、callocほとんど機能しているように見えます。

% setenv LD_PRELOAD "./libnano.so"
% ls
NANO: init()
NANO: malloc() found @0x3b36274dc0
NANO: calloc() found @0x3b362749e0
NANO: init()
NANO: malloc() found @0x3b36274dc0
NANO: calloc() found @0x3b362749e0
<directory contents>
...

つまり、「ls」はinit()2回呼び出されることを意味します。

編集出力からわかるように、次のホストプログラムは正しく機能することに注意してください-init()一度だけ呼び出され、calloc正常に挿入されます。

// build with: g++ test.cc -o test
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]) {

    void* p = malloc(123);
    printf("HOST p=%p\n", p);
    free(p);

    char* c = new char;
    printf("HOST c=%p\n", c);
    delete c;

    void* ca = calloc(10,10);
    printf("HOST ca=%p\n", ca);
    free(ca);
}

% setenv LD_PRELOAD "./libnano.so"
% ./test 
NANO: init()
NANO: malloc() found @0x3b36274dc0
NANO: calloc() found @0x3b362749e0
HOST p=0x601010
HOST c=0x601010
HOST ca=0x601030
4

5 に答える 5

6

私は少し遅れていることを知っています(6年)。しかし、私は今日オーバーライドしたかったので、内部的にを使用calloc()しているため、問題に直面しました。私は簡単なテクニックを使ってそれを解決し、ここでそれを共有することを考えました:dlsym()calloc()

static unsigned char buffer[8192];

void *calloc(size_t nmemb, size_t size)
{
    if (calloc_ptr == NULL) // obtained from dlsym
            return buffer;

    init(); // uses dlsym() to find address of the real calloc()

    return calloc_ptr(len);
}

void free(void *in)
{
    if (in == buffer)
        return;

    free_ptr(in);
}

bufferdlsym()実数calloc()が見つかり、calloc_ptr関数ポインタが初期化されるまでのニーズを満たします。

于 2017-09-12T11:28:33.600 に答える
3

2回の呼び出しに関して:関数をコンストラクターとして宣言したため、ライブラリがロードされたときに呼び出され、実装が最初に呼び出され__nano_init()たときに2回目に明示的に呼び出されます。一つを選ぶ。malloc()calloc()

calloc()アプリケーションをクラッシュさせるインターポーザーに関して:dlsym()およびを含む、使用している関数の一部は、fprintf()それ自体がメモリーの割り当てを試みて、インターポーザー関数を呼び出している可能性があります。結果を考慮し、それに応じて行動します。

于 2011-10-27T02:39:14.157 に答える
2

dlsymベースのフッキングを使用するとdlsym、メモリアロケータにコールバックするため、クラッシュが発生する可能性があります。以前の質問で提案したように、代わりにmallocフックを使用してください。これらは、実際に呼び出すことなくインストールできます。dlsym

于 2011-10-27T23:12:28.670 に答える
1

単にNULLを返す予備的な貧弱なcallocで逃げることができます。これは実際にはLinux、YMMVで機能します。

static void* poor_calloc(size_t nmemb, size_t size)
{
    // So dlsym uses calloc internally, which will lead to infinite recursion, since our calloc calls dlsym.
    // Apparently dlsym can cope with slightly wrong calloc, see for further explanation:
    // http://blog.bigpixel.ro/2010/09/interposing-calloc-on-linux
    return NULL; // This is a poor implementation of calloc!
}
于 2017-03-20T10:01:58.913 に答える
1

sbrkを使用して、「poorcalloc」にメモリを割り当てることもできます。

于 2021-04-19T22:50:18.923 に答える