Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uNQ2d-001b3e-8t for pgsql-bugs@arkaria.postgresql.org; Fri, 06 Jun 2025 05:54:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1uNQ2a-003yxB-2g for pgsql-bugs@arkaria.postgresql.org; Fri, 06 Jun 2025 05:54:56 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uNQ2Z-003yx2-Er for pgsql-bugs@lists.postgresql.org; Fri, 06 Jun 2025 05:54:56 +0000 Received: from fout-a5-smtp.messagingengine.com ([103.168.172.148]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1uNQ2X-000UdF-1h for pgsql-bugs@lists.postgresql.org; Fri, 06 Jun 2025 05:54:55 +0000 Received: from phl-compute-03.internal (phl-compute-03.phl.internal [10.202.2.43]) by mailfout.phl.internal (Postfix) with ESMTP id E28831380298; Fri, 6 Jun 2025 01:54:50 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-03.internal (MEProxy); Fri, 06 Jun 2025 01:54:50 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paquier.xyz; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1749189290; x=1749275690; bh=SHIzYqJnWK PuGvBFfAplQTebzzxbEfRfcdjIiBL8gQI=; b=N3RMcm4kkrYp+uwtkvNObMyZ4y Ap0QsRAHnSSOZFdoBwv+mFJ6PfHKVjNPMUHyv5EwzO1RBGup+GFzsVmoIsEpKr+H GvKLJLk+bgoY5jK6jfnZAFtNcgIBr0lTuWMS0JpYiXW0i6k8FggT7AXJUItizZYP VBvXmgQRCJYr79890LwS0VnIlh4b6XvG5NkXIgMGbzTcUm69/8zQQefgdxiIERjx JvRlI3+IUsJ5yUvNas0oE1hmrFX/ey+6Ly02TVSRrXwWooR/c3P9OahG9DlxjlYD rErdQmchizyXs9kES/yfKB66DyF6dY7mMTq8KCNgjp2ligHloTajcBDJ39Zw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1749189290; x=1749275690; bh=SHIzYqJnWKPuGvBFfAplQTebzzxbEfRfcdj IiBL8gQI=; b=XTp7NV28HAXwbvDkvHe788QxFxfqRhOtWIL8RdOR0QqUw+kU5Bs LkV5xp1tQrjXVTzmD6Fuft/rlu2kSjcN6GVqoQa+IzH8oQKXDSERWbbTyRDUpsYo dszqbwWlEqnJz+efSH4EysgJbMiHfbSwPgH1WCV2QqqRqwTJpJRiHnMxN+8zQMhC TsnPUUxK6Npn/o+DjPV9fNSZmK5NqyhYWUZhoYYKUwfZTomt4RppbtqAWF7o/2oJ mErKMd2kAHB2IkyDhxvylo6mNou8RZ93sK/tDaNbKu8bkyGjYcfjzdF9U/xmwwZf BXplIVpenviv82nBKYCQZ/VD/fHItDraXQA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtddugdegieekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggvpdfu rfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnh htshculddquddttddmnegfrhhlucfvnfffucdljedtmdenucfjughrpeffhffvvefukfhf gggtuggjsehgtderredttddunecuhfhrohhmpefoihgthhgrvghlucfrrghquhhivghruc eomhhitghhrggvlhesphgrqhhuihgvrhdrgiihiieqnecuggftrfgrthhtvghrnhepgfeh hefgudefudfgfeelgeeiffegfefhkeefffdvheefuddtheetgeelteevkeetnecuvehluh hsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepmhhitghhrggvlhes phgrqhhuihgvrhdrgiihiidpnhgspghrtghpthhtohepgedpmhhouggvpehsmhhtphhouh htpdhrtghpthhtohepjhhimhdrjhhonhgvshesuhhnihdqmhhuvghnshhtvghrrdguvgdp rhgtphhtthhopehtghhlsehsshhsrdhpghhhrdhprgdruhhspdhrtghpthhtohepphhgsh hqlhdqsghughhssehlihhsthhsrdhpohhsthhgrhgvshhqlhdrohhrghdprhgtphhtthho pehmrghrrghlihhsthekieesmhgrihhlrdhruh X-ME-Proxy: Feedback-ID: i0fe9450f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 6 Jun 2025 01:54:47 -0400 (EDT) Date: Fri, 6 Jun 2025 14:54:40 +0900 From: Michael Paquier To: Jim Jones Cc: Tom Lane , pgsql-bugs@lists.postgresql.org, maralist86@mail.ru Subject: Re: BUG #18943: Return value of a function 'xmlBufferCreate' is dereferenced at xpath.c:177 without checking for NUL Message-ID: References: <18943-2f2a04ab03904598@postgresql.org> <861593.1748970933@sss.pgh.pa.us> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="4AnGqknsL3b4jo7x" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --4AnGqknsL3b4jo7x Content-Type: multipart/mixed; boundary="DYI/odQVn+y4mvmw" Content-Disposition: inline --DYI/odQVn+y4mvmw Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Jun 05, 2025 at 04:15:19PM +0200, Jim Jones wrote: > On 05.06.25 11:47, Jim Jones wrote: >> Taking a further look at xml.c I am wondering if other functions might >> also need some attention in this regard: >>=20 >> * xmlTextWriterStartElement [3] >> * xmlTextWriterWriteAttribute [4] >> * xmlTextWriterWriteRaw [5] >> * xmlTextWriterEndAttribute [6] It seems to me that you mean xmlTextWriterEndElement() and not xmlTextWriterEndAttribute() for the last one. I've been looking at the rest of the callers (this took some time), like: - xmlTextWriterWriteBase64, OK. - xmlTextWriterWriteBinHex, OK. - xmlNewStringInputStream, which is intentional in xmlPgEntityLoader() - xmlAddChildList, where we expect valid input. - xmlXPathCompiledEval, where valid input is expected. - xmlXPathNewContext, which is incorrect, could fail an allocation. - xmlReadMemory, looks OK. - xmlBufferWriteChar, which could fail on OOM if they need to grow memory, but let's leave these as they are; I suspect that xmlBufferCreate() would fail anyway. >> We're assuming they never fail. Perhaps something like this? >> =A0... >> =A0nbytes =3D xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name); >> =A0if (nbytes =3D=3D -1 || xmlerrcxt->err_occurred) >> =A0 =A0 xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "could not allocate xmlT= extWriterStartElement"); Oh. These can return XML_ERR_NO_MEMORY as well, with more error patterns.. > There is also a further xmlXPathCastNodeToString() call in xml.c at > xml_xmlnodetoxmltype() - it calls xmlNodeGetContent() and it can return > NULL. And it's documented as a routine that returns an allocated string, so yes, we would miss allocation failures but we should not. I think that we should move the call of xmlXPathCastNodeToString() inside the PG_TRY block and rely on the xmlerrcxt given by the caller to log an error if an allocation fails, marking xmlChar *str as volatile to free it in the finally block if required. > The function pgxmlNodeSetToText() also calls xmlXPathCastNodeToString(), > but apparently xmlBufferAdd() can handle NULL values.[1] Yeah, the patch I have posted upthread gets that done better. What do you think? -- Michael --DYI/odQVn+y4mvmw Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v3-0001-xml2-Fix-error-handling-in-corner-cases.patch" Content-Transfer-Encoding: quoted-printable =46rom 6d2e680bb75d45435b704fcf4b7225697cad4da8 Mon Sep 17 00:00:00 2001 =46rom: Michael Paquier Date: Fri, 6 Jun 2025 14:53:35 +0900 Subject: [PATCH v3] xml2: Fix error handling in corner cases --- src/backend/utils/adt/xml.c | 73 +++++-- contrib/xml2/xpath.c | 418 ++++++++++++++++++++++++------------ contrib/xml2/xslt_proc.c | 26 ++- 3 files changed, 352 insertions(+), 165 deletions(-) diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index a4150bff2eae..43bc2432eb6c 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -529,14 +529,36 @@ xmltext(PG_FUNCTION_ARGS) #ifdef USE_LIBXML text *arg =3D PG_GETARG_TEXT_PP(0); text *result; - xmlChar *xmlbuf =3D NULL; + volatile xmlChar *xmlbuf =3D NULL; + PgXmlErrorContext *xmlerrcxt; =20 - xmlbuf =3D xmlEncodeSpecialChars(NULL, xml_text2xmlChar(arg)); + /* Otherwise, we gotta spin up some error handling. */ + xmlerrcxt =3D pg_xml_init(PG_XML_STRICTNESS_ALL); =20 - Assert(xmlbuf); + PG_TRY(); + { + xmlbuf =3D xmlEncodeSpecialChars(NULL, xml_text2xmlChar(arg)); + + if (xmlbuf =3D=3D NULL || xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate xmlChar"); + + result =3D cstring_to_text_with_len((const char *) xmlbuf, + xmlStrlen((const xmlChar *) xmlbuf)); + } + PG_CATCH(); + { + if (xmlbuf) + xmlFree((xmlChar *) xmlbuf); + + pg_xml_done(xmlerrcxt, true); + PG_RE_THROW(); + } + PG_END_TRY(); + + xmlFree((xmlChar *) xmlbuf); + pg_xml_done(xmlerrcxt, false); =20 - result =3D cstring_to_text_with_len((const char *) xmlbuf, xmlStrlen(xmlb= uf)); - xmlFree(xmlbuf); PG_RETURN_XML_P(result); #else NO_XML_SUPPORT(); @@ -931,7 +953,10 @@ xmlelement(XmlExpr *xexpr, xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, "could not allocate xmlTextWriter"); =20 - xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name); + if (xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name) < 0 || + xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR, + "could not start xml element"); =20 forboth(arg, named_arg_strings, narg, xexpr->arg_names) { @@ -939,19 +964,30 @@ xmlelement(XmlExpr *xexpr, char *argname =3D strVal(lfirst(narg)); =20 if (str) - xmlTextWriterWriteAttribute(writer, - (xmlChar *) argname, - (xmlChar *) str); + { + if (xmlTextWriterWriteAttribute(writer, + (xmlChar *) argname, + (xmlChar *) str) < 0 || + xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR, + "could not write xml attribute"); + } } =20 foreach(arg, arg_strings) { char *str =3D (char *) lfirst(arg); =20 - xmlTextWriterWriteRaw(writer, (xmlChar *) str); + if (xmlTextWriterWriteRaw(writer, (xmlChar *) str) < 0 || + xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR, + "could not write raw xml text"); } =20 - xmlTextWriterEndElement(writer); + if (xmlTextWriterEndElement(writer) < 0 || + xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INTERNAL_ERROR, + "could not end xml element"); =20 /* we MUST do this now to flush data out to the buffer ... */ xmlFreeTextWriter(writer); @@ -4220,20 +4256,27 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorCont= ext *xmlerrcxt) } else { - xmlChar *str; + volatile xmlChar *str =3D NULL; =20 - str =3D xmlXPathCastNodeToString(cur); PG_TRY(); { + char *escaped; + + str =3D xmlXPathCastNodeToString(cur); + if (str =3D=3D NULL || xmlerrcxt->err_occurred) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate xmlChar"); + /* Here we rely on XML having the same representation as TEXT */ - char *escaped =3D escape_xml((char *) str); + escaped =3D escape_xml((char *) str); =20 result =3D (xmltype *) cstring_to_text(escaped); pfree(escaped); } PG_FINALLY(); { - xmlFree(str); + if (str) + xmlFree((xmlChar *) str); } PG_END_TRY(); } diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 23d3f332dbaa..9345a6c2d08f 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -51,10 +51,10 @@ static text *pgxml_result_to_text(xmlXPathObjectPtr res= , xmlChar *toptag, =20 static xmlChar *pgxml_texttoxmlchar(text *textstring); =20 -static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, - xpath_workspace *workspace); +static xpath_workspace *pgxml_xpath(text *document, xmlChar *xpath, + PgXmlErrorContext *xmlerrcxt); =20 -static void cleanup_workspace(xpath_workspace *workspace); +static void cleanup_workspace(volatile xpath_workspace *workspace); =20 =20 /* @@ -89,18 +89,40 @@ xml_encode_special_chars(PG_FUNCTION_ARGS) { text *tin =3D PG_GETARG_TEXT_PP(0); text *tout; - xmlChar *ts, - *tt; + volatile xmlChar *tt =3D NULL; + PgXmlErrorContext *xmlerrcxt; =20 - ts =3D pgxml_texttoxmlchar(tin); + xmlerrcxt =3D pg_xml_init(PG_XML_STRICTNESS_ALL); =20 - tt =3D xmlEncodeSpecialChars(NULL, ts); + PG_TRY(); + { + xmlChar *ts; =20 - pfree(ts); + ts =3D pgxml_texttoxmlchar(tin); =20 - tout =3D cstring_to_text((char *) tt); + tt =3D xmlEncodeSpecialChars(NULL, ts); + if (tt =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate xmlChar"); + pfree(ts); =20 - xmlFree(tt); + tout =3D cstring_to_text((char *) tt); + } + PG_CATCH(); + { + if (tt !=3D NULL) + xmlFree((xmlChar *) tt); + + pg_xml_done(xmlerrcxt, true); + + PG_RE_THROW(); + } + PG_END_TRY(); + + if (tt !=3D NULL) + xmlFree((xmlChar *) tt); + + pg_xml_done(xmlerrcxt, false); =20 PG_RETURN_TEXT_P(tout); } @@ -122,62 +144,90 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar *septagname, xmlChar *plainsep) { - xmlBufferPtr buf; + volatile xmlBufferPtr buf =3D NULL; xmlChar *result; int i; + PgXmlErrorContext *xmlerrcxt; =20 - buf =3D xmlBufferCreate(); + /* spin some error handling */ + xmlerrcxt =3D pg_xml_init(PG_XML_STRICTNESS_ALL); =20 - if ((toptagname !=3D NULL) && (xmlStrlen(toptagname) > 0)) + PG_TRY(); { - xmlBufferWriteChar(buf, "<"); - xmlBufferWriteCHAR(buf, toptagname); - xmlBufferWriteChar(buf, ">"); - } - if (nodeset !=3D NULL) - { - for (i =3D 0; i < nodeset->nodeNr; i++) + buf =3D xmlBufferCreate(); + + if (buf =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate xmlBuffer"); + + if ((toptagname !=3D NULL) && (xmlStrlen(toptagname) > 0)) { - if (plainsep !=3D NULL) + xmlBufferWriteChar(buf, "<"); + xmlBufferWriteCHAR(buf, toptagname); + xmlBufferWriteChar(buf, ">"); + } + if (nodeset !=3D NULL) + { + for (i =3D 0; i < nodeset->nodeNr; i++) { - xmlBufferWriteCHAR(buf, - xmlXPathCastNodeToString(nodeset->nodeTab[i])); - - /* If this isn't the last entry, write the plain sep. */ - if (i < (nodeset->nodeNr) - 1) - xmlBufferWriteChar(buf, (char *) plainsep); - } - else - { - if ((septagname !=3D NULL) && (xmlStrlen(septagname) > 0)) + if (plainsep !=3D NULL) { - xmlBufferWriteChar(buf, "<"); - xmlBufferWriteCHAR(buf, septagname); - xmlBufferWriteChar(buf, ">"); + xmlBufferWriteCHAR(buf, + xmlXPathCastNodeToString(nodeset->nodeTab[i])); + + /* If this isn't the last entry, write the plain sep. */ + if (i < (nodeset->nodeNr) - 1) + xmlBufferWriteChar(buf, (char *) plainsep); } - xmlNodeDump(buf, - nodeset->nodeTab[i]->doc, - nodeset->nodeTab[i], - 1, 0); - - if ((septagname !=3D NULL) && (xmlStrlen(septagname) > 0)) + else { - xmlBufferWriteChar(buf, ""); + if ((septagname !=3D NULL) && (xmlStrlen(septagname) > 0)) + { + xmlBufferWriteChar(buf, "<"); + xmlBufferWriteCHAR(buf, septagname); + xmlBufferWriteChar(buf, ">"); + } + xmlNodeDump(buf, + nodeset->nodeTab[i]->doc, + nodeset->nodeTab[i], + 1, 0); + + if ((septagname !=3D NULL) && (xmlStrlen(septagname) > 0)) + { + xmlBufferWriteChar(buf, ""); + } } } } - } =20 - if ((toptagname !=3D NULL) && (xmlStrlen(toptagname) > 0)) - { - xmlBufferWriteChar(buf, ""); + if ((toptagname !=3D NULL) && (xmlStrlen(toptagname) > 0)) + { + xmlBufferWriteChar(buf, ""); + } + + result =3D xmlStrdup(buf->content); + if (result =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate result"); } - result =3D xmlStrdup(buf->content); + PG_CATCH(); + { + if (buf) + xmlBufferFree(buf); + + pg_xml_done(xmlerrcxt, true); + + PG_RE_THROW(); + } + PG_END_TRY(); + xmlBufferFree(buf); + pg_xml_done(xmlerrcxt, false); + return result; } =20 @@ -208,16 +258,29 @@ xpath_nodeset(PG_FUNCTION_ARGS) xmlChar *septag =3D pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(3)); xmlChar *xpath; text *xpres; - xmlXPathObjectPtr res; - xpath_workspace workspace; + volatile xpath_workspace *workspace; + PgXmlErrorContext *xmlerrcxt; =20 xpath =3D pgxml_texttoxmlchar(xpathsupp); + xmlerrcxt =3D pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); =20 - res =3D pgxml_xpath(document, xpath, &workspace); + PG_TRY(); + { + workspace =3D pgxml_xpath(document, xpath, xmlerrcxt); + xpres =3D pgxml_result_to_text(workspace->res, toptag, septag, NULL); + } + PG_CATCH(); + { + if (workspace) + cleanup_workspace(workspace); =20 - xpres =3D pgxml_result_to_text(res, toptag, septag, NULL); + pg_xml_done(xmlerrcxt, true); + PG_RE_THROW(); + } + PG_END_TRY(); =20 - cleanup_workspace(&workspace); + cleanup_workspace(workspace); + pg_xml_done(xmlerrcxt, false); =20 pfree(xpath); =20 @@ -240,16 +303,29 @@ xpath_list(PG_FUNCTION_ARGS) xmlChar *plainsep =3D pgxml_texttoxmlchar(PG_GETARG_TEXT_PP(2)); xmlChar *xpath; text *xpres; - xmlXPathObjectPtr res; - xpath_workspace workspace; + volatile xpath_workspace *workspace; + PgXmlErrorContext *xmlerrcxt; =20 xpath =3D pgxml_texttoxmlchar(xpathsupp); + xmlerrcxt =3D pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); =20 - res =3D pgxml_xpath(document, xpath, &workspace); + PG_TRY(); + { + workspace =3D pgxml_xpath(document, xpath, xmlerrcxt); + xpres =3D pgxml_result_to_text(workspace->res, NULL, NULL, plainsep); + } + PG_CATCH(); + { + if (workspace) + cleanup_workspace(workspace); =20 - xpres =3D pgxml_result_to_text(res, NULL, NULL, plainsep); + pg_xml_done(xmlerrcxt, true); + PG_RE_THROW(); + } + PG_END_TRY(); =20 - cleanup_workspace(&workspace); + cleanup_workspace(workspace); + pg_xml_done(xmlerrcxt, false); =20 pfree(xpath); =20 @@ -269,8 +345,8 @@ xpath_string(PG_FUNCTION_ARGS) xmlChar *xpath; int32 pathsize; text *xpres; - xmlXPathObjectPtr res; - xpath_workspace workspace; + volatile xpath_workspace *workspace; + PgXmlErrorContext *xmlerrcxt; =20 pathsize =3D VARSIZE_ANY_EXHDR(xpathsupp); =20 @@ -286,11 +362,24 @@ xpath_string(PG_FUNCTION_ARGS) xpath[pathsize + 7] =3D ')'; xpath[pathsize + 8] =3D '\0'; =20 - res =3D pgxml_xpath(document, xpath, &workspace); + xmlerrcxt =3D pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); =20 - xpres =3D pgxml_result_to_text(res, NULL, NULL, NULL); + PG_TRY(); + { + workspace =3D pgxml_xpath(document, xpath, xmlerrcxt); + xpres =3D pgxml_result_to_text(workspace->res, NULL, NULL, NULL); + } + PG_CATCH(); + { + if (workspace) + cleanup_workspace(workspace); =20 - cleanup_workspace(&workspace); + pg_xml_done(xmlerrcxt, true); + PG_RE_THROW(); + } + PG_END_TRY(); + + cleanup_workspace(workspace); =20 pfree(xpath); =20 @@ -308,24 +397,38 @@ xpath_number(PG_FUNCTION_ARGS) text *document =3D PG_GETARG_TEXT_PP(0); text *xpathsupp =3D PG_GETARG_TEXT_PP(1); /* XPath expression */ xmlChar *xpath; - float4 fRes; - xmlXPathObjectPtr res; - xpath_workspace workspace; + float4 fRes =3D 0.0; + bool isNull =3D false; + volatile xpath_workspace *workspace =3D NULL; + PgXmlErrorContext *xmlerrcxt; =20 xpath =3D pgxml_texttoxmlchar(xpathsupp); + xmlerrcxt =3D pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); =20 - res =3D pgxml_xpath(document, xpath, &workspace); + PG_TRY(); + { + workspace =3D pgxml_xpath(document, xpath, xmlerrcxt); + pfree(xpath); =20 - pfree(xpath); + if (workspace->res =3D=3D NULL) + isNull =3D true; + else + fRes =3D xmlXPathCastToNumber(workspace->res); + } + PG_CATCH(); + { + if (workspace) + cleanup_workspace(workspace); =20 - if (res =3D=3D NULL) - PG_RETURN_NULL(); + pg_xml_done(xmlerrcxt, true); + PG_RE_THROW(); + } + PG_END_TRY(); =20 - fRes =3D xmlXPathCastToNumber(res); + cleanup_workspace(workspace); + pg_xml_done(xmlerrcxt, false); =20 - cleanup_workspace(&workspace); - - if (xmlXPathIsNaN(fRes)) + if (isNull || xmlXPathIsNaN(fRes)) PG_RETURN_NULL(); =20 PG_RETURN_FLOAT4(fRes); @@ -341,21 +444,34 @@ xpath_bool(PG_FUNCTION_ARGS) text *xpathsupp =3D PG_GETARG_TEXT_PP(1); /* XPath expression */ xmlChar *xpath; int bRes; - xmlXPathObjectPtr res; - xpath_workspace workspace; + volatile xpath_workspace *workspace =3D NULL; + PgXmlErrorContext *xmlerrcxt; =20 xpath =3D pgxml_texttoxmlchar(xpathsupp); + xmlerrcxt =3D pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); =20 - res =3D pgxml_xpath(document, xpath, &workspace); + PG_TRY(); + { + workspace =3D pgxml_xpath(document, xpath, xmlerrcxt); + pfree(xpath); =20 - pfree(xpath); + if (workspace->res =3D=3D NULL) + bRes =3D 0; + else + bRes =3D xmlXPathCastToBoolean(workspace->res); + } + PG_CATCH(); + { + if (workspace) + cleanup_workspace(workspace); =20 - if (res =3D=3D NULL) - PG_RETURN_BOOL(false); + pg_xml_done(xmlerrcxt, true); + PG_RE_THROW(); + } + PG_END_TRY(); =20 - bRes =3D xmlXPathCastToBoolean(res); - - cleanup_workspace(&workspace); + cleanup_workspace(workspace); + pg_xml_done(xmlerrcxt, false); =20 PG_RETURN_BOOL(bRes); } @@ -364,62 +480,44 @@ xpath_bool(PG_FUNCTION_ARGS) =20 /* Core function to evaluate XPath query */ =20 -static xmlXPathObjectPtr -pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace) +static xpath_workspace * +pgxml_xpath(text *document, xmlChar *xpath, PgXmlErrorContext *xmlerrcxt) { int32 docsize =3D VARSIZE_ANY_EXHDR(document); - PgXmlErrorContext *xmlerrcxt; xmlXPathCompExprPtr comppath; + xpath_workspace *workspace =3D (xpath_workspace *) + palloc0(sizeof(xpath_workspace)); =20 workspace->doctree =3D NULL; workspace->ctxt =3D NULL; workspace->res =3D NULL; =20 - xmlerrcxt =3D pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); - - PG_TRY(); + workspace->doctree =3D xmlReadMemory((char *) VARDATA_ANY(document), + docsize, NULL, NULL, + XML_PARSE_NOENT); + if (workspace->doctree !=3D NULL) { - workspace->doctree =3D xmlReadMemory((char *) VARDATA_ANY(document), - docsize, NULL, NULL, - XML_PARSE_NOENT); - if (workspace->doctree !=3D NULL) - { - workspace->ctxt =3D xmlXPathNewContext(workspace->doctree); - workspace->ctxt->node =3D xmlDocGetRootElement(workspace->doctree); + workspace->ctxt =3D xmlXPathNewContext(workspace->doctree); + workspace->ctxt->node =3D xmlDocGetRootElement(workspace->doctree); =20 - /* compile the path */ - comppath =3D xmlXPathCtxtCompile(workspace->ctxt, xpath); - if (comppath =3D=3D NULL) - xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY, + /* compile the path */ + comppath =3D xmlXPathCtxtCompile(workspace->ctxt, xpath); + if (comppath =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY, "XPath Syntax Error"); =20 - /* Now evaluate the path expression. */ - workspace->res =3D xmlXPathCompiledEval(comppath, workspace->ctxt); + /* Now evaluate the path expression. */ + workspace->res =3D xmlXPathCompiledEval(comppath, workspace->ctxt); =20 - xmlXPathFreeCompExpr(comppath); - } + xmlXPathFreeCompExpr(comppath); } - PG_CATCH(); - { - cleanup_workspace(workspace); =20 - pg_xml_done(xmlerrcxt, true); - - PG_RE_THROW(); - } - PG_END_TRY(); - - if (workspace->res =3D=3D NULL) - cleanup_workspace(workspace); - - pg_xml_done(xmlerrcxt, false); - - return workspace->res; + return workspace; } =20 /* Clean up after processing the result of pgxml_xpath() */ static void -cleanup_workspace(xpath_workspace *workspace) +cleanup_workspace(volatile xpath_workspace *workspace) { if (workspace->res) xmlXPathFreeObject(workspace->res); @@ -438,34 +536,59 @@ pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar *septag, xmlChar *plainsep) { - xmlChar *xpresstr; + volatile xmlChar *xpresstr =3D NULL; + PgXmlErrorContext *xmlerrcxt; text *xpres; =20 if (res =3D=3D NULL) return NULL; =20 - switch (res->type) + /* spin some error handling */ + xmlerrcxt =3D pg_xml_init(PG_XML_STRICTNESS_ALL); + + PG_TRY(); { - case XPATH_NODESET: - xpresstr =3D pgxmlNodeSetToText(res->nodesetval, - toptag, - septag, plainsep); - break; + switch (res->type) + { + case XPATH_NODESET: + xpresstr =3D pgxmlNodeSetToText(res->nodesetval, + toptag, + septag, plainsep); + break; =20 - case XPATH_STRING: - xpresstr =3D xmlStrdup(res->stringval); - break; + case XPATH_STRING: + xpresstr =3D xmlStrdup(res->stringval); + if (xpresstr =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate result"); + break; =20 - default: - elog(NOTICE, "unsupported XQuery result: %d", res->type); - xpresstr =3D xmlStrdup((const xmlChar *) ""); + default: + elog(NOTICE, "unsupported XQuery result: %d", res->type); + xpresstr =3D xmlStrdup((const xmlChar *) ""); + if (xpresstr =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate result"); + } + + /* Now convert this result back to text */ + xpres =3D cstring_to_text((char *) xpresstr); } + PG_CATCH(); + { + if (xpresstr !=3D NULL) + xmlFree((xmlChar *) xpresstr); =20 - /* Now convert this result back to text */ - xpres =3D cstring_to_text((char *) xpresstr); + pg_xml_done(xmlerrcxt, true); + + PG_RE_THROW(); + } + PG_END_TRY(); =20 /* Free various storage */ - xmlFree(xpresstr); + xmlFree((xmlChar *) xpresstr); + + pg_xml_done(xmlerrcxt, false); =20 return xpres; } @@ -648,11 +771,16 @@ xpath_table(PG_FUNCTION_ARGS) for (j =3D 0; j < numpaths; j++) { ctxt =3D xmlXPathNewContext(doctree); + if (ctxt =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, + ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate XPath context"); + ctxt->node =3D xmlDocGetRootElement(doctree); =20 /* compile the path */ comppath =3D xmlXPathCtxtCompile(ctxt, xpaths[j]); - if (comppath =3D=3D NULL) + if (comppath =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY, "XPath Syntax Error"); @@ -671,6 +799,10 @@ xpath_table(PG_FUNCTION_ARGS) rownr < res->nodesetval->nodeNr) { resstr =3D xmlXPathCastNodeToString(res->nodesetval->nodeTab[row= nr]); + if (resstr =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, + ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate result"); had_values =3D true; } else @@ -680,11 +812,19 @@ xpath_table(PG_FUNCTION_ARGS) =20 case XPATH_STRING: resstr =3D xmlStrdup(res->stringval); + if (resstr =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, + ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate result"); break; =20 default: elog(NOTICE, "unsupported XQuery result: %d", res->type); resstr =3D xmlStrdup((const xmlChar *) ""); + if (resstr =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) + xml_ereport(xmlerrcxt, + ERROR, ERRCODE_OUT_OF_MEMORY, + "could not allocate result"); } =20 /* diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c index b720d89f754a..c8e7dd45ed5b 100644 --- a/contrib/xml2/xslt_proc.c +++ b/contrib/xml2/xslt_proc.c @@ -58,7 +58,7 @@ xslt_process(PG_FUNCTION_ARGS) volatile xsltSecurityPrefsPtr xslt_sec_prefs =3D NULL; volatile xsltTransformContextPtr xslt_ctxt =3D NULL; volatile int resstat =3D -1; - xmlChar *resstr =3D NULL; + volatile xmlChar *resstr =3D NULL; int reslen =3D 0; =20 if (fcinfo->nargs =3D=3D 3) @@ -86,7 +86,7 @@ xslt_process(PG_FUNCTION_ARGS) VARSIZE_ANY_EXHDR(doct), NULL, NULL, XML_PARSE_NOENT); =20 - if (doctree =3D=3D NULL) + if (doctree =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT, "error parsing XML document"); =20 @@ -95,14 +95,14 @@ xslt_process(PG_FUNCTION_ARGS) VARSIZE_ANY_EXHDR(ssheet), NULL, NULL, XML_PARSE_NOENT); =20 - if (ssdoc =3D=3D NULL) + if (ssdoc =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT, "error parsing stylesheet as XML document"); =20 /* After this call we need not free ssdoc separately */ stylesheet =3D xsltParseStylesheetDoc(ssdoc); =20 - if (stylesheet =3D=3D NULL) + if (stylesheet =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY, "failed to parse stylesheet"); =20 @@ -137,11 +137,15 @@ xslt_process(PG_FUNCTION_ARGS) restree =3D xsltApplyStylesheetUser(stylesheet, doctree, params, NULL, NULL, xslt_ctxt); =20 - if (restree =3D=3D NULL) + if (restree =3D=3D NULL || pg_xml_error_occurred(xmlerrcxt)) xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_ARGUMENT_FOR_XQUERY, "failed to apply stylesheet"); =20 - resstat =3D xsltSaveResultToString(&resstr, &reslen, restree, stylesheet= ); + resstat =3D xsltSaveResultToString((xmlChar **) &resstr, &reslen, + restree, stylesheet); + + if (resstat >=3D 0) + result =3D cstring_to_text_with_len((char *) resstr, reslen); } PG_CATCH(); { @@ -155,6 +159,8 @@ xslt_process(PG_FUNCTION_ARGS) xsltFreeStylesheet(stylesheet); if (doctree !=3D NULL) xmlFreeDoc(doctree); + if (resstr !=3D NULL) + xmlFree((xmlChar *) resstr); xsltCleanupGlobals(); =20 pg_xml_done(xmlerrcxt, true); @@ -170,17 +176,15 @@ xslt_process(PG_FUNCTION_ARGS) xmlFreeDoc(doctree); xsltCleanupGlobals(); =20 + if (resstr) + xmlFree((xmlChar *) resstr); + pg_xml_done(xmlerrcxt, false); =20 /* XXX this is pretty dubious, really ought to throw error instead */ if (resstat < 0) PG_RETURN_NULL(); =20 - result =3D cstring_to_text_with_len((char *) resstr, reslen); - - if (resstr) - xmlFree(resstr); - PG_RETURN_TEXT_P(result); #else /* !USE_LIBXSLT */ =20 --=20 2.49.0 --DYI/odQVn+y4mvmw-- --4AnGqknsL3b4jo7x Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEG72nH6vTowiyblFKnvQgOdbyQH0FAmhCgqAACgkQnvQgOdby QH1P3BAAou9tUNtzcdzn6EaZuFxRJ64mx2NBnfrDSUwU9RCn4MwndqinJn0Kd3FR rr2XALxMS+cKIdZFyTSXN+UJH1OLyiv1cU0EUJ6KKf6rBkoAehm5eV7EElnWlmsE iW3H1Pl4PFZPnSQE9IVEOqXYJgAsjDPHyyH00MwOX3winYR9VuqFkO1oVpzLnmdc 2/03FzOk2khuR7raRmd3ej3hNKNYMx037CY75TGnTANfxMuEYnEl0rTwblomuqQt PvMD+bskYZ6UVv5eNZGIQLgV3nDRk10s+F6AP/NANptB4T3hdFUA+vlMc8wN3K47 8rZLOnxissSmHWwH+b6Xd73Z5dJdd3JAfKISbQ6FATNCotXE/BW2B/2pY3wxLVxR /D6UgxoSsH5aNTaNAk/owzdM7lun7fAkA7J55+vMSIPVRpTD/WlkXaviM79gw9WN I7WVLwswwsvIK4+v6ykzTeMzlemAMvNn/bUmF9WyGRpYIF00Q5xFObtww0sTyzdd tE2YOXvBAG0IYoZdvYPkB3n/rdp88FE7Kq/+BQEvqFkV0OuRr7Ph+Ri/+VV7beZD jPp1pKnS67ks8x4eFuhlnVi0aez59LBSf3Fx5RZhSEo0HeHgXiVF+S1AXNx+VFAG uLRocD3L/d4beJ0pb+L9TqE0GeXsXFiHmhRZTncR26GIdqXm9l4= =SBDg -----END PGP SIGNATURE----- --4AnGqknsL3b4jo7x--