GSTREAMER最小程序泄漏内存

发布于 2025-02-12 07:42:40 字数 890 浏览 0 评论 0原文

我有一个最小的 gstreamer program:

#include <gst/gst.h>

int main() {
   gst_init(NULL, NULL);
   gst_deinit();
}

我使用gcc test.c $(pkg-config(pkg-config) -fflags -libs gstreamer-1.0)-fsanitize = address(GCC是版本12.1.0),运行它并从地址消毒剂中获取以下输出:

==87326==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16384 byte(s) in 1 object(s) allocated from:
    #0 0x7f53e28bfa89 in __interceptor_malloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7f53e26c1b19 in g_malloc (/usr/lib/libglib-2.0.so.0+0x5db19)

SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).

我是GSTREAMER和GLIB的新手。这对于GSTREAMER程序来说是正常的吗?如果是这样,在使用消毒剂进行单元测试时,忽略此泄漏的一种优雅方式是什么?

I have a minimal GStreamer program:

#include <gst/gst.h>

int main() {
   gst_init(NULL, NULL);
   gst_deinit();
}

I build it with gcc test.c $(pkg-config --cflags --libs gstreamer-1.0) -fsanitize=address (gcc is version 12.1.0), run it and get the following output from the address sanitizer:

==87326==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16384 byte(s) in 1 object(s) allocated from:
    #0 0x7f53e28bfa89 in __interceptor_malloc /usr/src/debug/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7f53e26c1b19 in g_malloc (/usr/lib/libglib-2.0.so.0+0x5db19)

SUMMARY: AddressSanitizer: 16384 byte(s) leaked in 1 allocation(s).

I'm new to GStreamer and GLib. Is this normal for GStreamer programs? And if it is, what would be an elegant way to ignore this leak when running unit tests with sanitizers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

时间你老了 2025-02-19 07:42:40

问题在于,有一些版本的 g_intern_string ,例如 libglib-2.0.so.0.6400.6 中的一个版本,当它们成长时,它们具有一个错误哈希地图的存储库数组,它们无法释放旧数组。

泄漏是在G_Intern_string的此拆卸中显示的最后一个指令:

   0x7ffff7b44a70 <g_intern_string>:    endbr64 
   0x7ffff7b44a74 <g_intern_string+4>:  push   %r12
   0x7ffff7b44a76 <g_intern_string+6>:  push   %rbp
   0x7ffff7b44a77 <g_intern_string+7>:  push   %rbx
   0x7ffff7b44a78 <g_intern_string+8>:  test   %rdi,%rdi
   0x7ffff7b44a7b <g_intern_string+11>: 
    je     0x7ffff7b44b88 <g_intern_string+280>
   0x7ffff7b44a81 <g_intern_string+17>: mov    %rdi,%rbp
   0x7ffff7b44a84 <g_intern_string+20>: 
    lea    0xc5225(%rip),%rdi        # 0x7ffff7c09cb0
   0x7ffff7b44a8b <g_intern_string+27>: callq  0x7ffff7b814d0 <g_mutex_lock>
   0x7ffff7b44a90 <g_intern_string+32>: 
    mov    0xc5211(%rip),%rdi        # 0x7ffff7c09ca8
   0x7ffff7b44a97 <g_intern_string+39>: mov    %rbp,%rsi
   0x7ffff7b44a9a <g_intern_string+42>: 
    callq  0x7ffff7b21710 <g_hash_table_lookup>
   0x7ffff7b44a9f <g_intern_string+47>: test   %eax,%eax
   0x7ffff7b44aa1 <g_intern_string+49>: 
    je     0x7ffff7b44ad0 <g_intern_string+96>
   0x7ffff7b44aa3 <g_intern_string+51>: mov    %eax,%eax
   0x7ffff7b44aa5 <g_intern_string+53>: lea    0x0(,%rax,8),%rbx
   0x7ffff7b44aad <g_intern_string+61>: 
    mov    0xc51ec(%rip),%rax        # 0x7ffff7c09ca0
   0x7ffff7b44ab4 <g_intern_string+68>: 
    lea    0xc51f5(%rip),%rdi        # 0x7ffff7c09cb0
   0x7ffff7b44abb <g_intern_string+75>: mov    (%rax,%rbx,1),%r12
   0x7ffff7b44abf <g_intern_string+79>: callq  0x7ffff7b81500 <g_mutex_unlock>
   0x7ffff7b44ac4 <g_intern_string+84>: pop    %rbx
   0x7ffff7b44ac5 <g_intern_string+85>: pop    %rbp
   0x7ffff7b44ac6 <g_intern_string+86>: mov    %r12,%rax
   0x7ffff7b44ac9 <g_intern_string+89>: pop    %r12
   0x7ffff7b44acb <g_intern_string+91>: retq   
   0x7ffff7b44acc <g_intern_string+92>: nopl   0x0(%rax)
   0x7ffff7b44ad0 <g_intern_string+96>: mov    %rbp,%rdi
   0x7ffff7b44ad3 <g_intern_string+99>: callq  0x7ffff7b446e0
   0x7ffff7b44ad8 <g_intern_string+104>:    
    mov    0xc51ba(%rip),%edi        # 0x7ffff7c09c98
   0x7ffff7b44ade <g_intern_string+110>:    mov    %rax,%rbp
   0x7ffff7b44ae1 <g_intern_string+113>:    mov    %edi,%edx
   0x7ffff7b44ae3 <g_intern_string+115>:    test   $0x7ff,%edi
   0x7ffff7b44ae9 <g_intern_string+121>:    
    jne    0x7ffff7b44b2f <g_intern_string+191>
   0x7ffff7b44aeb <g_intern_string+123>:    add    $0x800,%edi
   0x7ffff7b44af1 <g_intern_string+129>:    mov    $0x8,%esi
   0x7ffff7b44af6 <g_intern_string+134>:    xor    %r12d,%r12d
   0x7ffff7b44af9 <g_intern_string+137>:    movslq %edi,%rdi
   0x7ffff7b44afc <g_intern_string+140>:    
    callq  0x7ffff7b3a020 <g_malloc_n>
   0x7ffff7b44b01 <g_intern_string+145>:    
    movslq 0xc5190(%rip),%rdi        # 0x7ffff7c09c98
   0x7ffff7b44b08 <g_intern_string+152>:    mov    %rax,%rbx
   0x7ffff7b44b0b <g_intern_string+155>:    test   %edi,%edi
   0x7ffff7b44b0d <g_intern_string+157>:    
    jne    0x7ffff7b44b68 <g_intern_string+248>
   0x7ffff7b44b0f <g_intern_string+159>:    mov    $0x4000,%edx
   0x7ffff7b44b14 <g_intern_string+164>:    lea    (%rbx,%r12,1),%rdi
   0x7ffff7b44b18 <g_intern_string+168>:    xor    %esi,%esi
   0x7ffff7b44b1a <g_intern_string+170>:    
    callq  0x7ffff7aff2a0 <memset@plt>
   0x7ffff7b44b1f <g_intern_string+175>:    
    mov    %rbx,0xc517a(%rip)        # 0x7ffff7c09ca0

碰巧的是,LibgStreamer使用该功能足以使水桶阵列需要增长,从而触发泄漏。

例如,在Github上,浅virib源表明该代码已更改。实际避免泄漏的最佳方法是尝试使用较新版本的libglib。

测试中泄漏的特定值实际上是初始存储桶阵列,该数组是在初始化libglib时分配的:

#0  __GI___libc_malloc (bytes=16384) at malloc.c:3023
#1  0x00007ffff7b39e99 in g_malloc () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#2  0x00007ffff7b447d4 in  () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#3  0x00007ffff7fe0b9a in call_init
    (l=<optimized out>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe0d8, env=env@entry=0x7fffffffe0e8) at dl-init.c:72
#4  0x00007ffff7fe0ca1 in call_init
    (env=0x7fffffffe0e8, argv=0x7fffffffe0d8, argc=1, l=<optimized out>)
    at dl-init.c:30
#5  _dl_init
    (main_map=0x7ffff7ffe190, argc=1, argv=0x7fffffffe0d8, env=0x7fffffffe0e8)
    at dl-init.c:119
#6  0x00007ffff7fd013a in _dl_start_user () at /lib64/ld-linux-x86-64.so.2

(gdb) x/2i 0x00007ffff7b447d4
   0x7ffff7b447d4:  movl   $0x1,0xc54ba(%rip)        # 0x7ffff7c09c98
   0x7ffff7b447de:  mov    %rax,0xc54bb(%rip)        # 0x7ffff7c09ca0

因此,要抑制消毒剂中的此类错误,而不是避免泄漏,您必须告诉它要忽略它用G_Malloc作为堆栈的一部分的任何分配(可能会使您丢失更明显的泄漏)或告诉它至少在初始化GLIB和可能涉及 g_intern_string+140 的任何堆栈,具体取决于您的程序是否最终导致G_INTERN_STRING被称为足够多次,以使水桶阵列生长不止一次。

The issue is that there are some versions of g_intern_string, for example, the one in libglib-2.0.so.0.6400.6, that have a bug where, when they grow the buckets array for a hash map, they fail to free the old array.

The leak is on the last instruction shown in this disassembly of g_intern_string:

   0x7ffff7b44a70 <g_intern_string>:    endbr64 
   0x7ffff7b44a74 <g_intern_string+4>:  push   %r12
   0x7ffff7b44a76 <g_intern_string+6>:  push   %rbp
   0x7ffff7b44a77 <g_intern_string+7>:  push   %rbx
   0x7ffff7b44a78 <g_intern_string+8>:  test   %rdi,%rdi
   0x7ffff7b44a7b <g_intern_string+11>: 
    je     0x7ffff7b44b88 <g_intern_string+280>
   0x7ffff7b44a81 <g_intern_string+17>: mov    %rdi,%rbp
   0x7ffff7b44a84 <g_intern_string+20>: 
    lea    0xc5225(%rip),%rdi        # 0x7ffff7c09cb0
   0x7ffff7b44a8b <g_intern_string+27>: callq  0x7ffff7b814d0 <g_mutex_lock>
   0x7ffff7b44a90 <g_intern_string+32>: 
    mov    0xc5211(%rip),%rdi        # 0x7ffff7c09ca8
   0x7ffff7b44a97 <g_intern_string+39>: mov    %rbp,%rsi
   0x7ffff7b44a9a <g_intern_string+42>: 
    callq  0x7ffff7b21710 <g_hash_table_lookup>
   0x7ffff7b44a9f <g_intern_string+47>: test   %eax,%eax
   0x7ffff7b44aa1 <g_intern_string+49>: 
    je     0x7ffff7b44ad0 <g_intern_string+96>
   0x7ffff7b44aa3 <g_intern_string+51>: mov    %eax,%eax
   0x7ffff7b44aa5 <g_intern_string+53>: lea    0x0(,%rax,8),%rbx
   0x7ffff7b44aad <g_intern_string+61>: 
    mov    0xc51ec(%rip),%rax        # 0x7ffff7c09ca0
   0x7ffff7b44ab4 <g_intern_string+68>: 
    lea    0xc51f5(%rip),%rdi        # 0x7ffff7c09cb0
   0x7ffff7b44abb <g_intern_string+75>: mov    (%rax,%rbx,1),%r12
   0x7ffff7b44abf <g_intern_string+79>: callq  0x7ffff7b81500 <g_mutex_unlock>
   0x7ffff7b44ac4 <g_intern_string+84>: pop    %rbx
   0x7ffff7b44ac5 <g_intern_string+85>: pop    %rbp
   0x7ffff7b44ac6 <g_intern_string+86>: mov    %r12,%rax
   0x7ffff7b44ac9 <g_intern_string+89>: pop    %r12
   0x7ffff7b44acb <g_intern_string+91>: retq   
   0x7ffff7b44acc <g_intern_string+92>: nopl   0x0(%rax)
   0x7ffff7b44ad0 <g_intern_string+96>: mov    %rbp,%rdi
   0x7ffff7b44ad3 <g_intern_string+99>: callq  0x7ffff7b446e0
   0x7ffff7b44ad8 <g_intern_string+104>:    
    mov    0xc51ba(%rip),%edi        # 0x7ffff7c09c98
   0x7ffff7b44ade <g_intern_string+110>:    mov    %rax,%rbp
   0x7ffff7b44ae1 <g_intern_string+113>:    mov    %edi,%edx
   0x7ffff7b44ae3 <g_intern_string+115>:    test   $0x7ff,%edi
   0x7ffff7b44ae9 <g_intern_string+121>:    
    jne    0x7ffff7b44b2f <g_intern_string+191>
   0x7ffff7b44aeb <g_intern_string+123>:    add    $0x800,%edi
   0x7ffff7b44af1 <g_intern_string+129>:    mov    $0x8,%esi
   0x7ffff7b44af6 <g_intern_string+134>:    xor    %r12d,%r12d
   0x7ffff7b44af9 <g_intern_string+137>:    movslq %edi,%rdi
   0x7ffff7b44afc <g_intern_string+140>:    
    callq  0x7ffff7b3a020 <g_malloc_n>
   0x7ffff7b44b01 <g_intern_string+145>:    
    movslq 0xc5190(%rip),%rdi        # 0x7ffff7c09c98
   0x7ffff7b44b08 <g_intern_string+152>:    mov    %rax,%rbx
   0x7ffff7b44b0b <g_intern_string+155>:    test   %edi,%edi
   0x7ffff7b44b0d <g_intern_string+157>:    
    jne    0x7ffff7b44b68 <g_intern_string+248>
   0x7ffff7b44b0f <g_intern_string+159>:    mov    $0x4000,%edx
   0x7ffff7b44b14 <g_intern_string+164>:    lea    (%rbx,%r12,1),%rdi
   0x7ffff7b44b18 <g_intern_string+168>:    xor    %esi,%esi
   0x7ffff7b44b1a <g_intern_string+170>:    
    callq  0x7ffff7aff2a0 <memset@plt>
   0x7ffff7b44b1f <g_intern_string+175>:    
    mov    %rbx,0xc517a(%rip)        # 0x7ffff7c09ca0

It just happens that libgstreamer uses that function enough that the buckets array requires growth, triggering the leak.

A shallow look at the glib source, for example on github, suggests that this code has changed. The best way to actually avoid the leak would be to try to use a newer version of libglib.

The specific value that is leaked in your test is actually the initial buckets array, which is allocated when libglib is initialized:

#0  __GI___libc_malloc (bytes=16384) at malloc.c:3023
#1  0x00007ffff7b39e99 in g_malloc () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#2  0x00007ffff7b447d4 in  () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#3  0x00007ffff7fe0b9a in call_init
    (l=<optimized out>, argc=argc@entry=1, argv=argv@entry=0x7fffffffe0d8, env=env@entry=0x7fffffffe0e8) at dl-init.c:72
#4  0x00007ffff7fe0ca1 in call_init
    (env=0x7fffffffe0e8, argv=0x7fffffffe0d8, argc=1, l=<optimized out>)
    at dl-init.c:30
#5  _dl_init
    (main_map=0x7ffff7ffe190, argc=1, argv=0x7fffffffe0d8, env=0x7fffffffe0e8)
    at dl-init.c:119
#6  0x00007ffff7fd013a in _dl_start_user () at /lib64/ld-linux-x86-64.so.2

(gdb) x/2i 0x00007ffff7b447d4
   0x7ffff7b447d4:  movl   $0x1,0xc54ba(%rip)        # 0x7ffff7c09c98
   0x7ffff7b447de:  mov    %rax,0xc54bb(%rip)        # 0x7ffff7c09ca0

So to suppress such errors in a sanitizer, as opposed to avoiding the leak, you'd either have to tell it to ignore any allocations with g_malloc as part of the stack (which may leave you subject to missing some more significant leaks) or to tell it to ignore at least that specific allocation made when glib is initialized and possibly any stacks involving g_intern_string+140, depending on whether your program eventually causes g_intern_string to be called sufficiently many times that the buckets array grows more than once.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文