6

关于我以前的问题

我已经成功介入malloc,但calloc似乎问题更大。

也就是说,某些主机calloc陷入无限循环,内部可能存在内部calloc调用dlsym。但是,基本测试主机不会表现出这种行为,但我系统的“ls”命令会表现出这种行为。

这是我的代码:

// 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()被调用了两次。

编辑请注意,以下主机程序可以正常工作 -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);
}

buffer满足dlsym()直到真正找到并初始化calloc()我的函数指针的需要。calloc_ptr

于 2017-09-12T11:28:33.600 回答
3

关于__nano_init()被调用两次:您已将该函数声明为构造函数,因此在加载库时会调用它,并且在首次调用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 为“可怜的 calloc”分配内存。

于 2021-04-19T22:50:18.923 回答