shithub: libmujs

Download patch

ref: 822061539a0d9a028ee019ead51f75556640c32e
parent: a9d88e54afe2e6bfa1a284770604fdd6009f2fdd
author: Tor Andersson <tor.andersson@artifex.com>
date: Fri Jul 23 08:43:15 EDT 2021

Fix leaks if js_try runs out of exception stack space.

Since js_try can throw to its surrounding exception scope if it runs out
of space in the exception stack, we need to make sure to allocate
resources guarded by the try inside the try not outside it.

--- a/jsarray.c
+++ b/jsarray.c
@@ -289,7 +289,7 @@
 
 static void Ap_sort(js_State *J)
 {
-	struct sortslot *array = NULL;
+	struct sortslot * volatile array = NULL;
 	int i, n, len;
 
 	len = js_getlength(J, 0);
@@ -301,8 +301,6 @@
 	if (len >= INT_MAX / (int)sizeof(*array))
 		js_rangeerror(J, "array is too large to sort");
 
-	array = js_malloc(J, len * sizeof *array);
-
 	/* Holding objects where the GC cannot see them is illegal, but if we
 	 * don't allow the GC to run we can use qsort() on a temporary array of
 	 * js_Values for fast sorting.
@@ -314,6 +312,8 @@
 		js_free(J, array);
 		js_throw(J);
 	}
+
+	array = js_malloc(J, len * sizeof *array);
 
 	n = 0;
 	for (i = 0; i < len; ++i) {
--- a/jsregexp.c
+++ b/jsregexp.c
@@ -193,10 +193,15 @@
 static void Rp_toString(js_State *J)
 {
 	js_Regexp *re;
-	char *out;
+	char * volatile out = NULL;
 
 	re = js_toregexp(J, 0);
 
+	if (js_try(J)) {
+		js_free(J, out);
+		js_throw(J);
+	}
+
 	out = js_malloc(J, strlen(re->source) + 6); /* extra space for //gim */
 	strcpy(out, "/");
 	strcat(out, re->source);
@@ -205,10 +210,6 @@
 	if (re->flags & JS_REGEXP_I) strcat(out, "i");
 	if (re->flags & JS_REGEXP_M) strcat(out, "m");
 
-	if (js_try(J)) {
-		js_free(J, out);
-		js_throw(J);
-	}
 	js_pop(J, 0);
 	js_pushstring(J, out);
 	js_endtry(J);
--- a/jsstring.c
+++ b/jsstring.c
@@ -116,7 +116,7 @@
 {
 	int i, top = js_gettop(J);
 	int n;
-	char * volatile out;
+	char * volatile out = NULL;
 	const char *s;
 
 	if (top == 1)
@@ -124,8 +124,6 @@
 
 	s = checkstring(J, 0);
 	n = strlen(s);
-	out = js_malloc(J, n + 1);
-	strcpy(out, s);
 
 	if (js_try(J)) {
 		js_free(J, out);
@@ -132,6 +130,9 @@
 		js_throw(J);
 	}
 
+	out = js_malloc(J, n + 1);
+	strcpy(out, s);
+
 	for (i = 1; i < top; ++i) {
 		s = js_tostring(J, i);
 		n += strlen(s);
@@ -236,11 +237,17 @@
 
 static void Sp_toLowerCase(js_State *J)
 {
-	const char *src = checkstring(J, 0);
-	char *dst = js_malloc(J, UTFmax * strlen(src) + 1);
-	const char *s = src;
-	char *d = dst;
+	const char *s = checkstring(J, 0);
+	char * volatile dst = NULL;
+	char *d;
 	Rune rune;
+
+	if (js_try(J)) {
+		js_free(J, dst);
+		js_throw(J);
+	}
+
+	d = dst = js_malloc(J, UTFmax * strlen(s) + 1);
 	while (*s) {
 		s += chartorune(&rune, s);
 		rune = tolowerrune(rune);
@@ -247,10 +254,7 @@
 		d += runetochar(d, &rune);
 	}
 	*d = 0;
-	if (js_try(J)) {
-		js_free(J, dst);
-		js_throw(J);
-	}
+
 	js_pushstring(J, dst);
 	js_endtry(J);
 	js_free(J, dst);
@@ -258,11 +262,17 @@
 
 static void Sp_toUpperCase(js_State *J)
 {
-	const char *src = checkstring(J, 0);
-	char *dst = js_malloc(J, UTFmax * strlen(src) + 1);
-	const char *s = src;
-	char *d = dst;
+	const char *s = checkstring(J, 0);
+	char * volatile dst = NULL;
+	char *d;
 	Rune rune;
+
+	if (js_try(J)) {
+		js_free(J, dst);
+		js_throw(J);
+	}
+
+	d = dst = js_malloc(J, UTFmax * strlen(s) + 1);
 	while (*s) {
 		s += chartorune(&rune, s);
 		rune = toupperrune(rune);
@@ -269,10 +279,7 @@
 		d += runetochar(d, &rune);
 	}
 	*d = 0;
-	if (js_try(J)) {
-		js_free(J, dst);
-		js_throw(J);
-	}
+
 	js_pushstring(J, dst);
 	js_endtry(J);
 	js_free(J, dst);
@@ -299,23 +306,24 @@
 static void S_fromCharCode(js_State *J)
 {
 	int i, top = js_gettop(J);
+	char * volatile s = NULL;
+	char *p;
 	Rune c;
-	char *s, *p;
 
-	s = p = js_malloc(J, (top-1) * UTFmax + 1);
-
 	if (js_try(J)) {
 		js_free(J, s);
 		js_throw(J);
 	}
 
+	s = p = js_malloc(J, (top-1) * UTFmax + 1);
+
 	for (i = 1; i < top; ++i) {
 		c = js_touint32(J, i);
 		p += runetochar(p, &c);
 	}
 	*p = 0;
-	js_pushstring(J, s);
 
+	js_pushstring(J, s);
 	js_endtry(J);
 	js_free(J, s);
 }
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -562,14 +562,15 @@
 	if (js_isstring(J, -2) || js_isstring(J, -1)) {
 		const char *sa = js_tostring(J, -2);
 		const char *sb = js_tostring(J, -1);
+		char * volatile sab = NULL;
 		/* TODO: create js_String directly */
-		char *sab = js_malloc(J, strlen(sa) + strlen(sb) + 1);
-		strcpy(sab, sa);
-		strcat(sab, sb);
 		if (js_try(J)) {
 			js_free(J, sab);
 			js_throw(J);
 		}
+		sab = js_malloc(J, strlen(sa) + strlen(sb) + 1);
+		strcpy(sab, sa);
+		strcat(sab, sb);
 		js_pop(J, 2);
 		js_pushstring(J, sab);
 		js_endtry(J);
--- a/pp.c
+++ b/pp.c
@@ -28,10 +28,16 @@
 
 void js_ppfile(js_State *J, const char *filename, int minify)
 {
-	FILE *f;
-	char *s;
+	FILE * volatile f = NULL;
+	char * volatile s = NULL;
 	int n, t;
 
+	if (js_try(J)) {
+		js_free(J, s);
+		fclose(f);
+		js_throw(J);
+	}
+
 	f = fopen(filename, "rb");
 	if (!f) {
 		js_error(J, "cannot open file: '%s'", filename);
@@ -68,17 +74,11 @@
 
 	s[n] = 0; /* zero-terminate string containing file data */
 
-	if (js_try(J)) {
-		js_free(J, s);
-		fclose(f);
-		js_throw(J);
-	}
-
 	js_ppstring(J, filename, s, minify);
 
+	js_endtry(J);
 	js_free(J, s);
 	fclose(f);
-	js_endtry(J);
 }
 
 int