/* gcc4pointersubtractionbug.c
 * Written by Mikael Pettersson, [EMAIL PROTECTED], 2005-04-23.
 *
 * This program illustrates a code optimisation bug in
 * gcc-4.0.0 (final) and gcc-4.0.0-20050417, where a pointer
 * subtraction operation is compiled as a pointer addition.
 * Observed at -O2. gcc was configured for i686-pc-linux-gnu.
 *
 * This bug broke net/ipv4/devinet.c:devinet_sysctl_register()
 * in the linux-2.6.12-rc2 Linux kernel, causing /sbin/sysctl
 * to trigger kernel oopses.
 *
 * gcc-4.0.0-20050416 and earlier prereleases do not have this bug.
 */
#include <stdio.h>
#include <string.h>

#define NRVARS  5

struct ipv4_devconf {
    int var[NRVARS];
};
struct ipv4_devconf ipv4_devconf[2];

struct ctl_table {
    void *data;
};

struct devinet_sysctl_table {
    struct ctl_table devinet_vars[NRVARS];
};

void devinet_sysctl_relocate(struct devinet_sysctl_table *t,
                             struct ipv4_devconf *p)
{
    int i;

    for (i = 0; i < NRVARS; i++)
        /* Initially data points to a field in ipv4_devconf[0].
           This code relocates it to the corresponding field in *p.
           At -O2, gcc-4.0.0-20050417 and gcc-4.0.0 (final)
           miscompile this pointer subtraction as a pointer addition. */
        t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf[0];
}

struct devinet_sysctl_table devinet_sysctl;

int main(void)
{
    struct devinet_sysctl_table t;
    int i;

    for(i = 0; i < NRVARS; i++)
        devinet_sysctl.devinet_vars[i].data = &ipv4_devconf[0].var[i];

    memcpy(&t, &devinet_sysctl, sizeof t);
    devinet_sysctl_relocate(&t, &ipv4_devconf[1]);

    for(i = 0; i < NRVARS; i++)
        if (t.devinet_vars[i].data != &ipv4_devconf[1].var[i]) {
            fprintf(stderr, "t.devinet_vars[%u].data == %p, should be %p\n",
                    i,
                    t.devinet_vars[i].data,
                    &ipv4_devconf[1].var[i]);
            return 1;
        }

    printf("all ok\n");
    return 0;
}

-- 
           Summary: miscompiled pointer subtraction broke Linux kernel
           Product: gcc
           Version: 4.0.0
            Status: UNCONFIRMED
          Severity: critical
          Priority: P2
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: mikpe at csd dot uu dot se
                CC: gcc-bugs at gcc dot gnu dot org
 GCC build triplet: i686-pc-linux-gnu
  GCC host triplet: i686-pc-linux-gnu
GCC target triplet: i686-pc-linux-gnu


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21173

Reply via email to