From 4b2cc62e266cb39d0728dc473435fdf6ab4e8e89 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikic@php.net>
Date: Tue, 13 Dec 2016 17:54:30 +0100
Subject: [PATCH] More fixes for bug #73089

Insert a lot more DEREFs. Some may not be necessary, but better
safe than sorry. I'm thinking the soap_hash_str_find_deref function
should become part of the zend_hash API -- we need this in many
places.
---
 ext/soap/php_encoding.c | 50 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 17 deletions(-)

diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
index 7947b4cea39b..245f1b3e6109 100644
--- a/ext/soap/php_encoding.c
+++ b/ext/soap/php_encoding.c
@@ -283,6 +283,16 @@ static encodePtr find_encoder_by_type_name(sdlPtr sdl, const char *type)
 	return NULL;
 }
 
+static zval *soap_hash_str_find_deref(HashTable *ht, const char *str, size_t len) {
+	zval *zv = zend_hash_str_find(ht, str, len);
+	if (!zv) {
+		return NULL;
+	}
+
+	ZVAL_DEREF(zv);
+	return zv;
+}
+
 static zend_bool soap_check_zval_ref(zval *data, xmlNodePtr node) {
 	xmlNodePtr node_ptr;
 
@@ -380,6 +390,10 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml
 	xmlNodePtr node = NULL;
 	int add_type = 0;
 
+	if (data) {
+		ZVAL_DEREF(data);
+	}
+
 	/* Special handling of class SoapVar */
 	if (data &&
 	    Z_TYPE_P(data) == IS_OBJECT &&
@@ -388,14 +402,14 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml
 		encodePtr enc = NULL;
 		HashTable *ht = Z_OBJPROP_P(data);
 
-		if ((ztype = zend_hash_str_find(ht, "enc_type", sizeof("enc_type")-1)) == NULL ||
+		if ((ztype = soap_hash_str_find_deref(ht, "enc_type", sizeof("enc_type")-1)) == NULL ||
 		    Z_TYPE_P(ztype) != IS_LONG) {
 			soap_error0(E_ERROR, "Encoding: SoapVar has no 'enc_type' property");
 		}
 
-		if ((zstype = zend_hash_str_find(ht, "enc_stype", sizeof("enc_stype")-1)) != NULL &&
+		if ((zstype = soap_hash_str_find_deref(ht, "enc_stype", sizeof("enc_stype")-1)) != NULL &&
 		    Z_TYPE_P(zstype) == IS_STRING) {
-			if ((zns = zend_hash_str_find(ht, "enc_ns", sizeof("enc_ns")-1)) != NULL &&
+			if ((zns = soap_hash_str_find_deref(ht, "enc_ns", sizeof("enc_ns")-1)) != NULL &&
 			    Z_TYPE_P(zns) == IS_STRING) {
 				enc = get_encoder(SOAP_GLOBAL(sdl), Z_STRVAL_P(zns), Z_STRVAL_P(zstype));
 			} else {
@@ -422,13 +436,13 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml
 			enc = encode;
 		}
 
-		zdata = zend_hash_str_find(ht, "enc_value", sizeof("enc_value")-1);
+		zdata = soap_hash_str_find_deref(ht, "enc_value", sizeof("enc_value")-1);
 		node = master_to_xml(enc, zdata, style, parent);
 
 		if (style == SOAP_ENCODED || (SOAP_GLOBAL(sdl) && encode != enc)) {
-			if ((zstype = zend_hash_str_find(ht, "enc_stype", sizeof("enc_stype")-1)) != NULL &&
+			if ((zstype = soap_hash_str_find_deref(ht, "enc_stype", sizeof("enc_stype")-1)) != NULL &&
 			    Z_TYPE_P(zstype) == IS_STRING) {
-				if ((zns = zend_hash_str_find(ht, "enc_ns", sizeof("enc_ns")-1)) != NULL &&
+				if ((zns = soap_hash_str_find_deref(ht, "enc_ns", sizeof("enc_ns")-1)) != NULL &&
 				    Z_TYPE_P(zns) == IS_STRING) {
 					set_ns_and_type_ex(node, Z_STRVAL_P(zns), Z_STRVAL_P(zstype));
 				} else {
@@ -437,11 +451,11 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml
 			}
 		}
 
-		if ((zname = zend_hash_str_find(ht, "enc_name", sizeof("enc_name")-1)) != NULL &&
+		if ((zname = soap_hash_str_find_deref(ht, "enc_name", sizeof("enc_name")-1)) != NULL &&
 		    Z_TYPE_P(zname) == IS_STRING) {
 			xmlNodeSetName(node, BAD_CAST(Z_STRVAL_P(zname)));
 		}
-		if ((znamens = zend_hash_str_find(ht, "enc_namens", sizeof("enc_namens")-1)) != NULL &&
+		if ((znamens = soap_hash_str_find_deref(ht, "enc_namens", sizeof("enc_namens")-1)) != NULL &&
 		    Z_TYPE_P(znamens) == IS_STRING) {
 			xmlNsPtr nsp = encode_add_ns(node, Z_STRVAL_P(znamens));
 			xmlSetNs(node, nsp);
@@ -455,6 +469,7 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml
 			zend_string *type_name;
 
 			ZEND_HASH_FOREACH_STR_KEY_VAL(SOAP_GLOBAL(class_map), type_name, tmp) {
+				ZVAL_DEREF(tmp);
 				if (Z_TYPE_P(tmp) == IS_STRING &&
 				    ZSTR_LEN(ce->name) == Z_STRLEN_P(tmp) &&
 				    zend_binary_strncasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), Z_STRVAL_P(tmp), ZSTR_LEN(ce->name), ZSTR_LEN(ce->name)) == 0 &&
@@ -1193,6 +1208,7 @@ static zval* get_zval_property(zval* object, char* name, zval *rv)
 			if (property_info != ZEND_WRONG_PROPERTY_INFO && property_info &&
 			    zend_hash_exists(Z_OBJPROP_P(object), property_info->name)) {
 				zval_ptr_dtor(&member);
+				ZVAL_DEREF(data);
 				return data;
 			}
 			zval_ptr_dtor(&member);
@@ -1200,13 +1216,10 @@ static zval* get_zval_property(zval* object, char* name, zval *rv)
 		}
 		zval_ptr_dtor(&member);
 		EG(scope) = old_scope;
+		ZVAL_DEREF(data);
 		return data;
 	} else if (Z_TYPE_P(object) == IS_ARRAY) {
-		zval *data_ptr;
-
-		if ((data_ptr = zend_hash_str_find(Z_ARRVAL_P(object), name, strlen(name))) != NULL) {
-		  return data_ptr;
-		}
+		return soap_hash_str_find_deref(Z_ARRVAL_P(object), name, strlen(name));
 	}
 	return NULL;
 }
@@ -1421,7 +1434,7 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z
 		zval              *classname;
 		zend_class_entry  *tmp;
 
-		if ((classname = zend_hash_str_find(SOAP_GLOBAL(class_map), type->type_str, strlen(type->type_str))) != NULL &&
+		if ((classname = soap_hash_str_find_deref(SOAP_GLOBAL(class_map), type->type_str, strlen(type->type_str))) != NULL &&
 		    Z_TYPE_P(classname) == IS_STRING &&
 		    (tmp = zend_fetch_class(Z_STR_P(classname), ZEND_FETCH_CLASS_AUTO)) != NULL) {
 			ce = tmp;
@@ -1642,6 +1655,7 @@ static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, zval *
 					zval *val;
 
 					ZEND_HASH_FOREACH_VAL(ht, val) {
+						ZVAL_DEREF(val);
 						if (Z_TYPE_P(val) == IS_NULL && model->u.element->nillable) {
 							property = xmlNewNode(NULL, BAD_CAST("BOGUS"));
 							xmlAddChild(node, property);
@@ -1896,6 +1910,7 @@ static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNo
 
 				ZEND_HASH_FOREACH_VAL(prop, val) {
 					xmlNodePtr property;
+					ZVAL_DEREF(val);
 					if (Z_TYPE_P(val) == IS_NULL && array_el->nillable) {
 						property = xmlNewNode(NULL, BAD_CAST("BOGUS"));
 						xmlAddChild(xmlParam, property);
@@ -2327,6 +2342,7 @@ static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNod
 				    ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(el), el) {
 				    	break;
 				    } ZEND_HASH_FOREACH_END();
+					ZVAL_DEREF(el);
 					if (Z_TYPE_P(el) == IS_ARRAY) {
 						dims[i] = zend_hash_num_elements(Z_ARRVAL_P(el));
 					} else {
@@ -3520,20 +3536,20 @@ static encodePtr get_array_type(xmlNodePtr node, zval *array, smart_str *type)
 		    Z_OBJCE_P(tmp) == soap_var_class_entry) {
 			zval *ztype;
 
-			if ((ztype = zend_hash_str_find(Z_OBJPROP_P(tmp), "enc_type", sizeof("enc_type")-1)) == NULL ||
+			if ((ztype = soap_hash_str_find_deref(Z_OBJPROP_P(tmp), "enc_type", sizeof("enc_type")-1)) == NULL ||
 			    Z_TYPE_P(ztype) != IS_LONG) {
 				soap_error0(E_ERROR,  "Encoding: SoapVar has no 'enc_type' property");
 			}
 			cur_type = Z_LVAL_P(ztype);
 
-			if ((ztype = zend_hash_str_find(Z_OBJPROP_P(tmp), "enc_stype", sizeof("enc_stype")-1)) != NULL &&
+			if ((ztype = soap_hash_str_find_deref(Z_OBJPROP_P(tmp), "enc_stype", sizeof("enc_stype")-1)) != NULL &&
 			    Z_TYPE_P(ztype) == IS_STRING) {
 				cur_stype = Z_STRVAL_P(ztype);
 			} else {
 				cur_stype = NULL;
 			}
 
-			if ((ztype = zend_hash_str_find(Z_OBJPROP_P(tmp), "enc_ns", sizeof("enc_ns")-1)) != NULL &&
+			if ((ztype = soap_hash_str_find_deref(Z_OBJPROP_P(tmp), "enc_ns", sizeof("enc_ns")-1)) != NULL &&
 			    Z_TYPE_P(ztype) == IS_STRING) {
 				cur_ns = Z_STRVAL_P(ztype);
 			} else {
