[英]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.