Search code examples
cdlsymlibrary-interposition

Library interpositioning


I have been trying to intercept calls to malloc and free, following our textbook (CSAPP book). I have followed their exact code, and nearly the same code that I found online and I keep getting a segmentation fault. I heard our professor saying something about printf that mallocs and frees memory so I think that this happens because I am intercepting a malloc and since I am using a printf function inside the intercepting function, it will call itself recursively. However I can't seem to find a solution to solving this problem? Our professor demonstrated that intercepting worked ( he didn't show us the code) and prints our information every time a malloc occurs, so I do know that it's possible. Can anyone suggest a working method??

Here is the code that I used and get nothing: 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");
}

The result i'm getting:

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

This is the code that I tried and got segmentation fault (from 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;
}

The makefile from the git repo didn't work so I manually compiled the files and got:

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

I have been doing this for hours and I still get the same incorrect result, despite the fact that I copied textbook code. I would really appreciate any help!!


Solution

  • One way to deal with this is to turn off the printf when your return is called recursively:

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

    With this, if printf calls malloc, your routine will merely call the actual malloc (via mallocp) and return without causing another printf. You will miss printing information about a call to malloc that the printf does, but that is generally tolerable when interposing is being used to study the general program, not the C library.

    If you need to support multithreading, some additional work might be needed.

    The printf implementation might allocate a buffer only once, the first time it is used. In that case, you can initialize a flag that turns off the printf similar to the above, call printf once in the main routine (maybe be sure it includes a nice formatting task that causes printf to allocate a buffer, not a plain string), and then set the flag to turn on the printf call and leave it set for the rest of the program.

    Another option is for your malloc routine not to use printf at all but to cache data in a buffer to be written later by some other routine or to write raw data to a file using write, with that data interpreted and formatted by a separate program later. Or the raw data could be written by a pipe to a program that formats and prints it and that is not using your interposed malloc.