svn commit: r200279 - in stable/7: bin/sh
tools/regression/bin/sh/execution
Jilles Tjoelker
jilles at FreeBSD.org
Tue Dec 8 22:37:08 UTC 2009
Author: jilles
Date: Tue Dec 8 22:37:07 2009
New Revision: 200279
URL: http://svn.freebsd.org/changeset/base/200279
Log:
MFC r196483,r196634:
sh: Fix crash when undefining or redefining a currently executing function
Add a reference count to function definitions.
Memory may leak if a SIGINT arrives in interactive mode at exactly the wrong
time.
PR: bin/137640
Added:
stable/7/tools/regression/bin/sh/execution/
stable/7/tools/regression/bin/sh/execution/func1.0
- copied unchanged from r196483, head/tools/regression/bin/sh/execution/func1.0
stable/7/tools/regression/bin/sh/execution/func2.0
- copied unchanged from r196634, head/tools/regression/bin/sh/execution/func2.0
Modified:
stable/7/bin/sh/eval.c
stable/7/bin/sh/exec.c
stable/7/bin/sh/exec.h
stable/7/bin/sh/mknodes.c
stable/7/bin/sh/nodes.c.pat
Directory Properties:
stable/7/bin/sh/ (props changed)
stable/7/tools/regression/bin/sh/ (props changed)
Modified: stable/7/bin/sh/eval.c
==============================================================================
--- stable/7/bin/sh/eval.c Tue Dec 8 22:35:39 2009 (r200278)
+++ stable/7/bin/sh/eval.c Tue Dec 8 22:37:07 2009 (r200279)
@@ -773,6 +773,7 @@ evalcommand(union node *cmd, int flags,
INTOFF;
savelocalvars = localvars;
localvars = NULL;
+ reffunc(cmdentry.u.func);
INTON;
if (setjmp(jmploc.loc)) {
if (exception == EXSHELLPROC)
@@ -781,6 +782,7 @@ evalcommand(union node *cmd, int flags,
freeparam(&shellparam);
shellparam = saveparam;
}
+ unreffunc(cmdentry.u.func);
poplocalvars();
localvars = savelocalvars;
handler = savehandler;
@@ -792,11 +794,12 @@ evalcommand(union node *cmd, int flags,
mklocal(sp->text);
funcnest++;
if (flags & EV_TESTED)
- evaltree(cmdentry.u.func, EV_TESTED);
+ evaltree(getfuncnode(cmdentry.u.func), EV_TESTED);
else
- evaltree(cmdentry.u.func, 0);
+ evaltree(getfuncnode(cmdentry.u.func), 0);
funcnest--;
INTOFF;
+ unreffunc(cmdentry.u.func);
poplocalvars();
localvars = savelocalvars;
freeparam(&shellparam);
Modified: stable/7/bin/sh/exec.c
==============================================================================
--- stable/7/bin/sh/exec.c Tue Dec 8 22:35:39 2009 (r200278)
+++ stable/7/bin/sh/exec.c Tue Dec 8 22:37:07 2009 (r200279)
@@ -285,7 +285,7 @@ printentry(struct tblentry *cmdp, int ve
out1fmt("function %s", cmdp->cmdname);
if (verbose) {
INTOFF;
- name = commandtext(cmdp->param.func);
+ name = commandtext(getfuncnode(cmdp->param.func));
out1c(' ');
out1str(name);
ckfree(name);
@@ -582,7 +582,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;
@@ -669,7 +669,7 @@ addcmdentry(char *name, struct cmdentry
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;
@@ -704,7 +704,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);
}
Modified: stable/7/bin/sh/exec.h
==============================================================================
--- stable/7/bin/sh/exec.h Tue Dec 8 22:35:39 2009 (r200278)
+++ stable/7/bin/sh/exec.h Tue Dec 8 22:37:07 2009 (r200279)
@@ -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;
};
Modified: stable/7/bin/sh/mknodes.c
==============================================================================
--- stable/7/bin/sh/mknodes.c Tue Dec 8 22:35:39 2009 (r200278)
+++ stable/7/bin/sh/mknodes.c Tue Dec 8 22:37:07 2009 (r200279)
@@ -248,8 +248,11 @@ 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("struct funcdef *copyfunc(union node *);\n", hfile);
+ fputs("union node *getfuncnode(struct funcdef *);\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) {
Modified: stable/7/bin/sh/nodes.c.pat
==============================================================================
--- stable/7/bin/sh/nodes.c.pat Tue Dec 8 22:35:39 2009 (r200278)
+++ stable/7/bin/sh/nodes.c.pat Tue Dec 8 22:37:07 2009 (r200279)
@@ -35,6 +35,7 @@
#include <sys/param.h>
#include <stdlib.h>
+#include <stddef.h>
/*
* Routine for dealing with parsed shell commands.
*/
@@ -60,25 +61,40 @@ STATIC struct nodelist *copynodelist(str
STATIC char *nodesavestr(char *);
+struct funcdef {
+ unsigned int refcount;
+ union node n;
+};
/*
* 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;
}
+union node *
+getfuncnode(struct funcdef *fn)
+{
+ return fn == NULL ? NULL : &fn->n;
+}
+
STATIC void
calcsize(union node *n)
@@ -144,14 +160,26 @@ nodesavestr(char *s)
}
+void
+reffunc(struct funcdef *fn)
+{
+ if (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);
+ }
}
Copied: stable/7/tools/regression/bin/sh/execution/func1.0 (from r196483, head/tools/regression/bin/sh/execution/func1.0)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/7/tools/regression/bin/sh/execution/func1.0 Tue Dec 8 22:37:07 2009 (r200279, copy of r196483, head/tools/regression/bin/sh/execution/func1.0)
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+MALLOC_OPTIONS=J sh -c 'g() { g() { :; }; :; }; g' &&
+MALLOC_OPTIONS=J sh -c 'g() { unset -f g; :; }; g'
Copied: stable/7/tools/regression/bin/sh/execution/func2.0 (from r196634, head/tools/regression/bin/sh/execution/func2.0)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ stable/7/tools/regression/bin/sh/execution/func2.0 Tue Dec 8 22:37:07 2009 (r200279, copy of r196634, head/tools/regression/bin/sh/execution/func2.0)
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+f() { }
+f
+hash -v f >/dev/null
+f() { { }; }
+f
+hash -v f >/dev/null
+f() { { } }
+f
+hash -v f >/dev/null
More information about the svn-src-stable-7
mailing list