Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mimalloc (v2, v3) immediately crashes in mi_free on MacOS #1029

Open
Noxybot opened this issue Mar 7, 2025 · 5 comments
Open

mimalloc (v2, v3) immediately crashes in mi_free on MacOS #1029

Noxybot opened this issue Mar 7, 2025 · 5 comments

Comments

@Noxybot
Copy link

Noxybot commented Mar 7, 2025

MacOS 15.3.1, XCode 15.2.
Hi! I'm hitting the following issue: mimalloc seems to reliably crash our application.
The callstack is always the same:

* thread #2, stop reason = EXC_BAD_ACCESS (code=1, address=0x142000100)
  * frame #0: 0x000000010cfd5170 libmimalloc-optimized.2.dylib`mi_free(p=0x0000000143604080) at alloc.c:568:58 [opt]
    frame #1: 0x0000000180535bf8 libsystem_pthread.dylib`_pthread_tsd_cleanup + 488
    frame #2: 0x00000001805389bc libsystem_pthread.dylib`_pthread_exit + 84
    frame #3: 0x0000000180535954 libsystem_pthread.dylib`_pthread_wqthread_exit + 56
    frame #4: 0x0000000180534460 libsystem_pthread.dylib`_pthread_wqthread + 424

I suspect (and it what I've seen when I set breakpoint on "malloc") that TLS data is not allocated via mimalloc, ex:

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
  * frame #0: 0x000000018055c2ec libdyld.dylib`dyld4::LibSystemHelpers::malloc(unsigned long) const
    frame #1: 0x00000001801c850c dyld`dyld4::RuntimeState::_instantiateTLVs(unsigned long) + 220
    frame #2: 0x000000018054091c libdyld.dylib`tlv_get_addr + 108
....
some code which initializes thread_local variable...
....
    frame #13: 0x00000001801cf93c dyld`invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 592
    frame #14: 0x000000018020da0c dyld`invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 172
    frame #15: 0x00000001802013a8 dyld`invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 496
    frame #16: 0x00000001801b42dc dyld`dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 300
    frame #17: 0x000000018020033c dyld`dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 192
    frame #18: 0x0000000180202d10 dyld`dyld3::MachOFile::forEachInitializerPointerSection(Diagnostics&, void (unsigned int, unsigned int, bool&) block_pointer) const + 160
    frame #19: 0x000000018020d700 dyld`dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 432
    frame #20: 0x00000001801cf660 dyld`dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 176
    frame #21: 0x00000001801d6c3c dyld`dyld4::JustInTimeLoader::runInitializers(dyld4::RuntimeState&) const + 36
    frame #22: 0x00000001801cfd1c dyld`dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const + 312
    frame #23: 0x00000001801d400c dyld`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::operator()() const + 180
    frame #24: 0x00000001801cff0c dyld`dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const + 412
    frame #25: 0x00000001801ef28c dyld`dyld4::APIs::runAllInitializersForMain() + 424
    frame #26: 0x00000001801b98c8 dyld`dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3268
    frame #27: 0x00000001801b8bc0 dyld`dyld4::start(dyld4::KernelArgs*, void*, void*)::$_0::operator()() const + 544
    frame #28: 0x00000001801b805c dyld`start + 2304

but still is being deallocated via mimalloc... Any ideas or suggestions here? Thanks!

@Noxybot Noxybot changed the title mimalloc immediately crashes in mi_free on MacOS (v2, v3) mimalloc (v2, v3) immediately crashes in mi_free on MacOS Mar 7, 2025
@daanx
Copy link
Collaborator

daanx commented Mar 7, 2025

Darn -- I just released a fresh version -- ah well. I will look into this; if you have a small repro that would be great.
Did you try with v3 in debug mode? (v3 has a more precise map of valid pointers and can check that on free)

btw. I noticed too that recently the thread local data allocation is hard coded to use the system allocator :-(.

@Noxybot
Copy link
Author

Noxybot commented Mar 7, 2025

Reading about different TLS modes, it seems like local-exec should solve this issue by avoiding dynamic allocations during TLS initialization (not saying that mimalloc should use it, but rather the client code).
Anyway, so far I wasn't able to get it working with XCode 15.2. AppleClang seems to completely ignore __attribute__((tls_model("local-exec")))...

@Noxybot
Copy link
Author

Noxybot commented Mar 7, 2025

Looking at dyld source code : https://github.com/apple-oss-distributions/dyld/blob/b492ac15734277d89795b6f97f0e2feb1aa45595/dyld/DyldRuntimeState.cpp#L2329-L2332

// allocate buffer and fill with template
    // Note: the space for thread local variables is allocated with system malloc
    void* buffer = this->libSystemHelpers->malloc(initialContentSize);

seems to be calling into this https://github.com/apple-oss-distributions/dyld/blob/b492ac15734277d89795b6f97f0e2feb1aa45595/libdyld/LibSystemHelpers.cpp#L75-L78:

void* LibSystemHelpers::malloc(size_t size) const
{
    return ::malloc(size);
}

wondering if such calls can be intercepted ... (not with dynamic linking, i assume, since mimalloc has to be loaded after dyld)

@Noxybot
Copy link
Author

Noxybot commented Mar 7, 2025

Good news is that I was able to get it working with static override.
Basically, I had to disable MI_OSX_INTERPOSE and MI_OSX_ZONE.
Bad news is that MI_OSX_INTERPOSE seems to be absolutely useless (and even dangerous) as it implies dynamic linking which seems to be not reliable on MacOS (since dyld makes calls to malloc and no way mimalloc can be loaded before dyld...)

@Noxybot
Copy link
Author

Noxybot commented Mar 10, 2025

Hi, I woke up the other day - and it seems to magically work now :) I can't repo the issue anymore -- perhaps, I was not recompiling with the right TLS model? ... Weird.
But it only works with this fix #1028 - since sometimes we call aligned_alloc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants