1

我需要编写一个应该始终触发除以零信号(SIGFPE)的单元测试,这样我就可以测试和比较有/没有我的信号捕获模块会发生什么。

我的 Linux 信号捕捉/恢复模块已经开发完成,并按预期工作。当我为模块编写单元测试时,我遇到了一个小麻烦。

这些是 UT 代码(通过 GTest):

int do_div_by_0() {
    int j = 0;
    return 123 / j; /* During release-buidling, this div-op would be optimized out,
                       although it would be not when debug-building! */
};

TEST_F( SignalsHandling_F, divByZeroDying ) {
   ASSERT_EXIT( {
      do_div_by_0();
      
      // never should go here!
      exit( EXIT_SUCCESS );

   }, KilledBySignal( SIGFPE ), "" );
};

如果所有代码都在调试模式下构建,则没有问题。但是除法操作会在 Release 模式下被优化,因此 SIGFPE 信号永远不会被触发!

为了保持产品代码和测试代码之间的一致性,我必须在发布产品时将它们全部构建为发布模式。

如何编写一段总是触发信号 SIGFPE 的代码?

如果存在更“实际”的方法,我不想使用 raise() 函数,因为我想实际触发 SIGFPE 信号。

谢谢!请原谅我糟糕的英语!

4

2 回答 2

0
int do_div_by_0() {
   int j = 0;
   FILE *f = fopen("/tmp/foobar",  "r");
   if (f) {
     fscanf(f, "%d", &j);
     fclose(f);
   };
   return 123 / j; /* During release-buidling, this div-op would be optimized out,
                   although it would be not when debug-building! */
};

可能是一个解决方案。当前的GCC编译器(因此2020 年 9 月的GCC 10)无法/tmp/foobar在运行时找出文件的内容(即使使用 eg 进行了强烈优化gcc -O3 -Wall)。

当然,一个严肃的测试用例会涉及一些 shell 脚本填充它/tmp/foobar并使用一些environ(7)变量作为文件名。另请参阅要在测试 shell 脚本中使用的mktemp(1) 。

于 2020-09-23T17:45:44.703 回答
0

我认为克里斯多德的回答是最准确的。即忽略do_div_by_0 的返回值,以便编译器优化除法运算

我们在调用do_div_by_0的时候需要用到返回值,如下:

TEST_F( SignalsHandling_F, divByZeroDying ) {
   ASSERT_EXIT( {
      std::cerr << do_div_by_0();
      
      // never should go here!
      exit( EXIT_SUCCESS );

   }, KilledBySignal( SIGFPE ), "" );
};

有用!

谢谢大家!!!

于 2020-09-26T02:07:23.390 回答