12

我开发了一个跨平台库,它在套接字通信中公平地使用类型双关语。这个库已经在许多项目中使用,其中一些我可能不知道。

错误地使用这个库会导致危险的未定义行为。我想尽我所能确保这个库被正确使用。

当然,除了文档之外,在 G++ 下,我知道的最好的方法是使用-fstrict_aliasingand-Wstrict-aliasing选项。

在 GCC 下有没有办法在源文件级别应用这些选项?

换句话说,我想写如下内容:

MyFancyLib.h

#ifndef MY_FANCY_LIB_H
#define MY_FANCY_LIB_H

#pragma (something that pushes the current compiler options)
#pragma (something to set -fstrict_aliasing and -Wstrict-aliasing)

// ... my stuff ...

#pragma (something to pop the compiler options)

#endif

有办法吗?

4

3 回答 3

1

您可以尝试诊断编译指示并更改警告的错误级别。更多细节在这里:

http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

于 2013-10-17T16:17:08.253 回答
1

让我们从我认为是错误的前提开始:

错误地使用这个库会导致危险的未定义行为。我想尽我所能确保这个库被正确使用。

如果您的库确实以中断的方式进行类型双关语,那么无论传递了哪些编译器标志-fstrict-aliasing,它都会根据 C++ 标准具有未定义的行为。当使用某些标志(特别是 )编译时,该程序似乎可以在某些编译器上运行这一事实并没有改变这一点。-fno-strict-aliasing

因此,最好的解决方案就是按照 Florian 所说的去做:更改代码,使其符合 C++ 语言规范。除非你这样做,否则你永远如履薄冰。

“是的,是的”,你说,“但在那之前,我能做些什么来缓解这个问题?”

我建议包括在库初始化期间使用的运行时检查,以检测是否以一种会导致其行为异常的方式编译的情况。例如:

// Given two pointers to the *same* address, return 1 if the compiler
// is behaving as if -fstrict-aliasing is specified, and 0 if not.
//
// Based on https://blog.regehr.org/archives/959 .
static int sae_helper(int *h, long *k)
{
  // Write a 1.
  *h = 1;

  // Overwrite it with all zeroes using a pointer with a different type.
  // With naive semantics, '*h' is now 0.  But when -fstrict-aliasing is
  // enabled, the compiler will think 'h' and 'k' point to different
  // memory locations ...
  *k = 0;

  // ... and therefore will optimize this read as 1.
  return *h;
}

int strict_aliasing_enabled()
{
  long k = 0;

  // Undefined behavior!  But we're only doing this because other
  // code in the library also has undefined behavior, and we want
  // to predict how that code will behave.
  return sae_helper((int*)&k, &k);
}

(以上是 C 而不是 C++,只是为了便于在两种语言中使用。)

现在在您的初始化例程中,调用strict_aliasing_enabled(),如果它返回 1,则立即退出并显示错误消息,说明库编译不正确。这将有助于保护最终用户免受不当行为的影响,并提醒客户端程序的开发人员他们需要修复其构建。

我已经用 gcc-5.4.0 和 clang-8.0.1 测试了这段代码。-O2传递时,返回strict_aliasing_enabled()1。-O2 -fno-strict-aliasing传递时,该函数返回 0。

但是让我再次强调一下:我的代码有未定义的行为!(可以)不能保证它会起作用。符合标准的 C++ 编译器可以将其编译为返回 0、崩溃或引发全球热核战争的代码!-fno-strict-aliasing如果您需要它按预期运行,那么您可能已经在库中其他地方使用的代码也是如此。

于 2019-09-04T13:53:33.267 回答
0

如果您的库是仅标头库,我认为解决此问题的唯一方法是修复严格的别名违规。如果在您定义的类型之间发生冲突,您可以使用涉及联合或may_alias类型属性的常用技巧。如果您的库使用预定义的sockaddr类型,这可能会很困难。

于 2017-07-17T08:26:46.393 回答