如果使用数组,析构函数中会出现分段错误

问题描述 投票:0回答:1

清理向量时出现我无法理解的分段错误。删除数组访问(从底部第 3 行)可以消除崩溃,即使崩溃不在该行上。

下面的代码是我最终得到的最小的重现,是从更大的代码库中提取的(我确认它在 dtor 中崩溃,而不是在数组写入时崩溃)。

#include <array>
#include <cstddef>
#include <iostream>
#include <memory>
#include <vector>

class Deletable {
public:
  virtual ~Deletable() = default;
};

template <typename V> class DeletableHandle : public Deletable {
public:
  virtual V *get() = 0;
  virtual const V *get() const = 0;
};

template <typename V> class DeletableHolder final : public DeletableHandle<V> {
public:
  V *get() override { return &value_; }
  const V *get() const override { return &value_; }

private:
  V value_;
};

class InferenceContext2 {
public:
  template <size_t LI> auto *LayerScratchSpace() {
    using Area = std::array<int, 4>;
    while (buffers_.size() <= LI) {
      buffers_.emplace_back(nullptr);
    }
    if (buffers_[LI] == nullptr) {
      buffers_[LI] = std::make_unique<DeletableHolder<Area>>();
    }
    return reinterpret_cast<Area *>(buffers_[LI].get());
  }

private:
  std::vector<std::unique_ptr<Deletable>> buffers_;
};

int main() {
  InferenceContext2 ctx;
  auto area = ctx.LayerScratchSpace<0>();
  std::cout << area->size() << " " << (reinterpret_cast<intptr_t>(&area) % 128)
            << " " << alignof(std::remove_pointer_t<decltype(area)>) << "\n";

  // Commenting out the line below removes the crash
  (*area)[0] = 1;
  return 0;
}

在我更大的项目中,我有 ASAN,这就是它的意思(堆栈跟踪不同):

AddressSanitizer:DEADLYSIGNAL
=================================================================
==12==ERROR: AddressSanitizer: SEGV on unknown address 0x55f800000009 (pc 0x55f85eadc1c1 bp 0x7ffd295108b0 sp 0x7ffd29510890 T0)
==12==The signal is caused by a READ memory access.
    #0 0x55f85eadc1c1 in std::default_delete<uchen::memory::Deletable>::operator()(uchen::memory::Deletable*) const /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_ptr.h:85:2
    #1 0x55f85eadc0fb in std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>::~unique_ptr() /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_ptr.h:361:4
    #2 0x55f85eadc064 in void std::destroy_at<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>>(std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_construct.h:88:15
    #3 0x55f85eadd214 in void std::_Destroy<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>>(std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_construct.h:149:7
    #4 0x55f85eadd1e6 in void std::_Destroy_aux<false>::__destroy<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*>(std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*, std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_construct.h:163:6
    #5 0x55f85eadd1ac in void std::_Destroy<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*>(std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*, std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_construct.h:195:7
    #6 0x55f85eadd0d0 in void std::_Destroy<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*, std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>>(std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*, std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>*, std::allocator<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>>&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/alloc_traits.h:848:7
    #7 0x55f85eadd09e in std::vector<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>, std::allocator<std::unique_ptr<uchen::memory::Deletable, std::default_delete<uchen::memory::Deletable>>>>::~vector() /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:680:2
    #8 0x55f85ead8d24 in uchen::(anonymous namespace)::InferenceContext2::~InferenceContext2() /proc/self/cwd/test/arena.test.cc:71:7

使用 GCC 和 Clang 进行复制。使用

--std=c++20
进行构建。编译器版本:

eugene-aurora:~/code$ g++ --version
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

eugene-aurora:~/code$ clang++ --version
Ubuntu clang version 15.0.7
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
c++ c++11 segmentation-fault
1个回答
0
投票

buffers_[LI].get()
返回
DeletableHolder
的地址。
buffers_[LI]->get()
get()
上调用
DeletableHolder
,这确实是一个
Area *

在消除编译器警告之前请三思。

© www.soinside.com 2019 - 2024. All rights reserved.