Skip to content

Commit 9f7d888

Browse files
committed
Fix #80332: Completely broken array access functionality with DOMNamedNodeMap
The problem is the usage of zval_get_long(). In particular, if the string is non-numeric the result of zval_get_long() will be 0 without giving an error or warning. This is misleading for users: users get the impression that they can use strings to access the map because it coincidentally works for the first item (which is at index 0). Of course, this fails with any other index which causes confusion and bugs. This patch adds proper support for using string offsets while accessing the map. It does so by detecting if it's a non-numeric string, and then using the getNamedItem() method instead of item(). I had to split up the array access implementation code for DOMNodeList and DOMNamedNodeMap first to be able to do this. Closes GH-11468.
1 parent f194cdf commit 9f7d888

File tree

8 files changed

+318
-107
lines changed

8 files changed

+318
-107
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ PHP NEWS
4040
issues). (nielsdos)
4141
. Fixed bug GH-11404 (DOMDocument::saveXML and friends omit xmlns=""
4242
declaration for null namespace). (nielsdos)
43+
. Fixed bug #80332 (Completely broken array access functionality with
44+
DOMNamedNodeMap). (nielsdos)
4345

4446
- Opcache:
4547
. Fix allocation loop in zend_shared_alloc_startup(). (nielsdos)

ext/dom/namednodemap.c

+63-59
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* Since:
3232
*/
3333

34-
static int get_namednodemap_length(dom_object *obj)
34+
int php_dom_get_namednodemap_length(dom_object *obj)
3535
{
3636
dom_nnodemap_object *objmap = (dom_nnodemap_object *) obj->ptr;
3737
if (!objmap) {
@@ -65,95 +65,74 @@ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-
6565
*/
6666
int dom_namednodemap_length_read(dom_object *obj, zval *retval)
6767
{
68-
ZVAL_LONG(retval, get_namednodemap_length(obj));
68+
ZVAL_LONG(retval, php_dom_get_namednodemap_length(obj));
6969
return SUCCESS;
7070
}
7171

7272
/* }}} */
7373

74-
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1074577549
75-
Since:
76-
*/
77-
PHP_METHOD(DOMNamedNodeMap, getNamedItem)
74+
xmlNodePtr php_dom_named_node_map_get_named_item(dom_nnodemap_object *objmap, const char *named, bool may_transform)
7875
{
79-
zval *id;
80-
int ret;
81-
size_t namedlen=0;
82-
dom_object *intern;
8376
xmlNodePtr itemnode = NULL;
84-
char *named;
85-
86-
dom_nnodemap_object *objmap;
87-
xmlNodePtr nodep;
88-
xmlNotation *notep = NULL;
89-
90-
id = ZEND_THIS;
91-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &named, &namedlen) == FAILURE) {
92-
RETURN_THROWS();
93-
}
94-
95-
intern = Z_DOMOBJ_P(id);
96-
97-
objmap = (dom_nnodemap_object *)intern->ptr;
98-
9977
if (objmap != NULL) {
10078
if ((objmap->nodetype == XML_NOTATION_NODE) ||
10179
objmap->nodetype == XML_ENTITY_NODE) {
10280
if (objmap->ht) {
10381
if (objmap->nodetype == XML_ENTITY_NODE) {
104-
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, (xmlChar *) named);
82+
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, (const xmlChar *) named);
10583
} else {
106-
notep = (xmlNotation *)xmlHashLookup(objmap->ht, (xmlChar *) named);
84+
xmlNotationPtr notep = xmlHashLookup(objmap->ht, (const xmlChar *) named);
10785
if (notep) {
108-
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
86+
if (may_transform) {
87+
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
88+
} else {
89+
itemnode = (xmlNodePtr) notep;
90+
}
10991
}
11092
}
11193
}
11294
} else {
113-
nodep = dom_object_get_node(objmap->baseobj);
95+
xmlNodePtr nodep = dom_object_get_node(objmap->baseobj);
11496
if (nodep) {
115-
itemnode = (xmlNodePtr)xmlHasProp(nodep, (xmlChar *) named);
97+
itemnode = (xmlNodePtr)xmlHasProp(nodep, (const xmlChar *) named);
11698
}
11799
}
118100
}
101+
return itemnode;
102+
}
119103

104+
void php_dom_named_node_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const char *named, zval *return_value)
105+
{
106+
int ret;
107+
xmlNodePtr itemnode = php_dom_named_node_map_get_named_item(objmap, named, true);
120108
if (itemnode) {
121109
DOM_RET_OBJ(itemnode, &ret, objmap->baseobj);
122-
return;
123110
} else {
124-
RETVAL_NULL();
111+
RETURN_NULL();
125112
}
126113
}
127-
/* }}} end dom_namednodemap_get_named_item */
128114

129-
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-349467F9
115+
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-1074577549
130116
Since:
131117
*/
132-
PHP_METHOD(DOMNamedNodeMap, item)
118+
PHP_METHOD(DOMNamedNodeMap, getNamedItem)
133119
{
134-
zval *id;
135-
zend_long index;
136-
int ret;
137-
dom_object *intern;
138-
xmlNodePtr itemnode = NULL;
139-
140-
dom_nnodemap_object *objmap;
141-
xmlNodePtr nodep, curnode;
142-
int count;
120+
size_t namedlen;
121+
char *named;
143122

144-
id = ZEND_THIS;
145-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
146-
RETURN_THROWS();
147-
}
148-
if (index < 0 || ZEND_LONG_INT_OVFL(index)) {
149-
zend_argument_value_error(1, "must be between 0 and %d", INT_MAX);
123+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &named, &namedlen) == FAILURE) {
150124
RETURN_THROWS();
151125
}
152126

153-
intern = Z_DOMOBJ_P(id);
154-
155-
objmap = (dom_nnodemap_object *)intern->ptr;
127+
zval *id = ZEND_THIS;
128+
dom_nnodemap_object *objmap = Z_DOMOBJ_P(id)->ptr;
129+
php_dom_named_node_map_get_named_item_into_zval(objmap, named, return_value);
130+
}
131+
/* }}} end dom_namednodemap_get_named_item */
156132

133+
xmlNodePtr php_dom_named_node_map_get_item(dom_nnodemap_object *objmap, zend_long index)
134+
{
135+
xmlNodePtr itemnode = NULL;
157136
if (objmap != NULL) {
158137
if ((objmap->nodetype == XML_NOTATION_NODE) ||
159138
objmap->nodetype == XML_ENTITY_NODE) {
@@ -165,10 +144,10 @@ PHP_METHOD(DOMNamedNodeMap, item)
165144
}
166145
}
167146
} else {
168-
nodep = dom_object_get_node(objmap->baseobj);
147+
xmlNodePtr nodep = dom_object_get_node(objmap->baseobj);
169148
if (nodep) {
170-
curnode = (xmlNodePtr)nodep->properties;
171-
count = 0;
149+
xmlNodePtr curnode = (xmlNodePtr)nodep->properties;
150+
zend_long count = 0;
172151
while (count < index && curnode != NULL) {
173152
count++;
174153
curnode = (xmlNodePtr)curnode->next;
@@ -177,13 +156,38 @@ PHP_METHOD(DOMNamedNodeMap, item)
177156
}
178157
}
179158
}
159+
return itemnode;
160+
}
180161

162+
void php_dom_named_node_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value)
163+
{
164+
int ret;
165+
xmlNodePtr itemnode = php_dom_named_node_map_get_item(objmap, index);
181166
if (itemnode) {
182167
DOM_RET_OBJ(itemnode, &ret, objmap->baseobj);
183-
return;
168+
} else {
169+
RETURN_NULL();
170+
}
171+
}
172+
173+
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-349467F9
174+
Since:
175+
*/
176+
PHP_METHOD(DOMNamedNodeMap, item)
177+
{
178+
zend_long index;
179+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
180+
RETURN_THROWS();
181+
}
182+
if (index < 0 || ZEND_LONG_INT_OVFL(index)) {
183+
zend_argument_value_error(1, "must be between 0 and %d", INT_MAX);
184+
RETURN_THROWS();
184185
}
185186

186-
RETVAL_NULL();
187+
zval *id = ZEND_THIS;
188+
dom_object *intern = Z_DOMOBJ_P(id);
189+
dom_nnodemap_object *objmap = intern->ptr;
190+
php_dom_named_node_map_get_item_into_zval(objmap, index, return_value);
187191
}
188192
/* }}} end dom_namednodemap_item */
189193

@@ -254,7 +258,7 @@ PHP_METHOD(DOMNamedNodeMap, count)
254258
}
255259

256260
intern = Z_DOMOBJ_P(id);
257-
RETURN_LONG(get_namednodemap_length(intern));
261+
RETURN_LONG(php_dom_get_namednodemap_length(intern));
258262
}
259263
/* }}} end dom_namednodemap_count */
260264

ext/dom/nodelist.c

+23-27
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* Since:
3232
*/
3333

34-
static int get_nodelist_length(dom_object *obj)
34+
int php_dom_get_nodelist_length(dom_object *obj)
3535
{
3636
dom_nnodemap_object *objmap = (dom_nnodemap_object *) obj->ptr;
3737
if (!objmap) {
@@ -82,7 +82,7 @@ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-20
8282
*/
8383
int dom_nodelist_length_read(dom_object *obj, zval *retval)
8484
{
85-
ZVAL_LONG(retval, get_nodelist_length(obj));
85+
ZVAL_LONG(retval, php_dom_get_nodelist_length(obj));
8686
return SUCCESS;
8787
}
8888

@@ -99,36 +99,15 @@ PHP_METHOD(DOMNodeList, count)
9999
}
100100

101101
intern = Z_DOMOBJ_P(id);
102-
RETURN_LONG(get_nodelist_length(intern));
102+
RETURN_LONG(php_dom_get_nodelist_length(intern));
103103
}
104104
/* }}} end dom_nodelist_count */
105105

106-
/* }}} */
107-
108-
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-844377136
109-
Since:
110-
*/
111-
PHP_METHOD(DOMNodeList, item)
106+
void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value)
112107
{
113-
zval *id;
114-
zend_long index;
115108
int ret;
116-
dom_object *intern;
117109
xmlNodePtr itemnode = NULL;
118-
119-
dom_nnodemap_object *objmap;
120-
xmlNodePtr nodep, curnode;
121-
int count = 0;
122-
123-
id = ZEND_THIS;
124-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
125-
RETURN_THROWS();
126-
}
127-
128110
if (index >= 0) {
129-
intern = Z_DOMOBJ_P(id);
130-
131-
objmap = (dom_nnodemap_object *)intern->ptr;
132111
if (objmap != NULL) {
133112
if (objmap->ht) {
134113
if (objmap->nodetype == XML_ENTITY_NODE) {
@@ -145,10 +124,11 @@ PHP_METHOD(DOMNodeList, item)
145124
return;
146125
}
147126
} else if (objmap->baseobj) {
148-
nodep = dom_object_get_node(objmap->baseobj);
127+
xmlNodePtr nodep = dom_object_get_node(objmap->baseobj);
149128
if (nodep) {
129+
int count = 0;
150130
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
151-
curnode = nodep->children;
131+
xmlNodePtr curnode = nodep->children;
152132
while (count < index && curnode != NULL) {
153133
count++;
154134
curnode = curnode->next;
@@ -175,6 +155,22 @@ PHP_METHOD(DOMNodeList, item)
175155

176156
RETVAL_NULL();
177157
}
158+
159+
/* {{{ URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-844377136
160+
Since:
161+
*/
162+
PHP_METHOD(DOMNodeList, item)
163+
{
164+
zend_long index;
165+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) {
166+
RETURN_THROWS();
167+
}
168+
169+
zval *id = ZEND_THIS;
170+
dom_object *intern = Z_DOMOBJ_P(id);
171+
dom_nnodemap_object *objmap = intern->ptr;
172+
php_dom_nodelist_get_item_into_zval(objmap, index, return_value);
173+
}
178174
/* }}} end dom_nodelist_item */
179175

180176
ZEND_METHOD(DOMNodeList, getIterator)

0 commit comments

Comments
 (0)