Intel pin:如何检测重新分配的大小

Intel pin: how to detect realloc size

我有一个下面的 pin 工具,比如 trace.cpp(与 pin 工具 manual 中的完全一样):

#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)

它完美地检测到第一个(注意 c 代码中的 calloc 调用),但它检测到 4096 的 realloc(如果我在这里错了请纠正我)。但是,我相信它应该检测到 4 (sizeof int)。

我哪里错了?有什么方法可以检测到正确的尺寸(或者我在这里遗漏了什么)?

我对该工具进行了以下更改:

#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是return指令指针的地址。

您正在使用跟踪工具跟踪对 mallocfree 的实际调用。您似乎没有跟踪对 callocrealloc 的调用,大概是基于这些函数最终会调用 malloc 的假设。

但这不一定是真的。例如,如果 realloc 检测到现有的内存块已经足够大,可以满足请求,它可以 return 它的第一个参数而不做任何更多的事情,所以你不会看到对 malloc 的任何调用.这显然是您的示例中发生的情况,因为您的 realloc 调用请求的内存少于 calloc 分配的内存,并且我们可以看到它没有在此处执行此操作,因为 [=] 的地址18=] 当调用 free 时与 calloc.

分配的块相同

如果现有分配比请求大得多,realloc 可能会选择将块复制到更小的分配中,可能使用 malloc 获得。 .但即使 realloc 确实决定减少已分配内存的大小,也不能保证它需要新的分配。在某些实现中,可以拆分现有块,将不需要的部分添加到空闲列表中。这不会涉及调用 freemalloc.

那么,如果 malloc(4096) 不是来自 realloc,那么它是从哪里来的呢?最有可能的答案是 malloc 是从标准库中调用的。例如,printf 可能已经注意到它需要为 stdout 分配一个输出缓冲区,因此它调用 malloc 来获取一些内存。

简而言之,您可能需要跟踪所有内存管理函数才能清楚地了解正在发生的事情。