首页 文章

问题是在-02或以上优化的框架中重载operator new和delete [关闭]

提问于
浏览
0

我们面临的问题是libc与xcode 9.2捆绑在一起

Scenario

我们有一个重载operator new和delete的框架 . 这些operator new和delete的定义将隐藏在dll中,并在此处定义了apple指南:https://developer.apple.com/library/content/technotes/tn2185/_index.html#//apple_ref/doc/uid/DTS10004200-CH1-SECTION13

我们还有一个应用程序,它链接到这个框架并重载它自己的operator new和delete .

Problem

现在,问题是如果在框架内创建一个字符串(std :: string),它会调用应用程序端操作符new进行内存分配,但在销毁时,它调用框架端操作符delete . 由于应用程序端和框架端的不同堆实现,这可能会导致内存损坏,并且肯定是一个问题 .

仅当使用-o2或更高优化级别时,才会在框架的发布版本中观察到此问题 . 如果我们将-fno-inline标志传递给编译器,则不会出现此问题 . xcode 8.2也没有观察到这个问题 .

在进一步研究这个问题后,我发现basic_string的析构函数是在当前版本的libc中内联的,而libc与xcode 8.2捆绑在一起的情况并非如此 . 在clang论坛上对此进行了一些讨论:https://reviews.llvm.org/D24599

我的猜测是因为在运行时链接中内联,basic_string的析构函数引用框架端操作符delete来释放分配的内存,但我需要确认我的理论 .

如果是这种情况,那么我们应该使用-fno-inline标志构建我们的框架吗?如果我们使用这个标志或者我们应该考虑其他任何方法,是否有任何重大的性能损失?

定义重载运算符new和delete:

void * operator new(size_t len)throw(std :: bad_alloc)

void * operator new(std :: size_t len,const std :: nothrow_t&_nothrow)throw()

void * operator new [](size_t len)throw(std :: bad_alloc)

void operator delete(void * ptr)throw()

void operator delete(void * ptr,const std :: nothrow_t&_nothrow)throw()

void operator delete [](void * ptr)throw()

寻求帮助

如果需要,我会提供更多信息

1 回答

  • 1

    来自技术说明:

    您的替换件将在应用范围内有效 . 即使其他链接单元(共享库)中的代码也会调用您的自定义新建和删除 . 在整个应用程序(所有链接单元)中,替换的new和delete应该只有一个定义 . 这将确保如果通过共享库边界传输内存所有权,则将正确删除它 .

    您的应用程序中有两个new / delete定义 . 这已经是Bad(tm)了 .

    通常,共享库不应覆盖这些运算符,除非这是共享库的唯一作业 . 否则,应用程序很可能会链接到多个重写的new / delete定义 . 在极少数情况下,共享库可能会发现使用这些运算符的私有定义很方便 . 这是通过链接-unexported_symbols_list文件名标志并将以下符号放在unexport文件中来完成的 .

    你能仔细检查图书馆是否真的遵循了这条规则 - 即没有导出符号?

    这样做时,作者必须确保不将内存所有权转移到此共享库中或从中转出 . 请注意,内存所有权传输可以以微妙的方式发生,例如传递引用计数对象(例如std :: string),抛出包含堆分配消息的异常(例如std :: runtime_error)或者具有内联的资源分配构造函数,相应的析构函数未内联(反之亦然) .

    我建议不要使用-fno-inline标志作为“快速修复”,因为这可能只隐藏当前的,明显的问题(多个新的/删除定义),同时仍然允许内存损坏 . 如果你无法摆脱重复的定义(这将是更好的选择IMO),你只能尝试确保 Headers 永远不会包含任何分配内存而能够内联 - 但即便如此我d既困难又有风险 .

相关问题