dyld threadLocalVariables.c - calling _tlv_atexit during tlv_finalize is undefined behavior

Originator:tyler.m.kopf
Number:rdar://47416656 Date Originated:January 20 2019
Status:Open Resolved:
Product:macOS + SDK Product Version:
Classification: Reproducible:
 
Area:
Something not on this list

Summary:

Relevant source here: https://opensource.apple.com/source/dyld/dyld-635.2/src/threadLocalVariables.c.auto.html
Discussion of how this issue affected rust here: https://github.com/rust-lang/rust/issues/57534

While tlv_finalize is iterating through the TLVTerminator list, more calls to _tlv_atexit can be triggered which can cause the list tlv_finalize is iterating through to be reallocated resulting in all sorts of memory corruption issues.

A fix would be to change tlv_finalize to something like this:

static void tlv_finalize(void* storage)
{
    do {
        pthread_setspecific(tlv_terminators_key, NULL);
        struct TLVTerminatorList* list = (struct TLVTerminatorList*)storage;
        // destroy in reverse order of construction
        for(uint32_t i=list->useCount; i > 0 ; --i) {
            struct TLVTerminatorListEntry* entry = &list->entries[i-1];
            if ( entry->termFunc != NULL ) {
                (*entry->termFunc)(entry->objAddr);
            }
        }
        free(storage);
        storage = pthread_getspecific(tlv_terminators_key);
    } while(storage != NULL);
}

Steps to Reproduce:

Compile and run the attached source file using this command.

clang++ --std=c++17 -fsanitize=address main.cpp && ./a.out

Expected Results:

No complaints from address sanitizer.

Actual Results:

=================================================================
==87273==ERROR: AddressSanitizer: attempting double-free on 0x603000000310 in thread T0:
    #0 0x10b34310d in wrap_free (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x5710d)
    #1 0x7fff7f9af1d6 in exit (libsystem_c.dylib:x86_64+0x5d1d6)
    #2 0x7fff7f90608b in start (libdyld.dylib:x86_64+0x1708b)

0x603000000310 is located 0 bytes inside of 24-byte region [0x603000000310,0x603000000328)
freed by thread T0 here:
    #0 0x10b34310d in wrap_free (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x5710d)
    #1 0x7fff7f905963 in _tlv_atexit (libdyld.dylib:x86_64+0x16963)
    #2 0x10b0dd3da in A::~A() (a.out:x86_64+0x1000013da)
    #3 0x10b0dd2f4 in A::~A() (a.out:x86_64+0x1000012f4)
    #4 0x7fff7f905d7e in tlv_finalize (libdyld.dylib:x86_64+0x16d7e)
    #5 0x7fff7f9af1d6 in exit (libsystem_c.dylib:x86_64+0x5d1d6)
    #6 0x7fff7f90608b in start (libdyld.dylib:x86_64+0x1708b)

previously allocated by thread T0 here:
    #0 0x10b342f53 in wrap_malloc (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x56f53)
    #1 0x7fff7f905974 in _tlv_atexit (libdyld.dylib:x86_64+0x16974)
    #2 0x10b0df9a1 in __cxx_global_var_init (a.out:x86_64+0x1000039a1)
    #3 0x10b0df924 in __tls_init (a.out:x86_64+0x100003924)
    #4 0x10b0ddc78 in thread-local wrapper routine for thread_a (a.out:x86_64+0x100001c78)
    #5 0x10b0ddbe3 in main (a.out:x86_64+0x100001be3)
    #6 0x7fff7f906084 in start (libdyld.dylib:x86_64+0x17084)

SUMMARY: AddressSanitizer: double-free (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x5710d) in wrap_free
==87273==ABORTING
Abort trap: 6

Version/Build:

OSX 10.14

Configuration:

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!