diff options
| author | 2025-12-30 10:34:11 +0100 | |
|---|---|---|
| committer | 2025-12-30 10:37:13 +0100 | |
| commit | e77538515802276d76dfcb28c9b8dc140d5afe02 (patch) | |
| tree | 48ece54a12bc4a447db386214b29b3e9890925e7 | |
| parent | 2b6b6b79beba618ab46c353a59a1c90539340021 (diff) | |
c: SYM expr should store decl ref as an index, not pointer
Because envdecls (now declsbuf) can be resized and invalidate those
pointers. I missed this because the default initialization size of that
buffer (and the fact that it would mostly only manifest with
function-local expressions) made it not really come up in practice.
Silly
| -rw-r--r-- | c/c.c | 103 | ||||
| -rw-r--r-- | c/c.h | 6 | ||||
| -rw-r--r-- | c/eval.c | 2 |
3 files changed, 59 insertions, 52 deletions
@@ -172,7 +172,7 @@ isexprtok(struct comp *cm) /* Environment (scope) management */ /**********************************/ -static vec_of(struct decl) envdecls; +struct envdecls declsbuf; struct tagged { /* a tagged type declaration */ union type ty; struct span span; @@ -192,9 +192,9 @@ static pmap_of(ushort) tldeclmap; static void envdown(struct comp *cm, struct env *e) { - assert(cm->env->decl + cm->env->ndecl == envdecls.n); + assert(cm->env->decl + cm->env->ndecl == declsbuf.n); assert(cm->env->tagged + cm->env->ntagged == envtagged.n); - e->decl = envdecls.n; + e->decl = declsbuf.n; e->tagged = envtagged.n; e->ndecl = e->ntagged = 0; e->up = cm->env; @@ -205,22 +205,22 @@ static void envup(struct comp *cm) { struct env *env = cm->env; - assert(env->decl + env->ndecl == envdecls.n); - envdecls.n -= env->ndecl; + assert(env->decl + env->ndecl == declsbuf.n); + declsbuf.n -= env->ndecl; envtagged.n -= env->ntagged; assert(env->up); cm->env = env->up; } -struct decl * +int envadddecl(struct env *env, const struct decl *d) { - assert(env->decl + env->ndecl == envdecls.n); - vpush(&envdecls, *d); - assert(envdecls.n < 1<<16); + assert(env->decl + env->ndecl == declsbuf.n); + vpush(&declsbuf, *d); + assert(declsbuf.n < 1<<16); ++env->ndecl; - if (!env->up) pmap_set(&tldeclmap, d->name, envdecls.n-1); - return &envdecls.p[envdecls.n - 1]; + if (!env->up) pmap_set(&tldeclmap, d->name, declsbuf.n-1); + return declsbuf.n - 1; } /* iters in reversed order of insertion (most to least recent) */ @@ -229,8 +229,8 @@ static inline bool enviterdecl(struct decl **d, struct env *env) { if (!env->ndecl) return 0; - if (!*d) *d = &envdecls.p[env->decl + env->ndecl - 1]; - else if (*d == &envdecls.p[env->decl]) return 0; + if (!*d) *d = &declsbuf.p[env->decl + env->ndecl - 1]; + else if (*d == &declsbuf.p[env->decl]) return 0; else --*d; return 1; } @@ -292,7 +292,7 @@ redeclarationok(const struct decl *old, const struct decl *new) return 0; } -static struct decl * +static int putdecl(struct comp *cm, const struct decl *decl) { assert(!decl->isbuiltin); @@ -301,7 +301,7 @@ putdecl(struct comp *cm, const struct decl *decl) if (!env->up) { ushort *pi = pmap_get(&tldeclmap, decl->name); if (pi) { - l = &envdecls.p[*pi]; + l = &declsbuf.p[*pi]; goto Match; } } else for (l = NULL; enviterdecl(&l, env);) { @@ -316,7 +316,7 @@ putdecl(struct comp *cm, const struct decl *decl) note(&l->span, "previously declared here"); break; } - if (l->isdef && !decl->isdef) return l; + if (l->isdef && !decl->isdef) return l - declsbuf.p; break; } } @@ -332,7 +332,7 @@ finddecl(struct comp *cm, internstr name) for (struct env *e = cm->env; e; e = e->up) { if (!e->up) { ushort *pi = pmap_get(&tldeclmap, name); - if (pi) return &envdecls.p[*pi]; + if (pi) return &declsbuf.p[*pi]; } else for (struct decl *l = NULL; enviterdecl(&l, e);) { if (name == l->name) return l; @@ -733,20 +733,20 @@ callexpr(struct comp *cm, const struct span *span_, const struct expr *callee) bool printsig = 0; const struct builtin *builtin = NULL; - if (callee->t == ESYM && !callee->ty.t && callee->sym->isbuiltin) { - builtin = callee->sym->builtin; + if (callee->t == ESYM && !callee->ty.t && declsbuf.p[callee->decl].isbuiltin) { + builtin = declsbuf.p[callee->decl].builtin; assert(!ty.t); } if (callee->t == ESYM && ty.t == IMPLICITFUNCTY) { /* implicit function decl.. */ - internstr name = (void *)callee->sym; + internstr name = callee->implicitsym; struct decl decl = { (ty = mkfntype(mktype(TYINT), 0, NULL, /* kandr */ 1, 0)), .scls = SCEXTERN, .span = span, .name = name, .sym = name }; warn(&span, "call to undeclared function '%s'", name); ((struct expr *)callee)->ty = decl.ty; - ((struct expr *)callee)->sym = putdecl(cm, &decl); + ((struct expr *)callee)->decl = putdecl(cm, &decl); } if (!builtin) { @@ -1093,18 +1093,18 @@ Unary: assert(decl && decl->scls == SCSTATIC); goto Sym; } else if (peek(cm, NULL) == '(') { /* implicit function decl? */ - ex = mkexpr(ESYM, tk.span, mktype(IMPLICITFUNCTY), .sym = (void *)tk.name); + ex = mkexpr(ESYM, tk.span, mktype(IMPLICITFUNCTY), .implicitsym = tk.name); } else { error(&tk.span, "undeclared identifier %'tk", &tk); - ex = mkexpr(ESYM, tk.span, mktype(TYINT), .sym = NULL); + ex = mkexpr(ESYM, tk.span, mktype(TYINT), .implicitsym = NULL); } } else if (decl->scls == SCTYPEDEF) { error(&tk.span, "unexpected typename %'tk (expected expression)", &tk); - ex = mkexpr(ESYM, tk.span, decl->ty, .sym = NULL); + ex = mkexpr(ESYM, tk.span, decl->ty, .implicitsym = NULL); } else if (decl->isenum) { ex = mkexpr(ENUMLIT, tk.span, decl->ty, .i = decl->value); } else Sym: { - ex = mkexpr(ESYM, tk.span, decl->ty, .qual = decl->qual, .sym = decl); + ex = mkexpr(ESYM, tk.span, decl->ty, .qual = decl->qual, .decl = decl - declsbuf.p); } break; } case TKWsizeof: case TKW_Alignof: case TKWalignof: @@ -1398,7 +1398,7 @@ dumpini(struct initparser *ip) static bool globsym(union ref *psym, const struct expr *ex) { - if (ex->t == EINIT || ex->t == ESTRLIT || (ex->t == ESYM && (ex->sym->scls & (SCSTATIC | SCEXTERN)))) { + if (ex->t == EINIT || ex->t == ESTRLIT || (ex->t == ESYM && (declsbuf.p[ex->decl].scls & (SCSTATIC | SCEXTERN)))) { *psym = expraddr(NULL, ex); return 1; } @@ -2853,7 +2853,7 @@ expraddr(struct function *fn, const struct expr *ex) switch (ex->t) { case ESYM: - decl = ex->sym; + decl = &declsbuf.p[ex->decl]; assert(decl != NULL); switch (decl->scls) { case SCAUTO: case SCREGISTER: @@ -3309,8 +3309,8 @@ compilecall(struct function *fn, const struct expr *ex) struct instr insnsbuf[10]; vec_of(struct instr) insns = VINIT(insnsbuf, countof(insnsbuf)); - if (sub[0].t == ESYM && sub[0].sym->isbuiltin) { - return sub[0].sym->builtin->comp(fn, (struct expr *)ex, 0); + if (sub[0].t == ESYM && declsbuf.p[sub[0].decl].isbuiltin) { + return declsbuf.p[sub[0].decl].builtin->comp(fn, (struct expr *)ex, 0); } ins.op = Ocall; if (isagg(ex->ty)) { @@ -3332,7 +3332,7 @@ compilecall(struct function *fn, const struct expr *ex) vfree(&insns); ins.r = mkcallarg(mkirtype(ex->ty), ex->narg, td->variadic ? td->nmemb : td->kandr ? 0 : -1); union ref r = addinstr(fn, ins); - if (sub[0].t == ESYM && sub[0].sym->noret) /* trap if noreturn func returns */ + if (sub[0].t == ESYM && declsbuf.p[sub[0].decl].noret) /* trap if noreturn func returns */ puttrap(fn); return r; } @@ -4309,31 +4309,33 @@ localdecl(struct comp *cm, struct function *fn, bool forini) } Initz: if (st.varini) { - struct decl *d = putdecl(cm, &decl); + int d = putdecl(cm, &decl); + union type ty = decl.ty; bool statik = decl.scls & (SCSTATIC | SCEXTERN); - ini = initializer(cm, &d->ty, statik ? EVSTATICINI : EVFOLD, + ini = initializer(cm, &ty, statik ? EVSTATICINI : EVFOLD, /* globl? */ decl.scls == SCEXTERN, decl.qual, statik ? decl.sym : NULL); + declsbuf.p[d].ty = ty; put = 1; pdecl(&st, cm); if (!statik) { /* fix alloca for actual size, for implicitly sized arrays */ - assert(!isincomplete(d->ty)); - EMITS instrtab[decl.id] = mkalloca(typesize(d->ty), typealign(d->ty)); + assert(!isincomplete(ty)); + EMITS instrtab[decl.id] = mkalloca(typesize(ty), typealign(ty)); - if (!initcheck(d->ty, &ini)) { + if (!initcheck(ty, &ini)) { struct span span = decl.span; joinspan(&span.ex, ini.span.ex); error(&span, "cannot initialize '%ty' variable with '%ty'", - d->ty, ini.ty); + ty, ini.ty); } EMITS { - if (ini.t == EINIT || (d->ty.t == TYARRAY && ini.t == ESTRLIT)) - geninit(fn, d->ty, mkref(RTMP, decl.id), &ini); - else if (isagg(d->ty)) - structcopy(fn, d->ty, mkref(RTMP, decl.id), exprvalue(fn, &ini)); + if (ini.t == EINIT || (ty.t == TYARRAY && ini.t == ESTRLIT)) + geninit(fn, ty, mkref(RTMP, decl.id), &ini); + else if (isagg(ty)) + structcopy(fn, ty, mkref(RTMP, decl.id), exprvalue(fn, &ini)); else { - genstore(fn, d->ty, mkref(RTMP, decl.id), - cvt(fn, d->ty, ini.ty, exprvalue(fn, &ini))); + genstore(fn, ty, mkref(RTMP, decl.id), + cvt(fn, ty, ini.ty, exprvalue(fn, &ini))); } } } else if (decl.scls == SCEXTERN) { @@ -4501,7 +4503,7 @@ tldecl(struct comp *cm) error(&st.pspans[i], "parameter has incomplete type '%ty'", td->param[i]); } decl.isdef = 1; - struct decl *d = putdecl(cm, &decl); + struct decl *d = &declsbuf.p[putdecl(cm, &decl)]; struct function fn = { &cm->fnarena, .name = decl.name, .globl = d->scls != SCSTATIC, .fnty = decl.ty, .retty = td->ret }; irinit(&fn); function(cm, &fn, st.pnames, st.pspans, st.pqual); @@ -4509,13 +4511,16 @@ tldecl(struct comp *cm) irdump(&fn); irfini(&fn); } else if (decl.name) { - struct decl *d = putdecl(cm, &decl); + int idecl = putdecl(cm, &decl); + struct decl *d = &declsbuf.p[idecl]; if (st.varini) { - if (isagg(d->ty) && isincomplete(d->ty)) - error(&d->span, "initialization of variable with incomplete type '%ty'", d->ty); - struct expr ini = initializer(cm, &d->ty, EVSTATICINI, d->scls != SCSTATIC, d->qual, d->sym); + if (isagg(decl.ty) && isincomplete(decl.ty)) + error(&decl.span, "initialization of variable with incomplete type '%ty'", decl.ty); + struct expr ini = initializer(cm, &decl.ty, EVSTATICINI, d->scls != SCSTATIC, d->qual, d->sym); + d = &declsbuf.p[idecl]; + d->ty = decl.ty; if (d->scls == SCEXTERN && !noscls) { - struct span span = d->span; + struct span span = decl.span; joinspan(&span.ex, ini.span.ex); warn(&span, "'extern' variable has initializer"); } @@ -4558,7 +4563,7 @@ docomp(struct comp *cm) istr_main = intern("main"); istr_memset = intern("memset"); if (!cm->env) { - vinit(&envdecls, NULL, 1<<10); + vinit(&declsbuf, NULL, 1<<10); pmap_init(&tldeclmap, 1<<8); cm->env = &toplevel; } @@ -45,7 +45,8 @@ struct expr { }; uint n; } s; /* ESTRLIT */ - struct decl *sym; /* ESYM */ + int decl; /* ESYM, index into declsbuf */ + internstr implicitsym; /* ESYM (undeclared) */ struct init *init; /* EINIT */ }; }; @@ -101,9 +102,10 @@ struct decl { }; }; +extern struct envdecls {vec_of(struct decl);} declsbuf; extern union type cvalistty; struct function; -struct decl *envadddecl(struct env *env, const struct decl *d); +int envadddecl(struct env *env, const struct decl *d); bool assigncheck(union type t, const struct expr *src); union ref expraddr(struct function *, const struct expr *); union ref compileexpr(struct function *, const struct expr *, bool discard); @@ -158,7 +158,7 @@ unop(struct expr *ex, enum evalmode mode) static bool isglobsym(const struct expr *ex) { - return ex->t == ESTRLIT || (ex->t == ESYM && ex->sym && (ex->sym->scls & (SCSTATIC | SCEXTERN))); + return ex->t == ESTRLIT || (ex->t == ESYM && ex->ty.t < NTYPETAG && (declsbuf.p[ex->decl].scls & (SCSTATIC | SCEXTERN))); } static bool |