库插入

Library interpositioning

我一直在尝试按照我们的教科书(CSAPP 书)拦截对 malloc 和 free 的调用。 我遵循了他们的确切代码,以及我在网上找到的几乎相同的代码,但我一直遇到分段错误。我听到我们的教授说了一些关于 printf 的 malloc 和释放内存的事情,所以我认为发生这种情况是因为我正在拦截 malloc 并且因为我在拦截函数中使用了 printf 函数,它会递归地调用自己。 但是我似乎找不到解决这个问题的方法?我们的教授证明拦截有效(他没有向我们展示代码)并在每次发生 malloc 时打印我们的信息,所以我知道这是可能的。 谁能推荐一种工作方法??

这是我使用过但什么也没得到的代码: mymalloc.c

#ifdef RUNTIME
// Run-time interposition of malloc and free based on // dynamic linker's (ld-linux.so) LD_PRELOAD mechanism #define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h> #include <dlfcn.h>
void *malloc(size_t size) {
static void *(*mallocp)(size_t size) = NULL; char *error;
void *ptr;
// get address of libc malloc
if (!mallocp) {
mallocp = dlsym(RTLD_NEXT, "malloc"); if ((error = dlerror()) != NULL) {
            fputs(error, stderr);
            exit(EXIT_FAILURE);
         }
}
ptr = mallocp(size);
printf("malloc(%d) = %p\n", (int)size, ptr); return ptr;
}
#endif

test.c

#include <stdio.h>
#include <stdlib.h>
int main(){
   printf("main\n");
   int* a = malloc(sizeof(int)*5);
   a[0] = 1;
   printf("end\n");
}

我得到的结果:

$ gcc -o test test.c
$ gcc -DRUNTIME -shared -fPIC mymalloc.c -o mymalloc.so
$ LD_PRELOAD=./mymalloc.so ./test
Segmentation Fault

这是我尝试过但出现分段错误的代码(来自 https://gist.github.com/iamben/4124829):

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void* malloc(size_t size)
{
        static void* (*rmalloc)(size_t) = NULL;
        void* p = NULL;

        // resolve next malloc
        if(!rmalloc) rmalloc = dlsym(RTLD_NEXT, "malloc");

        // do actual malloc
        p = rmalloc(size);

        // show statistic
        fprintf(stderr, "[MEM | malloc] Allocated: %lu bytes\n", size);

        return p;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_LEN 128

int main(int argc, const char *argv[])
{
        char *c;
        char *str1 = "Hello ";
        char *str2 = "World";

        //allocate an empty string
        c = malloc(STR_LEN * sizeof(char));
        c[0] = 0x0;

        //and concatenate str{1,2}
        strcat(c, str1);
        strcat(c, str2);

        printf("New str: %s\n", c);


        return 0;
}

来自 git 仓库的 makefile 没有工作所以我手动编译文件并得到:

$ gcc -shared -fPIC libint.c -o libint.so
$ gcc -o str str.c
$ LD_PRELOAD=./libint.so ./str
Segmentation fault

我已经这样做了几个小时,但我仍然得到同样的错误结果,尽管我复制了教科书代码。如果有任何帮助,我将不胜感激!!

处理此问题的一种方法是在递归调用 return 时关闭 printf

static char ACallIsInProgress = 0;
if (!ACallIsInProgress)
{
    ACallIsInProgress = 1;
    printf("malloc(%d) = %p\n", (int)size, ptr);
    ACallIsInProgress = 0;
}
return ptr;

这样,如果 printf 调用 malloc,您的例程将仅调用实际的 malloc(通过 mallocp)和 return 而不会导致另一个 printf.您将错过有关 printf 调用 malloc 的打印信息,但是当使用插入来研究一般程序而不是 C 库时,这通常是可以容忍的。

如果您需要支持多线程,可能需要做一些额外的工作。

printf 实现可能只分配一次缓冲区,即第一次使用它。在这种情况下,您可以初始化一个标志来关闭 printf 与上面类似,在 main 例程中调用一次 printf (也许可以确定它包含一个很好的格式化任务,这会导致printf 分配缓冲区,而不是普通字符串),然后设置标志以打开 printf 调用并为程序的其余部分保留它。

另一个选项是您的 malloc 例程根本不使用 printf 而是将数据缓存在缓冲区中以便稍后由其他例程写入或将原始数据写入文件使用write,稍后由单独的程序解释和格式化该数据。或者原始数据可以通过管道写入格式化和打印它的程序,而不是使用你插入的 malloc.