Skip to content

Temporary mi_heap objects causing TLD buffer overrun #1146

@XnLogicaL

Description

@XnLogicaL

Summary

I am trying to wrap various mimalloc functions with a C++ class using mi_heap_t objects, however, upon calling mi_heap_destroy AddressSanitizer reports a buffer overrun on the TLD buffer associated with said mi_heap_t object. It appears that such behavior only occurs when mi_heap_destroy is called more than once within the lifetime of the program (even when called on distinct mi_heap_t objects).

(No multithreading involved, all behavior observed on T0)

Environment

  • OS: Ubuntu 24.04
  • CPU: Intel i9 i9900k [x86] (don't know if this is relevant or not)
  • Compiler: g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
  • Relevant compiler flags: -fsanitize=address,undefined,leak
  • Relevant linker flags: -fsanitize=address,undefined,leak
  • Active mimalloc commit hash: 09a2709

Minimal reproduction

Simple C++ class that wraps mi_heap_t (deleted move/copy semantics)

class Wrapper {
 public:
  mi_heap_t* heap;

  Wrapper() : heap(mi_heap_new()) {}
  ~Wrapper() { mi_heap_destroy(heap); }
}

Note that this simple reproduction snippet only appears to crash under specific conditions (that I am certain is related to repeated calls to mi_heap_destroy), as opposed to a certain crash in a larger project that virtually implement mi_heap objects in the same way.

AddressSanitizer output:

=================================================================
==21152==ERROR: AddressSanitizer: global-buffer-overflow on address 0x74a5f71931a0 at pc 0x74a5f7118b16 bp 0x7ffce0d62ae0 sp 0x7ffce0d62ad0
READ of size 8 at 0x74a5f71931a0 thread T0
    #0 0x74a5f7118b15 in mi_stat_update /home/user/dev/via-lang/thirdparty/mimalloc/src/stats.c:41
    #1 0x74a5f7118f33 in _mi_stat_decrease /home/user/dev/via-lang/thirdparty/mimalloc/src/stats.c:61
    #2 0x74a5f710dd24 in mi_segment_page_clear /home/user/dev/via-lang/thirdparty/mimalloc/src/segment.c:1026
    #3 0x74a5f710e32b in _mi_segment_page_free /home/user/dev/via-lang/thirdparty/mimalloc/src/segment.c:1058
    #4 0x74a5f70d60d2 in _mi_heap_page_destroy /home/user/dev/via-lang/thirdparty/mimalloc/src/heap.c:365
    #5 0x74a5f70d342b in mi_heap_visit_pages /home/user/dev/via-lang/thirdparty/mimalloc/src/heap.c:46
    #6 0x74a5f70d610d in _mi_heap_destroy_pages /home/user/dev/via-lang/thirdparty/mimalloc/src/heap.c:371
    #7 0x74a5f70d633f in mi_heap_destroy /home/user/dev/via-lang/thirdparty/mimalloc/src/heap.c:405
    #8 0x56d8a2f8d3f4 in via::ScopedAllocator::~ScopedAllocator() /home/user/dev/via-lang/src/via-core/support/memory.h:201
    #9 0x56d8a30bb50a in via::VirtualMachine::~VirtualMachine() (/home/user/dev/via-lang/build/src/via-cli/via-cli+0x1a0350a) (BuildId: cd6ef4c17845494cec4d5aff0bee4566f2fb335b)
    #10 0x56d8a30b08b6 in via::Module::load_source_file(via::ModuleManager*, via::Module*, char const*, std::filesystem::__cxx11::path const&, via::ast::StmtImport const*, via::ModulePerms, via::ModuleFlags) /home/user/dev/via-lang/src/via-core/module/module.cpp:324
    #11 0x56d8a2f82f6e in main /home/user/dev/via-lang/src/via-cli/main.cpp:158
    #12 0x74a5f602a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #13 0x74a5f602a28a in __libc_start_main_impl ../csu/libc-start.c:360
    #14 0x56d8a2f80974 in _start (/home/user/dev/via-lang/build/src/via-cli/via-cli+0x18c8974) (BuildId: cd6ef4c17845494cec4d5aff0bee4566f2fb335b)

0x74a5f71931a0 is located 16 bytes after global variable 'tld_main' defined in '/home/user/dev/via-lang/thirdparty/mimalloc/src/init.c:153:37' (0x74a5f7191d80) of size 5136
0x74a5f71931a0 is located 32 bytes before global variable '_mi_heap_main' defined in '/home/user/dev/via-lang/thirdparty/mimalloc/src/init.c:160:31' (0x74a5f71931c0) of size 3088
SUMMARY: AddressSanitizer: global-buffer-overflow /home/user/dev/via-lang/thirdparty/mimalloc/src/stats.c:41 in mi_stat_update
Shadow bytes around the buggy address:
  0x74a5f7192f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7192f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7193000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7193080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7193100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x74a5f7193180: 00 00 f9 f9[f9]f9 f9 f9 00 00 00 00 00 00 00 00
  0x74a5f7193200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7193280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7193300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7193380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x74a5f7193400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==21152==ABORTING

Notes

I am not familiar with the internals/footguns of mimalloc, so if I am misusing something please let me know. But from what I understand, such behavior is not intended.

Thanks in advance!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions