modules: client-node: memory leak due to non-portable use of realloc()
realloc(ptr, 0)
where ptr
is not NULL
behaves as free(ptr)
in glibc, but it does not behave as such e.g. in musl. This can lead to memory leaks, e.g.:
Direct leak of 3906 byte(s) in 3906 object(s) allocated from:
#0 0x7f4544d48652 in __interceptor_realloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:164
#1 0x7f453d966bd1 (/usr/lib/libasan.so.6.0.0+0x35ebd1)
#2 0x7f453d978f9f (/usr/lib/libasan.so.6.0.0+0x370f9f)
#3 0x7f453d97a42c (/usr/lib/libasan.so.6.0.0+0x37242c)
#4 0x7f45446582b1 in pw_impl_port_remove ../src/pipewire/impl-port.c:1080
#5 0x7f4544669bbf in pw_impl_port_destroy ../src/pipewire/impl-port.c:1102
#6 0x7f45446052cb in node_port_info ../src/pipewire/impl-node.c:1386
#7 0x7f453d979fff (/usr/lib/libasan.so.6.0.0+0x371fff)
#8 0x7f453d97a6b4 (/usr/lib/libasan.so.6.0.0+0x3726b4)
#9 0x7f453d9abc44 (/usr/lib/libasan.so.6.0.0+0x3a3c44)
#10 0x7f453ee87a66 (<unknown module>)
#11 0x7f453ee88b5e (<unknown module>)
#12 0x7f453f414c51 (<unknown module>)
#13 0x7f453f417b4e (<unknown module>)
#14 0x7f45445a7cae in pw_main_loop_run ../src/pipewire/main-loop.c:155
#15 0x5565ef8282df in main ../src/daemon/pipewire.c:129
#16 0x7f45434cab24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
(asan registers registers a 1 byte leak if it's not configured to behave as glibc with regards to realloc(ptr, 0)
).
The gdb
stack trace reveals the exact location of the problem:
Thread 1 "pipewire" hit Breakpoint 2, pw_impl_port_remove (port=port@entry=0x61d00003fc80) at ../src/pipewire/impl-port.c:1049
1049 {
[D][65287.513429] pw.port | [ impl-port.c: 1056 pw_impl_port_remove()] 0x61d00003fc80: remove added:0
[D][65287.513470] pw.port | [ impl-port.c: 550 pw_impl_port_set_mix()] 0x61d00003fc80: mix node 0x61d0000403a0->0x61d000040338
[D][65287.513497] mod.client-node | [ client-node.c: 1581 node_port_removed()] 0x62900007d220: port 0x61d00003fc80 remove
Thread 1 "pipewire" hit Breakpoint 1, __interceptor_realloc (ptr=0x60400001b990, size=size@entry=0) at /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:158
158 /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp: Nincs ilyen fájl vagy könyvtár.
#0 __interceptor_realloc (ptr=0x60400001b990, size=size@entry=0) at /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:158
#1 0x00007ffff0266bd2 in do_update_port (this=this@entry=0x62900007d220, port=port@entry=0x61d000040380, change_mask=change_mask@entry=3, n_params=n_params@entry=0, params=params@entry=0x0, info=info@entry=0x0) at ../src/modules/module-client-node/client-node.c:496
#2 0x00007ffff0278fa0 in clear_port (this=this@entry=0x62900007d220, port=port@entry=0x61d000040380) at ../src/modules/module-client-node/client-node.c:529
#3 0x00007ffff027a42d in node_port_removed (data=0x62900007d200, port=0x61d00003fc80) at ../src/modules/module-client-node/client-node.c:1584
#4 0x00007ffff6f732b2 in pw_impl_port_remove (port=port@entry=0x61d00003fc80) at ../src/pipewire/impl-port.c:1080
#5 0x00007ffff6f84bc0 in pw_impl_port_destroy (port=port@entry=0x61d00003fc80) at ../src/pipewire/impl-port.c:1102
#6 0x00007ffff6f168a9 in pw_impl_node_destroy (node=node@entry=0x61d00003ca80) at ../src/pipewire/impl-node.c:1786
#7 0x00007ffff6f18dbb in global_destroy (data=0x61d00003ca80) at ../src/pipewire/impl-node.c:632
#8 0x00007ffff6e7ff3c in pw_global_destroy (global=global@entry=0x60b000044e50) at ../src/pipewire/global.c:378
#9 0x00007ffff6d99bba in registry_destroy (object=<optimized out>, id=96) at ../src/pipewire/impl-core.c:140
#10 0x00007ffff1796adc in registry_demarshal_destroy (object=<optimized out>, msg=<optimized out>) at ../src/modules/module-protocol-native/protocol-native.c:732
#11 0x00007ffff1787a67 in process_messages (data=data@entry=0x616000002010) at ../src/modules/module-protocol-native.c:246
#12 0x00007ffff1788b5f in connection_data (data=0x616000002010, fd=<optimized out>, mask=1) at ../src/modules/module-protocol-native.c:317
#13 0x00007ffff1d14c52 in source_io_func (source=0x608000003da0) at ../spa/plugins/support/loop.c:347
#14 0x00007ffff1d17b4f in loop_iterate (object=0x62d000000428, timeout=<optimized out>) at ../spa/plugins/support/loop.c:335
#15 0x00007ffff6ec2caf in pw_main_loop_run (loop=loop@entry=0x60400000cf50) at ../src/pipewire/main-loop.c:155
#16 0x00005555555582e0 in main (argc=<optimized out>, argv=<optimized out>) at ../src/daemon/pipewire.c:129
static void
do_update_port(struct node *this,
struct port *port,
uint32_t change_mask,
uint32_t n_params,
const struct spa_pod **params,
const struct spa_port_info *info)
{
uint32_t i;
if (change_mask & PW_CLIENT_NODE_PORT_UPDATE_PARAMS) {
spa_log_debug(this->log, "%p: port %u update %d params", this, port->id, n_params);
for (i = 0; i < port->n_params; i++)
free(port->params[i]);
port->n_params = n_params;
port->params = realloc(port->params, port->n_params * sizeof(struct spa_pod *)); // <-----
for (i = 0; i < port->n_params; i++) {
port->params[i] = params[i] ? spa_pod_copy(params[i]) : NULL;
}
}
// ...
There may be other places (for example, in the session-manager
module and in introspect.c
) where the same issue could potentially manifest itself.