Search code examples
catomicglibcinline-assemblylibc

What is the purpose of glibc's atomic_forced_read function?


I am trying to understand the purpose of the definition of atomic_forced_read which shows up frequently in the GNU libc implementation of malloc.c.

I am not great when it comes to inline assembly, but it looks like this returns the exact same value, with the same type as the input value. what am I missing here?

Atomic forced read definition in atomic.h

523 #ifndef atomic_forced_read
524 # define atomic_forced_read(x) \
525   ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; })
526 #endif

Link to atomic.h

https://code.woboq.org/userspace/glibc/include/atomic.h.html


Solution

  • One usage is of atomic_forced_read:

    #if HAVE_MALLOC_INIT_HOOK
      void (*hook) (void) = atomic_forced_read(__malloc_initialize_hook);
      if (hook != NULL)
        (*hook)();
    #endif
    

    It appears that __malloc_initialize_hook can be changed from another thread, so that if __malloc_initialize_hook is loaded once more from memory after the NULL check its value may have changed back to NULL.

    atomic_forced_read makes sure that __malloc_initialize_hook is loaded into a register due to =routput constraint, so that __malloc_initialize_hook isn't reloaded from memory after the NULL check. That empty asm breaks compiler dependency of hook on __malloc_initialize_hook, since hook is now initialized with __x stored in a register and not __malloc_initialize_hook. After hook has been initialized with __x, the latter is gone and cannot be possibly reloaded.


    In C11 mode that __malloc_initialize_hook can be atomic_uintptr_t and atomic_load_explicit(&__malloc_initialize_hook, memory_order_relaxed) can be used instead of atomic_forced_read to load __malloc_initialize_hook from memory exactly once.