【问题标题】:How to catch an error resulting from an invalid memory block being destroyed如何捕获因无效内存块被破坏而导致的错误
【发布时间】:2016-01-26 19:05:08
【问题描述】:

下面的代码使得析构函数被调用两次。

#include <iostream>
#include <memory>
#include <exception>
#include <cstdlib> 

void myterminate()
{
    std::cout << "terminate\n";
    abort();
}

class data 
{
    int a;
public:
    data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
    ~data() { std::cout << "dtor " << a << "\n"; }
    static data failure(int a) { return data(a); }
};

void main()
{
    std::set_terminate(myterminate); //terminate is not called
    try
    {
        std::unique_ptr<data> u;
        u.reset(&data::failure(1));
        std::cout << "no worries\n"; //this prints 
        //destructor called at try-block end and attempt to destruct an invalid memory block.
    }
    catch (...)
    {
        std::cout << "caught\n"; //this can not catch the error
    }
    std::cout << "end\n"; //program crash, will not be called
}

如何在生产中发现这样的错误?

在发布版本中,程序崩溃。在 Debug 上构建它,在我的系统上是:

【问题讨论】:

  • C++ - 应该是int main
  • 我不确定它是否由语言指定,两次删除对象是未定义的行为,std::set_terminate 没有义务响应未定义的行为。
  • 您的代码具有未定义的行为,因此在运行时“捕获”错误将毫无意义。你需要修复这个错误。
  • 为什么不按“Wiederholen”进行调试?
  • 。您确保在测试中发现它,然后在代码投入生产之前对其进行修复。好的单元测试应该能够捕捉到这一点。

标签: c++ c++11 unique-ptr terminate-handler


【解决方案1】:

如何在生产中发现这样的错误?

你不能。该标准说无效的内存访问具有未定义的行为。没有“捕捉”UB 的标准方法。捕获和终止处理程序用于异常,它们是定义的行为。

你可以做的是,在生产中使用调试版本,并使用 valgrind 或类似工具运行它,这样你至少可以分析错误。

【讨论】:

    【解决方案2】:

    “try/catch”这样的错误不会捕捉到,因为这种情况下崩溃的概率很大。但是你可以尝试捕捉破坏的瞬间,使用信号和更男子气概的退出程序。 移开视线:#include , signal(), sig_atomic_t ...

    【讨论】:

      【解决方案3】:

      首先,如您将 main 声明为 void main 的 cmets 中所述,其中标准在 § 3.6.1 中仅允许两种形式

      1. 实现不应预定义主要功能。这个功能 不得超载。 它应该有一个声明的返回类型 type int,否则它的类型是实现定义的。一个 实施应允许两者

        (2.1) — () 返回 int 和

        的函数

        (2.2) — (int, pointer to point to char) 返回 int 的函数

      其次,您正在重置您的unique_ptr 以管理一个临时对象,当unique_ptr 在其范围结束时被销毁时,deleted 将导致未定义的行为。您无法预测/捕获未定义行为导致的错误。

      你应该做什么(如果你真的想使用动态分配的内存)你可以返回一个指向堆上对象的指针:

      #include <iostream>
      #include <memory>
      #include <exception>
      #include <cstdlib> 
      
      void myterminate()
      {
          std::cout << "terminate\n";
          abort();
      }
      
      class data 
      {
          int a;
      public:
          data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
          ~data() { std::cout << "dtor " << a << "\n"; }
          static data* failure(int a) { return new data(a); }
      };
      
      int main()
      {
          std::set_terminate(myterminate); //terminate is not called
          try
          {
              std::unique_ptr<data> u;
              u.reset(data::failure(1));
              std::cout << "no worries\n"; //this prints 
              //destructor called at try-block end and attempt to destruct an invalid memory block.
          }
          catch (...)
          {
              std::cout << "caught\n"; //this can not catch the error
          }
          std::cout << "end\n"; //program crash, will not be called
      }
      

      在线代码:http://melpon.org/wandbox/permlink/pdiijgDxBshVOYRu

      【讨论】:

      • 问题不在于如何修复代码,而在于如何捕捉(故意的)错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多