shithub: libmujs

Download patch

ref: a9e6b4cd017e594964a56c2294875c4240b1ead8
parent: 051d504cfbe8f6034ba18df72858b62b1d8570b4
author: Tor Andersson <tor.andersson@artifex.com>
date: Sat Nov 1 09:01:05 EDT 2014

Fix bug in maintaining property enumeration list.

The tail pointer in the linked list head was mismanaged, leading
to using free memory when properties are inserted after deleting
a property such that the tail points to the deleted node.

--- a/jsproperty.c
+++ b/jsproperty.c
@@ -97,15 +97,17 @@
 	return *result = newproperty(J, name);
 }
 
-static void freeproperty(js_State *J, js_Property *node)
+static void freeproperty(js_State *J, js_Object *obj, js_Property *node)
 {
 	if (node->next)
 		node->next->prevp = node->prevp;
+	else
+		obj->tailp = node->prevp;
 	*node->prevp = node->next;
 	js_free(J, node);
 }
 
-static js_Property *delete(js_State *J, js_Property *node, const char *name)
+static js_Property *delete(js_State *J, js_Object *obj, js_Property *node, const char *name)
 {
 	js_Property *temp, *succ;
 
@@ -112,18 +114,18 @@
 	if (node != &sentinel) {
 		int c = strcmp(name, node->name);
 		if (c < 0) {
-			node->left = delete(J, node->left, name);
+			node->left = delete(J, obj, node->left, name);
 		} else if (c > 0) {
-			node->right = delete(J, node->right, name);
+			node->right = delete(J, obj, node->right, name);
 		} else {
 			if (node->left == &sentinel) {
 				temp = node;
 				node = node->right;
-				freeproperty(J, temp);
+				freeproperty(J, obj, temp);
 			} else if (node->right == &sentinel) {
 				temp = node;
 				node = node->left;
-				freeproperty(J, temp);
+				freeproperty(J, obj, temp);
 			} else {
 				succ = node->right;
 				while (succ->left != &sentinel)
@@ -131,7 +133,7 @@
 				node->name = succ->name;
 				node->atts = succ->atts;
 				node->value = succ->value;
-				node->right = delete(J, node->right, succ->name);
+				node->right = delete(J, obj, node->right, succ->name);
 			}
 		}
 
@@ -162,6 +164,8 @@
 
 	obj->type = type;
 	obj->properties = &sentinel;
+	obj->head = NULL;
+	obj->tailp = &obj->head;
 	obj->prototype = prototype;
 	obj->extensible = 1;
 	return obj;
@@ -205,14 +209,9 @@
 
 	obj->properties = insert(J, obj->properties, name, &result);
 	if (!result->prevp) {
-		if (!obj->head) {
-			result->prevp = &obj->head;
-			obj->tail = obj->head = result;
-		} else {
-			result->prevp = &obj->tail->next;
-			obj->tail->next = result;
-			obj->tail = result;
-		}
+		result->prevp = obj->tailp;
+		*obj->tailp = result;
+		obj->tailp = &result->next;
 	}
 	return result;
 }
@@ -219,7 +218,7 @@
 
 void jsV_delproperty(js_State *J, js_Object *obj, const char *name)
 {
-	obj->properties = delete(J, obj->properties, name);
+	obj->properties = delete(J, obj, obj->properties, name);
 }
 
 /* Flatten hierarchy of enumerable properties into an iterator object */
--- a/jsvalue.h
+++ b/jsvalue.h
@@ -62,7 +62,7 @@
 	enum js_Class type;
 	int extensible;
 	js_Property *properties;
-	js_Property *head, *tail; /* for enumeration */
+	js_Property *head, **tailp; /* for enumeration */
 	js_Object *prototype;
 	union {
 		int boolean;
@@ -101,7 +101,7 @@
 {
 	const char *name;
 	js_Property *left, *right;
-	js_Property **prevp, *next; /* for enumeration */
+	js_Property *next, **prevp; /* for enumeration */
 	int level;
 	int atts;
 	js_Value value;