13

I have developed a cross-platform library which makes fair use of type-punning in socket communications. This library is already being used in a number of projects, some of which I may not be aware of.

Using this library incorrectly can result in dangerously Undefined Behavior. I would like to ensure to the best of my ability that this library is being used properly.

Aside from documentation of course, under G++ the best way I'm aware of to do that is to use the -fstrict_aliasing and -Wstrict-aliasing options.

Is there a way under GCC to apply these options at a source file level?

In other words, I'd like to write something like the following:

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

Is there a way?

John Dibling
  • 99,718
  • 31
  • 186
  • 324

4 Answers4

3

I rather dislike nay-sayers. You can see an excellent post at this page: https://www.codingame.com/playgrounds/58302/using-pragma-for-compile-optimization

All the other answers clearly have nothing to do with the question so here is the actual documentation for GCC:

https://gcc.gnu.org/onlinedocs/gcc/Pragmas.html

Other compilers will have their own methods so you will need to look those up and create some macros to handle this.

Best of luck. Sorry that it took you 10 years to get any relevant answer.

Patrick Sturm
  • 393
  • 1
  • 13
0

You can try the Diagnostic pragmas and change the level in error for your warnings. More details here:

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

asalic
  • 949
  • 4
  • 10
0

If your library is a header-only library, I think the only way to deal with this is to fix the strict aliasing violations. If the violations occur between types you define, you can use the usual tricks involving unions, or the may_alias type attribute. If your library uses the predefined sockaddr types, this could be difficult.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
0

Let's start with what I think is a false premise:

Using this library incorrectly can result in dangerously Undefined Behavior. I would like to ensure to the best of my ability that this library is being used properly.

If your library does type punning in a way that -fstrict-aliasing breaks, then it has undefined behavior according to the C++ standard regardless of what compiler flags are passed. The fact that the program seems to work on certain compilers when compiled with certain flags (in particular, -fno-strict-aliasing) does not change that.

Therefore, the best solution is to do what Florian said: change the code so it conforms to the C++ language specification. Until you do that, you're perpetually on thin ice.

"Yes, yes", you say, "but until then, what can I do to mitigate the problem?"

I recommend including a run-time check, used during library initialization, to detect the condition of having been compiled in a way that will cause it to misbehave. For example:

// 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);
}

(The above is C rather than C++ just to ease use in both languages.)

Now in your initialization routine, call strict_aliasing_enabled(), and if it returns 1, bail out immediately with an error message saying the library has been compiled incorrectly. This will help protect end users from misbehavior and alert the developers of the client programs that they need to fix their build.

I have tested this code with gcc-5.4.0 and clang-8.0.1. When -O2 is passed, strict_aliasing_enabled() returns 1. When -O2 -fno-strict-aliasing is passed, that function returns 0.

But let me emphasize again: my code has undefined behavior! There is (can be) no guarantee it will work. A standard-conforming C++ compiler could compile it into code that returns 0, crashes, or that initiates Global Thermonuclear War! Which is also true of the code you're presumably already using elsewhere in the library if you need -fno-strict-aliasing for it to behave as intended.

Scott McPeak
  • 8,803
  • 2
  • 40
  • 79
  • The test code is utterly broken in the presence of strict aliasing: it may or may not give the expected result. GCC likes to do bizarre things with the code exhibiting UB, including giving paradoxical results. E.g. the check may give a positive result when inlined and negative when not inlined (in the same program), or whatever else. – Ruslan Sep 04 '19 at 16:02
  • @Ruslan Yes, that's what I meant by the final paragraph. I've clarified it further. – Scott McPeak Sep 04 '19 at 17:05
  • Wow, @ScottMcPeak. I wish you had written this 6 years ago. – John Dibling Sep 12 '19 at 23:31