Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 问题是在具有-02或更高优化的框架中重载运算符new和delete_C++_Llvm_New Operator_Clang++_Xcode9.2 - Fatal编程技术网

C++ 问题是在具有-02或更高优化的框架中重载运算符new和delete

C++ 问题是在具有-02或更高优化的框架中重载运算符new和delete,c++,llvm,new-operator,clang++,xcode9.2,C++,Llvm,New Operator,Clang++,Xcode9.2,我们面临着xcode 9.2附带的libc++的问题 场景: 我们有一个重载运算符new和delete的框架。 这些运算符new和delete的定义隐藏在dll中,apple指南定义如下: 此外,我们还有一个应用程序,该应用程序针对该框架进行链接,并重载其自己的运算符new和delete 问题: 现在的问题是,如果在框架内创建一个字符串(std::string),它将调用应用程序端操作符new来分配内存,但在销毁时,它将调用 框架端操作符删除。由于应用程序端和框架端的堆实现不同,这可能导致内存损

我们面临着xcode 9.2附带的libc++的问题

场景

我们有一个重载运算符new和delete的框架。 这些运算符new和delete的定义隐藏在dll中,apple指南定义如下:

此外,我们还有一个应用程序,该应用程序针对该框架进行链接,并重载其自己的运算符new和delete

问题

现在的问题是,如果在框架内创建一个字符串(std::string),它将调用应用程序端操作符new来分配内存,但在销毁时,它将调用 框架端操作符删除。由于应用程序端和框架端的堆实现不同,这可能导致内存损坏,这无疑是一个问题

只有在使用-o2或更高的优化级别时,才在框架的发布构建中观察到这个问题。若我们将-fno内联标志传递给编译器,则不会观察到此问题。xcode 8.2也没有发现这个问题

进一步研究这个问题后,我发现basic_string的析构函数在当前版本的libc++中是内联的,而与xcode 8.2绑定的libc++则不同。 在clang论坛上对此进行了一些讨论:

我的猜测是,由于运行时链接期间的内联,basic_字符串的析构函数引用框架端操作符delete来释放分配的内存,但我需要确认我的理论

如果是这种情况,那么我们应该使用-fno-inline标志构建我们的框架吗?如果我们使用这个标志,或者有其他的方法,我们应该考虑什么? 重载运算符new和delete的定义:

void*操作符new(size\t len)throw(std::bad\u alloc){…}

void*运算符new(std::size\t len,const std::nothrow\t&\u nothrow)throw(){…}

void*操作符new[](size_t len)throw(std::bad_alloc){…}

void操作符delete(void*ptr)throw(){…}

void操作符delete(void*ptr,const std::nothrow\u t&\u nothrow)throw(){…}

void运算符delete[](void*ptr)throw(){…}

寻求帮助


如果需要,我将从技术说明中提供更多信息:

你的替代品将在应用范围内有效。甚至其他链接单元(共享库)中的代码也会调用自定义的new和delete。 在整个应用程序(所有链接单元)中,被替换的new和delete应该只有一个定义。这将确保如果跨共享库边界传输内存所有权,它将被正确删除

应用程序中有两个“新建/删除”定义。这已经很糟糕了(tm)

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

您能否再次检查库是否真的遵循了该规则,即未导出符号

在执行此操作时,作者必须确保内存所有权不会转移到或移出此共享库。请注意,内存所有权转移可能以微妙的方式发生,例如传递引用计数对象(例如std::string)、引发包含堆分配消息的异常(例如std::runtime_error)或内联资源分配构造函数,而相应的析构函数不内联(反之亦然)。


我建议不要使用-fno内联标志作为“快速修复”,因为这可能只会隐藏当前明显的问题(多个新的/删除的定义),同时仍然允许进一步的内存损坏。如果你无法摆脱重复的定义(在我看来,这是更好的选择),您只能尝试确保头文件在能够内联时不包含任何分配内存的内容,但我认为这既困难又有风险。

通常一些未定义的行为会通过积极的优化暴露出来。在没有看到代码的情况下,我认为这是您将得到的最佳猜测。请按此处所述发布一个MVCE:如果您谈论的是
void*::operator new(std::size_t)
void::operator delete(void*)
或类似的全局函数,拥有多个集合违反了一个定义规则。由于这是未定义的行为,编译器和链接器系统可能会或可能不会容忍这种行为,并且可能会或可能不会产生有用的行为。我不认为准确地追踪这种情况何时发生以及为什么不发生有多大价值。顺便说一句,阅读(也在)关于(也在)的文章,是一个,而不是一个。它使用我用nm工具验证过的编译器,框架并没有导出任何版本的运算符new和delete。正如我提到的,它在低于9.2的xcode中工作得非常好,所以这个问题可能是由于链接中提到的基本字符串析构函数的内联而引入的。