【问题标题】:Segmentation Fault, previously not there when compiled with GNU, Now using Clang分段错误,以前用 GNU 编译时不存在,现在使用 Clang
【发布时间】:2016-11-18 18:22:17
【问题描述】:

所以我在读到clang是一个更严格的标准实现,但这真的让我感到困惑......

void readInputFile(const string inputFileName, Geometry &planeGeom, FlightConditions &FC, AircraftChar & aeroChar,
vector<string> &runFileResults, int &vorlaxRun, int &lateralTrue)
{
   int inputRuns;
   char infile[32], blank, cTest[32], iTest[32];
   char aircraftInpFile[80];
   char vorlaxCommand[80];
   string casTest, inpTest;
   double S_ref,span,Cbar,Xbar,Zbar,St_ref,mac_t,Sf_ref,CD_0,Mach,Uinf,rho;
   FILE *ofpInput;

   strcpy(infile,inputFileName.c_str());
   ofpInput = fopen(infile, "r");
   assert(ofpInput!=NULL);

   fscanf(ofpInput, "%i", &lateralTrue);  //0--false only longitudinal analysis, 1--true long and lateral
   printf("lateralTrue = %i\n",lateralTrue);

   fscanf(ofpInput, "%i", &vorlaxRun);    //0--false will input aero data, 1--true will input run files and execute vorlax
   printf("Are we running Vorlax? -- %i\n",vorlaxRun);

   fscanf(ofpInput, "%i", &inputRuns);             //for looping to run all the needed vorlax files
   printf("inputRuns = %i\n",inputRuns);
   runFileResults.resize(2*inputRuns);

   cout << "I made it to the part where I am reading" << vorlaxRun << "\n" << endl;

   fscanf(ofpInput, "%s", &blank);    //reading in data from input file
   fscanf(ofpInput, "%lf %s", &planeGeom.S, &blank);
   fscanf(ofpInput, "%lf %s", &planeGeom.b, &blank);
   fscanf(ofpInput, "%lf %s", &planeGeom.cBar, &blank);
   fscanf(ofpInput, "%lf %s", &planeGeom.xBar, &blank);
   fscanf(ofpInput, "%lf %s", &planeGeom.zBar, &blank);
   fscanf(ofpInput, "%lf %s", &planeGeom.St, &blank);
   fscanf(ofpInput, "%lf %s", &planeGeom.mact, &blank);
   fscanf(ofpInput, "%lf %s", &planeGeom.Sf, &blank);
   fscanf(ofpInput, "%lf %s", &aeroChar.CD_0, &blank);
   fscanf(ofpInput, "%lf %s", &aeroChar.e, &blank);
   fscanf(ofpInput, "%lf %s", &FC.mach, &blank);
   fscanf(ofpInput, "%lf %s", &FC.uinf, &blank);
   fscanf(ofpInput, "%lf %s", &FC.rho, &blank);
   fscanf(ofpInput, "%lf %s", &FC.alpha, &blank);
   fscanf(ofpInput, "%lf %s", &aeroChar.dEdA, &blank);

   cout << "I made it past reading all the planeGeom stuff " << vorlaxRun << "\n" << endl;

   //Commented out code section for debugging purposes...

   cout << "I made it past reading all the aeroChar stuff" << "\n" << endl;

所以看起来 int vorlaxRun 导致问题的原因很奇怪,所以我将它添加到我的打印中(如您在上面看到的)以查看发生了什么,这就是我得到的输出。

Reading inputFileMavericAftCGApproachFlapsDown.dat
lateralTrue = 0
Are we running Vorlax? -- 0
inputRuns = 0
I made it to the part where I am reading0

Segmentation fault: 11

如果我取出正在打印的第二个 vorlaxRun 实例,这就是我得到的

Reading inputFileMavericAftCGApproachFlapsDown.dat
lateralTrue = 0
Are we running Vorlax? -- 0
inputRuns = 0
I made it to the part where I am reading0

I made it past reading all the planeGeom stuff 

I made it past reading all the aeroChar stuff

Abort trap: 6

我想我会期待中止陷阱 6,因为在查看正在发生的事情的过程中我不得不注释掉一堆行。但我不明白为什么删除将变量打印到屏幕的第二个实例会导致它神奇地工作......或者为什么如果我将它添加到最后一个 cout 上然后我会得到这个:

 Reading inputFileMavericAftCGApproachFlapsDown.dat
 lateralTrue = 0
 Are we running Vorlax? -- 0
 inputRuns = 0
 I made it to the part where I am reading0

 I made it past reading all the planeGeom stuff 

 Segmentation fault: 11

希望我已经提供了足够的信息。我对clang完全陌生,在谷歌搜索和搜索之后,我在g ++中从未遇到过任何问题我仍然迷路......

【问题讨论】:

  • 为什么要将 C 代码与 C++ 混合使用?
  • 编译所有警告和调试信息(例如g++ -Wall -g 或clang -Wall -g)。我没有阅读你的代码,但我猜你有一些undefined behavior。使用gdb 调试器
  • fscanf(ofpInput, "%s", &amp;blank); 很可能是undefined behavior
  • 阅读您正在调用的每个函数的文档,尤其是en.cppreference.com/w/cpp/io/c/fscanf
  • 也坚持使用 C 或 C++ 代码——尤其是在涉及 IO 时。恕我直言,这两种机制不能很好地协同工作。

标签: c++ segmentation-fault g++ clang


【解决方案1】:

正如 Basile Starynkevitch 正确指出的那样,您的程序展示了 undefined behavior。

表现出这种行为的程序可以做任何事情。这包括似乎在使用一种编译器编译时可以正常工作,而在使用另一种编译器(或使用不同的优化级别,或针对不同的平台)编译时会崩溃。

这样的程序也可能表现得不规律,例如在随机的地方崩溃,或者当它的某些部分被注释掉时会以不同的方式崩溃。

第一个(但绝不是唯一的)未定义行为的实例可以从这段代码 sn-p 中猜到:

char infile[32], ...;
strcpy(infile,inputFileName.c_str());

我们可以从您的输出中猜测inputFileName 的值"inputFileMavericAftCGApproachFlapsDown.dat",它需要 42 个字符来存储在一个数组中,而您将该值复制到一个 32 字节的缓冲区中,从而导致堆栈溢出(是产生未定义行为的众多方法之一)。

顺便说一句,该副本完全没有意义,也没有任何用处。你应该通过 const 引用而不是值来传递 inputFileName。

那么,你应该怎么做呢?

  1. 找一个对C和C++有所了解的有能力的导师,你真的需要一个。
  2. 按照 Basile 的建议阅读文档。
  3. 使用Address Sanitizer 编译您的代码(Clang 和 GCC 都支持)。如果会发现这个特定的错误,以及 Basile 在 cmets 中指出的那个错误,可能还有更多。
  4. 一旦您修复了 Address Sanitizer 发现的所有错误,请继续访问 Memory Sanitizer 了解更多错误。

在您的程序经过 sanitizer-clean 之后,它将有更好的机会正常工作,但仍不能保证没有错误。

【讨论】:

  • 感谢您指出我“真的需要”一位 C++ 导师。这是几年前的旧代码,我正试图以最小的努力恢复,像这样的 cmets 在学习环境中是刻薄且不必要的。是的,我用地址清理程序编译了它,但这并没有帮助,因此我在这里发布,实际上我得到的调试信息将我指向变量 vorlaxRun。
猜你喜欢
  • 2019-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多