Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 546454f

Browse files
committed
Fix intratransaction memory leaks in xml_recv, xmlconcat, xmlroot, and
xml_parse, all arising from the same sloppy usage of parse_xml_decl. The original coding had that function returning its output string parameters in the libxml context, which is long-lived, and all but one of its callers neglected to free the strings afterwards. The easiest and most bulletproof fix is to return the strings in the local palloc context instead, since that's short-lived. This was only costing a dozen or two bytes per function call, but that adds up fast if the function is called repeatedly ... Noted while poking at the more general problem of what to do with our libxml memory allocation hooks. Back-patch to 8.3, which has the identical coding.
1 parent f23bdda commit 546454f

File tree

1 file changed

+28
-12
lines changed
  • src/backend/utils/adt

1 file changed

+28
-12
lines changed

src/backend/utils/adt/xml.c

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.86 2009/04/08 21:51:38 petere Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.87 2009/05/12 20:17:40 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -236,8 +236,6 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
236236
}
237237
appendStringInfoString(&buf, str + len);
238238

239-
if (version)
240-
xmlFree(version);
241239
pfree(str);
242240

243241
return buf.data;
@@ -455,7 +453,7 @@ xmlconcat(List *args)
455453
if (!version)
456454
global_version_no_value = true;
457455
else if (!global_version)
458-
global_version = xmlStrdup(version);
456+
global_version = version;
459457
else if (xmlStrcmp(version, global_version) != 0)
460458
global_version_no_value = true;
461459

@@ -918,6 +916,24 @@ xml_init(void)
918916
|| xmlIsCombiningQ(c) \
919917
|| xmlIsExtender_ch(c))
920918

919+
/* pnstrdup, but deal with xmlChar not char; len is measured in xmlChars */
920+
static xmlChar *
921+
xml_pnstrdup(const xmlChar *str, size_t len)
922+
{
923+
xmlChar *result;
924+
925+
result = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
926+
memcpy(result, str, len * sizeof(xmlChar));
927+
result[len] = 0;
928+
return result;
929+
}
930+
931+
/*
932+
* str is the null-terminated input string. Remaining arguments are
933+
* output arguments; each can be NULL if value is not wanted.
934+
* version and encoding are returned as locally-palloc'd strings.
935+
* Result is 0 if OK, an error code if not.
936+
*/
921937
static int
922938
parse_xml_decl(const xmlChar * str, size_t *lenp,
923939
xmlChar ** version, xmlChar ** encoding, int *standalone)
@@ -930,6 +946,7 @@ parse_xml_decl(const xmlChar * str, size_t *lenp,
930946

931947
xml_init();
932948

949+
/* Initialize output arguments to "not present" */
933950
if (version)
934951
*version = NULL;
935952
if (encoding)
@@ -971,7 +988,7 @@ parse_xml_decl(const xmlChar * str, size_t *lenp,
971988
return XML_ERR_VERSION_MISSING;
972989

973990
if (version)
974-
*version = xmlStrndup(p + 1, q - p - 1);
991+
*version = xml_pnstrdup(p + 1, q - p - 1);
975992
p = q + 1;
976993
}
977994
else
@@ -999,7 +1016,7 @@ parse_xml_decl(const xmlChar * str, size_t *lenp,
9991016
return XML_ERR_MISSING_ENCODING;
10001017

10011018
if (encoding)
1002-
*encoding = xmlStrndup(p + 1, q - p - 1);
1019+
*encoding = xml_pnstrdup(p + 1, q - p - 1);
10031020
p = q + 1;
10041021
}
10051022
else
@@ -1172,24 +1189,23 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
11721189
xmlChar *version = NULL;
11731190
int standalone = -1;
11741191

1175-
doc = xmlNewDoc(NULL);
1176-
11771192
res_code = parse_xml_decl(utf8string,
11781193
&count, &version, NULL, &standalone);
11791194
if (res_code != 0)
11801195
xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT,
11811196
"invalid XML content: invalid XML declaration",
11821197
res_code);
11831198

1199+
doc = xmlNewDoc(version);
1200+
Assert(doc->encoding == NULL);
1201+
doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
1202+
doc->standalone = standalone;
1203+
11841204
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
11851205
utf8string + count, NULL);
11861206
if (res_code != 0)
11871207
xml_ereport(ERROR, ERRCODE_INVALID_XML_CONTENT,
11881208
"invalid XML content");
1189-
1190-
doc->version = xmlStrdup(version);
1191-
doc->encoding = xmlStrdup((xmlChar *) "UTF-8");
1192-
doc->standalone = standalone;
11931209
}
11941210

11951211
xmlFreeParserCtxt(ctxt);

0 commit comments

Comments
 (0)