Пин Intel: как определить размер realloc - PullRequest
1 голос
/ 01 июля 2019

У меня есть следующий инструмент для булавок, скажем trace.cpp (точно так же, как в инструменте для булавок руководство ):

#include "pin.H"
#include <iostream>
#include <fstream>

/* ===================================================================== */
/* Names of malloc and free */
/* ===================================================================== */
#if defined(TARGET_MAC)
#define MALLOC "_malloc"
#define FREE "_free"
#else
#define MALLOC "malloc"
#define FREE "free"
#endif

/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */

std::ofstream TraceFile;

/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
    "o", "malloctrace.out", "specify trace file name");

/* ===================================================================== */


/* ===================================================================== */
/* Analysis routines                                                     */
/* ===================================================================== */

VOID Arg1Before(CHAR * name, ADDRINT size)
{
  std::cout << name << "(" << size << ")" << endl;

}

VOID MallocAfter(ADDRINT ret)
{
  std::cout << "  returns " << ret << endl;
}


/* ===================================================================== */
/* Instrumentation routines                                              */
/* ===================================================================== */

VOID Image(IMG img, VOID *v)
{
    // Instrument the malloc() and free() functions.  Print the input argument
    // of each malloc() or free(), and the return value of malloc().
    //
    //  Find the malloc() function.
    RTN mallocRtn = RTN_FindByName(img, MALLOC);
    if (RTN_Valid(mallocRtn))
    {
        RTN_Open(mallocRtn);

        // Instrument malloc() to print the input argument value and the return value.
        RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
                       IARG_ADDRINT, MALLOC,
                       IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
                       IARG_END);
        RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)MallocAfter,
                       IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);

        RTN_Close(mallocRtn);
    }

    // Find the free() function.
    RTN freeRtn = RTN_FindByName(img, FREE);
    if (RTN_Valid(freeRtn))
    {
        RTN_Open(freeRtn);
        // Instrument free() to print the input argument value.
        RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
                       IARG_ADDRINT, FREE,
                       IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
                       IARG_END);
        RTN_Close(freeRtn);
    }
}

/* ===================================================================== */

VOID Fini(INT32 code, VOID *v)
{
    TraceFile.close();
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage()
{
    cerr << "This tool produces a trace of calls to malloc." << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

/* ===================================================================== */
/* Main                                                                  */
/* ===================================================================== */

int main(int argc, char *argv[])
{
    // Initialize pin & symbol manager
    PIN_InitSymbols();
    if( PIN_Init(argc,argv) )
    {
        return Usage();
    }

    // Write to a file since cout and cerr maybe closed by the application
    TraceFile.open(KnobOutputFile.Value().c_str());
    TraceFile << hex;
    TraceFile.setf(ios::showbase);

    // Register Image to be called to instrument functions.
    IMG_AddInstrumentFunction(Image, 0);
    PIN_AddFiniFunction(Fini, 0);

    // Never returns
    PIN_StartProgram();

    return 0;
}

(Единственное отличие состоит в том, что он печатает вместо сохранения в выходном файле)

У меня есть следующий пример кода c - example.c:

#include <stdio.h>
#include <stdlib.h>

struct A {
    int x[10];
    int y[1];
};

int main()
{
  struct A *ptr = calloc(1, sizeof(struct A));
  ptr->x[10] = 4;
  printf("%i\n", ptr->x[10]);
  ptr = realloc(ptr, sizeof(int));
  ptr->x[10] = 4;
  printf("%i\n", ptr->x[10]);
  free(ptr);
  return 0;
}

Когда я запускаю его с помощью булавки, он выдает следующий вывод:

$ pin -t obj-intel64/trace.so -- ./example.o | tail
  returns 139865991781744
malloc(272)
  returns 139865991785984
malloc(44)
  returns 33456736
malloc(4096)
  returns 33456800
free(33456736)
4
4

Обратите внимание на пару malloc звонков:

malloc(44)
malloc(4096)

Он отлично обнаруживает первый (обратите внимание на вызов calloc в коде c), но обнаруживает 4096 для realloc (поправьте меня, если я здесь не прав). Но я полагаю, что вместо этого должно быть обнаружено 4 (sizeof int).

Не могли бы вы сказать мне, где я иду не так? Есть ли способ определить правильный размер (или, может быть, я что-то здесь упускаю)?

Ответы [ 2 ]

3 голосов
/ 01 июля 2019

Вы используете инструмент трассировки для отслеживания фактических вызовов на malloc и free. Похоже, вы не отслеживаете вызовы calloc и realloc, предположительно, исходя из предположения, что эти функции в конечном итоге вызовут malloc.

Это не обязательно правда, хотя. Например, если realloc обнаружит, что существующий блок памяти уже достаточно большой, чтобы удовлетворить запрос, он может просто вернуть свой первый аргумент, не делая ничего больше, поэтому вы не увидите никакого вызова malloc. Очевидно, это то, что произошло в вашем примере, так как ваш realloc запрос требует меньше памяти, чем было выделено calloc, и мы можем видеть, что он здесь этого не сделал, поскольку адрес ptr при free вызывается так же, как блок, выделенный calloc.

Если существующее выделение намного больше, чем запрос, realloc может выбрать скопировать блок в выделение меньшего размера, возможно, полученное с помощью malloc. , Но даже если realloc решит уменьшить размер выделенной памяти, нет гарантии, что ему потребуется новое выделение. В некоторых реализациях можно разбить существующий блок, добавив ненужную часть в список свободных. Это не будет связано с вызовом либо free или malloc.

Итак, если malloc(4096) не приходит от realloc, откуда оно? Скорее всего, ответ таков: malloc был вызван из стандартной библиотеки. Например, printf мог заметить, что ему нужно выделить выходной буфер для stdout, поэтому он вызывает malloc, чтобы получить немного памяти.

Короче говоря, вам, вероятно, необходимо проследить все функции управления памятью, чтобы получить четкое представление о том, что происходит.

0 голосов
/ 01 июля 2019

Я внес следующие изменения в инструмент:

#include "pin.H"
#include <iostream>
#include <fstream>

/* ===================================================================== */
/* Names of malloc and free */
/* ===================================================================== */
#if defined(TARGET_MAC)
#define MALLOC "_malloc"
#define FREE "_free"
#else
#define MALLOC "malloc"
#define FREE "free"
#endif

/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */

std::ofstream TraceFile;

/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
    "o", "malloctrace.out", "specify trace file name");

/* ===================================================================== */


/* ===================================================================== */
/* Analysis routines                                                     */
/* ===================================================================== */

VOID Arg1Before(CHAR * name, ADDRINT addr, ADDRINT size, ADDRINT return_ip)
{
    std::cout << name << " : " << addr << "(" << size << ")" << " : " << return_ip << endl;

}

VOID MallocAfter(ADDRINT ret)
{
    std::cout << "  returns " << ret << endl;
}


/* ===================================================================== */
/* Instrumentation routines                                              */
/* ===================================================================== */

VOID Image(IMG img, VOID *v)
{
    // Instrument the malloc() and free() functions.  Print the input argument
    // of each malloc() or free(), and the return value of malloc().
    //
    //  Find the malloc() function.
    RTN mallocRtn = RTN_FindByName(img, "realloc");
    if (RTN_Valid(mallocRtn))
    {
        RTN_Open(mallocRtn);

        // Instrument malloc() to print the input argument value and the return value.
        RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
                       IARG_ADDRINT, "realloc",
                       IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
                       IARG_FUNCARG_ENTRYPOINT_VALUE, 1,
                       IARG_END);
        RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)MallocAfter,
                       IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);

        RTN_Close(mallocRtn);
    }

    // Find the free() function.
    RTN freeRtn = RTN_FindByName(img, FREE);
    if (RTN_Valid(freeRtn))
    {
        RTN_Open(freeRtn);
        // Instrument free() to print the input argument value.
        RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)Arg1Before,
                       IARG_ADDRINT, FREE,
                       IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
                       IARG_END);
        RTN_Close(freeRtn);
    }
}

/* ===================================================================== */

VOID Fini(INT32 code, VOID *v)
{
    TraceFile.close();
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage()
{
    cerr << "This tool produces a trace of calls to malloc." << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

/* ===================================================================== */
/* Main                                                                  */
/* ===================================================================== */

int main(int argc, char *argv[])
{
    // Initialize pin & symbol manager
    PIN_InitSymbols();
    if( PIN_Init(argc,argv) )
    {
        return Usage();
    }

    // Write to a file since cout and cerr maybe closed by the application
    TraceFile.open(KnobOutputFile.Value().c_str());
    TraceFile << hex;
    TraceFile.setf(ios::showbase);

    // Register Image to be called to instrument functions.
    IMG_AddInstrumentFunction(Image, 0);
    PIN_AddFiniFunction(Fini, 0);

    // Never returns
    PIN_StartProgram();

    return 0;
}

Я нашел имя подпрограммы «realloc» вместо «malloc» и затем передал:

IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
IARG_FUNCARG_ENTRYPOINT_VALUE, 1,

в функцию Arg1Before, чтобы обнаружить два аргумента вызова функции realloc.

А затем в функции Arg1Before:

VOID Arg1Before(CHAR * name, ADDRINT addr, ADDRINT size, ADDRINT return_ip)

здесь, size - размер выделенной памяти, addr - адрес указателя, а return_ip - адрес указателя инструкции возврата.

Надеюсь, это кому-нибудь поможет.

...