Description:
From code analysis:
void *_lf_alloc_new(LF_PINS *pins)
{
LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg);
uchar *node;
for (;;)
{
do
{
(1)
node= allocator->top;
_lf_pin(pins, 0, node);
} while (node != allocator->top && LF_BACKOFF);
if (!node)
{
(2)
node= (void *)my_malloc(allocator->element_size, MYF(MY_WME));
if (allocator->constructor)
allocator->constructor(node);
#ifdef MY_LF_EXTRA_DEBUG
if (likely(node != 0))
my_atomic_add32(&allocator->mallocs, 1);
#endif
break;
}
(3)
if (my_atomic_casptr((void **)(char *)&allocator->top,
(void *)&node, anext_node(node)))
break;
}
_lf_unpin(pins, 0);
return node;
}
When the atomic CAS operation from (3) fails, the code loops again in the
for (;;) loop.
In this case, memory allocated in (2) is lost, since 'node' is assigned to
a new value in (1).
This seems to be the root cause of spurious memory leaks such as:
==23899==
==23899== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 3 from 1)
==23899== malloc/free: in use at exit: 48 bytes in 2 blocks.
==23899== malloc/free: 5,483 allocs, 5,481 frees, 66,622,748 bytes allocated.
==23899== For counts of detected errors, rerun with: -v
==23899== searching for pointers to 2 not-freed blocks.
==23899== checked 1,596,840 bytes.
==23899==
==23899== 20 bytes in 1 blocks are definitely lost in loss record 1 of 2
==23899== at 0x4024D5E: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==23899== by 0x873C90B: my_malloc (my_malloc.c:37)
==23899== by 0x874A9D0: _lf_alloc_new (lf_alloc-pin.c:503)
==23899== by 0x87B2BBB: lf_hash_insert (lf_hash.c:373)
==23899== by 0x87D43CB: find_or_create_file(PFS_thread*, PFS_file_class*, char const*, unsigned) (pfs_instr.cc:802)
==23899== by 0x87E0F23: _ZL30get_thread_file_name_locker_v1j18PSI_file_operationPKcPKv (pfs.cc:1297)
==23899== by 0x82F44BD: _ZL24inline_mysql_file_createjPKcjS0_iii (mysql_file.h:861)
==23899== by 0x82F470F: _ZL15create_pid_filev (mysqld.cc:9547)
==23899== by 0x82F91BE: signal_hand (mysqld.cc:2926)
==23899== by 0x87E138B: pfs_spawn_thread(void*) (pfs.cc:1007)
==23899== by 0x406A174: start_thread (in /lib/libpthread-2.8.so)
==23899== by 0x42BFDAD: clone (in /lib/libc-2.8.so)
==23899==
==23899== LEAK SUMMARY:
==23899== definitely lost: 20 bytes in 1 blocks.
==23899== possibly lost: 0 bytes in 0 blocks.
==23899== still reachable: 0 bytes in 0 blocks.
==23899== suppressed: 28 bytes in 1 blocks.
which was detected in mysql-azalea-perfschema.
How to repeat:
Read the code.
Note that for atomic operations to fail, you need a multi core machine,
when using native atomic operations.
Suggested fix:
Reuse the allocated node instead of allocating a new one in each loop iteration
Description: From code analysis: void *_lf_alloc_new(LF_PINS *pins) { LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg); uchar *node; for (;;) { do { (1) node= allocator->top; _lf_pin(pins, 0, node); } while (node != allocator->top && LF_BACKOFF); if (!node) { (2) node= (void *)my_malloc(allocator->element_size, MYF(MY_WME)); if (allocator->constructor) allocator->constructor(node); #ifdef MY_LF_EXTRA_DEBUG if (likely(node != 0)) my_atomic_add32(&allocator->mallocs, 1); #endif break; } (3) if (my_atomic_casptr((void **)(char *)&allocator->top, (void *)&node, anext_node(node))) break; } _lf_unpin(pins, 0); return node; } When the atomic CAS operation from (3) fails, the code loops again in the for (;;) loop. In this case, memory allocated in (2) is lost, since 'node' is assigned to a new value in (1). This seems to be the root cause of spurious memory leaks such as: ==23899== ==23899== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 3 from 1) ==23899== malloc/free: in use at exit: 48 bytes in 2 blocks. ==23899== malloc/free: 5,483 allocs, 5,481 frees, 66,622,748 bytes allocated. ==23899== For counts of detected errors, rerun with: -v ==23899== searching for pointers to 2 not-freed blocks. ==23899== checked 1,596,840 bytes. ==23899== ==23899== 20 bytes in 1 blocks are definitely lost in loss record 1 of 2 ==23899== at 0x4024D5E: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so) ==23899== by 0x873C90B: my_malloc (my_malloc.c:37) ==23899== by 0x874A9D0: _lf_alloc_new (lf_alloc-pin.c:503) ==23899== by 0x87B2BBB: lf_hash_insert (lf_hash.c:373) ==23899== by 0x87D43CB: find_or_create_file(PFS_thread*, PFS_file_class*, char const*, unsigned) (pfs_instr.cc:802) ==23899== by 0x87E0F23: _ZL30get_thread_file_name_locker_v1j18PSI_file_operationPKcPKv (pfs.cc:1297) ==23899== by 0x82F44BD: _ZL24inline_mysql_file_createjPKcjS0_iii (mysql_file.h:861) ==23899== by 0x82F470F: _ZL15create_pid_filev (mysqld.cc:9547) ==23899== by 0x82F91BE: signal_hand (mysqld.cc:2926) ==23899== by 0x87E138B: pfs_spawn_thread(void*) (pfs.cc:1007) ==23899== by 0x406A174: start_thread (in /lib/libpthread-2.8.so) ==23899== by 0x42BFDAD: clone (in /lib/libc-2.8.so) ==23899== ==23899== LEAK SUMMARY: ==23899== definitely lost: 20 bytes in 1 blocks. ==23899== possibly lost: 0 bytes in 0 blocks. ==23899== still reachable: 0 bytes in 0 blocks. ==23899== suppressed: 28 bytes in 1 blocks. which was detected in mysql-azalea-perfschema. How to repeat: Read the code. Note that for atomic operations to fail, you need a multi core machine, when using native atomic operations. Suggested fix: Reuse the allocated node instead of allocating a new one in each loop iteration