aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-26 20:06:48 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-26 20:33:51 +0200
commitd04fc712e30b681117afaad490fec2a747b390c6 (patch)
tree6b60ab1de6c02dcb1d85bfd49923443a0a25da7c
parent85241c7b0b4558f405f7e633ad62520299b8396d (diff)
downloadbusybox-w32-d04fc712e30b681117afaad490fec2a747b390c6.tar.gz
busybox-w32-d04fc712e30b681117afaad490fec2a747b390c6.tar.bz2
busybox-w32-d04fc712e30b681117afaad490fec2a747b390c6.zip
ash: [VAR] Fix loss of variables when hash collides
Upstream commit: Date: Tue, 6 Jul 2010 17:40:53 +0800 [VAR] Fix loss of variables when hash collides Brian Koropoff reported that the new var patches broke the following script: #!/bin/dash GDM_LANG="bar" OPTION="foo" unset GDM_LANG # OPTION has mysteriously become unset echo "$OPTION" He correctly diagnosed this as a result of removing all variables in the hash chain preceding the one that should be removed in setvareq. He also provided a patch to fix this. This patch is based on his but without keeping the original vpp. As a result, we now store new variables at the end of the hash chain instead of the beginning. To make this work, setvareq/setvar now returns the vp pointer modified. In case they're used to unset a variable the pointer returned is undefined. This is because mklocal needs it and used to get it by assuming that the new variable always appear at the beginning of the chain. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 3604af4fc..5bb59355c 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2237,14 +2237,15 @@ bltinlookup(const char *name)
2237 * will go away. 2237 * will go away.
2238 * Called with interrupts off. 2238 * Called with interrupts off.
2239 */ 2239 */
2240static void 2240static struct var *
2241setvareq(char *s, int flags) 2241setvareq(char *s, int flags)
2242{ 2242{
2243 struct var *vp, **vpp; 2243 struct var *vp, **vpp;
2244 2244
2245 vpp = hashvar(s); 2245 vpp = hashvar(s);
2246 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 2246 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2247 vp = *findvar(vpp, s); 2247 vpp = findvar(vpp, s);
2248 vp = *vpp;
2248 if (vp) { 2249 if (vp) {
2249 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) { 2250 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2250 const char *n; 2251 const char *n;
@@ -2257,7 +2258,7 @@ setvareq(char *s, int flags)
2257 } 2258 }
2258 2259
2259 if (flags & VNOSET) 2260 if (flags & VNOSET)
2260 return; 2261 goto out;
2261 2262
2262 if (vp->var_func && !(flags & VNOFUNC)) 2263 if (vp->var_func && !(flags & VNOFUNC))
2263 vp->var_func(var_end(s)); 2264 vp->var_func(var_end(s));
@@ -2271,14 +2272,14 @@ setvareq(char *s, int flags)
2271 out_free: 2272 out_free:
2272 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE) 2273 if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
2273 free(s); 2274 free(s);
2274 return; 2275 goto out;
2275 } 2276 }
2276 2277
2277 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 2278 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2278 } else { 2279 } else {
2279 /* variable s is not found */ 2280 /* variable s is not found */
2280 if (flags & VNOSET) 2281 if (flags & VNOSET)
2281 return; 2282 goto out;
2282 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET) 2283 if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
2283 goto out_free; 2284 goto out_free;
2284 vp = ckzalloc(sizeof(*vp)); 2285 vp = ckzalloc(sizeof(*vp));
@@ -2290,13 +2291,16 @@ setvareq(char *s, int flags)
2290 s = ckstrdup(s); 2291 s = ckstrdup(s);
2291 vp->var_text = s; 2292 vp->var_text = s;
2292 vp->flags = flags; 2293 vp->flags = flags;
2294
2295 out:
2296 return vp;
2293} 2297}
2294 2298
2295/* 2299/*
2296 * Set the value of a variable. The flags argument is ored with the 2300 * Set the value of a variable. The flags argument is ored with the
2297 * flags of the variable. If val is NULL, the variable is unset. 2301 * flags of the variable. If val is NULL, the variable is unset.
2298 */ 2302 */
2299static void 2303static struct var *
2300setvar(const char *name, const char *val, int flags) 2304setvar(const char *name, const char *val, int flags)
2301{ 2305{
2302 const char *q; 2306 const char *q;
@@ -2304,6 +2308,7 @@ setvar(const char *name, const char *val, int flags)
2304 char *nameeq; 2308 char *nameeq;
2305 size_t namelen; 2309 size_t namelen;
2306 size_t vallen; 2310 size_t vallen;
2311 struct var *vp;
2307 2312
2308 q = endofname(name); 2313 q = endofname(name);
2309 p = strchrnul(q, '='); 2314 p = strchrnul(q, '=');
@@ -2325,8 +2330,10 @@ setvar(const char *name, const char *val, int flags)
2325 p = mempcpy(p, val, vallen); 2330 p = mempcpy(p, val, vallen);
2326 } 2331 }
2327 *p = '\0'; 2332 *p = '\0';
2328 setvareq(nameeq, flags | VNOSAVE); 2333 vp = setvareq(nameeq, flags | VNOSAVE);
2329 INT_ON; 2334 INT_ON;
2335
2336 return vp;
2330} 2337}
2331 2338
2332static void FAST_FUNC 2339static void FAST_FUNC
@@ -9336,10 +9343,9 @@ mklocal(char *name)
9336 if (vp == NULL) { 9343 if (vp == NULL) {
9337 /* variable did not exist yet */ 9344 /* variable did not exist yet */
9338 if (eq) 9345 if (eq)
9339 setvareq(name, VSTRFIXED); 9346 vp = setvareq(name, VSTRFIXED);
9340 else 9347 else
9341 setvar(name, NULL, VSTRFIXED); 9348 vp = setvar(name, NULL, VSTRFIXED);
9342 vp = *vpp; /* the new variable */
9343 lvp->flags = VUNSET; 9349 lvp->flags = VUNSET;
9344 } else { 9350 } else {
9345 lvp->text = vp->var_text; 9351 lvp->text = vp->var_text;