I have a following pin tool, say trace.cpp
(exactly as is in a pin tool 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;
}
(The only variation is that it prints the instead of storing it in the output file)
I have a following c code example - 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;
}
When I run it with the pin tool, it produces the following output:
$ 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
Notice the couple of malloc
calls:
malloc(44)
malloc(4096)
It detects the first one perfectly (notice calloc call in the c code), but it detects 4096 for realloc (correct me if I'm wrong here). But, I believe it supposed to detect 4 (sizeof int) instead.
Where am I going wrong? Is there any way by which the correct size can be detected (or maybe I am missing something here)?
You are using the trace tool to trace actual calls to malloc
and free
. You don't seem to be tracing calls to calloc
and realloc
, presumably on the assumption that those functions will eventually call malloc
.
That's not necessarily true, though. For example, if realloc
detects that the existing memory block is already sufficiently big to satisfy the request, it can just return its first argument without doing anything more, so you won't see any call to malloc. This is evidently what happened in your example, since your realloc
call asks for less memory than was allocated by calloc
, and we can see that it didn't do that here, since the address of ptr
when free
is called is the same as the block allocated by calloc
.
If the existing allocation is much bigger than the request, realloc
may choose to copy the block into a smaller allocation, possibly acquired with malloc
. . But even if realloc
does decide to reduce the size of the allocated memory, there is no guarantee that it wiil need a new allocation. On some implementations, it is possible to split the existing block, adding the unneeded part to the free list. That won't involve a call to either free
or malloc
.
So if the malloc(4096)
doesn't come from the realloc
, where does it come from? Most likely, the answer is that malloc
was called from the standard library. For example, printf
might have noticed that it needs to allocate an output buffer for stdout
, so it calls malloc
to get some memory.
In short, you probably need to trace all memory management functions to get a clear idea of what is going on.