Source: gcc-4.1
Version: 4.1.1ds2-21

Just for reference: the standard compiler on Debian etch (i386)
miscompiles the attached test programme with -fwrapv -O2 and
-fwrapv -Os, but not with -fwrapv -O1 or without -fwrapv.

If there's a workaround I can apply to the source (texpand was
the function changed) please tell me.
/* Copyright (c) Thorsten Glaser. Part of mksh, under the MirOS Licence. */

#include <err.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BIT(i)          (1 << (i))      /* define bit in flag */
#define DEFINED         BIT(1)  /* is defined in block */
#define FINUSE          BIT(9)  /* function being executed */

#define INIT_TBLS       8       /* initial table size (power of 2) */
#define PERTURB_SHIFT   5       /* see Python 2.5.4 Objects/dictobject.c */

#ifndef SIZE_MAX
#ifdef SIZE_T_MAX
#define SIZE_MAX        SIZE_T_MAX
#else
#define SIZE_MAX        ((size_t)-1)
#endif
#endif
#define notoktoadd(val, cnst)   ((val) > (SIZE_MAX - (cnst)))
#define checkoktoadd(val, cnst) do {                                    \
        if (notoktoadd((val), (cnst)))                                  \
                errx(1,"overflow");                     \
} while (/* CONSTCOND */ 0)

struct lalloc {
        struct lalloc *next;
};
typedef struct lalloc Area;
typedef int32_t mksh_ari_t;
typedef uint32_t mksh_uari_t;
struct op;
typedef int Tflag;

struct table {
        Area *areap;            /* area to allocate entries */
        struct tbl **tbls;      /* hashed table items */
        uint32_t size;          /* table size (always 2^n) */
        uint32_t nfree;         /* free table entries */
};

struct tbl {                    /* table item */
        Area *areap;            /* area to allocate from */
        union {
                char *s;                /* string */
                mksh_ari_t i;           /* integer */
                mksh_uari_t u;          /* unsigned integer */
                int (*f)(const char **); /* int function */
                struct op *t;           /* "function" tree */
        } val;                  /* value */
        union {
                struct tbl *array;      /* array values */
                const char *fpath;      /* temporary path to undef function */
        } u;
        union {
                int field;      /* field with for -L/-R/-Z */
                int errno_;     /* CEXEC/CTALIAS */
        } u2;
        int type;               /* command type (see below), base (if INTEGER),
                                 * or offset from val.s of value (if EXPORT) */
        Tflag flag;             /* flags */
        union {
                uint32_t hval;          /* hash(name) */
                uint32_t index;         /* index for an array */
        } ua;
        char name[4];           /* name -- variable length */
};


static void texpand(struct table *, size_t);

static void
texpand(struct table *tp, size_t nsize)
{
        size_t i, j, osize = tp->size, perturb;
        struct tbl *tblp, **pp;
        struct tbl **ntblp, **otblp = tp->tbls;

        i = 1;
        i <<= 30;
        if (nsize > i)
                errx(1, "hash table size limit reached");

        ntblp = malloc(nsize * sizeof(struct tbl *));
        memset(ntblp, 0, nsize * sizeof(struct tbl *));
        tp->size = nsize;
        if (nsize == i) {
                /* cannot be grown any more, use a fixed value */
                tp->nfree = i - 65536;
        } else /* (nsize < 2^30) */ {
                /* table can get 80% full */
                tp->nfree = (nsize * 4) / 5;
        }
        tp->tbls = ntblp;
        if (otblp == NULL)
                return;

        /* from here on nsize := mask */
        nsize--;
        for (i = 0; i < osize; i++)
                if ((tblp = otblp[i]) != NULL) {
                        if ((tblp->flag & DEFINED)) {
                                /* search for free hash table slot */
                                j = (perturb = tblp->ua.hval) & nsize;
                                goto find_first_empty_slot;
 find_next_empty_slot:
                                j = (j << 2) + j + perturb + 1;
                                perturb >>= PERTURB_SHIFT;
 find_first_empty_slot:
                                pp = &ntblp[j & nsize];
                                if (*pp != NULL)
                                        goto find_next_empty_slot;
                                /* found an empty hash table slot */
                                *pp = tblp;
                                tp->nfree--;
                        } else if (!(tblp->flag & FINUSE)) {
                                free(tblp);
                        }
                }
        free(otblp);
}

void
ktinit(struct table *tp, Area *ap, size_t tsize)
{
        tp->areap = ap;
        tp->tbls = NULL;
        tp->size = tp->nfree = 0;
        if (tsize)
                texpand(tp, tsize);
}

/* table, name (key) to search for, hash(name), rv pointer to tbl ptr */
static struct tbl *
ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
{
        size_t j, perturb, mask;
        struct tbl **pp, *p;

        mask = tp->size - 1;
        /* search for hash table slot matching name */
        j = (perturb = h) & mask;
        goto find_first_slot;
 find_next_slot:
        j = (j << 2) + j + perturb + 1;
        perturb >>= PERTURB_SHIFT;
 find_first_slot:
        pp = &tp->tbls[j & mask];
        if ((p = *pp) != NULL && (p->ua.hval != h || !(p->flag & DEFINED) ||
            strcmp(p->name, name)))
                goto find_next_slot;
        /* p == NULL if not found, correct found entry otherwise */
        if (ppp)
                *ppp = pp;
        return (p);
}

/* table, name (key) to enter, hash(n) */
struct tbl *
ktenter(struct table *tp, const char *n, uint32_t h)
{
        struct tbl **pp, *p;
        size_t len;

        if (tp->size == 0)
                texpand(tp, INIT_TBLS);
 Search:
        if ((p = ktscan(tp, n, h, &pp)))
                return (p);

        if (tp->nfree == 0) {
                /* too full */
                texpand(tp, 2 * tp->size);
                goto Search;
        }

        /* create new tbl entry */
        len = strlen(n);
        checkoktoadd(len, offsetof(struct tbl, name[0]) + 1);
        p = malloc(offsetof(struct tbl, name[0]) + ++len);
        p->flag = 0;
        p->type = 0;
        p->areap = tp->areap;
        p->ua.hval = h;
        p->u2.field = 0;
        p->u.array = NULL;
        memcpy(p->name, n, len);

        /* enter in tp->tbls */
        tp->nfree--;
        *pp = p;
        return (p);
}

int
main(void)
{
        struct table t;

        ktinit(&t, NULL, 64);
        ktenter(&t, "foo", 123);
        printf("ok\n");
        return (0);
}

Reply via email to