previous  next  index

Identify Theft by Clang

For some time now, I receive bug reports against Libgcrypt and GnuPG where the claim is that there is a bug in the code (surprise). Given that both projects have been build on a wide range on platforms using many different C compilers, I was amazed that clang was able to still find other flaws in the code.

On closer inspection it turned out that clang pretends to be gcc! For example clang 3.1 claims to be gcc 4.2.1:

if (!LangOpts.MicrosoftMode) {
  // Currently claim to be compatible with GCC 4.2.1-5621, but only if we're
  // not compiling for MSVC compatibility
  Builder.defineMacro("__GNUC_MINOR__", "2");
  Builder.defineMacro("__GNUC_PATCHLEVEL__", "1");
  Builder.defineMacro("__GNUC__", 4");
  Builder.defineMacro("__GXX_ABI_VERSION", "1002");
}

Well, I would not complain too much about it if clang would really be compatible with that gcc version. But, it is not even compatible to more than 10 years old gcc versions. One example is that clang does not grok the gcc feature of defining extern inline functions. Certain inline asm code does not work either.

Clang is praised a lot for being able to compile all kind of stuff with better performance than gcc. However it often does this only by claiming to be gcc and hoping that it works out.

I consider this default behaviour of clang as an impolite act against the free software community. Do they really want us to change existing code to

#if defined(__GNUC__) && !defined(__clang__)

? I have been hacking C for more than a quarter of a century but can't remember compilers to steal others identity.

Clang folks, please stop defining _GNUC__ by default.

2013-12-11 comment by Jörg Sonnenberger

People make take you more serious if you actually checked your facts. When it comes to "extern inline" Clang behaves just like GCC would IF the later is in C99 mode. Both define __GNUC_STDC_INLINE__ in that case to declare that they prefer to confirm to C99 and not the original GCCism. For inline assembler it would help to say if the problem is the stricter integrated assembler or the checking of constraints…

2013-12-11 comment by Nick Lewycky

Thanks for the comments, as a clang contributor I want to let you know that we're aware of the issues here. Unfortunately, the GCC developers didn't define one way to check for the presence of an extension and another way to check which compiler is in use. You're assuming that __GNUC__ specifies that the compiler is GCC, but I could equally claim that __GNUC__ means that the compiler supports GNU C extensions. You mention that don't know of any other compiler that does this, but both ICC (Intel) and the EDG frontend in its gcc-compatibility mode also define __GNUC__.

And clang does support GNU C extensions. There are very few extensions we won't support (_builtinvaargpacklen comes to mind) and there are always bugs, but it works out of the box codebase. Again unfortunately, gcc doesn't provide per-extension feature tests. Hopefully gcc will adopt our feature checking macros some day: http://clang.llvm.org/docs/LanguageExtensions.html#id2 As for extern inline, I suspect the problem is that clang defaults to C99 while GCC defaults to C89. Try passing -std=gnu89 or -fgnu89-inline to clang, or better, realize that 1999 was a long time ago and start passing -std=gnu99 to gcc and update your code. See http://clang.llvm.org/compatibility.html#inline

Inline assembly is a thornier issue, one I'd need to deal with on a case-by-case basis. In general if it isn't working with clang then either the inline asm was wrong and not guaranteed to work with future gcc's per gcc's own documentation, or you've encountered a clang bug, which is sadly more common than I'd like.