C++程序导致终端崩溃--我该如何调试?

3
请勿问我如何做到的——我一点也不知道。
下面的代码会使我的终端和任何运行时分析工具崩溃,但不会引发任何静态检查工具警告。Valgrind、cppcheck和gdb基本无用。g++ -Wall没有给我任何有用的提示。
代码的目标是通过USB串行连接将字符写入audrino。第一个参数传递audrino地址。传递一个无符号整数并将其强制转换为无符号字符。
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <iostream>

using namespace std;

int main(int argc,char** argv){

  struct termios stdio;
  int tty_fd;

  unsigned char ctrlChar;
  unsigned int ctrlInt;

  tty_fd=open(argv[1], O_RDWR | O_NONBLOCK);
  tcgetattr(tty_fd, &stdio);
  cfmakeraw(&stdio);
  stdio.c_cc[VMIN]  = 1;
  stdio.c_cc[VTIME] = 0;
  tcsetattr(tty_fd,TCSANOW, &stdio);
  tcsetattr(tty_fd,TCSAFLUSH, &stdio);
  fcntl(tty_fd, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);

  cfsetospeed(&stdio,B9600);            // 9600 baud
  cfsetispeed(&stdio,B9600);            // 9600 baud

  cout << "ready on " << argv[1] << endl;

  scanf("%u", ctrlInt);
  cout <<"recieved initial read.\n";
  while (ctrlInt < 256){
    ctrlChar = ((char) ctrlInt);
    cout << ctrlInt << ctrlChar << endl;
    write(tty_fd,&ctrlChar,1);
    cout << "sent to audrino.\n";
    scanf("%u", ctrlInt);
  }

  cout << "done!" << endl;

  close(tty_fd);
  return 0;
}

如果这看起来合理,我将提交一个错误报告。

系统规格:最新的 Arch Linux 64 位,在“g++ -g -Wall code.c”编译。


你尝试过检查核心转储吗? - victor.t
它在技术上成功退出,所以我不知道如何从中取出核心转储。我编程已经五年了,从未见过程序这样做。我很无助。 - Josh
2个回答

5
如果你说“崩溃了我的终端”,那么很可能是因为你在stdout(也就是你的终端)上设置了各种标志位为零。你调用了tcsetattr(),把几乎所有的终端控制标志位都清零了。
你应该使用tcgetattr()获取当前终端标志位,修改你想要修改的标志位,然后将该结构体用于调用tcsetattr()。不这样做甚至是未定义的行为

如果指向termios_ptermios结构体的值不是由对fildes调用tcgetattr()的结果派生的,则tcsetattr()的影响是未定义的;应用程序只应修改在tcgetattr()tcsetattr()之间由本规范定义的字段和标志,保留所有其他字段和标志未修改。


我太傻了,以为示例代码是好的...我明天再试试。 - Josh
2
同样适用于对 fcntl(2) 的调用 - 你不应该仅调用 fcntl(..., F_SETFL, <flags>),而是应该调用 fcntl(..., F_SETFL, <flags> | fcntl(..., F_GETFL)),以保留先前的标志并添加你想要的标志。 - Adam Rosenfield
我必须报告一个坏消息。虽然终端不再发怒,但仍然无响应,实际上已经崩溃了。这并没有回答我的问题,但无疑有所帮助。代码已在上面更新。 - Josh
1
@Josh:你仍然将那个结构体的许多成员设置为0。你真的想将存储在c_iflagsc_oflags等中的所有标志都设置为零吗?虽然我不是termios的专家,但将所有这些标志设置为0(无论意味着什么)听起来不像是一个好主意... - sth
另一个更新。终端没有崩溃,但仍存在终端问题。在程序执行期间,读写被关闭。代码已经更新。 - Josh
显示剩余2条评论

2
如果您使用Linux操作系统,您可以使用strace命令。
strace ./yourProgram

你也可以调试核心转储文件。
ulimit -c unlimited
g++ -g ...

当程序崩溃时,将会创建核心转储文件。

gdb ./yourProgram coredump

使用bt命令查看崩溃信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接