Skip to content

Commit 99c3fe5

Browse files
author
Vladimir Mezentsev
committedMar 25, 2024
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 <[email protected]> PR gprofng/31460 * libcollector/heaptrace.c: Use the __thread variable to check for * reentry. Clean up code.
1 parent 02d02fc commit 99c3fe5

File tree

1 file changed

+62
-98
lines changed

1 file changed

+62
-98
lines changed
 

‎gprofng/libcollector/heaptrace.c

+62-98
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ static ModuleInterface module_interface = {
6262
static CollectorInterface *collector_interface = NULL;
6363
static int heap_mode = 0;
6464
static CollectorModule heap_hndl = COLLECTOR_MODULE_ERR;
65-
static unsigned heap_key = COLLECTOR_TSD_INVALID_KEY;
65+
static const Heap_packet heap_packet0 = { .comm.tsize = sizeof ( Heap_packet) };
66+
static __thread int reentrance = 0;
6667

67-
#define CHCK_REENTRANCE(x) ( !heap_mode || ((x) = collector_interface->getKey( heap_key )) == NULL || (*(x) != 0) )
68-
#define PUSH_REENTRANCE(x) ((*(x))++)
69-
#define POP_REENTRANCE(x) ((*(x))--)
68+
#define CHCK_REENTRANCE ( !heap_mode || reentrance != 0 )
69+
#define PUSH_REENTRANCE (reentrance++)
70+
#define POP_REENTRANCE (reentrance--)
7071
#define gethrtime collector_interface->getHiResTime
7172

7273
static void *(*__real_malloc)(size_t) = NULL;
@@ -81,14 +82,6 @@ void *__libc_malloc (size_t);
8182
void __libc_free (void *);
8283
void *__libc_realloc (void *, size_t);
8384

84-
static void
85-
collector_memset (void *s, int c, size_t n)
86-
{
87-
unsigned char *s1 = s;
88-
while (n--)
89-
*s1++ = (unsigned char) c;
90-
}
91-
9285
void
9386
__collector_module_init (CollectorInterface *_collector_interface)
9487
{
@@ -139,14 +132,6 @@ open_experiment (const char *exp)
139132
if (params == NULL) /* Heap data collection not specified */
140133
return COL_ERROR_HEAPINIT;
141134

142-
heap_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
143-
if (heap_key == (unsigned) - 1)
144-
{
145-
Tprintf (0, "heaptrace: TSD key create failed.\n");
146-
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
147-
SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
148-
return COL_ERROR_HEAPINIT;
149-
}
150135
collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_HEAPTRACE);
151136
collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
152137
module_interface.description);
@@ -205,7 +190,6 @@ static int
205190
close_experiment (void)
206191
{
207192
heap_mode = 0;
208-
heap_key = COLLECTOR_TSD_INVALID_KEY;
209193
Tprintf (0, "heaptrace: close_experiment\n");
210194
return 0;
211195
}
@@ -215,7 +199,6 @@ detach_experiment (void)
215199
/* fork child. Clean up state but don't write to experiment */
216200
{
217201
heap_mode = 0;
218-
heap_key = COLLECTOR_TSD_INVALID_KEY;
219202
Tprintf (0, "heaptrace: detach_experiment\n");
220203
return 0;
221204
}
@@ -265,74 +248,67 @@ void *
265248
malloc (size_t size)
266249
{
267250
void *ret;
268-
int *guard;
269-
Heap_packet hpacket;
270251
/* Linux startup workaround */
271252
if (!heap_mode)
272253
{
273-
void *ppp = (void *) __libc_malloc (size);
274-
Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)...\n", (long) size, ppp);
275-
return ppp;
254+
ret = (void *) __libc_malloc (size);
255+
Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)\n", (long) size, ret);
256+
return ret;
276257
}
277258
if (NULL_PTR (malloc))
278259
init_heap_intf ();
279-
if (CHCK_REENTRANCE (guard))
260+
if (CHCK_REENTRANCE)
280261
{
281262
ret = (void *) CALL_REAL (malloc)(size);
282263
Tprintf (DBG_LT4, "heaptrace: real malloc(%ld) = %p\n", (long) size, ret);
283264
return ret;
284265
}
285-
PUSH_REENTRANCE (guard);
286-
287-
ret = (void *) CALL_REAL (malloc)(size);
288-
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
289-
hpacket.comm.tsize = sizeof ( Heap_packet);
266+
PUSH_REENTRANCE;
267+
Heap_packet hpacket = heap_packet0;
290268
hpacket.comm.tstamp = gethrtime ();
269+
ret = (void *) CALL_REAL (malloc)(size);
291270
hpacket.mtype = MALLOC_TRACE;
292271
hpacket.size = (Size_type) size;
293272
hpacket.vaddr = (intptr_t) ret;
294-
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
273+
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
274+
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
295275
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
296-
POP_REENTRANCE (guard);
297-
return (void *) ret;
276+
POP_REENTRANCE;
277+
return ret;
298278
}
299279

300280
/*------------------------------------------------------------- free */
301281

302282
void
303283
free (void *ptr)
304284
{
305-
int *guard;
306-
Heap_packet hpacket;
307285
/* Linux startup workaround */
308286
if (!heap_mode)
309287
{
310288
// Tprintf(DBG_LT4,"heaptrace: LINUX free(%p)...\n",ptr);
311289
__libc_free (ptr);
312290
return;
313291
}
314-
if (NULL_PTR (malloc))
292+
if (NULL_PTR (free))
315293
init_heap_intf ();
316-
if (CHCK_REENTRANCE (guard))
294+
if (ptr == NULL)
295+
return;
296+
if (CHCK_REENTRANCE)
317297
{
318298
CALL_REAL (free)(ptr);
319299
return;
320300
}
321-
if (ptr == NULL)
322-
return;
323-
PUSH_REENTRANCE (guard);
324-
301+
PUSH_REENTRANCE;
325302
/* Get a timestamp before 'free' to enforce consistency */
326-
hrtime_t ts = gethrtime ();
303+
Heap_packet hpacket = heap_packet0;
304+
hpacket.comm.tstamp = gethrtime ();
327305
CALL_REAL (free)(ptr);
328-
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
329-
hpacket.comm.tsize = sizeof ( Heap_packet);
330-
hpacket.comm.tstamp = ts;
331306
hpacket.mtype = FREE_TRACE;
332307
hpacket.vaddr = (intptr_t) ptr;
333-
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
308+
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
309+
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
334310
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
335-
POP_REENTRANCE (guard);
311+
POP_REENTRANCE;
336312
return;
337313
}
338314

@@ -341,9 +317,6 @@ void *
341317
realloc (void *ptr, size_t size)
342318
{
343319
void *ret;
344-
int *guard;
345-
Heap_packet hpacket;
346-
347320
/* Linux startup workaround */
348321
if (!heap_mode)
349322
{
@@ -354,51 +327,48 @@ realloc (void *ptr, size_t size)
354327
}
355328
if (NULL_PTR (realloc))
356329
init_heap_intf ();
357-
if (CHCK_REENTRANCE (guard))
330+
if (CHCK_REENTRANCE)
358331
{
359332
ret = (void *) CALL_REAL (realloc)(ptr, size);
360333
return ret;
361334
}
362-
PUSH_REENTRANCE (guard);
363-
hrtime_t ts = gethrtime ();
335+
PUSH_REENTRANCE;
336+
Heap_packet hpacket = heap_packet0;
337+
hpacket.comm.tstamp = gethrtime ();
364338
ret = (void *) CALL_REAL (realloc)(ptr, size);
365-
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
366-
hpacket.comm.tsize = sizeof ( Heap_packet);
367-
hpacket.comm.tstamp = ts;
368339
hpacket.mtype = REALLOC_TRACE;
369340
hpacket.size = (Size_type) size;
370341
hpacket.vaddr = (intptr_t) ret;
371-
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
342+
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
343+
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
372344
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
373-
POP_REENTRANCE (guard);
374-
return (void *) ret;
345+
POP_REENTRANCE;
346+
return ret;
375347
}
376348

377349
/*------------------------------------------------------------- memalign */
378350
void *
379351
memalign (size_t align, size_t size)
380352
{
381353
void *ret;
382-
int *guard;
383-
Heap_packet hpacket;
384354
if (NULL_PTR (memalign))
385355
init_heap_intf ();
386-
if (CHCK_REENTRANCE (guard))
356+
if (CHCK_REENTRANCE)
387357
{
388358
ret = (void *) CALL_REAL (memalign)(align, size);
389359
return ret;
390360
}
391-
PUSH_REENTRANCE (guard);
392-
ret = (void *) CALL_REAL (memalign)(align, size);
393-
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
394-
hpacket.comm.tsize = sizeof ( Heap_packet);
361+
PUSH_REENTRANCE;
362+
Heap_packet hpacket = heap_packet0;
395363
hpacket.comm.tstamp = gethrtime ();
364+
ret = (void *) CALL_REAL (memalign)(align, size);
396365
hpacket.mtype = MALLOC_TRACE;
397366
hpacket.size = (Size_type) size;
398367
hpacket.vaddr = (intptr_t) ret;
399-
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
368+
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
369+
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
400370
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
401-
POP_REENTRANCE (guard);
371+
POP_REENTRANCE;
402372
return ret;
403373
}
404374

@@ -408,26 +378,24 @@ void *
408378
valloc (size_t size)
409379
{
410380
void *ret;
411-
int *guard;
412-
Heap_packet hpacket;
413-
if (NULL_PTR (memalign))
381+
if (NULL_PTR (valloc))
414382
init_heap_intf ();
415-
if (CHCK_REENTRANCE (guard))
383+
if (CHCK_REENTRANCE)
416384
{
417385
ret = (void *) CALL_REAL (valloc)(size);
418386
return ret;
419387
}
420-
PUSH_REENTRANCE (guard);
421-
ret = (void *) CALL_REAL (valloc)(size);
422-
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
423-
hpacket.comm.tsize = sizeof ( Heap_packet);
388+
PUSH_REENTRANCE;
389+
Heap_packet hpacket = heap_packet0;
424390
hpacket.comm.tstamp = gethrtime ();
391+
ret = (void *) CALL_REAL (valloc)(size);
425392
hpacket.mtype = MALLOC_TRACE;
426393
hpacket.size = (Size_type) size;
427394
hpacket.vaddr = (intptr_t) ret;
428-
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
395+
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
396+
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
429397
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
430-
POP_REENTRANCE (guard);
398+
POP_REENTRANCE;
431399
return ret;
432400
}
433401

@@ -436,30 +404,28 @@ void *
436404
calloc (size_t size, size_t esize)
437405
{
438406
void *ret;
439-
int *guard;
440-
Heap_packet hpacket;
441407
if (NULL_PTR (calloc))
442408
{
443409
if (in_init_heap_intf != 0)
444410
return NULL; // Terminate infinite loop
445411
init_heap_intf ();
446412
}
447-
if (CHCK_REENTRANCE (guard))
413+
if (CHCK_REENTRANCE)
448414
{
449415
ret = (void *) CALL_REAL (calloc)(size, esize);
450416
return ret;
451417
}
452-
PUSH_REENTRANCE (guard);
453-
ret = (void *) CALL_REAL (calloc)(size, esize);
454-
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
455-
hpacket.comm.tsize = sizeof ( Heap_packet);
418+
PUSH_REENTRANCE;
419+
Heap_packet hpacket = heap_packet0;
456420
hpacket.comm.tstamp = gethrtime ();
421+
ret = (void *) CALL_REAL (calloc)(size, esize);
457422
hpacket.mtype = MALLOC_TRACE;
458423
hpacket.size = (Size_type) (size * esize);
459424
hpacket.vaddr = (intptr_t) ret;
460-
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
425+
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
426+
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
461427
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
462-
POP_REENTRANCE (guard);
428+
POP_REENTRANCE;
463429
return ret;
464430
}
465431

@@ -469,19 +435,17 @@ calloc (size_t size, size_t esize)
469435
void
470436
__collector_heap_record (int mtype, size_t size, void *vaddr)
471437
{
472-
int *guard;
473-
Heap_packet hpacket;
474-
if (CHCK_REENTRANCE (guard))
438+
if (CHCK_REENTRANCE)
475439
return;
476-
PUSH_REENTRANCE (guard);
477-
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
478-
hpacket.comm.tsize = sizeof ( Heap_packet);
440+
PUSH_REENTRANCE;
441+
Heap_packet hpacket = heap_packet0;
479442
hpacket.comm.tstamp = gethrtime ();
480443
hpacket.mtype = mtype;
481444
hpacket.size = (Size_type) size;
482445
hpacket.vaddr = (intptr_t) vaddr;
483-
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
446+
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl,
447+
hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
484448
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
485-
POP_REENTRANCE (guard);
449+
POP_REENTRANCE;
486450
return;
487451
}

0 commit comments

Comments
 (0)
Please sign in to comment.