【问题标题】:What is the purpose of glibc's atomic_forced_read function?glibc 的 atomic_forced_read 函数的目的是什么?
【发布时间】:2020-01-24 17:07:33
【问题描述】:

我试图理解 atomic_forced_read 定义的目的,它经常出现在 malloc.c 的 GNU libc 实现中。

当涉及到内联汇编时,我不是很好,但看起来它返回完全相同的值,具有与输入值相同的类型。我在这里错过了什么?

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

链接到 atomic.h

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

【问题讨论】:

  • 什么你的问题是什么?! atomic_forced_read 和空指针有什么关系?!
  • 顺便说一句,C 标准一直要求free(0) 是安全的并且什么也不做。 已经有(不兼容和/或 1989 年之前的)C 库会崩溃,但现在你几乎肯定不会遇到一个,除非你正在做逆向计算。 (有关详细信息,请参阅 dandan78 的链接。)
  • 在我看来类似于Linux内核中的ACCESS_ONCE。它只是强制读取寄存器,但我不知道这与易失性读取相比如何。如果数据已经在寄存器中,它会强制重新加载吗?它会阻止编译器将目标的访问转换为源数据的访问吗?
  • @PeterCordes:在 malloc 中,它用于防止检查钩子函数指针是否为 NULL 和调用它之间的竞争条件。它的目的是访问共享变量,前提是您知道访问将是原子的(支持平台的适当大小和对齐方式),并防止编译器删除/复制您的负载。我只是不知道它真正提供了什么保证,尤其是。与易失性读取相比。
  • @ninjalj:听起来很复杂;只需将共享值加载到本地,然后在调用它之前检查它是否为非 NULL。不需要特殊的魔法来防止 NULL 检查被优化掉,除非指针早晚无条件地取消引用。 (然后编译器会将其优化掉,因为 deref 暗示非 NULL 因为 UB)。 OP 仍然没有在问题中包含用例,我也没有费心去寻找自己。

标签: c atomic glibc inline-assembly libc


【解决方案1】:

一种用法是atomic_forced_read

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

看来__malloc_initialize_hook 可以从另一个线程更改,因此如果在NULL 之后再次从内存中加载__malloc_initialize_hook,则检查其值可能已更改回NULL

atomic_forced_read 确保由于=routput 约束将__malloc_initialize_hook 加载到寄存器中,因此__malloc_initialize_hookNULL 检查后不会从内存中重新加载。空的asm 破坏了hook__malloc_initialize_hook 的编译器依赖性,因为hook 现在是用存储在寄存器中的__x 而不是__malloc_initialize_hook 初始化的。在hook__x 初始化后,后者就消失了,不可能重新加载。


在 C11 模式下,__malloc_initialize_hook 可以是 atomic_uintptr_tatomic_load_explicit(&__malloc_initialize_hook, memory_order_relaxed) 可以代替 atomic_forced_read 从内存中加载一次 __malloc_initialize_hook

【讨论】:

  • 是的,它“清洗”了__malloc_initialize_hook 的值,因此优化器无法决定加载全局两次。正如 ninjali 对这个问题所评论的那样,sourceware.org/bugzilla/show_bug.cgi?id=9957 表明即使使用本地(但没有 asmvolatile),S390 也确实发生了这种情况。
  • @PeterCordes 您提到了“洗钱”,但是,std::launder 是一个相当特殊且有限的工具,请参阅WG21 P0532R0 On launder()
猜你喜欢
  • 2017-02-10
  • 2012-01-14
  • 2013-05-22
  • 2012-06-08
  • 1970-01-01
  • 2013-07-31
  • 2014-01-19
  • 2018-04-24
相关资源
最近更新 更多