Bug 91197 - [8,9 regression] alignment test program used in perl does not work with -O2 anymore
Summary: [8,9 regression] alignment test program used in perl does not work with -O2 a...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: other (show other bugs)
Version: 9.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-07-18 11:53 UTC by Rolf Eike Beer
Modified: 2019-07-19 06:50 UTC (History)
0 users

See Also:
Host:
Target: i?86-*-*
Build:
Known to work: 7.3.0
Known to fail: 8.3.0, 9.1.0
Last reconfirmed: 2019-07-19 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rolf Eike Beer 2019-07-18 11:53:22 UTC
The story is in https://bugs.gentoo.org/676062 and especially https://rt.perl.org/Public/Bug/Display.html?id=133495

This test program, taken from the above perl bug, incorrectly returns 0 when built with -O2 on gcc 8.3 and 9.1, but is fine with 7.3 and probably everything before. Building with -g only makes things work:

#include <stdio.h>
#define I_STDLIB
#ifdef I_STDLIB
#include <stdlib.h>
#endif
#define U32 unsigned long
#define BYTEORDER 0x4321
#define U8 unsigned char
#include <signal.h>
#ifdef SIGBUS
void bletch(int s) { exit(4); }
#endif
int main() {
#if BYTEORDER == 0x1234 || BYTEORDER == 0x4321
    volatile U8 buf[8];
    volatile U32 *up;
    int i;

    if (sizeof(U32) != 4) {
        printf("sizeof(U32) is not 4, but %d\n", sizeof(U32));
        exit(1);
    }

    fflush(stdout);

#ifdef SIGBUS
    signal(SIGBUS, bletch);
#endif

    buf[0] = 0;
    buf[1] = 0;
    buf[2] = 0;
    buf[3] = 1;
    buf[4] = 0;
    buf[5] = 0;
    buf[6] = 0;
    buf[7] = 1;

    for (i = 0; i < 4; i++) {
        up = (U32*)(buf + i);
        if (! ((*up == 1 << (8*i)) ||   /* big-endian */
               (*up == 1 << (8*(3-i)))  /* little-endian */
              )
           )
        {
            printf("read failed (%x)\n", *up);
            exit(2);
        }
    }

    /* write test */
    for (i = 0; i < 4; i++) {
        up = (U32*)(buf + i);
        *up = 0xBeef;
        if (*up != 0xBeef) {
            printf("write failed (%x)\n", *up);
            exit(3);
        }
    }

    exit(0);
#else
    printf("1\n");
    exit(1);
#endif
    return 0;
}
Comment 1 Andreas Schwab 2019-07-18 12:09:57 UTC
You are relying on undefined behaviour.
Comment 2 Richard Biener 2019-07-19 06:29:57 UTC
Not sure what this progam wants to test but I see it passing (exit code zero,
no prints).

Why is returning 0 wrong?
Comment 3 Rolf Eike Beer 2019-07-19 06:44:03 UTC
It returns the alignment rather than printing. 4 is the correct return code.
Comment 4 Andrew Pinski 2019-07-19 06:50:46 UTC
(U32*)(buf + i)

Is undefined behavior since buf+i will mostly be unaligned.

NOTE most likely is unrolling the loop and changing the code from crashing to something which will not crash.  That is valid thing to do as it was undefined beforehand.