forked from Imagelibrary/binutils-gdb
gprofng: fix infinite recursion on calloc with multi-threaded applications
libcollector uses pthread_getspecific() and pthread_setspecific() to access thread local memory. libcollector uses this memory to check that interposed functions (like malloc, calloc or free) don't have recursion. The first time we call calloc(), we call pthread_setspecific() to create a thread-specific value. On Ubuntu machine, pthread_setspecific() calls calloc(), and we cannot intercept such recursion. gcc supports thread-local storage. For example, static __thread int reentrance = 0; I rewrote code using this instead of pthread_setspecific(). gprofng/ChangeLog 2024-03-23 Vladimir Mezentsev <vladimir.mezentsev@oracle.com> PR gprofng/31460 * libcollector/heaptrace.c: Use the __thread variable to check for * reentry. Clean up code.
This commit is contained in:
@@ -62,11 +62,12 @@ static ModuleInterface module_interface = {
|
|||||||
static CollectorInterface *collector_interface = NULL;
|
static CollectorInterface *collector_interface = NULL;
|
||||||
static int heap_mode = 0;
|
static int heap_mode = 0;
|
||||||
static CollectorModule heap_hndl = COLLECTOR_MODULE_ERR;
|
static CollectorModule heap_hndl = COLLECTOR_MODULE_ERR;
|
||||||
static unsigned heap_key = COLLECTOR_TSD_INVALID_KEY;
|
static const Heap_packet heap_packet0 = { .comm.tsize = sizeof ( Heap_packet) };
|
||||||
|
static __thread int reentrance = 0;
|
||||||
|
|
||||||
#define CHCK_REENTRANCE(x) ( !heap_mode || ((x) = collector_interface->getKey( heap_key )) == NULL || (*(x) != 0) )
|
#define CHCK_REENTRANCE ( !heap_mode || reentrance != 0 )
|
||||||
#define PUSH_REENTRANCE(x) ((*(x))++)
|
#define PUSH_REENTRANCE (reentrance++)
|
||||||
#define POP_REENTRANCE(x) ((*(x))--)
|
#define POP_REENTRANCE (reentrance--)
|
||||||
#define gethrtime collector_interface->getHiResTime
|
#define gethrtime collector_interface->getHiResTime
|
||||||
|
|
||||||
static void *(*__real_malloc)(size_t) = NULL;
|
static void *(*__real_malloc)(size_t) = NULL;
|
||||||
@@ -81,14 +82,6 @@ void *__libc_malloc (size_t);
|
|||||||
void __libc_free (void *);
|
void __libc_free (void *);
|
||||||
void *__libc_realloc (void *, size_t);
|
void *__libc_realloc (void *, size_t);
|
||||||
|
|
||||||
static void
|
|
||||||
collector_memset (void *s, int c, size_t n)
|
|
||||||
{
|
|
||||||
unsigned char *s1 = s;
|
|
||||||
while (n--)
|
|
||||||
*s1++ = (unsigned char) c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
__collector_module_init (CollectorInterface *_collector_interface)
|
__collector_module_init (CollectorInterface *_collector_interface)
|
||||||
{
|
{
|
||||||
@@ -139,14 +132,6 @@ open_experiment (const char *exp)
|
|||||||
if (params == NULL) /* Heap data collection not specified */
|
if (params == NULL) /* Heap data collection not specified */
|
||||||
return COL_ERROR_HEAPINIT;
|
return COL_ERROR_HEAPINIT;
|
||||||
|
|
||||||
heap_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
|
|
||||||
if (heap_key == (unsigned) - 1)
|
|
||||||
{
|
|
||||||
Tprintf (0, "heaptrace: TSD key create failed.\n");
|
|
||||||
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
|
|
||||||
SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
|
|
||||||
return COL_ERROR_HEAPINIT;
|
|
||||||
}
|
|
||||||
collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_HEAPTRACE);
|
collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_HEAPTRACE);
|
||||||
collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
|
collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
|
||||||
module_interface.description);
|
module_interface.description);
|
||||||
@@ -205,7 +190,6 @@ static int
|
|||||||
close_experiment (void)
|
close_experiment (void)
|
||||||
{
|
{
|
||||||
heap_mode = 0;
|
heap_mode = 0;
|
||||||
heap_key = COLLECTOR_TSD_INVALID_KEY;
|
|
||||||
Tprintf (0, "heaptrace: close_experiment\n");
|
Tprintf (0, "heaptrace: close_experiment\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -215,7 +199,6 @@ detach_experiment (void)
|
|||||||
/* fork child. Clean up state but don't write to experiment */
|
/* fork child. Clean up state but don't write to experiment */
|
||||||
{
|
{
|
||||||
heap_mode = 0;
|
heap_mode = 0;
|
||||||
heap_key = COLLECTOR_TSD_INVALID_KEY;
|
|
||||||
Tprintf (0, "heaptrace: detach_experiment\n");
|
Tprintf (0, "heaptrace: detach_experiment\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -265,36 +248,33 @@ void *
|
|||||||
malloc (size_t size)
|
malloc (size_t size)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
int *guard;
|
|
||||||
Heap_packet hpacket;
|
|
||||||
/* Linux startup workaround */
|
/* Linux startup workaround */
|
||||||
if (!heap_mode)
|
if (!heap_mode)
|
||||||
{
|
{
|
||||||
void *ppp = (void *) __libc_malloc (size);
|
ret = (void *) __libc_malloc (size);
|
||||||
Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)...\n", (long) size, ppp);
|
Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)\n", (long) size, ret);
|
||||||
return ppp;
|
return ret;
|
||||||
}
|
}
|
||||||
if (NULL_PTR (malloc))
|
if (NULL_PTR (malloc))
|
||||||
init_heap_intf ();
|
init_heap_intf ();
|
||||||
if (CHCK_REENTRANCE (guard))
|
if (CHCK_REENTRANCE)
|
||||||
{
|
{
|
||||||
ret = (void *) CALL_REAL (malloc)(size);
|
ret = (void *) CALL_REAL (malloc)(size);
|
||||||
Tprintf (DBG_LT4, "heaptrace: real malloc(%ld) = %p\n", (long) size, ret);
|
Tprintf (DBG_LT4, "heaptrace: real malloc(%ld) = %p\n", (long) size, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
PUSH_REENTRANCE (guard);
|
PUSH_REENTRANCE;
|
||||||
|
Heap_packet hpacket = heap_packet0;
|
||||||
ret = (void *) CALL_REAL (malloc)(size);
|
|
||||||
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
|
|
||||||
hpacket.comm.tsize = sizeof ( Heap_packet);
|
|
||||||
hpacket.comm.tstamp = gethrtime ();
|
hpacket.comm.tstamp = gethrtime ();
|
||||||
|
ret = (void *) CALL_REAL (malloc)(size);
|
||||||
hpacket.mtype = MALLOC_TRACE;
|
hpacket.mtype = MALLOC_TRACE;
|
||||||
hpacket.size = (Size_type) size;
|
hpacket.size = (Size_type) size;
|
||||||
hpacket.vaddr = (intptr_t) ret;
|
hpacket.vaddr = (intptr_t) ret;
|
||||||
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
|
||||||
|
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
||||||
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
||||||
POP_REENTRANCE (guard);
|
POP_REENTRANCE;
|
||||||
return (void *) ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------- free */
|
/*------------------------------------------------------------- free */
|
||||||
@@ -302,8 +282,6 @@ malloc (size_t size)
|
|||||||
void
|
void
|
||||||
free (void *ptr)
|
free (void *ptr)
|
||||||
{
|
{
|
||||||
int *guard;
|
|
||||||
Heap_packet hpacket;
|
|
||||||
/* Linux startup workaround */
|
/* Linux startup workaround */
|
||||||
if (!heap_mode)
|
if (!heap_mode)
|
||||||
{
|
{
|
||||||
@@ -311,28 +289,26 @@ free (void *ptr)
|
|||||||
__libc_free (ptr);
|
__libc_free (ptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (NULL_PTR (malloc))
|
if (NULL_PTR (free))
|
||||||
init_heap_intf ();
|
init_heap_intf ();
|
||||||
if (CHCK_REENTRANCE (guard))
|
if (ptr == NULL)
|
||||||
|
return;
|
||||||
|
if (CHCK_REENTRANCE)
|
||||||
{
|
{
|
||||||
CALL_REAL (free)(ptr);
|
CALL_REAL (free)(ptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ptr == NULL)
|
PUSH_REENTRANCE;
|
||||||
return;
|
|
||||||
PUSH_REENTRANCE (guard);
|
|
||||||
|
|
||||||
/* Get a timestamp before 'free' to enforce consistency */
|
/* Get a timestamp before 'free' to enforce consistency */
|
||||||
hrtime_t ts = gethrtime ();
|
Heap_packet hpacket = heap_packet0;
|
||||||
|
hpacket.comm.tstamp = gethrtime ();
|
||||||
CALL_REAL (free)(ptr);
|
CALL_REAL (free)(ptr);
|
||||||
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
|
|
||||||
hpacket.comm.tsize = sizeof ( Heap_packet);
|
|
||||||
hpacket.comm.tstamp = ts;
|
|
||||||
hpacket.mtype = FREE_TRACE;
|
hpacket.mtype = FREE_TRACE;
|
||||||
hpacket.vaddr = (intptr_t) ptr;
|
hpacket.vaddr = (intptr_t) ptr;
|
||||||
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
|
||||||
|
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
||||||
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
||||||
POP_REENTRANCE (guard);
|
POP_REENTRANCE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,9 +317,6 @@ void *
|
|||||||
realloc (void *ptr, size_t size)
|
realloc (void *ptr, size_t size)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
int *guard;
|
|
||||||
Heap_packet hpacket;
|
|
||||||
|
|
||||||
/* Linux startup workaround */
|
/* Linux startup workaround */
|
||||||
if (!heap_mode)
|
if (!heap_mode)
|
||||||
{
|
{
|
||||||
@@ -354,24 +327,23 @@ realloc (void *ptr, size_t size)
|
|||||||
}
|
}
|
||||||
if (NULL_PTR (realloc))
|
if (NULL_PTR (realloc))
|
||||||
init_heap_intf ();
|
init_heap_intf ();
|
||||||
if (CHCK_REENTRANCE (guard))
|
if (CHCK_REENTRANCE)
|
||||||
{
|
{
|
||||||
ret = (void *) CALL_REAL (realloc)(ptr, size);
|
ret = (void *) CALL_REAL (realloc)(ptr, size);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
PUSH_REENTRANCE (guard);
|
PUSH_REENTRANCE;
|
||||||
hrtime_t ts = gethrtime ();
|
Heap_packet hpacket = heap_packet0;
|
||||||
|
hpacket.comm.tstamp = gethrtime ();
|
||||||
ret = (void *) CALL_REAL (realloc)(ptr, size);
|
ret = (void *) CALL_REAL (realloc)(ptr, size);
|
||||||
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
|
|
||||||
hpacket.comm.tsize = sizeof ( Heap_packet);
|
|
||||||
hpacket.comm.tstamp = ts;
|
|
||||||
hpacket.mtype = REALLOC_TRACE;
|
hpacket.mtype = REALLOC_TRACE;
|
||||||
hpacket.size = (Size_type) size;
|
hpacket.size = (Size_type) size;
|
||||||
hpacket.vaddr = (intptr_t) ret;
|
hpacket.vaddr = (intptr_t) ret;
|
||||||
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
|
||||||
|
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
||||||
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
||||||
POP_REENTRANCE (guard);
|
POP_REENTRANCE;
|
||||||
return (void *) ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------- memalign */
|
/*------------------------------------------------------------- memalign */
|
||||||
@@ -379,26 +351,24 @@ void *
|
|||||||
memalign (size_t align, size_t size)
|
memalign (size_t align, size_t size)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
int *guard;
|
|
||||||
Heap_packet hpacket;
|
|
||||||
if (NULL_PTR (memalign))
|
if (NULL_PTR (memalign))
|
||||||
init_heap_intf ();
|
init_heap_intf ();
|
||||||
if (CHCK_REENTRANCE (guard))
|
if (CHCK_REENTRANCE)
|
||||||
{
|
{
|
||||||
ret = (void *) CALL_REAL (memalign)(align, size);
|
ret = (void *) CALL_REAL (memalign)(align, size);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
PUSH_REENTRANCE (guard);
|
PUSH_REENTRANCE;
|
||||||
ret = (void *) CALL_REAL (memalign)(align, size);
|
Heap_packet hpacket = heap_packet0;
|
||||||
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
|
|
||||||
hpacket.comm.tsize = sizeof ( Heap_packet);
|
|
||||||
hpacket.comm.tstamp = gethrtime ();
|
hpacket.comm.tstamp = gethrtime ();
|
||||||
|
ret = (void *) CALL_REAL (memalign)(align, size);
|
||||||
hpacket.mtype = MALLOC_TRACE;
|
hpacket.mtype = MALLOC_TRACE;
|
||||||
hpacket.size = (Size_type) size;
|
hpacket.size = (Size_type) size;
|
||||||
hpacket.vaddr = (intptr_t) ret;
|
hpacket.vaddr = (intptr_t) ret;
|
||||||
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
|
||||||
|
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
||||||
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
||||||
POP_REENTRANCE (guard);
|
POP_REENTRANCE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,26 +378,24 @@ void *
|
|||||||
valloc (size_t size)
|
valloc (size_t size)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
int *guard;
|
if (NULL_PTR (valloc))
|
||||||
Heap_packet hpacket;
|
|
||||||
if (NULL_PTR (memalign))
|
|
||||||
init_heap_intf ();
|
init_heap_intf ();
|
||||||
if (CHCK_REENTRANCE (guard))
|
if (CHCK_REENTRANCE)
|
||||||
{
|
{
|
||||||
ret = (void *) CALL_REAL (valloc)(size);
|
ret = (void *) CALL_REAL (valloc)(size);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
PUSH_REENTRANCE (guard);
|
PUSH_REENTRANCE;
|
||||||
ret = (void *) CALL_REAL (valloc)(size);
|
Heap_packet hpacket = heap_packet0;
|
||||||
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
|
|
||||||
hpacket.comm.tsize = sizeof ( Heap_packet);
|
|
||||||
hpacket.comm.tstamp = gethrtime ();
|
hpacket.comm.tstamp = gethrtime ();
|
||||||
|
ret = (void *) CALL_REAL (valloc)(size);
|
||||||
hpacket.mtype = MALLOC_TRACE;
|
hpacket.mtype = MALLOC_TRACE;
|
||||||
hpacket.size = (Size_type) size;
|
hpacket.size = (Size_type) size;
|
||||||
hpacket.vaddr = (intptr_t) ret;
|
hpacket.vaddr = (intptr_t) ret;
|
||||||
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
|
||||||
|
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
||||||
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
||||||
POP_REENTRANCE (guard);
|
POP_REENTRANCE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,30 +404,28 @@ void *
|
|||||||
calloc (size_t size, size_t esize)
|
calloc (size_t size, size_t esize)
|
||||||
{
|
{
|
||||||
void *ret;
|
void *ret;
|
||||||
int *guard;
|
|
||||||
Heap_packet hpacket;
|
|
||||||
if (NULL_PTR (calloc))
|
if (NULL_PTR (calloc))
|
||||||
{
|
{
|
||||||
if (in_init_heap_intf != 0)
|
if (in_init_heap_intf != 0)
|
||||||
return NULL; // Terminate infinite loop
|
return NULL; // Terminate infinite loop
|
||||||
init_heap_intf ();
|
init_heap_intf ();
|
||||||
}
|
}
|
||||||
if (CHCK_REENTRANCE (guard))
|
if (CHCK_REENTRANCE)
|
||||||
{
|
{
|
||||||
ret = (void *) CALL_REAL (calloc)(size, esize);
|
ret = (void *) CALL_REAL (calloc)(size, esize);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
PUSH_REENTRANCE (guard);
|
PUSH_REENTRANCE;
|
||||||
ret = (void *) CALL_REAL (calloc)(size, esize);
|
Heap_packet hpacket = heap_packet0;
|
||||||
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
|
|
||||||
hpacket.comm.tsize = sizeof ( Heap_packet);
|
|
||||||
hpacket.comm.tstamp = gethrtime ();
|
hpacket.comm.tstamp = gethrtime ();
|
||||||
|
ret = (void *) CALL_REAL (calloc)(size, esize);
|
||||||
hpacket.mtype = MALLOC_TRACE;
|
hpacket.mtype = MALLOC_TRACE;
|
||||||
hpacket.size = (Size_type) (size * esize);
|
hpacket.size = (Size_type) (size * esize);
|
||||||
hpacket.vaddr = (intptr_t) ret;
|
hpacket.vaddr = (intptr_t) ret;
|
||||||
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
|
||||||
|
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
||||||
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
||||||
POP_REENTRANCE (guard);
|
POP_REENTRANCE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,19 +435,17 @@ calloc (size_t size, size_t esize)
|
|||||||
void
|
void
|
||||||
__collector_heap_record (int mtype, size_t size, void *vaddr)
|
__collector_heap_record (int mtype, size_t size, void *vaddr)
|
||||||
{
|
{
|
||||||
int *guard;
|
if (CHCK_REENTRANCE)
|
||||||
Heap_packet hpacket;
|
|
||||||
if (CHCK_REENTRANCE (guard))
|
|
||||||
return;
|
return;
|
||||||
PUSH_REENTRANCE (guard);
|
PUSH_REENTRANCE;
|
||||||
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
|
Heap_packet hpacket = heap_packet0;
|
||||||
hpacket.comm.tsize = sizeof ( Heap_packet);
|
|
||||||
hpacket.comm.tstamp = gethrtime ();
|
hpacket.comm.tstamp = gethrtime ();
|
||||||
hpacket.mtype = mtype;
|
hpacket.mtype = mtype;
|
||||||
hpacket.size = (Size_type) size;
|
hpacket.size = (Size_type) size;
|
||||||
hpacket.vaddr = (intptr_t) vaddr;
|
hpacket.vaddr = (intptr_t) vaddr;
|
||||||
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
|
||||||
|
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
|
||||||
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
|
||||||
POP_REENTRANCE (guard);
|
POP_REENTRANCE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user