内存违规:SIGSEGV 和“找不到虚拟表的链接器符号...”

Posted

技术标签:

【中文标题】内存违规:SIGSEGV 和“找不到虚拟表的链接器符号...”【英文标题】:Memory violation: SIGSEGV and 'can't find linker symbol for virtual table...' 【发布时间】:2015-11-05 12:06:44 【问题描述】:

我在 C++ 代码中遇到内存冲突错误,这让我抓狂。我必须使用一些现有的类,它们几乎在其他任何地方都能正常工作。

我正在尝试制作自定义 Array 对象的副本,而不是稍后修改内部值。但是那个复制操作有问题……

症状如下:

Segmentation fault 复制后,但不是立即

警告:can't find linker symbol for virtual table for 'MyClass<T>' value

MyClass<T>与问题部分无关,搜索后发现vtable被覆盖(link)时可能会出现此错误。

SIGSEGV 出现在这个 sn-p 的末尾:

// New boxes based on previous content, so first make a copy
Array<Box> nextBoxes(size);
int ic = followingItems.length();  // Array<int> followingItems() : some item id
for (int b = 0; b < size; ++b) 
    Box box(ic, capacity);
    const Box& oBox = currentBoxes[b];  // Array<Box> currentBoxes(size);
    for (int i = 0; i < ic; ++i) 
        if (oBox[i])
            box.add(i);
    
    nextBoxes.add(box);


createConfig(nextBoxes, nextItems);
...
generateCostMatrix(nextBoxes, costMatrix); // <--[SIGSEGV] without any reason, variables are fine

这就是我完全迷失的地方。我尝试使用std::vector 而不是Array&lt;Box&gt; nextBoxes,但问题仍然存在,只是出现在不同的位置。

这是“遗留”类中的一个:

class Box 

    Array<bool> items;  // mask of all tools
    int capacity, itemCount, count;
public:
    Box();
    Box(int num, int cap)
      : items(num), capacity(cap), itemCount(num), count(0)
    
        for (int i = 0; i < num; i++)
            items.add(false);
    
    Box(const Box& value)...
    ~Box()...
    ...

来自崩溃位置的微小调试器信息:

array = new T[maxlen]
// values: array=0x0, maxlen=30, len=0 --> looks OK

(在 Array&lt;T&gt; 类的深处,在哪里并不重要,因为总是像这里一样发生在 new 行中,而且总是没有明显的原因)

【问题讨论】:

首先在调试器中运行以捕获崩溃,然后在代码中找到崩溃发生的位置并检查所有相关变量的值。如果您仍然无法弄清楚,那么至少告诉我们崩溃发生的位置和变量值。 在 Array 模板类中 add 有什么作用 我用崩溃位置和add() 的定义扩展了这个问题。希望你能看到我看不到的东西。 memset(array, 0, maxLen * sizeof(T)); 是一个错误,你应该改用默认初始化。 您可能会覆盖数组边界和/或在某处使用悬空引用。此类问题应包括MCVE。从错误的代码开始向后工作,一次删除大部分,直到您拥有仍然存在问题的最小程序。 【参考方案1】:

嗯,有些事情没有引起我的注意... 过度索引数组主要发生在索引超出范围时。有时数组太短,或者索引太长,或者你创建了错误大小的数组。最后一个案例发生在这里。

我回答这个问题的原因是:

我看到了引用的警告消息,但在完全不同的情况下(真正的链接问题,当 vtable 中实际上缺少一个节点时)。在我的情况下,虚拟表被覆盖,令人惊讶的是,由于一些糟糕的数组处理。

对于未来的谷歌人来说,这对于调试 SIGSEGV 很有用 出现在一个奇怪的位置。

我学到了什么:

总是仔细检查容器对象(不仅仅是索引变量)

三重检查您提出新问题时引用的来源(是的,该问题的关键行中有错字)


这里是解决方案,不是那么重要,但为了完整性......

ic 的价值是“坏人”,需要深入我的项目才能发现它,但我会解释一下:

int ic = followingItems.length(); // where Arra<int> followingItems(x);

followingItems是需要插入的ids(Arra&lt;int&gt;)项的列表。 x 可以在[1, allItemCount] 范围内

Box 类中,Array&lt;bool&gt; items 是一个布尔掩码,用于标记项目是否在框中。不知不觉,items.length() = allItemCount 所以:

followingItems.length <= allItemCount

首先,我意识到ic 一直运行到87 而不是400。我想复制全部内容,但只测试并添加了前 87 项。 考虑到这一点,我发现了主要错误:

Box box(ic, capacity);

第一个参数应该是所有项目的数量,但又是 87 而不是 400。好吧,那是相当痛苦的......

【讨论】:

以上是关于内存违规:SIGSEGV 和“找不到虚拟表的链接器符号...”的主要内容,如果未能解决你的问题,请参考以下文章

信号 SIGSEGV:当我使用 go-python3 时,分段违规代码 = 0x1

SIGSEGV 内存访问冲突

SIGBUS 和 SIGSEGV

SIGSEGV 是不是交付给每个线程?

什么导致 SIGSEGV

HSQLDB 内存设置的 HSQLDB 约束违规和 SQL 查询日志