簡體   English   中英

為什么這會導致 Seg。 故障,我該如何使用 GDB 來調試它?

[英]Why would this cause a Seg. fault, and how can I use GDB to debug it?

代碼本身非常簡單。 我正在使用Catch2進行單元測試,(我真的很喜歡它的界面)並進入gdb ,但沒有獲得有關 Seg 的有用信息。 所述簡單代碼拋出的錯誤。

我確切地知道是什么導致了問題,但我不知道為什么,或者我不知道我如何從gdb獲得有問題的代碼行(我廣泛使用了 Python 等價物pdb ,但 Python 中的錯誤似乎更直截了當)。

觸發器文件

#ifndef FLOP
#define FLOP
class Flop {
     private:
        int tiles_[200][200][200];
     public:
          Flop();
}
#endif

觸發器文件

#include "Flop.hpp"
Flop::Flop() { }

test_Flop.cpp

#include "catch.hpp"
#include "Flop.hpp"
SCENARIO("I bang my head against a wall") {
    Flop flop;
    WHEN("I try to run this test") {
        THEN("This program SEGFAULTs") {
            REQUIRE(1==1);
        }
    }
}

main.cpp包含它應該包含的所有內容,以及下載的catch.hpp (按照教程的說明)。

我使用以下命令編譯它: g++ Flop.cpp test_Flop.cpp main.cpp -o run_test並使用gdb -ex run --args ./run_test -b運行它,這允許 Catch2 進入調試器。 結果是這樣的:

Program received signal SIGSEGV, Segmentation fault.
0x0000555555566e9e in ____C_A_T_C_H____T_E_S_T____0() ()

使用回溯:

#0  0x0000555555566e9e in ____C_A_T_C_H____T_E_S_T____0() ()
#1  0x000055555557e15e in Catch::TestInvokerAsFunction::invoke() const ()
#2  0x000055555557d7b1 in Catch::TestCase::invoke() const ()
#3  0x0000555555577f0a in Catch::RunContext::invokeActiveTestCase() ()
#4  0x0000555555577c59 in Catch::RunContext::runCurrentTest(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) ()
#5  0x000055555557671b in Catch::RunContext::runTest(Catch::TestCase const&) ()
#6  0x00005555555797cc in Catch::(anonymous namespace)::TestGroup::execute() ()
#7  0x000055555557ab49 in Catch::Session::runInternal() ()
#8  0x000055555557a853 in Catch::Session::run() ()
#9  0x00005555555b6195 in int Catch::Session::run<char>(int, char const* const*) ()
#10 0x000055555558fdf0 in main ()

好的。 所以, SIGSEGV表明我們試圖讀/寫進程無權訪問的內存。 如果在Flop.hpp 中,我改為說int tiles_[10][10][10] ,那么一切正常。 那么將tiles_設置為更大的大小是否會以某種方式保留一塊無法訪問的內存? 我是 C++ 的新手(因此在我編程時真正考慮計算機中發生的事情是int tiles_[200][200][200] )所以如果我錯了,請糾正我,但int tiles_[200][200][200]不應該遠遠超過 32MB 的內存,對吧?

因此,我有幾個問題:

  • 為什么這會導致分段錯誤?
  • 如何使用gdb讓我找到有問題的代碼行? 此代碼的非簡化版本總共有幾百行。 幸運的是,我的問題在類定義的早期,但是注釋掉所有內容和(煞費苦心地)逐行取消注釋仍然需要一段時間,這就是gdb旨在防止的!

數組的大小

int tiles_[200][200][200];

大約 30 MB,假設sizeof(int) == 4

這大於典型的堆棧大小限制,因此您將在創建此類型的自動變量時允許使用的堆棧空間之外寫入

Flop flop;

程序可用的堆棧量通常限制在幾 MB 左右,具體取決於操作系統和設置。

gdb為您提供了分段錯誤的位置:測試函數的入口。 函數中局部變量的堆棧空間通常在進入函數時分配,因此這是堆棧溢出可能在分段錯誤中表現出來的地方(或者取決於堆棧的處理方式,當越界堆棧第一次寫入/讀取空間)。

不要將大對象直接保存為成員或具有自動存儲時間(即在堆棧上)。 而是通過指針間接分配動態分配大對象(即在空閑存儲/堆上)。

最簡單的方法是使用std::vector而不是內置數組。 這通常也比內置數組更可取,如果您需要存儲多個相同類型的對象,這應該是您的默認選擇。

在需要編譯時大小的非分配數組的特定情況下, std::array也優於內置數組。 通過這種方式,您可以完全避免使用內置數組。

或者, std::unique_ptr<...>允許您在動態分配的間接std::unique_ptr<...>中包裝任何對象類型(也包括內置數組)。

暫無
暫無

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

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