Message ID | c3903caf-06a7-e321-4fa9-5abe0a0f2ae9@gigawatt.nl (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Herbert Xu |
Headers | show |
Series | Simplify alias storage. | expand |
On Wed, Jan 11, 2023 at 06:23:41PM +0000, Harald van Dijk wrote: > > if (ap) { > if (!(ap->flag & ALIASINUSE)) { > - ckfree(ap->val); > + ckfree(ap->name); > } I think this breaks ALIASINUSE. When an alias is marked as INUSE, it will be freed by input.c (popstring). However, your patch doesn't touch input.c at all. Thanks,
On 06/04/2024 08:19, Herbert Xu wrote: > On Wed, Jan 11, 2023 at 06:23:41PM +0000, Harald van Dijk wrote: >> >> if (ap) { >> if (!(ap->flag & ALIASINUSE)) { >> - ckfree(ap->val); >> + ckfree(ap->name); >> } > > I think this breaks ALIASINUSE. When an alias is marked as INUSE, > it will be freed by input.c (popstring). However, your patch doesn't > touch input.c at all. You're quite right, thanks for spotting that. A test case that covers that is alias foo=' alias foo="echo Hello" ' foo foo Here, the storage of the original 'foo' alias needs to be kept while the expansion is ongoing, even when the second 'alias' overwrites the original definition. This bug is fixed by below additional patch. However, the patch conflicts with c8db655b because scanning 'name' will now find the '=' character and continue on from that to check the value. That should be relatively easy to avoid, but I am not sure it is worth it. Cheers, Harald van Dijk diff --git a/src/input.c b/src/input.c index 38969a7..4604945 100644 --- a/src/input.c +++ b/src/input.c @@ -386,7 +386,7 @@ pushstring(char *s, void *ap) sp->ap = (struct alias *)ap; if (ap) { ((struct alias *)ap)->flag |= ALIASINUSE; - sp->string = s; + sp->string = ((struct alias *)ap)->name; } parsefile->nextc = s; parsefile->nleft = len; @@ -405,7 +405,7 @@ static void popstring(void) parsefile->nextc[-1] == '\t') { checkkwd |= CHKALIAS; } - if (sp->string != sp->ap->val) { + if (sp->string != sp->ap->name) { ckfree(sp->string); } }
On Thu, Apr 25, 2024 at 09:46:45PM +0100, Harald van Dijk wrote: > > You're quite right, thanks for spotting that. A test case that covers that > is > > alias foo=' > alias foo="echo Hello" > ' > foo > foo > > Here, the storage of the original 'foo' alias needs to be kept while the > expansion is ongoing, even when the second 'alias' overwrites the original > definition. This bug is fixed by below additional patch. Could you please post a combined patch? Thanks! > However, the patch conflicts with c8db655b because scanning 'name' will now > find the '=' character and continue on from that to check the value. That > should be relatively easy to avoid, but I am not sure it is worth it. Don't worry about that one. I can back it out if necessary. In fact, I'll probably fix it in a different way as I'm adding multi-byte support. Cheers,
diff --git a/src/alias.c b/src/alias.c index fcad43b..bb963a6 100644 --- a/src/alias.c +++ b/src/alias.c @@ -41,6 +41,7 @@ #include "mystring.h" #include "alias.h" #include "options.h" /* XXX for argptr (should remove?) */ +#include "var.h" #define ATABSIZE 39 @@ -55,25 +56,26 @@ void setalias(const char *name, const char *val) { struct alias *ap, **app; + size_t namelen; app = __lookupalias(name); ap = *app; INTOFF; if (ap) { if (!(ap->flag & ALIASINUSE)) { - ckfree(ap->val); + ckfree(ap->name); } - ap->val = savestr(val); ap->flag &= ~ALIASDEAD; } else { /* not found */ ap = ckmalloc(sizeof (struct alias)); - ap->name = savestr(name); - ap->val = savestr(val); ap->flag = 0; ap->next = 0; *app = ap; } + namelen = val - name; + ap->name = savestr(name); + ap->val = ap->name + namelen; INTON; } @@ -150,8 +152,7 @@ aliascmd(int argc, char **argv) } else printalias(ap); } else { - *v++ = '\0'; - setalias(n, v); + setalias(n, v + 1); } } @@ -190,36 +191,23 @@ freealias(struct alias *ap) { next = ap->next; ckfree(ap->name); - ckfree(ap->val); ckfree(ap); return next; } void printalias(const struct alias *ap) { - out1str(single_quote(ap->name)); - out1fmt("=%s\n", single_quote(ap->val)); + out1fmt("%s\n", single_quote(ap->name)); } STATIC struct alias ** __lookupalias(const char *name) { - unsigned int hashval; struct alias **app; - const char *p; - unsigned int ch; - p = name; - - ch = (unsigned char)*p; - hashval = ch << 4; - while (ch) { - hashval += ch; - ch = (unsigned char)*++p; - } - app = &atab[hashval % ATABSIZE]; + app = &atab[hashval(name) % ATABSIZE]; for (; *app; app = &(*app)->next) { - if (equal(name, (*app)->name)) { + if (varequal(name, (*app)->name)) { break; } } diff --git a/src/var.c b/src/var.c index b70d72c..64d93aa 100644 --- a/src/var.c +++ b/src/var.c @@ -625,12 +625,7 @@ void unsetvar(const char *s) STATIC struct var ** hashvar(const char *p) { - unsigned int hashval; - - hashval = ((unsigned char) *p) << 4; - while (*p && *p != '=') - hashval += (unsigned char) *p++; - return &vartab[hashval % VTABSIZE]; + return &vartab[hashval(p) % VTABSIZE]; } @@ -644,19 +639,19 @@ hashvar(const char *p) int varcmp(const char *p, const char *q) { - int c, d; - - while ((c = *p) == (d = *q)) { - if (!c || c == '=') - goto out; + int c = *p, d = *q; + while (c == d) { + if (!c) + break; p++; q++; + c = *p; + d = *q; + if (c == '=') + c = '\0'; + if (d == '=') + d = '\0'; } - if (c == '=') - c = 0; - if (d == '=') - d = 0; -out: return c - d; } diff --git a/src/var.h b/src/var.h index aa7575a..2aece9d 100644 --- a/src/var.h +++ b/src/var.h @@ -153,6 +153,21 @@ int unsetcmd(int, char **); void unsetvar(const char *); int varcmp(const char *, const char *); +static inline unsigned int hashval(const char *p) +{ + unsigned int hashval; + + hashval = ((unsigned char) *p) << 4; + while (*p) { + hashval += (unsigned char) *p++; + if (*p == '=') + break; + } + + return hashval; +} + + static inline int varequal(const char *a, const char *b) { return !varcmp(a, b); } -- 2.39.0