2

(A long story... you can directly jump to the question at the end...)

I need to use realpath(3) so I wrote a simple example to try it:

$> cat realpath.c
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

int main(int argc, char * argv[])
{
    char pathname[PATH_MAX];

    if (realpath(argv[1], pathname) < 0) {
        perror("realpath");
        return 1;
    }

    printf("%s\n", pathname);

    return 0;
}
$> gcc -Wall -o realpath realpath.c
$> ls /xxx
ls: cannot access '/xxx': No such file or directory
$> ./realpath /xxx/foo/bar
/xxx

The result of ./realpath /xxx/foo/bar surprised me. According to the manual it makes more sense to fail with ENOENT. I even referred to the POSIX and found no answer. After quite some time I reread the manual and found realpath(3) returns char * rather than int. I was really irritated by gcc.

Question

So why doesn't gcc (even with -Wall) warn about if (ptr < 0)?

Community
  • 1
  • 1
pynexj
  • 19,215
  • 5
  • 38
  • 56
  • Related: [How to turn on (literally) ALL of GCC's warnings?](https://stackoverflow.com/questions/11714827/how-to-turn-on-literally-all-of-gccs-warnings) – Martin R Feb 08 '18 at 10:03
  • 2
    Because `0` is a perfectly legal *null pointer constant*. You are comparing the result of `realpath`, which is a pointer, with a null pointer. Not that it is legal, but this violation does not require a diagnostic. – n. m. could be an AI Feb 08 '18 at 10:03
  • Because comparing a pointer to 0 is well defined. It pretty much only makes sense to do that comparison for equality, but it seems the compiler doesn't really have that special case to a special case to warn for that (at least mine doesn't, maybe some newer versions of gcc do). – Art Feb 08 '18 at 10:06
  • You always want to use -Wpedantic in addition to -Wall. – n. m. could be an AI Feb 08 '18 at 10:10
  • 1
    for me it's ok for `if (ptr == 0 /* NULL */)` or `if (ptr != 0)`. when does it make sense for `> 0` or `< 0`? i believe gcc has a good reason not to warn this by default. no? – pynexj Feb 08 '18 at 10:10
  • @Art: I think less than comparison between pointers is only allowed, when they point to the same array. – MikeMB Feb 08 '18 at 10:35
  • @MikeMB Yup. But how is the compiler supposed to know that two pointers it has are to the same array? Especially since one of them is returned by a function that it knows nothing about. That's what I meant by a "special case", it is possible for the compiler to remember that one of the pointers involved in a comparison is a null pointer, but that requires extra effort. And it appears that newer versions of gcc do that effort. The older version I tried with doesn't. – Art Feb 08 '18 at 10:44
  • There are some obscure systems that use negative addresses to separate "kernel space" from "user space". – Lundin Feb 08 '18 at 12:01
  • @Lundin, this makes much sense. – pynexj Feb 08 '18 at 12:45
  • @pynexj It really doesn't, but some badly-written programs/operative systems simply abuse the pointer type. See https://stackoverflow.com/questions/3304795/can-a-pointer-address-ever-be-negative – Lundin Feb 08 '18 at 12:49
  • i mean it makes sense to explain why gcc not giving warnings for this by default. – pynexj Feb 08 '18 at 12:55
  • @Art: It knows that one of the operands is a nullptr, so the pointers can never point to the same array. – MikeMB Feb 08 '18 at 15:49
  • 1
    I personally use `-std=` together with `-Wall -Wextra -Wpedantic -Wconversion`. – Davislor Mar 10 '18 at 02:47

2 Answers2

11

gcc -Wall does not enable all of GCC's warnings! See this question for more information.

In your case, you need to add the -Wextra flag:

gcc -Wall -Wextra -o realpath realpath.c

According to GCC's documentation:

This enables some extra warning flags that are not enabled by -Wall.

The option -Wextra also prints warning messages for the following cases:

  • A pointer is compared against integer zero with <, <=, >, or >=.

  • [...]

Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
5

So why doesn't gcc (even with -Wall) report a warning for if (ptr < 0)?

The name given to the -Wall flag is actually misleading, since it does not enable all compiler warnings.

You need to pass -Wextra. This way, you will get the following compiler warning:

warning: ordered comparison of pointer with integer zero [-Wextra]
JFMR
  • 23,265
  • 4
  • 52
  • 76