summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2009-08-23 21:09:46 +0000
committerjilles <jilles@FreeBSD.org>2009-08-23 21:09:46 +0000
commit4a8e08a1103988b9e44d3ae9584cd654796998b1 (patch)
tree907e1a91ca6ca57f1742a6081e71d2fcd1f405a4 /bin
parentf0ee7a159b9f49405e827b40fed36a844334c3ac (diff)
downloadFreeBSD-src-4a8e08a1103988b9e44d3ae9584cd654796998b1.zip
FreeBSD-src-4a8e08a1103988b9e44d3ae9584cd654796998b1.tar.gz
sh: Fix crash when undefining or redefining a currently executing function.
Add a reference count to function definitions. Memory may leak if multiple SIGINTs arrive in interactive mode, this will be fixed later by changing SIGINT handling. PR: bin/137640
Diffstat (limited to 'bin')
-rw-r--r--bin/sh/eval.c7
-rw-r--r--bin/sh/exec.c8
-rw-r--r--bin/sh/exec.h3
-rw-r--r--bin/sh/mknodes.c9
-rw-r--r--bin/sh/nodes.c.pat35
5 files changed, 44 insertions, 18 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 39e1660..8dfa7dd 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -785,6 +785,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
INTOFF;
savelocalvars = localvars;
localvars = NULL;
+ reffunc(cmdentry.u.func);
INTON;
savehandler = handler;
if (setjmp(jmploc.loc)) {
@@ -794,6 +795,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
freeparam(&shellparam);
shellparam = saveparam;
}
+ unreffunc(cmdentry.u.func);
poplocalvars();
localvars = savelocalvars;
handler = savehandler;
@@ -805,11 +807,12 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
funcnest++;
exitstatus = oexitstatus;
if (flags & EV_TESTED)
- evaltree(cmdentry.u.func, EV_TESTED);
+ evaltree(&cmdentry.u.func->n, EV_TESTED);
else
- evaltree(cmdentry.u.func, 0);
+ evaltree(&cmdentry.u.func->n, 0);
funcnest--;
INTOFF;
+ unreffunc(cmdentry.u.func);
poplocalvars();
localvars = savelocalvars;
freeparam(&shellparam);
diff --git a/bin/sh/exec.c b/bin/sh/exec.c
index 3dc8895..639a23c 100644
--- a/bin/sh/exec.c
+++ b/bin/sh/exec.c
@@ -286,7 +286,7 @@ printentry(struct tblentry *cmdp, int verbose)
out1fmt("function %s", cmdp->cmdname);
if (verbose) {
INTOFF;
- name = commandtext(cmdp->param.func);
+ name = commandtext(&cmdp->param.func->n);
out1c(' ');
out1str(name);
ckfree(name);
@@ -583,7 +583,7 @@ deletefuncs(void)
while ((cmdp = *pp) != NULL) {
if (cmdp->cmdtype == CMDFUNCTION) {
*pp = cmdp->next;
- freefunc(cmdp->param.func);
+ unreffunc(cmdp->param.func);
ckfree(cmdp);
} else {
pp = &cmdp->next;
@@ -670,7 +670,7 @@ addcmdentry(char *name, struct cmdentry *entry)
INTOFF;
cmdp = cmdlookup(name, 1);
if (cmdp->cmdtype == CMDFUNCTION) {
- freefunc(cmdp->param.func);
+ unreffunc(cmdp->param.func);
}
cmdp->cmdtype = entry->cmdtype;
cmdp->param = entry->u;
@@ -705,7 +705,7 @@ unsetfunc(char *name)
struct tblentry *cmdp;
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
- freefunc(cmdp->param.func);
+ unreffunc(cmdp->param.func);
delete_cmd_entry();
return (0);
}
diff --git a/bin/sh/exec.h b/bin/sh/exec.h
index 9f81a6a..e3b9acd 100644
--- a/bin/sh/exec.h
+++ b/bin/sh/exec.h
@@ -46,11 +46,12 @@ enum {
TYPECMD_TYPE /* type */
};
+union node;
struct cmdentry {
int cmdtype;
union param {
int index;
- union node *func;
+ struct funcdef *func;
} u;
int special;
};
diff --git a/bin/sh/mknodes.c b/bin/sh/mknodes.c
index f0afca6..904f9f4 100644
--- a/bin/sh/mknodes.c
+++ b/bin/sh/mknodes.c
@@ -248,8 +248,13 @@ output(char *file)
fputs("\tstruct nodelist *next;\n", hfile);
fputs("\tunion node *n;\n", hfile);
fputs("};\n\n\n", hfile);
- fputs("union node *copyfunc(union node *);\n", hfile);
- fputs("void freefunc(union node *);\n", hfile);
+ fputs("struct funcdef {\n", hfile);
+ fputs("\tunsigned int refcount;\n", hfile);
+ fputs("\tunion node n;\n", hfile);
+ fputs("};\n\n\n", hfile);
+ fputs("struct funcdef *copyfunc(union node *);\n", hfile);
+ fputs("void reffunc(struct funcdef *);\n", hfile);
+ fputs("void unreffunc(struct funcdef *);\n", hfile);
fputs(writer, cfile);
while (fgets(line, sizeof line, patfile) != NULL) {
diff --git a/bin/sh/nodes.c.pat b/bin/sh/nodes.c.pat
index 10dab26..b6a8559 100644
--- a/bin/sh/nodes.c.pat
+++ b/bin/sh/nodes.c.pat
@@ -35,6 +35,7 @@
#include <sys/param.h>
#include <stdlib.h>
+#include <stddef.h>
/*
* Routine for dealing with parsed shell commands.
*/
@@ -65,17 +66,22 @@ STATIC char *nodesavestr(char *);
* Make a copy of a parse tree.
*/
-union node *
+struct funcdef *
copyfunc(union node *n)
{
+ struct funcdef *fn;
+
if (n == NULL)
return NULL;
- funcblocksize = 0;
+ funcblocksize = offsetof(struct funcdef, n);
funcstringsize = 0;
calcsize(n);
- funcblock = ckmalloc(funcblocksize + funcstringsize);
- funcstring = (char *)funcblock + funcblocksize;
- return copynode(n);
+ fn = ckmalloc(funcblocksize + funcstringsize);
+ fn->refcount = 1;
+ funcblock = (char *)fn + offsetof(struct funcdef, n);
+ funcstring = (char *)fn + funcblocksize;
+ copynode(n);
+ return fn;
}
@@ -144,14 +150,25 @@ nodesavestr(char *s)
}
+void
+reffunc(struct funcdef *fn)
+{
+ fn->refcount++;
+}
+
/*
- * Free a parse tree.
+ * Decrement the reference count of a function definition, freeing it
+ * if it falls to 0.
*/
void
-freefunc(union node *n)
+unreffunc(struct funcdef *fn)
{
- if (n)
- ckfree(n);
+ if (fn) {
+ fn->refcount--;
+ if (fn->refcount > 0)
+ return;
+ ckfree(fn);
+ }
}
OpenPOWER on IntegriCloud