aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-05-27 11:32:55 +0800
committermaximilian attems <max@stro.at>2011-06-03 18:04:50 +0200
commit72ae21a738fd9b493d2b360869f3e69639bcce0e (patch)
treec333fdd0deb2de958f58ca2e572e0e30be2dfad7
parentb315f1cb18435f3f6d827af37a045cb6186f4ff2 (diff)
downloadklibc-72ae21a738fd9b493d2b360869f3e69639bcce0e.tar.gz
[klibc] [VAR] Fix poplocalvar on abnormal exit from function
The new localvar code broke the abnormal exit from functions and built-ins by not restoring the original localvar state. This patch fixes this by storing the previous localvar state so that we always unwind correctly in case of an abnormal exit. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: maximilian attems <max@stro.at>
-rw-r--r--usr/dash/eval.c5
-rw-r--r--usr/dash/var.c14
-rw-r--r--usr/dash/var.h5
3 files changed, 18 insertions, 6 deletions
diff --git a/usr/dash/eval.c b/usr/dash/eval.c
index 1c5d13e76da1c..9c18440745657 100644
--- a/usr/dash/eval.c
+++ b/usr/dash/eval.c
@@ -681,6 +681,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
evalcommand(union node *cmd, int flags)
#endif
{
+ struct localvar_list *localvar_stop;
struct stackmark smark;
union node *argp;
struct arglist arglist;
@@ -703,7 +704,7 @@ evalcommand(union node *cmd, int flags)
/* First expand the arguments. */
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
setstackmark(&smark);
- pushlocalvars();
+ localvar_stop = pushlocalvars();
back_exitstatus = 0;
cmdentry.cmdtype = CMDBUILTIN;
@@ -837,7 +838,6 @@ bail:
if (forkshell(jp, cmd, FORK_FG) != 0) {
exitstatus = waitforjob(jp);
INTON;
- poplocalvars(0);
break;
}
FORCEINTON;
@@ -878,6 +878,7 @@ raise:
out:
popredir(execcmd);
+ unwindlocalvars(localvar_stop);
if (lastarg)
/* dsl: I think this is intended to be used to support
* '_' in 'vi' command mode during line editing...
diff --git a/usr/dash/var.c b/usr/dash/var.c
index 40bd3fdce2c2e..f456fbdd14f54 100644
--- a/usr/dash/var.c
+++ b/usr/dash/var.c
@@ -144,8 +144,7 @@ INIT {
}
RESET {
- while (localvar_stack)
- poplocalvars(0);
+ unwindlocalvars(0);
}
#endif
@@ -570,7 +569,7 @@ poplocalvars(int keep)
/*
* Create a new localvar environment.
*/
-void pushlocalvars(void)
+struct localvar_list *pushlocalvars(void)
{
struct localvar_list *ll;
@@ -580,6 +579,15 @@ void pushlocalvars(void)
ll->next = localvar_stack;
localvar_stack = ll;
INTON;
+
+ return ll->next;
+}
+
+
+void unwindlocalvars(struct localvar_list *stop)
+{
+ while (localvar_stack != stop)
+ poplocalvars(0);
}
diff --git a/usr/dash/var.h b/usr/dash/var.h
index 363f3055cbe0f..097b2550184a1 100644
--- a/usr/dash/var.h
+++ b/usr/dash/var.h
@@ -69,6 +69,8 @@ struct localvar {
const char *text; /* saved text */
};
+struct localvar_list;
+
extern struct localvar *localvars;
extern struct var varinit[];
@@ -139,8 +141,9 @@ int showvars(const char *, int, int);
int exportcmd(int, char **);
int localcmd(int, char **);
void mklocal(char *);
-void pushlocalvars(void);
+struct localvar_list *pushlocalvars(void);
void poplocalvars(int);
+void unwindlocalvars(struct localvar_list *stop);
int unsetcmd(int, char **);
void unsetvar(const char *);
int varcmp(const char *, const char *);