shithub: libmujs

Download patch

ref: aba272ac959329476ce73bc7d69d14ad7779c754
parent: 2e196dd0fc7344c175c9bdca79388acdfa1c15a2
author: Tor Andersson <[email protected]>
date: Wed Sep 24 12:02:04 EDT 2014

Fix bug where some environment records were not marked by GC.

Environments when calling a function were saved in a local variable.
Therefore the garbage collector did not see them in its list of roots
to follow, resulting in environments being freed while still in use.

--- a/jsgc.c
+++ b/jsgc.c
@@ -120,6 +120,7 @@
 	int nenv = 0, nfun = 0, nobj = 0;
 	int genv = 0, gfun = 0, gobj = 0;
 	int mark;
+	int i;
 
 	mark = J->gcmark = J->gcmark == 1 ? 2 : 1;
 
@@ -129,6 +130,8 @@
 	jsG_markobject(J, mark, J->Boolean_prototype);
 	jsG_markobject(J, mark, J->Number_prototype);
 	jsG_markobject(J, mark, J->String_prototype);
+	jsG_markobject(J, mark, J->RegExp_prototype);
+	jsG_markobject(J, mark, J->Date_prototype);
 
 	jsG_markobject(J, mark, J->Error_prototype);
 	jsG_markobject(J, mark, J->EvalError_prototype);
@@ -142,7 +145,11 @@
 	jsG_markobject(J, mark, J->G);
 
 	jsG_markstack(J, mark);
+
 	jsG_markenvironment(J, mark, J->E);
+	jsG_markenvironment(J, mark, J->GE);
+	for (i = 0; i < J->envtop; ++i)
+		jsG_markenvironment(J, mark, J->envstack[i]);
 
 	prevnextenv = &J->gcenv;
 	for (env = J->gcenv; env; env = nextenv) {
--- a/jsi.h
+++ b/jsi.h
@@ -49,6 +49,7 @@
 /* Limits */
 
 #define JS_STACKSIZE 256	/* value stack size */
+#define JS_ENVLIMIT 64		/* environment stack size */
 #define JS_TRYLIMIT 64		/* exception stack size */
 #define JS_GCLIMIT 10000	/* run gc cycle every N allocations */
 
@@ -92,6 +93,7 @@
 {
 	jmp_buf buf;
 	js_Environment *E;
+	int envtop;
 	int top, bot;
 	short *pc;
 };
@@ -172,6 +174,10 @@
 	js_Environment *gcenv;
 	js_Function *gcfun;
 	js_Object *gcobj;
+
+	/* environments on the call stack but currently not in scope */
+	int envtop;
+	js_Environment *envstack[JS_ENVLIMIT];
 
 	/* exception stack */
 	int trylen;
--- a/jsrun.c
+++ b/jsrun.c
@@ -801,16 +801,26 @@
 
 /* Function calls */
 
+static void jsR_savescope(js_State *J, js_Environment *newE)
+{
+	if (J->envtop + 1 >= JS_ENVLIMIT)
+		js_stackoverflow(J);
+	J->envstack[J->envtop++] = J->E;
+	J->E = newE;
+}
+
+static void jsR_restorescope(js_State *J)
+{
+	J->E = J->envstack[--J->envtop];
+}
+
 static void jsR_calllwfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope)
 {
-	js_Environment *saveE;
 	js_Value v;
 	unsigned int i;
 
-	saveE = J->E;
+	jsR_savescope(J, scope);
 
-	J->E = scope;
-
 	if (n > F->numparams) {
 		js_pop(J, F->numparams - n);
 		n = F->numparams;
@@ -823,18 +833,17 @@
 	TOP = --BOT; /* clear stack */
 	js_pushvalue(J, v);
 
-	J->E = saveE;
+	jsR_restorescope(J);
 }
 
 static void jsR_callfunction(js_State *J, unsigned int n, js_Function *F, js_Environment *scope)
 {
-	js_Environment *saveE;
 	js_Value v;
 	unsigned int i;
 
-	saveE = J->E;
+	scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
 
-	J->E = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
+	jsR_savescope(J, scope);
 
 	if (F->arguments) {
 		js_newobject(J);
@@ -866,7 +875,7 @@
 	TOP = --BOT; /* clear stack */
 	js_pushvalue(J, v);
 
-	J->E = saveE;
+	jsR_restorescope(J);
 }
 
 static void jsR_callscript(js_State *J, unsigned int n, js_Function *F)
@@ -991,6 +1000,7 @@
 	if (J->trylen == JS_TRYLIMIT)
 		js_error(J, "try: exception stack overflow");
 	J->trybuf[J->trylen].E = J->E;
+	J->trybuf[J->trylen].envtop = J->envtop;
 	J->trybuf[J->trylen].top = J->top;
 	J->trybuf[J->trylen].bot = J->bot;
 	J->trybuf[J->trylen].pc = pc;
@@ -1002,6 +1012,7 @@
 		js_Value v = js_tovalue(J, -1);
 		--J->trylen;
 		J->E = J->trybuf[J->trylen].E;
+		J->envtop = J->trybuf[J->trylen].envtop;
 		J->top = J->trybuf[J->trylen].top;
 		J->bot = J->trybuf[J->trylen].bot;
 		js_pushvalue(J, v);