Re: XML functions can exhaust backend memory with libxml2 < 2.11

From: Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com>
To: Jim Jones <jim(dot)jones(at)uni-muenster(dot)de>
Cc: PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: XML functions can exhaust backend memory with libxml2 < 2.11
Date: 2026-11-12 08:17:36
Message-ID: CADC0DFF-9C3B-4E02-AA70-6DBF5F644D48@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

> On Nov 11, 2026, at 19:06, Jim Jones <jim(dot)jones(at)uni-muenster(dot)de> wrote:
>
> Hi
>
> xml_errorHandler() appends every libxml2 error to err_buf without a
> limit. libxml2 caps reported parser errors at 100 (XML_MAX_ERRORS [1,2])
> since 2.11, but older versions, still shipped by current distributions,
> report them all. A document with one non-fatal namespace error per
> element can make err_buf reach MaxAllocSize, and enlargeStringInfo()
> then raises ERROR from inside the libxml2 callback. The longjmp abandons
> the document libxml2 was building, so it is not freed until the session
> ends.
>
> Any user can trigger it with xpath(), xmlexists() or xmltable. Depending
> on the host, a few calls get the backend killed by the OOM killer. I was
> able to reproduce it with the postgres:18 docker image:
>
> $ podman run -d --name pgtest --memory 3g --memory-swap 3g -e
> POSTGRES_HOST_AUTH_METHOD=trust postgres:18 -c logging_collector=on
> 18b8de253790882cbbf3a0f63828d1ea136723f6d2e7a3f3379cf8e079b08f71
>
> $ podman exec -itu postgres pgtest psql
> psql (18.6 (Debian 18.6-1.pgdg13+2))
> Type "help" for help.
>
> postgres=# select xpath('/r', ('<r>' || repeat('<p:a/>', 5200000) ||
> '</r>')::xml) is not null;
> ERROR: string buffer exceeds maximum allowed length (1073741823 bytes)
> DETAIL: Cannot enlarge string buffer containing 1073741630 bytes by 208
> more bytes.
> postgres=# select xpath('/r', ('<r>' || repeat('<p:a/>', 5200000) ||
> '</r>')::xml) is not null;
> ERROR: string buffer exceeds maximum allowed length (1073741823 bytes)
> DETAIL: Cannot enlarge string buffer containing 1073741630 bytes by 208
> more bytes.
> postgres=# select xpath('/r', ('<r>' || repeat('<p:a/>', 5200000) ||
> '</r>')::xml) is not null;
> server closed the connection unexpectedly
> This probably means the server terminated abnormally
> before or while processing the request.
> The connection to the server was lost. Attempting reset: Failed.
> The connection to the server was lost. Attempting reset: Failed.
> !?> \! grep oom_kill /sys/fs/cgroup/memory.events
> oom_kill 1
> !?> \! grep -h "terminated by signal" $PGDATA/log/*.log
> 2026-11-11 10:18:22.585 UTC [1] LOG: client backend (PID 76) was
> terminated by signal 9: Killed
> !?>
>
> The attached patch stops collecting messages after 100, the same limit
> libxml2 2.11+ applies itself with XML_MAX_ERRORS, but I am not sure this
> is the right way to fix it. Any suggestions on this approach?
>
> Best, Jim
>
> 1 - https://github.com/GNOME/libxml2/blob/master/parserInternals.c#L54
> 2 -
> https://github.com/GNOME/libxml2/commit/59b33661784359c6d3a8309ddbd2129fb2688548<v1-0001-Limit-the-number-of-libxml2-messages-collected-in.patch>

I just have a question. Though libxml2 caches 1000 messages, if PG has to follow that? Can we just keep the first relevant error?

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Jim Jones 2026-11-12 08:40:56 Re: XML functions can exhaust backend memory with libxml2 < 2.11
Previous Message Amit Kapila 2026-11-12 07:57:48 Re: Crashes on a partition whose concurrent detach never finished