microsoft / mimalloc

mimalloc is a compact general purpose allocator with excellent performance.
MIT License
10.6k stars 865 forks source link

page leak at program done (Linux) #811

Open mgood7123 opened 1 year ago

mgood7123 commented 1 year ago
-- Override standard malloc (MI_OVERRIDE=ON)
-- Set full secure build (MI_SECURE=ON)
-- Set debug level to full internal invariant checking (MI_DEBUG_FULL=ON)
-- Enable abort() calls on memory allocation failure (MI_XMALLOC=ON)
-- Enable printing of error and warning messages by default (MI_SHOW_ERRORS=ON)
-- Use the C++ compiler to compile (MI_USE_CXX=ON)
-- 
-- Library base name: mimalloc-secure-debug
-- Version          : 2.1
-- Build type       : debug
-- C++ Compiler     : /usr/bin/clang++
-- Compiler flags   : -Wno-deprecated;-Wall;-Wextra;-Wno-unknown-pragmas;-fvisibility=hidden;-Wpedantic;-Wno-static-in-inline;-ftls-model=initial-exec;-fno-builtin-malloc
-- Compiler defines : MI_SECURE=4;MI_DEBUG=3;MI_XMALLOC=1;MI_SHOW_ERRORS=1
-- Link libraries   : /usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/librt.so
-- Build targets    : shared

in the following page, it seems that

   186    mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free);
   187    do {
   188      head = mi_tf_block(tfree);

results in a nullptr head

   190    } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tfree, tfreex));
   191  
   192    // return if the list is empty
-> 193    if (head == NULL) return;

which prevents it from being added to the page->local_free list for freeing

Process 1554835 stopped
* thread #1, name = 'stack_exe', stop reason = step in
    frame #0: 0x00007ffff7f6d2b9 libmimalloc-secure-debug.so.2`_mi_page_free_collect(page=0x0000039f2a000168, force=true) at page.c:227:7
   224    }
   225  
   226    // and the local free list
-> 227    if (page->local_free != NULL) {
   228      if mi_likely(page->free == NULL) {
   229        // usual case
   230        page->free = page->local_free;
(lldb) s
Process 1554835 stopped
* thread #1, name = 'stack_exe', stop reason = step in
    frame #0: 0x00007ffff7f6d399 libmimalloc-secure-debug.so.2`_mi_page_free_collect(page=0x0000039f2a000168, force=true) at page.c:248:3
   245      }
   246    }
   247  
-> 248    mi_assert_internal(!force || page->local_free == NULL);
   249  }
   250  
   251 
(mi_page_t) $88 = {
  slice_count = 8
  slice_offset = 0
  is_committed = '\x01'
  is_zero_init = '\0'
  capacity = 6
  reserved = 6
  flags = {
    full_aligned = '\0'
    x = (in_full = '\0', has_aligned = '\0')
  }
  free_is_zero = '\0'
  retire_expire = '\0'
  free = 0x000003c6bc04c000
  used = 1
  xblock_size = 81920
  local_free = nullptr
  keys = ([0] = 13741470998209409230, [1] = 15678695610853349057)
  xthread_free = {
    std::__atomic_base<unsigned long> = (_M_i = 0)
  }
  xheap = {
    std::__atomic_base<unsigned long> = (_M_i = 140737353679952)
  }
  next = nullptr
  prev = nullptr
  padding = ([0] = 0)
}
Process 1554835 stopped
* thread #1, name = 'stack_exe', stop reason = breakpoint 12.1
    frame #0: 0x00007ffff7f6d43c libmimalloc-secure-debug.so.2`_mi_page_thread_free_collect(page=0x0000039f2a000168) at page.c:189:30
   186    mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free);
   187    do {
   188      head = mi_tf_block(tfree);
-> 189      tfreex = mi_tf_set_block(tfree,NULL);
   190    } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tfree, tfreex));
   191  
   192    // return if the list is empty
(lldb) p head
(mi_block_t *) $89 = nullptr
(lldb) bt
* thread #1, name = 'stack_exe', stop reason = breakpoint 12.1
  * frame #0: 0x00007ffff7f6d43c libmimalloc-secure-debug.so.2`_mi_page_thread_free_collect(page=0x0000039f2a000168) at page.c:189:30
    frame #1: 0x00007ffff7f6d2b9 libmimalloc-secure-debug.so.2`_mi_page_free_collect(page=0x0000039f2a000168, force=true) at page.c:223:5
    frame #2: 0x00007ffff7f65485 libmimalloc-secure-debug.so.2`mi_heap_page_collect(heap=0x00007ffff7f90450, pq=0x00007ffff7f90d00, page=0x0000039f2a000168, arg_collect=0x00007fffffffdbf4, arg2=0x0000000000000000) at heap.c:97:3
    frame #3: 0x00007ffff7f6438d libmimalloc-secure-debug.so.2`mi_heap_visit_pages(heap=0x00007ffff7f90450, fn=(libmimalloc-secure-debug.so.2`mi_heap_page_collect(mi_heap_s*, mi_page_queue_s*, mi_page_s*, void*, void*) at heap.c:92), arg1=0x00007fffffffdbf4, arg2=0x0000000000000000)(mi_heap_s*, mi_page_queue_s*, mi_page_s*, void*, void*), void*, void*) at heap.c:46:12
    frame #4: 0x00007ffff7f63d7c libmimalloc-secure-debug.so.2`mi_heap_collect_ex(heap=0x00007ffff7f90450, collect=MI_FORCE) at heap.c:154:3
    frame #5: 0x00007ffff7f63e84 libmimalloc-secure-debug.so.2`::mi_heap_collect(heap=0x00007ffff7f90450, force=true) at heap.c:178:3
    frame #6: 0x00007ffff7f63ecf libmimalloc-secure-debug.so.2`::mi_collect(force=true) at heap.c:182:3
    frame #7: 0x00007ffff7f675fe libmimalloc-secure-debug.so.2`mi_process_done() at init.c:633:5
    frame #8: 0x00007ffff7923ac6 libc.so.6`__cxa_finalize(d=0x00007ffff7f8f470) at cxa_finalize.c:83:6
    frame #9: 0x00007ffff7f559b3 libmimalloc-secure-debug.so.2`__do_global_dtors_aux + 35
    frame #10: 0x00007ffff7fe2373 ld-linux-x86-64.so.2`_dl_fini at dl-fini.c:138:9
    frame #11: 0x00007ffff79234d7 libc.so.6`__run_exit_handlers(status=0, listp=0x00007ffff7ab6718, run_list_atexit=true, run_dtors=true) at exit.c:108:8
    frame #12: 0x00007ffff792367a libc.so.6`__GI_exit(status=<unavailable>) at exit.c:139:3
    frame #13: 0x00007ffff790bd11 libc.so.6`__libc_start_main(main=(stack_exe`main at executable.cpp:26), argc=1, argv=0x00007fffffffdeb8, init=(stack_exe`__libc_csu_init), fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffdea8) at libc-start.c:342:3
    frame #14: 0x000000000040234a stack_exe`_start + 42
(lldb) r
Process 1555080 launched: '/home/DATA/git/Gecko/HTML/qparse/StackAllocator/debug_EXECUTABLE/stack_exe' (x86_64)
mimalloc: process init: 0x7ffff7edd740
mimalloc: debug level : 3
mimalloc: secure level: 4
mimalloc: mem tracking: none
mimalloc: using 1 numa regions
mimalloc: option 'show_errors': 1
mimalloc: option 'show_stats': 1
mimalloc: option 'verbose': 1
mimalloc: option 'eager_commit': 1
mimalloc: option 'arena_eager_commit': 2
mimalloc: option 'purge_decommits': 1
mimalloc: option 'allow_large_os_pages': 0
mimalloc: option 'reserve_huge_os_pages': 0
mimalloc: option 'reserve_huge_os_pages_at': -1
mimalloc: option 'reserve_os_memory': 0
mimalloc: option 'deprecated_segment_cache': 0
mimalloc: option 'deprecated_page_reset': 0
mimalloc: option 'abandoned_page_purge': 0
mimalloc: option 'deprecated_segment_reset': 0
mimalloc: option 'eager_commit_delay': 1
mimalloc: option 'purge_delay': 10
mimalloc: option 'use_numa_nodes': 0
mimalloc: option 'limit_os_alloc': 0
mimalloc: option 'os_tag': 100
mimalloc: option 'max_errors': 16
mimalloc: option 'max_warnings': 16
mimalloc: option 'max_segment_reclaim': 8
mimalloc: option 'destroy_on_exit': 0
mimalloc: option 'arena_reserve': 1048576
mimalloc: option 'arena_purge_mult': 10
mimalloc: option 'purge_extend_delay': 1
Process 1555080 stopped
* thread #1, name = 'stack_exe', stop reason = breakpoint 1.1
    frame #0: 0x00007ffff7f6d43c libmimalloc-secure-debug.so.2`_mi_page_thread_free_collect(page=0x0000051b86000168) at page.c:189:30
   186    mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free);
   187    do {
   188      head = mi_tf_block(tfree);
-> 189      tfreex = mi_tf_set_block(tfree,NULL);
   190    } while (!mi_atomic_cas_weak_acq_rel(&page->xthread_free, &tfree, tfreex));
   191  
   192    // return if the list is empty
(lldb) p head
(mi_block_t *) $0 = nullptr
(lldb) bt
* thread #1, name = 'stack_exe', stop reason = breakpoint 1.1
  * frame #0: 0x00007ffff7f6d43c libmimalloc-secure-debug.so.2`_mi_page_thread_free_collect(page=0x0000051b86000168) at page.c:189:30
    frame #1: 0x00007ffff7f6d2b9 libmimalloc-secure-debug.so.2`_mi_page_free_collect(page=0x0000051b86000168, force=true) at page.c:223:5
    frame #2: 0x00007ffff7f65485 libmimalloc-secure-debug.so.2`mi_heap_page_collect(heap=0x00007ffff7f90450, pq=0x00007ffff7f90d00, page=0x0000051b86000168, arg_collect=0x00007fffffffdbf4, arg2=0x0000000000000000) at heap.c:97:3
    frame #3: 0x00007ffff7f6438d libmimalloc-secure-debug.so.2`mi_heap_visit_pages(heap=0x00007ffff7f90450, fn=(libmimalloc-secure-debug.so.2`mi_heap_page_collect(mi_heap_s*, mi_page_queue_s*, mi_page_s*, void*, void*) at heap.c:92), arg1=0x00007fffffffdbf4, arg2=0x0000000000000000)(mi_heap_s*, mi_page_queue_s*, mi_page_s*, void*, void*), void*, void*) at heap.c:46:12
    frame #4: 0x00007ffff7f63d7c libmimalloc-secure-debug.so.2`mi_heap_collect_ex(heap=0x00007ffff7f90450, collect=MI_FORCE) at heap.c:154:3
    frame #5: 0x00007ffff7f63e84 libmimalloc-secure-debug.so.2`::mi_heap_collect(heap=0x00007ffff7f90450, force=true) at heap.c:178:3
    frame #6: 0x00007ffff7f63ecf libmimalloc-secure-debug.so.2`::mi_collect(force=true) at heap.c:182:3
    frame #7: 0x00007ffff7f675fe libmimalloc-secure-debug.so.2`mi_process_done() at init.c:633:5
    frame #8: 0x00007ffff7923ac6 libc.so.6`__cxa_finalize(d=0x00007ffff7f8f470) at cxa_finalize.c:83:6
    frame #9: 0x00007ffff7f559b3 libmimalloc-secure-debug.so.2`__do_global_dtors_aux + 35
    frame #10: 0x00007ffff7fe2373
    frame #11: 0x00007ffff79234d7 libc.so.6`__run_exit_handlers(status=0, listp=<unavailable>, run_list_atexit=true, run_dtors=true) at exit.c:108:8
    frame #12: 0x00007ffff792367a libc.so.6`__GI_exit(status=<unavailable>) at exit.c:139:3
    frame #13: 0x00007ffff790bd11 libc.so.6`__libc_start_main(main=(stack_exe`main at executable.cpp:26), argc=1, argv=0x00007fffffffdeb8, init=(stack_exe`__libc_csu_init), fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffdea8) at libc-start.c:342:3
    frame #14: 0x000000000040234a stack_exe`_start + 42
(lldb) c
Process 1555080 resuming
heap stats:     peak       total       freed     current        unit       count   
normal  49:    80.3 KiB    80.3 KiB     0          80.3 KiB    80.3 KiB     1        not all freed

heap stats:     peak       total       freed     current        unit       count   
    normal:    80.3 Ki     80.3 Ki      0          80.3 Ki     80.3 KiB     1        not all freed!
     large:     0           0           0           0                                ok
      huge:     0           0           0           0                                ok
     total:    80.3 KiB    80.3 KiB     0          80.3 KiB                          not all freed
malloc req:    71.2 KiB    71.2 KiB     0          71.2 KiB                          not all freed

  reserved:    32.0 MiB    32.0 MiB     0          32.0 MiB                          
 committed:    32.0 MiB    32.0 MiB     0          32.0 MiB                          
     reset:     0      
    purged:     0      
   touched:   546.1 KiB   546.1 KiB     0         546.1 KiB                          not all freed
  segments:     1           1           0           1                                not all freed!
-abandoned:     0           0           0           0                                ok
   -cached:     0           0           0           0                                ok
     pages:     1           1           0           1                                not all freed!
-abandoned:     0           0           0           0                                ok
 -extended:     1      
 -noretire:     0      
     mmaps:     1      
   commits:     0      
    resets:     0      
    purges:     0      
   threads:     0           0           0           0                                ok
  searches:     0.0 avg
numa nodes:     1
   elapsed:    30.852 s
   process: user: 0.002 s, system: 0.004 s, faults: 0, rss: 14.8 MiB, commit: 32.0 MiB
mimalloc: process done: 0x7ffff7edd740
Process 1555080 exited with status = 0 (0x00000000) 
(lldb) 
(lldb) b mi_malloc
Breakpoint 2: where = libmimalloc-secure-debug.so.2`::mi_malloc(size_t) + 12 at alloc.c:176:25, address = 0x00007ffff7f58f5c
(lldb) r
Process 1555119 launched: '/home/DATA/git/Gecko/HTML/qparse/StackAllocator/debug_EXECUTABLE/stack_exe' (x86_64)
Process 1555119 stopped
* thread #1, name = 'stack_exe', stop reason = breakpoint 2.1
    frame #0: 0x00007ffff7f58f5c libmimalloc-secure-debug.so.2`::mi_malloc(size=72704) at alloc.c:176:25
   173  }
   174  
   175  mi_decl_nodiscard extern inline mi_decl_restrict void* mi_malloc(size_t size) mi_attr_noexcept {
-> 176    return mi_heap_malloc(mi_prim_get_default_heap(), size);
   177  }
   178  
   179  // zero initialized small block
(lldb) bt
* thread #1, name = 'stack_exe', stop reason = breakpoint 2.1
  * frame #0: 0x00007ffff7f58f5c libmimalloc-secure-debug.so.2`::mi_malloc(size=72704) at alloc.c:176:25
    frame #1: 0x00007ffff7ca5a1a libstdc++.so.6`___lldb_unnamed_symbol7579 + 58
(lldb)