【问题标题】:How to interpret a GDB backtrace in order to determine a segmentation fault?如何解释 GDB 回溯以确定分段错误?
【发布时间】:2018-03-17 23:46:19
【问题描述】:

我正在上入门级编程课程。我知道分段错误是由于沿途某处的内存存储错误造成的。我写的程序应该接受一个给我们的文件,这个文件是代码,包含解码它的指令,然后打印解码的消息。

我们有几个测试用例,我的代码运行其中一些,但不是最后一个。我今天第一次了解了用于调试的 GDB,并使用 backtrace full 来尝试找出错误的来源,但我不完全确定如何解释它给我的信息。

这是我写的代码。 **编辑出来的代码

当我进行回溯时,这是它告诉我的。

   #2  0x0000000000401523 in main () at main.cpp:42
    second = 61 '='
    third = 72 'H'
    msg = 0x606308
    i = 8
    chars = ""
    first = 90 'Z'
    numMess = 8
    out = <incomplete type>
    name = "input4.txt"
    in = <incomplete type>
    arr = "IJKLMNOPQRSTUVWXYZABCDEFGH"

我不知道回溯告诉我什么,我不确定如何处理这些信息来发现和修复我的错误。

【问题讨论】:

  • 如果您使用std::vector 而不是new[ ],您将有机会在不使用 gdb 的情况下发现错误。而不是Messages *msg; msg = new Messages[numMess];,您可以这样做:std::vector&lt;Messages&gt; msg(numMess);,然后使用vector::at() 来检测越界访问。
  • 两者比较如何?我们之前没有在课堂上讨论过 std::vector。
  • 请注意,i = 8 和 numMess = 8。for 循环在第三部分的条件下退出,只有第二部分。
  • @jgwentworth -- 向量使用相同的语法来访问元素 -- 它实际上与您现在发布的代码没有什么不同(除了声明)。然而std::vector附加 函数来测试越界访问。如果您改为使用at() 而不是[ ],您将得到std::out_of_range 异常,而不是seg 错误和gdb 堆栈跟踪。至于你的班级,如果他们正在教 new []delete [] 在 C++ 中创建动态数组,请找一位新老师。
  • @jgwentworth for (chars; std::getline(in, chars); i &lt; numMess) for 循环中的“停止”条件是什么?或者保持该循环运行的条件是什么?鉴于这些信息,应该很容易看出事情是如何爆发的。如果文件中有 1000 行,而我是个恶作剧者,输入 numMess 为 10 怎么办?

标签: c++ debugging segmentation-fault gdb


【解决方案1】:

来自跟踪的提示是

i = 8
chars = ""
numMess = 8

i 等于 numMess 并且 chars 为空。

为什么这很重要?查看numMess 的来源,我们看到它用于调整msg 指向的动态数组的大小,而msg 后来被i 索引。当i 等于numMess 时,msg[i] 越界。

那么这是怎么发生的呢?

string chars;
getline(in, chars); // this doesn't make much sense. Reconsider it
for (chars; std::getline(in, chars); i < numMess) {

这里出了问题。 for 循环应该类似于

for (initializer ; exit condition ; iterator to advance the loop)

但是

for (chars; // does nothing. Compiler may be warning you
     std::getline(in, chars); // loop exits on failed read
     i < numMess) { // does nothing to advance the loop

这里没有任何东西可以防止i 超过numMess,因为i &lt; numMess 没有被用作退出条件。是的,但是为什么std::getline(in, chars); 在到达文件末尾时不退出循环?文件末尾的空行。 chars 已成功设置为空字符串。

for ( ; // nothing happening here
     i < numMess and std::getline(in, chars) ;
     ++i) { // and remove the ++i from the end of the loop.

让您摆脱当前的困境,并可能为您提供一个满足您需求的程序。没测试过。

但是如果文件中有错误并且文件在到达numMess之前就退出了怎么办?这就是 PaulMckenzie 想要解决的问题。你最好不要完全信任numMess,而是选择类似的东西

int numMess = 0;
in >> numMess; // not that we care
vector<Messages> msg;

//read file
int i = 0;
string chars;
while (std::getline(in, chars)) { // get each line. Note this gets the empty line, too
    Messages temp; // make a temporary for storage

    temp.messageNum = i + 1;
    temp.codedMessage = chars;


    //decode file
    for (char &j : chars) {
        if (j - 'A' >= 0 && j - 'A' < 26)
            j = arr[j - 'A'];
    }
    temp.decodedMessage = chars;
    msg.push_back(temp);
}

【讨论】:

  • 进行更改后,我现在遇到两个编译错误。一个是在打印段'out
  • 反转循环中的测试。首先测试i &lt; numMess 效率更高,因为测试返回0 的std::getline 需要读取文件。
  • PaulMcKenzie 好点。 @jgwentworth 我没有建议您更改代码应该导致msg 没有超出范围。 and is identical to &amp;&amp;
  • 我在编译时仍然遇到同样的错误,告诉我 numMess 和 msg 没有在范围内定义。我认为它们是全局的,因为我在循环之外声明它们,但它们需要我再次声明吗?
  • 我需要查看您的代码的当前状态以告诉您出了什么问题。我将我的修改粘贴到您问题中的代码中,没有收到任何错误。
猜你喜欢
  • 2017-12-21
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
相关资源
最近更新 更多