diff options
| author | 2026-03-18 23:10:25 +0100 | |
|---|---|---|
| committer | 2026-03-18 23:10:25 +0100 | |
| commit | 1b782f049fa96d7ebccf93ad2b05fc30b938c870 (patch) | |
| tree | d4048328308d676f05a9312af63e55e09459da8e | |
| parent | 626c927bb70519e630402093ff4fba432d2ac8c5 (diff) | |
c: fix edge cases with zero sized bitfields and static initializers
| -rw-r--r-- | src/c.c | 13 | ||||
| -rw-r--r-- | src/c_eval.c | 8 | ||||
| -rw-r--r-- | test/17-misc.c | 20 |
3 files changed, 31 insertions, 10 deletions
@@ -1461,6 +1461,7 @@ iniwrite(CComp *cm, InitParser *ip, uint off, uint bitsiz, uint bitoff, Type ty, if (nerror) return; if (ip->dyn) { if (ip->ddat.n < off + siz) { + /* extending ddata, can only happen for unknown-size arrays */ uint old = ip->ddat.n; vresize(&ip->ddat, off + siz); memset(ip->ddat.p + old, 0, ip->ddat.n - old); @@ -1702,7 +1703,7 @@ designators(InitParser *ip, CComp *cm) bool some = 0; for (;;) { - uint off, bitsiz, bitoff; + uint off, bitsiz, bitoff; uvlong idx = ~0ull; if (match(cm, &tk, '[')) { Expr ex = commaexpr(cm); @@ -1879,8 +1880,9 @@ initializer(CComp *cm, Type *ty, enum evalmode ev, bool globl, if (!nerror) { off = objnewdat(sym, sec, globl, siz = typesize(*ty), align = typealign(*ty)); p = sec == Srodata ? objout.rodata.p : objout.data.p; + assert(ip->ddat.n <= siz); memcpy(p + off, ip->ddat.p, ip->ddat.n); - memset(p + off + ip->ddat.n, 0, typesize(*ty) - ip->ddat.n); + memset(p + off + ip->ddat.n, 0, siz - ip->ddat.n); for (InitReloc *rel = ip->drel; rel; rel = rel->link) { objreloc(rel->sym, targ_64bit ? REL_ABS64 : REL_ABS32, sec, off + rel->off, rel->addend); } @@ -2028,11 +2030,8 @@ buildagg(CComp *cm, enum typetag tt, internstr name, int id) } else { bitsiz = ex.i; if (bitsiz == 0) { - if (bitftypesiz) { - bitfbyteoff += bitftypesiz; - bitfbyteoff = alignup(bitfbyteoff, typealign(decl.ty)); - } - bitoff = 0; + bitsiz = bitftypesiz - bitoff; + continue; } else if (bitftypesiz && bitftypesiz < tysize) { /* end of previous bitfield */ bitoff = 0; diff --git a/src/c_eval.c b/src/c_eval.c index eff7e94..dce1457 100644 --- a/src/c_eval.c +++ b/src/c_eval.c @@ -139,7 +139,7 @@ truthy(const Expr *ex) static bool unop(Expr *ex, enum evalmode mode) { - Expr *sub = ex->sub; + Expr *sub = ex->sub, ex2; if (mode >= EVSTATICINI && ex->t == EDEREF) { uvlong off; @@ -175,10 +175,14 @@ unop(Expr *ex, enum evalmode mode) p = sub->sub[1].s.p, len = sub->sub[1].s.n; csiz = typesize(typechild(sub->sub[1].ty)); goto StrRead; + } else if (ex->ty.t == TYARRAY && eval(sub, mode)) { + sub->ty = ex->ty; + *ex = *sub; + return 1; } else return 0; } else if (ex->t == EADDROF) { assert(ex->ty.t == TYPTR); - Expr ex2 = staticaddrof(ex->sub, mode); + ex2 = staticaddrof(ex->sub, mode); if (!ex2.t) return 0; ex2.span = ex->span; ex2.ty = ex->ty; diff --git a/test/17-misc.c b/test/17-misc.c index ffd2470..73f09d1 100644 --- a/test/17-misc.c +++ b/test/17-misc.c @@ -1,5 +1,6 @@ /* EXPECT: -1155497588 +S3 =16, f2@8, q@14 */ typedef unsigned long long uvlong; @@ -29,11 +30,26 @@ _Static_assert(!__is_constexpr(fn1(0)), ""); #include <stddef.h> #include <stdint.h> struct foo { int *a, b[2]; }; + +static int g_37[3][5] = {{1,2,3,4,5},{11,12,13,14,15}}; static intptr_t offst[] = { (long)((struct foo *)0)->b, (long)&((struct foo *)0)->a, (long)&((struct foo *)0)->b[1], - (intptr_t)("12" - 5) + (intptr_t)("12" - 5), +}; +static int *g_131 = &g_37[0][4]; +static int *g_132 = &g_37[1][3]; +static int *g_133 = &g_37[2][0]; + +#include <stdint.h> +struct S3 { + unsigned f0 : 21; + volatile unsigned f1 : 13; + unsigned f2; + unsigned : 0; + short f3 : 13; + char q; }; extern int printf(const char *, ...); @@ -43,4 +59,6 @@ int main() { assert(offst[0] == offsetof(struct foo, b)); assert(offst[1] == offsetof(struct foo, a)); assert(offst[2] == offsetof(struct foo, b[1])); + assert(*g_131 == 5 && *g_132 == 14 && *g_133 == 0); + printf("S3 =%d, f2@%d, q@%d\n", (int)sizeof(struct S3), (int)offsetof(struct S3, f2), (int)offsetof(struct S3, q)); } |