在 OSX 上替换 libstdc++.dylib (4.0) 全局新建和删除运算符

发布于 2024-09-14 07:06:13 字数 2081 浏览 2 评论 0原文

我正在努力用 XCode 3.2、GCC 4.2、libstdc++ 4.0 动态版本替换全局 new 和删除运算符。

我直接从标题“new”中获取原型并实现它们。它们粘贴在下面。

该项目是一个 .plugin,因此是一个动态库。该插件必须将分配委托给主应用程序自己的分配/释放例程,这些例程位于旧的 C SDK 中。

我自己对 new/delete 的所有调用以及 std::list 和 std::map 分配都被正确替换,但当 std::vector::push_back 必须增加其缓冲区时则不然。在这种情况下,我的运算符 new 未被调用,但我的运算符删除被调用。我知道这一点,因为我在新运算符分配的任何缓冲区的前四个字节中写入了一个令牌,并在运算符删除中检查了该令牌。请参阅下面的违规代码。

extern "C++"
{
__attribute__((visibility("default"))) void* operator new(std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void* operator new[](std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void operator delete(void*) throw();
__attribute__((visibility("default"))) void operator delete[](void*) throw();
__attribute__((visibility("default"))) void* operator new(std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void* operator new[](std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete(void*, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete[](void*, const std::nothrow_t&) throw();

}

当“yo”超出范围时,以下代码将导致断言,因为为 std::vector 分配的内存不是由我的运算符 new 分配的。

   {
        std::vector<std::string> yo;
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

下面的代码是可以的,因为 std::vector::reserve 调用我的运算符 new:

   {
        std::vector<std::string> yo;
        yo.reserve(4);
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

GBD (调试器) 在需要增加缓冲区时不会让 met 进入 std::vector::push_back 实现(该方法名为_M_插入_aux)。我所知道的是,我的运算符 new 从未从 std::vector::push_back 调用。

上面的解决方法不能应用于我正在使用的所有第三方库。其中之一是push_back的大用户。

我尝试静态链接到 libstdc++.a 但我遇到了同样的问题。

std::vector< 是否有一些专门化std::string >不使用全局新运算符?

顺便说一句,这在带有 VS9 的 Windows 上完美运行。

I'm trying hard to replace the global new and delete operators with XCode 3.2, GCC 4.2, libstdc++ 4.0, dynamic version.

I took the protypes directly from the header "new" and implemented them. They are pasted below.

The project is a .plugin so a dynamic lib. This plug-in MUST delegate allocation to the main application's own alloc/free routines, which are in an old C SDK.

All my own call to new/delete along with std::list and std::map allocations are correctly replaced, BUT not when std::vector::push_back has to grow its buffer. It that case, my operator new is not called but my operator delete is. I know that, because I write a token in the first four bytes of any buffer allocated by my new operator and I check this token in operator delete. See below for offending code.

extern "C++"
{
__attribute__((visibility("default"))) void* operator new(std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void* operator new[](std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void operator delete(void*) throw();
__attribute__((visibility("default"))) void operator delete[](void*) throw();
__attribute__((visibility("default"))) void* operator new(std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void* operator new[](std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete(void*, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete[](void*, const std::nothrow_t&) throw();

}

The following code will cause an assert when "yo" goes out of scope because the memory allocated for the std::vector was not allocated by my operator new.

   {
        std::vector<std::string> yo;
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

The following code is ok because std::vector::reserve calls my operator new:

   {
        std::vector<std::string> yo;
        yo.reserve(4);
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

GBD (debugger) won't let met step into the std::vector::push_back implementation when it need to grow the buffer (the method is named _M_insert_aux). All I know is that my operator new is never called from std::vector::push_back.

The workaround above can't be applied to all the 3rd party libs that I'm using. One of which is a big user of push_back.

I tried linking statically to libstdc++.a but I'm having the same issue.

Is there some specialization for std::vector< std::string > that doesn't use the global new operator?

BTW this worked perfectly on windows with VS9.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌逼全场 2024-09-21 07:06:13

我最终通过使用乔治·科斯坦萨的技术解决了我的问题:做相反的事情。

我没有尝试让我的运算符成为新的并删除可见项,而是完全隐藏了它们。

诀窍是在每个静态库和静态库中设置它们。在捆绑包设置中:

  • 设置 C++ 标准库类型:
  • 默认隐藏静态符号:选中
  • 修复和修复继续:取消选中(非常重要,否则会默默地禁用以前的设置)

并执行清理所有操作因为使用 XCode 3.2 在更改这些设置后简单地点击“构建”是行不通的。

显然,我改变了运算符 new &删除原型:

#pragma GCC visibility push(hidden)

extern "C++"
{
    void* operator new(std::size_t) throw (std::bad_alloc);
    void* operator new[](std::size_t) throw (std::bad_alloc);
    void operator delete(void*) throw();
    void operator delete[](void*) throw();
    void* operator new(std::size_t, const std::nothrow_t&) throw();
    void* operator new[](std::size_t, const std::nothrow_t&) throw();
    void operator delete(void*, const std::nothrow_t&) throw();
    void operator delete[](void*, const std::nothrow_t&) throw();
} // extern "C++"

#pragma GCC visibility pop

不,为什么会这样?必须同时具有静态 + 隐藏符号才能工作。它似乎保护我的捆绑插件免受内联其分配器的 STL 专业化实现的影响。

另请注意,这只发生在从大型应用程序动态加载的捆绑插件中。在从控制台应用程序调用的一个简单的 .dylib 项目中,任何设置都可以正常工作。

I finally solved my problem by using George Costanza's technique: doing the opposite.

Instead of trying to make my operators new and delete visibles, I hid them completely.

The trick is to set these in every static libs & in the bundle settings:

  • Set C++ Standard Library Type : Static
  • Symbols Hidden by Default: Checked
  • Fix & Continue: Unchecked (very important otherwise silently disable previous setting)

and do a clean all & build because with XCode 3.2 simply hitting Build after changing these settings won't work.

Obviously, I changed the operator new & delete prototypes to:

#pragma GCC visibility push(hidden)

extern "C++"
{
    void* operator new(std::size_t) throw (std::bad_alloc);
    void* operator new[](std::size_t) throw (std::bad_alloc);
    void operator delete(void*) throw();
    void operator delete[](void*) throw();
    void* operator new(std::size_t, const std::nothrow_t&) throw();
    void* operator new[](std::size_t, const std::nothrow_t&) throw();
    void operator delete(void*, const std::nothrow_t&) throw();
    void operator delete[](void*, const std::nothrow_t&) throw();
} // extern "C++"

#pragma GCC visibility pop

No why does that work? Must have both Static + Hidden Symbols to work. It seems to shield my bundle plug-in from STL specializations implementations that inlined their allocators.

Also note that this only happened in a bundle plug-in dynamically loaded from a big app. In a trivial .dylib project called from a console application everything worked fine with any settings.

残月升风 2024-09-21 07:06:13

我不太确定如何准确地执行您所要求的操作,但您可以通过使用自定义分配器在 STL 中实现您自己的分配语义。

http://www.cplusplus.com/reference/std/memory/allocator/< /a>

我想我记得当我查看 C++ 的 Hans-Bohen GC 时,该库将用 GC 版本替换 new/delete,但您仍然必须将分配器传递给您希望使用的 STL 结构。

此外,您正在使用的库中可能有一些代码仍在使用 malloc。值得思考的事情。

I'm not exactly sure how to do exactly what you're asking, but you can achieve your own allocation semantics in the STL by using a custom allocator.

http://www.cplusplus.com/reference/std/memory/allocator/

I think I remember when I was looking at the Hans-Bohen GC for C++ that the library would replace new/delete with a GC version but you still had to pass an allocator to the STL structures you wished to use.

Also, there may be code within libraries you are using still using malloc. Something to think about.

内心旳酸楚 2024-09-21 07:06:13

_M_insert_aux 位于 vector.tcc 中,令人烦恼的是它与 GCC 不能很好地配合。然而,快速扫描表明它像其他方法一样正确调用分配器。

  pointer __new_start(this->_M_allocate(__len));

您可以尝试在 operator new 中设置断点,定义打印调试输出的自定义分配器(可以从 std::allocator 派生),或者在 < code>new_allocator.h:91 库应在其中调用您的覆盖。

_M_insert_aux is in vector.tcc which annoyingly doesn't play well with GCC. However, a quick scan shows it calls the allocator properly just like other methods.

  pointer __new_start(this->_M_allocate(__len));

You might try setting a breakpoint in your operator new, defining a custom allocator (you can derive from std::allocator) which prints debugging output, or setting a breakpoint in new_allocator.h:91 where the library should call your override.

温柔女人霸气范 2024-09-21 07:06:13

最可能的解释是 GCC 的 std::vector 内部实现包括 new 的额外重载。 MSVC 有许多额外的运算符新重载。您将需要分解源代码或创建一个新的自定义分配器。

The most likely explanation is that GCC's internal implementation of std::vector includes additional overloads of new. MSVC has many extra operator new overloads. You will need to rip apart the source code or make a new custom allocator.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文