如何捕获由于无效的内存块被破坏而导致的错误

时间:2016-01-26 09:53:51

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

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

#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构建它我的系统是: enter image description here

3 个答案:

答案 0 :(得分:4)

  

我如何在制作中发现这样的错误?

你做不到。该标准表示无效的内存访问具有未定义的行为。没有标准的方式去捕捉&#34; UB。捕获和终止处理程序用于异常,这些异常是定义的行为。

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

答案 1 :(得分:1)

&#34;尝试/捕获&#34;这样的错误不会被捕获,因为在这种情况下崩溃的可能性很大。但是,你可以尝试捕捉一个破坏的时刻,使用信号和更多的有尊严的退出计划。 远看:#include,signal(),sig_atomic_t ......

答案 2 :(得分:0)

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

  
      
  1. 实现不应预定义主函数。这个功能   不得超载。 它应具有声明的返回类型   int ,但其他类型是实现定义的。一个   实施应允许两者

         

    (2.1) - ()返回int和

    的函数      

    (2.2) - 一个函数(int,指向char的指针)返回int

  2.   

其次,您正在重置unique_ptr以管理一个临时值,当unique_ptr在其范围的末尾被销毁时,delete d将导致未定义的行为。您无法预测/捕获由未定义行为导致的错误。

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

#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