【问题标题】:How to produce codes that always trigger signal SIGFPE(div by zero)?如何生成始终触发信号 SIGFPE(div by zero) 的代码?
【发布时间】:2021-01-09 23:31:14
【问题描述】:

我需要编写一个应该始终触发除以零信号 (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 信号。

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

【问题讨论】:

  • 您是否尝试在全局范围内简单地声明j?编译器无法证明j,即使它被初始化为0,也不可能在另一个翻译单元中被修改。
  • 或者使用volatile 限定符。
  • 通常为了避免此类问题,您需要将一些测试代码放在不同的编译单元中,这样编译器就无法在它们之间进行优化。即使这样,如果启用链接时间优化,您也会遇到问题。

标签: c++ unit-testing optimization divide-by-zero sigfpe


【解决方案1】:
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 编译器(所以 GCC 10 在 2020 年 9 月)无法在运行时找出文件 /tmp/foobar 的内容(即使使用例如 gcc -O3 -Wall 进行了强烈优化)。

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

【讨论】:

  • 问题很可能是do_div_by_0被内联了,然后除法被消除了,因为返回值被忽略了,不受这里的附加代码影响...
  • @ChrisDodd 是的!你说对了!我按照你的提示试了一下!只是因为func的结果被忽略了,所以gcc总是优化掉除法代码!如果我使用 func 的结果,无论如何它都不会被优化出来!
  • @ChrisDodd 你能添加一个正式的答案吗?我想我应该接受你的回答。
【解决方案2】:

我认为 ChrisDodd 的回答是最准确的。 IE。 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 ), "" );
};

有效!

谢谢大家!!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    相关资源
    最近更新 更多