簡體   English   中英

零星崩潰,其中回溯顯示在奇怪的行調用析構函數

[英]Sporadic crash where backtrace shows destructor call at strange line

我有一個通常運行良好的程序,但今天它在啟動時崩潰了。 之后立即再次運行它工作得很好,所以不幸的是我不能給出一個最小的例子。 但是,代碼如下所示:

    #include "Configuration.hpp"
    #include "Program.hpp"
  
    int main()
      {
         ConfigurationReader confReader; // this is line 6, where gdb indicates a 
                                         // segfault in the *destructor* of 
                                         // ConfigurationReader

         confReader.readConf();
         Conf & conf = confReader.getConf();
         Program program(conf);
         program.run();
 
        return 0;
     }

該程序報告了一個段錯誤,並在 gdb 中啟動核心,它說段錯誤發生在上面代碼示例中的第 6 行,在ConfigurationReader析構函數中。

當然,在這里調用析構函數是沒有意義的,因為只有一個ConfigurationReader實例在浮動,並且在main結束時它超出范圍之前不應該析構。 即使進行了積極的優化,它也無法在program執行之前銷毀,因為program被傳遞到confReader內部的confReader

問題:這里已經(或可能已經)發生了什么? 是否有一些我沒有看到的未定義行為? gdb的堆棧跟蹤是否非常錯誤? 我應該懷疑構建過程出了什么問題嗎?

注意:我知道最好不要讓ConfigurationReader擁有它讀入的Conf實例,但這不是這個問題的內容。 請不要回復只是告訴我這樣做而不解決實際問題。

更新:正如約翰在評論中指出的,我還應該在這里提供一些關於ConfigurationReader::getConf信息:

class ConfigurationReader
{
  private:

    Conf conf;

  public:

    // ...

    Conf & getConf() { return conf; }
}

更新 2:我刪除了行號以使代碼示例可復制,並添加了一條注釋,指示gdb在哪里顯示正在調用的析構函數。

注 2:正如我最初所說,不幸的是,我無法提供一個最小的可重現示例。 我無法在玩具程序中重現此問題。 我什至無法在實際程序中重現這個問題; 這種崩潰只發生過一次,永遠。

我實際上能夠在這里解決我自己的問題,部分是為了回應評論中 PaulMcKenzie 的問題。 為了說明,這是一個玩具程序:

class C { };

class D
{
  public:

    ~D()
    {
      int * p = nullptr;
      int x = *p;
    }
};

class E { };

class F { };

int main(int, char **)
{
  C c;
  D d; // this is line 21
  E e;
  F f;

  return 0;
}

d析構時,這當然會在main()結束時崩潰,因為我故意在析構函數中放置了一個段錯誤。

如果我使用調試符號構建它,然后在 gdb 中運行它,我會得到以下回溯:

#0  0x00005555555546cc in D::~D (this=0x7fffffffde67, __in_chrg=<optimized out>) at program.cpp:10
#1  0x000055555555469a in main () at program.cpp:21

請注意它在堆棧幀 1 中報告的行號。當然,實際上第 22、23、24、25 和 26 行已經完成,我們可以通過在需要時進行登錄來證明這一點。

顯然, gdb (或工具的任何部分負責將行號與編譯器輸出相關聯)已經決定,當對象超出范圍時,析構函數調用應該與最終導致它們的實際代碼行相關聯,即對象被構造。

所以大概我的程序中發生的事情是程序完成了,而崩潰實際上發生在運行中的時間比指示的要晚得多。 (這是它自己的問題,因為program.run()是一個沒有退出條件的無限循環。由於ConfigurationReader的析構函數不是可訪問的,並且以前從未運行過,因此它不能正常工作也就不足為奇了.)

僅憑您發布的代碼無法找出實際問題。 因此,這不是您問題的答案,而是一種幫助您使用 gdb 自己找到解決方案的方法。 不過,評論有點大。

在 gdb 中運行您的程序並在main的最開始處停止。 您可以為此使用start命令。 現在在程序的最后一條指令處添加一個斷點。 您可以在 gdb 中使用b _exit 只有當問題沒有發生時,你的程序才應該到達這個斷點。 當您在 gdb 中添加斷點時,您會得到一個標識該斷點的數字。 假設_exit中的斷點是斷點 2。您可以在 gdb 中添加“命令”,當遇到某個特定斷點時,該命令應自動運行。 使用commands 2將命令添加到斷點 2 並鍵入run (添加run命令),按 ENTER,然后鍵入end (完成輸入命令)。 現在輸入run開始運行你的程序。

有了這個,您的程序將在 gdb 中運行,如果沒有發生錯誤,它將在遇到最后一條指令時從頭開始再次運行。 當錯誤最終發生時,gdb 將停止執行,您可以使用實際進程(而不是僅使用核心轉儲)來調查問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM