Bug 38167 - [4.2 Regression] Accessor to stdin breaks on -O2 optimization
Summary: [4.2 Regression] Accessor to stdin breaks on -O2 optimization
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.2.4
: P3 normal
Target Milestone: 4.3.0
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2008-11-17 01:59 UTC by Aleksi Nurmi
Modified: 2009-03-31 15:50 UTC (History)
2 users (show)

See Also:
Host: x86_64-pc-linux-gnu
Target:
Build:
Known to work: 4.4.0 4.3.0
Known to fail: 4.2.4 4.2.5
Last reconfirmed:


Attachments
preprocessed source (3.01 KB, text/plain)
2008-11-17 02:01 UTC, Aleksi Nurmi
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Aleksi Nurmi 2008-11-17 01:59:33 UTC
It appears that the following inline accessor function to stdin doesn't do it's job if -O2 optimization is turned on, thus letting a null pointer pass and causing a segfault. This doesn't happen if the function is not declared inline. 

Version: gcc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
Command line: gcc -O2 -o fault fault.c
GNU libc 2.7 is known for its non-constant stdin and is probably required to actually get a segfault.

Code in readable format:

#include <stdio.h>

struct iostream {
    FILE *f;
};

static struct iostream our_stdin = { 0 };

inline void access_iostream(struct iostream* ios)
{
    if (ios->f == 0)
        if (ios == &our_stdin)
            ios->f = stdin;
}

void read_char(struct iostream* ios)
{
    access_iostream(ios);
    fgetc(ios->f);
}

int main()
{  
    read_char(&our_stdin);

    return 0;
}
Comment 1 Aleksi Nurmi 2008-11-17 02:01:36 UTC
Created attachment 16707 [details]
preprocessed source
Comment 2 Jakub Jelinek 2008-11-17 08:46:03 UTC
Works just fine here, with both 4.3 and 4.4, -O2 and -O0.
Comment 3 Aleksi Nurmi 2008-11-17 14:06:46 UTC
Works for me on 4.1.3 20080308 (prerelease) (Ubuntu 4.1.2-21ubuntu1) and (Ubuntu 20081013-0ubuntu2) 4.3.3 20081014 (prerelease), too.

But not in 4.2.4 (Ubuntu 4.2.4-1ubuntu3).
Comment 4 Aleksi Nurmi 2008-11-17 15:11:05 UTC
I found an even shorter way to make it segfault, with no inline functions at all. It's an -O2 problem, then.

#include <stdio.h>

struct iostream {
    FILE *f;
};

static struct iostream our_stdin = { 0 };

void read_char(struct iostream* ios)
{
    if (ios->f == 0)
        if (ios == &our_stdin)
            ios->f = stdin;
    fgetc(ios->f);
}

int main()
{
    read_char(&our_stdin);

    return 0;
}
Comment 5 Aleksi Nurmi 2008-11-17 15:53:41 UTC
GDB output showing that libc (debug) received a null pointer:

Program received signal SIGSEGV, Segmentation fault.
_IO_getc (fp=0x0) at getc.c:40
40	  _IO_acquire_lock (fp);
(gdb) print fp
$1 = (FILE *) 0x0
(gdb) up
#1  0x000000000040051e in main () at fault.c:20
20	    read_char(&our_stdin);
(gdb) print our_stdin.f
$2 = (FILE *) 0x7f75cc0c96a0
(gdb) print stdin
$3 = (struct _IO_FILE *) 0x7f75cc0c96a0
Comment 6 Andrew Pinski 2008-11-24 17:46:45 UTC
This is most likely one of the aliasing bugs.  Does -fno-strict-aliasing fix the issue?
Comment 7 Aleksi Nurmi 2008-11-24 18:17:48 UTC
(In reply to comment #6)
> This is most likely one of the aliasing bugs.  Does -fno-strict-aliasing fix
> the issue?

Nope. I did a little research and it seems that -fno-tree-vrp fixes it.
Comment 8 Joseph S. Myers 2009-03-31 15:50:45 UTC
Closing 4.2 branch, fixed in 4.3.