Bug#629244: gcc-4.1: miscompiles with -fwrapv
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 to: