Библиотечное взаимодействие

Я пытался перехватить вызовы malloc и free, следуя нашему учебнику (книга CSAPP). Я следовал их точному коду и почти тому же коду, который я нашел в Интернете, и я продолжаю получать ошибку сегментации. Я слышал, как наш профессор говорил что-то о 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

тест.с

      #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;
}

Makefile из репозитория git не работал, поэтому я вручную скомпилировал файлы и получил:

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

Я делаю это часами и все равно получаю тот же неверный результат, несмотря на то, что я скопировал код из учебника. Буду очень признателен за любую помощь!!

1 ответ

Один из способов справиться с этим — отключить рекурсивное вызов функции return:

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

При этом, если вызовы, ваша подпрограмма просто вызовет фактический malloc(через ) и вернуться, не вызывая другой . Вы пропустите вывод информации о вызове, который делает, но это, как правило, терпимо, когда вставка используется для изучения общей программы, а не библиотеки C.

Если вам нужно поддерживать многопоточность, может потребоваться дополнительная работа.

Реализация может выделить буфер только один раз, когда он используется в первый раз. В этом случае вы можете инициализировать флаг, который отключает аналогичный приведенному выше вызов, один раз в (может быть, убедитесь, что она включает в себя хорошую задачу форматирования, которая заставляет выделять буфер, а не простую строку), а затем установите флаг, чтобы включить вызов и оставить его установленным для остальной части программы.

Другой вариант - для вашей рутины не использовать вообще, кроме как кэшировать данные в буфере для записи позже какой-либо другой процедурой или записывать необработанные данные в файл, используя , а позже эти данные будут интерпретированы и отформатированы отдельной программой. Или необработанные данные могут быть записаны по конвейеру в программу, которая форматирует и печатает их и не использует ваш вставленный .

Другие вопросы по тегам