_Orphan_range 使用静态向量时崩溃 [英] _Orphan_range crash when using static vector

查看:46
本文介绍了_Orphan_range 使用静态向量时崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中,我使用静态对象的构造函数来收集指针,例如注册方法.很简单,没有魔法.但是在开始时我遇到了崩溃,我无法解释这里发生了什么.崩溃可在 Windows 上使用 MSVC 或 Clang 重现,两者都使用 MSVC 标头.给出了以下简单示例.谁能给我一个提示,为什么这会导致问题?

In my project, I use the constructor of a static object to collect pointers, like a registration method. Very simply, no magic. But during the start I experience a crash, and I can't explain what's happening here. The crash is reproducible on Windows with MSVC or Clang, both using the MSVC headers. Given is the following simple example. Can anyone give me a hint why this could cause issues?

这段代码在 Linux 上的 GCC 和 Clang 中似乎工作得很好:

This code seems to work just fine in GCC and Clang on Linux:

https://gcc.godbolt.org/z/vSKdpW

static int bar = 1;

static Registration abc(&bar);

foo.cpp

static std::vector<void*> registrations;

void add_to_array(void* p)
{
    registrations.push_back(p);
}

foo.h

class Registration
{
public:
    Registration(void* op)
    {
        add_to_array(op);
    }
};

执行导致以下崩溃(_Pnext 为 0x8.)

Executing results in the following crash (_Pnext was 0x8.)

void _Orphan_range(pointer _First, pointer _Last) const { // orphan iterators within specified (inclusive) range
#if _ITERATOR_DEBUG_LEVEL == 2
    _Lockit _Lock(_LOCK_DEBUG);

    _Iterator_base12** _Pnext = &_Mypair._Myval2._Myproxy->_Myfirstiter;
    while (*_Pnext) {    <=======================   **_Pnext** was 0x8.

有谁知道为什么不能使用静态向量来简单地收集指向对象的指针?foo.cpp 是唯一使用带有 push_back 的向量的文件.该数组不会在其他任何地方修改.

Does anyone know why a static vector can't be used to simply collect pointers to objects? foo.cpp is the only file that uses the vector with push_back. The array is not modified anywhere else.

推荐答案

刚刚使用 VS2019 运行时调试了一个类似的问题,我会继续说这几乎肯定是由零初始化(但未构造)向量引起的.

Having debugged a similar issue just now using VS2019 runtime, I'll go ahead and say this is almost assuredly caused by a zero initialized (but not constructed) vector.

取证,就我而言,看起来像这样:_Pnext 的值为 0x8,因为 _Myproxy 为空._ITERATOR_DEBUG_LEVEL 设置为 2(即:在调试配置文件中),_Myproxy 被取消引用,导致此崩溃,但 Release 不会崩溃,因为该代码被完全跳过.

The forensics, in my case, looked like this: the value of _Pnext was 0x8 because _Myproxy is null. With _ITERATOR_DEBUG_LEVEL set to 2 (i.e.: in Debug profile), _Myproxy gets dereferenced, leading to this crash, but Release won't crash since that code is skipped altogether.

现在,查看 MSVC142/VS2019 的 vector 实现,您会看到每个构造函数都调用 _Alloc_proxy,它为 _Myproxy 分配一些内存并分配价值.因此,如果构造函数已被调用,则您必须拥有一个非空的 _Myproxy.

Now, looking at MSVC142/VS2019's implementation of vector, you'll see that every single constructor calls _Alloc_proxy, which is what allocates some memory for _Myproxy and assigns the value. So if the constructor had been invoked, you would've necessarily have a non-null _Myproxy.

C++ 中的静态初始化分两步进行:零初始化,然后以任意的、链接器确定的顺序进行静态初始化.看起来,按照您最终的顺序,Foo.cpp 的 Registration 在 Bar.cpp 的 registrations 向量之前构造,有效地调用 push_back零初始化(但未构造)向量.

Static initialization in C++ occurs in two steps: zero initialization, followed by static initialization in an arbitrary, linker determined order. It appears that in the order you end up with, Foo.cpp's Registration gets constructed before Bar.cpp's registrations vector, effectively calling push_back on a zero initialized (but not constructed) vector.

因此,正如评论所建议的那样,您绝对应该重新安排静态初始化,以便在使用之前正确构造您的向量.

So as the comments suggested, you should definitely rearrange your static initialization so that your vector is properly constructed before using it.

(就我而言,我正在为包含向量的结构分配内存,但没有在该内存上调用放置 operator new.对于像我一样发现这个问题的其他人,请看对于归零但未构造的向量的任何来源.)

(In my case, I was allocating memory for a struct containing a vector, but not calling placement operator new on that memory. To anyone else finding this question like I did, look for any source of a zeroed but not constructed vector.)

这篇关于_Orphan_range 使用静态向量时崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆