The %p conversion and cast to void*

Let me begin by confessing that I am not a Clang user -- I use gcc
since that's what comes with my Linux distribution by default.

I teach a course which involves some programming in C. Some of
my students do use Clang. The following issue involving Clang
was brought to me by them and I have no explanation for it.
I will pass any helpful comments that I receive here to them
for their information. Therefore, I thank you in advance.

Consider the following C program:

---file: tryme.c --------------------------------------
#include <stdio.h>
int main(void)
{
  int n;
  printf("%p\n", (void *)&n);
  return 0;
}

It used to generate a warning in clang but it was spectacularly annoying and so was removed because it generated a huge number of false positives. The C standard does require that the argument for %p 'be a pointer to void', but the only platforms where any other data pointer (in the same address space) would be problematic are ones that do not natively support byte addressing and so need different pointer types for char* and void* and anything word aligned. Clang does not support any such architectures and a lot of C code that people compile with clang / gcc would break on such architectures.

The choice is to either have a warning that you are violating the letter of the C spec, but that your code will still work on every platform that you're likely to ever care about (and I say this as someone working on an architecture with a very unusual pointer representation, for which this warning would *still* be a false positive), or to allow this code through.

Clang policy is that good code ought to be able to use -Wall -Werror by default, because warnings that have too high a false positive rate are not present. If warnings are too likely to produce false positives (i.e. flag things that work fine on every system where the code is plausibly likely to run), then it doesn't help the programmer, it just makes them turn off the warning.

David

It seems reasonable for this kind of warning to go under some -pedantic flag, something like "-Wformat-pedantic".

It seems reasonable for this kind of warning to go under some -pedantic
flag, something like "-Wformat-pedantic".

Possibly, though there's also a general aversion to adding off-by-default
warnings to clang because they end up undertested and a burden on the
codebase (in terms of complexity, etc) with relatively little value.

Do you have a real-world example where this warning would help developers to avoid a bug?

David

I’m also concerned about off-by-default warnings, which is one of the reasons my default set of warning flags starts with -Weverything.

I encourage other developers to do the same as part of implementing a ‘subtractive’ (or ‘blacklist’) strategy for enabling warnings rather than an ‘additive’ (or ‘whitelist’) strategy: Enable everything and then disable just specific warnings if necessary after evaluating them. The value being that you’re less likely to miss useful warnings, and when the compiler is updated with new warnings you get made aware of them automatically.

Obviously this is useful for everyday development, rather than for end users just installing programs from a source repository, so release source packages for end users won’t use -Weverything -Werror. It’s just for developers actively working on a project, and in that use-case it’s very nice.

IIRC I originally got the suggestion from an email by Chris Lattner on this list. Since I had good experiences with it I started promoting it, and I’ve seen some other people saying similar things.

http://www.bignerdranch.com/blog/a-bit-on-warnings/
http://amattn.com/p/better_apps_clang_weverything_or_wall_is_a_lie.html
http://stackoverflow.com/questions/16384530/clang-in-xcode-start-with-weverything-and-manually-disable-particular-warnin
https://news.ycombinator.com/item?id=7282277

Depends on how you define 'bug'. I include most kinds of undefined behavior, and if I came upon this warning in any of my code during everyday development I would fix it.

In my view, the only reason not to at least have an option to diagnose any particular kind of undefined behavior is if there's no reasonable way to implement such a diagnosis.

At the same time I think many of 'pedantic' warnings are under that label because

This is not undefined behaviour, it is implementation-defined behaviour, and it is implementation-defined behaviour that is shared across all vaguely modern C implementations, including some quite exotic ones.

The 'fix' for the warning clutters the code and makes it less readable. People reading the code will wonder why you're casting the value to a pointer, when they thought it was already a pointer.

Having a warning if you pass a function pointer as the parameter for %p (which we currently lack) would be entirely sensible, as there *are* platforms with C implementations where data pointer and function pointer representations differ and the C standard makes no guarantee that these will work - though this warning might be silenced in POSIX mode, as POSIX relies on the ability to cast void* to a function pointer. Having a warning for something that:

- Works on every current implementation
- Is used by so much code that no future implementation can safely break it

is a complete waste of everyone's time.

David

Depends on how you define 'bug'. I include most kinds of undefined behavior, and if I came upon this warning in any of my code during everyday development I would fix it.

This is not undefined behaviour, it is implementation-defined behaviour, and it is implementation-defined behaviour that is shared across all vaguely modern C implementations, including some quite exotic ones.

Are you sure? My copy of the C99 spec says "• If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined." [7.19.6.1p9] and the conversion specification 'p' is specified with "The argument shall be a pointer to void." The C11 draft I have says the same.

I understand there may be more to it than that and that I may have missed something somewhere else which turns this into implementation defined behavior, but as it stands it does look to me like undefined behavior. So I think that accepting other types of pointers would qualify as a conforming extension rather than implementation defined behavior.

The 'fix' for the warning clutters the code and makes it less readable. People reading the code will wonder why you're casting the value to a pointer, when they thought it was already a pointer.

It's a simple cast to void*, and they ought to understand that pointers can have different types and why one might cast between types. They'll learn exactly why if they try to remove the cast and start getting a diagnostic.

Having a warning if you pass a function pointer as the parameter for %p (which we currently lack) would be entirely sensible, as there *are* platforms with C implementations where data pointer and function pointer representations differ and the C standard makes no guarantee that these will work - though this warning might be silenced in POSIX mode, as POSIX relies on the ability to cast void* to a function pointer.

I agree; converting between data and function pointers is either undefined behavior or an optionally supported feature, depending on the spec. Having flags to catch that is similarly worthwhile.

  Having a warning for something that:

- Works on every current implementation
- Is used by so much code that no future implementation can safely break it

is a complete waste of everyone's time.

David

I see value in both flagging undefined behavior and in the ability to turn off extensions.

If you want a practical benefit: gcc has this warning, which may be converted to an error. Users developing under clang may prefer to catch this earlier so that it doesn't show up at a later time when the code is compiled under gcc with -Wall -Wextra -pedantic -Werror.