Skip to content

Commit c5f6a8b

Browse files
authored
Minor improvements to ext/xml memory management (#18071)
1 parent c80e450 commit c5f6a8b

File tree

1 file changed

+64
-48
lines changed

1 file changed

+64
-48
lines changed

ext/xml/xml.c

+64-48
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ typedef struct {
8686
int toffset;
8787
int curtag;
8888
zend_long ctag_index;
89-
char **ltags;
89+
zend_string **ltags;
9090
bool lastwasopen;
9191
bool skipwhite;
9292
bool isparsing;
@@ -116,8 +116,6 @@ ZEND_GET_MODULE(xml)
116116

117117
#define XML_MAXLEVEL 255 /* XXX this should be dynamic */
118118

119-
#define SKIP_TAGSTART(str) ((str) + (parser->toffset > strlen(str) ? strlen(str) : parser->toffset))
120-
121119
static zend_class_entry *xml_parser_ce;
122120
static zend_object_handlers xml_parser_object_handlers;
123121

@@ -138,7 +136,7 @@ inline static unsigned short xml_encode_us_ascii(unsigned char);
138136
inline static char xml_decode_us_ascii(unsigned short);
139137
static void xml_xmlchar_zval(const XML_Char *, int, const XML_Char *, zval *);
140138
static int xml_xmlcharlen(const XML_Char *);
141-
static void xml_add_to_info(xml_parser *parser, const char *name);
139+
static void xml_add_to_info(xml_parser *parser, zend_string *name);
142140
inline static zend_string *xml_decode_tag(xml_parser *parser, const XML_Char *tag);
143141

144142
void xml_startElementHandler(void *, const XML_Char *, const XML_Char **);
@@ -311,7 +309,6 @@ static inline xml_parser *xml_parser_from_obj(zend_object *obj) {
311309

312310
static zend_object *xml_parser_create_object(zend_class_entry *class_type) {
313311
xml_parser *intern = zend_object_alloc(sizeof(xml_parser), class_type);
314-
memset(intern, 0, sizeof(xml_parser) - sizeof(zend_object));
315312

316313
zend_object_std_init(&intern->std, class_type);
317314
object_properties_init(&intern->std, class_type);
@@ -323,8 +320,11 @@ static void xml_parser_free_ltags(xml_parser *parser)
323320
{
324321
if (parser->ltags) {
325322
int inx;
326-
for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++)
327-
efree(parser->ltags[ inx ]);
323+
for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++) {
324+
if (parser->ltags[inx]) {
325+
zend_string_release_ex(parser->ltags[inx], false);
326+
}
327+
}
328328
efree(parser->ltags);
329329
}
330330
}
@@ -553,7 +553,7 @@ static int xml_xmlcharlen(const XML_Char *s)
553553
/* }}} */
554554

555555
/* {{{ xml_add_to_info() */
556-
static void xml_add_to_info(xml_parser *parser, const char *name)
556+
static void xml_add_to_info(xml_parser *parser, zend_string *name)
557557
{
558558
zval *element;
559559

@@ -564,11 +564,10 @@ static void xml_add_to_info(xml_parser *parser, const char *name)
564564
SEPARATE_ARRAY(Z_REFVAL(parser->info));
565565
zend_array *arr = Z_ARRVAL_P(Z_REFVAL(parser->info));
566566

567-
size_t name_len = strlen(name);
568-
if ((element = zend_hash_str_find(arr, name, name_len)) == NULL) {
567+
if ((element = zend_hash_find(arr, name)) == NULL) {
569568
zval values;
570569
array_init(&values);
571-
element = zend_hash_str_update(arr, name, name_len, &values);
570+
element = zend_hash_update(arr, name, &values);
572571
}
573572

574573
add_next_index_long(element, parser->curtag);
@@ -592,6 +591,17 @@ static zend_string *xml_decode_tag(xml_parser *parser, const XML_Char *tag)
592591
}
593592
/* }}} */
594593

594+
static zend_string *xml_stripped_tag(zend_string *tag_name, int offset)
595+
{
596+
if (offset == 0) {
597+
return zend_string_copy(tag_name);
598+
} else if (offset >= ZSTR_LEN(tag_name)) {
599+
return ZSTR_EMPTY_ALLOC();
600+
} else {
601+
return zend_string_init(ZSTR_VAL(tag_name) + offset, ZSTR_LEN(tag_name) - offset, false);
602+
}
603+
}
604+
595605
static zval *xml_get_separated_data(xml_parser *parser)
596606
{
597607
if (EXPECTED(Z_TYPE_P(Z_REFVAL(parser->data)) == IS_ARRAY)) {
@@ -632,7 +642,7 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha
632642
if (ZEND_FCC_INITIALIZED(parser->startElementHandler)) {
633643
zval args[3];
634644
ZVAL_COPY(&args[0], &parser->index);
635-
ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name)));
645+
ZVAL_STR(&args[1], xml_stripped_tag(tag_name, parser->toffset));
636646
array_init(&args[2]);
637647

638648
while (attributes && *attributes) {
@@ -651,7 +661,7 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha
651661

652662
zend_call_known_fcc(&parser->startElementHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL);
653663
zval_ptr_dtor(&args[0]);
654-
zval_ptr_dtor(&args[1]);
664+
zval_ptr_dtor_str(&args[1]);
655665
zval_ptr_dtor(&args[2]);
656666
}
657667

@@ -663,15 +673,15 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha
663673
array_init(&tag);
664674
array_init(&atr);
665675

666-
char *skipped_tag_name = SKIP_TAGSTART(ZSTR_VAL(tag_name));
667-
668-
xml_add_to_info(parser, skipped_tag_name);
676+
zend_string *stripped_tag = xml_stripped_tag(tag_name, parser->toffset);
677+
xml_add_to_info(parser, stripped_tag);
669678

670-
add_assoc_string(&tag, "tag", skipped_tag_name);
679+
add_assoc_str(&tag, "tag", stripped_tag); /* transfer lifetime */
671680
add_assoc_string(&tag, "type", "open");
672681
add_assoc_long(&tag, "level", parser->level);
673682

674-
parser->ltags[parser->level-1] = estrdup(ZSTR_VAL(tag_name));
683+
/* Because toffset may change, we should use the original tag name */
684+
parser->ltags[parser->level - 1] = zend_string_copy(tag_name);
675685
parser->lastwasopen = 1;
676686

677687
attributes = (const XML_Char **) attrs;
@@ -733,11 +743,11 @@ void xml_endElementHandler(void *userData, const XML_Char *name)
733743
if (ZEND_FCC_INITIALIZED(parser->endElementHandler)) {
734744
zval args[2];
735745
ZVAL_COPY(&args[0], &parser->index);
736-
ZVAL_STRING(&args[1], SKIP_TAGSTART(ZSTR_VAL(tag_name)));
746+
ZVAL_STR(&args[1], xml_stripped_tag(tag_name, parser->toffset));
737747

738748
zend_call_known_fcc(&parser->endElementHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL);
739749
zval_ptr_dtor(&args[0]);
740-
zval_ptr_dtor(&args[1]);
750+
zval_ptr_dtor_str(&args[1]);
741751
}
742752

743753
if (!Z_ISUNDEF(parser->data) && !EG(exception)) {
@@ -749,17 +759,19 @@ void xml_endElementHandler(void *userData, const XML_Char *name)
749759
add_assoc_string(zv, "type", "complete");
750760
}
751761
} else {
752-
char *skipped_tag_name = SKIP_TAGSTART(ZSTR_VAL(tag_name));
762+
zend_string *stripped_tag = xml_stripped_tag(tag_name, parser->toffset);
753763

754-
xml_add_to_info(parser, skipped_tag_name);
764+
xml_add_to_info(parser, stripped_tag);
755765

756766
zval *data = xml_get_separated_data(parser);
757767
if (EXPECTED(data)) {
758768
array_init(&tag);
759-
add_assoc_string(&tag, "tag", skipped_tag_name);
769+
add_assoc_str(&tag, "tag", stripped_tag); /* transfer lifetime */
760770
add_assoc_string(&tag, "type", "close");
761771
add_assoc_long(&tag, "level", parser->level);
762772
zend_hash_next_index_insert(Z_ARRVAL_P(data), &tag);
773+
} else {
774+
zend_string_release_ex(stripped_tag, false);
763775
}
764776
}
765777

@@ -769,7 +781,11 @@ void xml_endElementHandler(void *userData, const XML_Char *name)
769781
zend_string_release_ex(tag_name, 0);
770782

771783
if ((parser->ltags) && (parser->level <= XML_MAXLEVEL)) {
772-
efree(parser->ltags[parser->level-1]);
784+
zend_string **str = &parser->ltags[parser->level - 1];
785+
if (*str) {
786+
zend_string_release_ex(*str, false);
787+
*str = NULL;
788+
}
773789
}
774790

775791
parser->level--;
@@ -792,7 +808,7 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len)
792808

793809
zend_call_known_fcc(&parser->characterDataHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL);
794810
zval_ptr_dtor(&args[0]);
795-
zval_ptr_dtor(&args[1]);
811+
zval_ptr_dtor_str(&args[1]);
796812
}
797813

798814
if (Z_ISUNDEF(parser->data) || EG(exception)) {
@@ -868,8 +884,9 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len)
868884
} ZEND_HASH_FOREACH_END();
869885
if (parser->level <= XML_MAXLEVEL && parser->level > 0 && (doprint || (! parser->skipwhite))) {
870886
array_init(&tag);
871-
xml_add_to_info(parser,SKIP_TAGSTART(parser->ltags[parser->level-1]));
872-
add_assoc_string(&tag, "tag", SKIP_TAGSTART(parser->ltags[parser->level-1]));
887+
zend_string *stripped_tag = xml_stripped_tag(parser->ltags[parser->level - 1], parser->toffset);
888+
xml_add_to_info(parser, stripped_tag);
889+
add_assoc_str(&tag, "tag", stripped_tag); /* transfer lifetime */
873890
add_assoc_str(&tag, "value", decoded_value);
874891
add_assoc_string(&tag, "type", "cdata");
875892
add_assoc_long(&tag, "level", parser->level);
@@ -900,8 +917,8 @@ void xml_processingInstructionHandler(void *userData, const XML_Char *target, co
900917

901918
zend_call_known_fcc(&parser->processingInstructionHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL);
902919
zval_ptr_dtor(&args[0]);
903-
zval_ptr_dtor(&args[1]);
904-
zval_ptr_dtor(&args[2]);
920+
zval_ptr_dtor_str(&args[1]);
921+
zval_ptr_dtor_str(&args[2]);
905922
}
906923
/* }}} */
907924

@@ -921,7 +938,7 @@ void xml_defaultHandler(void *userData, const XML_Char *s, int len)
921938

922939
zend_call_known_fcc(&parser->defaultHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL);
923940
zval_ptr_dtor(&args[0]);
924-
zval_ptr_dtor(&args[1]);
941+
zval_ptr_dtor_str(&args[1]);
925942
}
926943
/* }}} */
927944

@@ -947,11 +964,11 @@ void xml_unparsedEntityDeclHandler(void *userData,
947964

948965
zend_call_known_fcc(&parser->unparsedEntityDeclHandler, /* retval */ NULL, /* param_count */ 6, args, /* named_params */ NULL);
949966
zval_ptr_dtor(&args[0]);
950-
zval_ptr_dtor(&args[1]);
951-
zval_ptr_dtor(&args[2]);
952-
zval_ptr_dtor(&args[3]);
953-
zval_ptr_dtor(&args[4]);
954-
zval_ptr_dtor(&args[5]);
967+
zval_ptr_dtor_str(&args[1]);
968+
zval_ptr_dtor_str(&args[2]);
969+
zval_ptr_dtor_str(&args[3]);
970+
zval_ptr_dtor_str(&args[4]);
971+
zval_ptr_dtor_str(&args[5]);
955972
}
956973
/* }}} */
957974

@@ -975,10 +992,10 @@ void xml_notationDeclHandler(void *userData, const XML_Char *notationName,
975992

976993
zend_call_known_fcc(&parser->notationDeclHandler, /* retval */ NULL, /* param_count */ 5, args, /* named_params */ NULL);
977994
zval_ptr_dtor(&args[0]);
978-
zval_ptr_dtor(&args[1]);
979-
zval_ptr_dtor(&args[2]);
980-
zval_ptr_dtor(&args[3]);
981-
zval_ptr_dtor(&args[4]);
995+
zval_ptr_dtor_str(&args[1]);
996+
zval_ptr_dtor_str(&args[2]);
997+
zval_ptr_dtor_str(&args[3]);
998+
zval_ptr_dtor_str(&args[4]);
982999
}
9831000
/* }}} */
9841001

@@ -1004,10 +1021,10 @@ int xml_externalEntityRefHandler(XML_Parser userData, const XML_Char *openEntity
10041021

10051022
zend_call_known_fcc(&parser->externalEntityRefHandler, /* retval */ &retval, /* param_count */ 5, args, /* named_params */ NULL);
10061023
zval_ptr_dtor(&args[0]);
1007-
zval_ptr_dtor(&args[1]);
1008-
zval_ptr_dtor(&args[2]);
1009-
zval_ptr_dtor(&args[3]);
1010-
zval_ptr_dtor(&args[4]);
1024+
zval_ptr_dtor_str(&args[1]);
1025+
zval_ptr_dtor_str(&args[2]);
1026+
zval_ptr_dtor_str(&args[3]);
1027+
zval_ptr_dtor_str(&args[4]);
10111028

10121029
/* TODO Better handling from callable return value */
10131030
if (!Z_ISUNDEF(retval)) {
@@ -1037,8 +1054,8 @@ void xml_startNamespaceDeclHandler(void *userData,const XML_Char *prefix, const
10371054

10381055
zend_call_known_fcc(&parser->startNamespaceDeclHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL);
10391056
zval_ptr_dtor(&args[0]);
1040-
zval_ptr_dtor(&args[1]);
1041-
zval_ptr_dtor(&args[2]);
1057+
zval_ptr_dtor_str(&args[1]);
1058+
zval_ptr_dtor_str(&args[2]);
10421059
}
10431060
/* }}} */
10441061

@@ -1058,7 +1075,7 @@ void xml_endNamespaceDeclHandler(void *userData, const XML_Char *prefix)
10581075

10591076
zend_call_known_fcc(&parser->endNamespaceDeclHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL);
10601077
zval_ptr_dtor(&args[0]);
1061-
zval_ptr_dtor(&args[1]);
1078+
zval_ptr_dtor_str(&args[1]);
10621079
}
10631080
/* }}} */
10641081

@@ -1448,8 +1465,7 @@ PHP_FUNCTION(xml_parse_into_struct)
14481465

14491466
parser->level = 0;
14501467
xml_parser_free_ltags(parser);
1451-
parser->ltags = safe_emalloc(XML_MAXLEVEL, sizeof(char *), 0);
1452-
memset(parser->ltags, 0, XML_MAXLEVEL * sizeof(char *));
1468+
parser->ltags = ecalloc(XML_MAXLEVEL, sizeof(zend_string *));
14531469

14541470
XML_SetElementHandler(parser->parser, xml_startElementHandler, xml_endElementHandler);
14551471
XML_SetCharacterDataHandler(parser->parser, xml_characterDataHandler);

0 commit comments

Comments
 (0)