Bug 85778 - unexpected results with -O2, wrong code?
Summary: unexpected results with -O2, wrong code?
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: other (show other bugs)
Version: 8.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-05-14 18:19 UTC by Matthias Klose
Modified: 2018-05-15 20:17 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Klose 2018-05-14 18:19:18 UTC
seen with GCC 5 and all newer version. Is this wrong-code?

$ cat testcase.c 
#include <stdio.h>
#include <sys/stat.h>

#define PRINT \
  if (foo == NULL) \
    printf("foo in func() is %p, NULL (expected)\n", foo); \
  else \
    printf("foo in func() is %p, not NULL (NOT EXPECTED!)\n", foo);

void func(const char *foo) {
  struct stat stat_buf;

  PRINT;
  stat(foo, &stat_buf);
  PRINT;
}

int main() {
  const char *foo = NULL;
  struct stat stat_buf;

  func(NULL);

  PRINT;
  stat(foo, &stat_buf);
  PRINT;
  return 0;
}

$ gcc -O0 testcase.c && ./a.out 
foo in func() is (nil), NULL (expected)
foo in func() is (nil), NULL (expected)
foo in func() is (nil), NULL (expected)
foo in func() is (nil), NULL (expected)
$ gcc -O2 testcase.c && ./a.out 
foo in func() is (nil), NULL (expected)
foo in func() is (nil), not NULL (NOT EXPECTED!)
foo in func() is (nil), NULL (expected)
foo in func() is (nil), NULL (expected)
Comment 1 Andrew Pinski 2018-05-14 18:27:19 UTC
It depends on if glibc is adding the nonnull attribute to stat or is it GCC.  Also what does the C (and POSIX) standard says about a null pointer being passed as the string to stat.
Comment 2 Scott Emmons 2018-05-14 23:28:08 UTC
Just to add a few more details, I discovered this via "cronolog", which does this pattern of stat() with a null pathname. Not that it makes the code correct, and it could easily be guarded against, however this code has been working fine since 2001 [1].

There's a few more details in the downstream bug report [2].

[1] https://github.com/fordmason/cronolog/blame/83f9e99d6bd5cb8f5cc06723f4d79d1265582340/src/cronoutils.c#L250
[2] https://bugs.launchpad.net/ubuntu/+source/gcc-5/+bug/1770676
Comment 3 Richard Biener 2018-05-15 07:32:15 UTC
glibc has stat annotated with nonnull(1, 2)
Comment 4 Scott Emmons 2018-05-15 15:44:58 UTC
> glibc has stat annotated with nonnull(1, 2)

1. Can you provide a reference to this code? This is helpful so that other people running into this (and it *will* happen, this ancient code no longer runs correctly). Thank you.

2. The manpage for stat(2) should be updated to reflect that calling stat() with a NULL pathname will result in unpredictable behavior.

3. I'll create a pull request against cronolog and work with Debian/Ubuntu to at least get it fixed in those distributions.
Comment 5 Martin Sebor 2018-05-15 20:17:43 UTC
(In reply to Scott Emmons from comment #4)
> > glibc has stat annotated with nonnull(1, 2)
> 
> 1. Can you provide a reference to this code? This is helpful so that other
> people running into this (and it *will* happen, this ancient code no longer
> runs correctly). Thank you.

stat() is a POSIX function and (similarly to C) POSIX specifies (in 2.1.1 Use and Implementation of Functions of XSH) that:

If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer), the behavior is undefined.

A link to the section in the latest spec:
pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_01_01