[PATCH] Fix heap-buffer-overflow in PGTYPEStimestamp_defmt_scan()
Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.
You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:
docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t253479psql -h localhost -U postgresBuilt from patchset v3 (message #3), August 23, 2026 at 09:32 AM.
Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:
git clone --branch t253479_3 https://github.com/hackorum-dev/postgres.gitIn a checkout you already have, add the fork once:
git remote add hackorum https://github.com/hackorum-dev/postgres.gitthen, for this patchset and every later one:
git fetch hackorum t253479_3 && git checkout t253479_3Patchset v3 (message #3) is on t253479_3
Hello, hackers!
We used the Clang Static Analyzer and found a heap-buffer-overflow in the PGTYPEStimestamp_defmt_scan() function inside src/interfaces/ecpg/pgtypeslib/dt_common.c. When processing template tokens like '%D', '%r', '%R', or '%T', the code allocates a temporary buffer based on the length of the remaining input string (pstr). However, it later concatenates the remaining format string (pfmt) into this buffer using strcat(). If an application attempts to parse a short or truncated time string using a longer, complex format pattern, the format string suffix will exceed the allocated memory, causing a heap-buffer-overflow.
The issue can be reproduced with a minimal test case (compiling this with AddressSanitizer):
timestamp ts;
PGTYPEStimestamp_defmt_asc("1", "%D %H:%M:%S", &ts);
ERROR: AddressSanitizer: heap-buffer-overflow WRITE of size 10 at 0x... 0 bytes after 10-byte region
#0 strcat
#1 PGTYPEStimestamp_defmt_scan dt_common.c:2667
#2 PGTYPEStimestamp_defmt_asc timestamp.c:841 allocated by pgtypes_alloc common.c:12
The solution is to allocate memory based on the length of the format string (pfmt) instead of the input string (pstr), as it is the string being appended.
Best regards,
Maria Sivirilova
Kanatbek Kanybekov
On 19 Aug 2026, at 08:55, Sivirilova Marija <m.sivirilova@ftdata.ru> wrote:
Hello, hackers!
We used the Clang Static Analyzer and found a heap-buffer-overflow in the PGTYPEStimestamp_defmt_scan() function inside src/interfaces/ecpg/pgtypeslib/dt_common.c. When processing template tokens like '%D', '%r', '%R', or '%T', the code allocates a temporary buffer based on the length of the remaining input string (pstr). However, it later concatenates the remaining format string (pfmt) into this buffer using strcat(). If an application attempts to parse a short or truncated time string using a longer, complex format pattern, the format string suffix will exceed the allocated memory, causing a heap-buffer-overflow.
The issue can be reproduced with a minimal test case (compiling this with AddressSanitizer):
Can you please add testcases to the patch, to make sure we cover these
edgecases in the regression tests.
--
Daniel Gustafsson
I'm sending you an updated patch. A test has been added to src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc. It works without compiling AddressSanitizer.
Test result before patch:
...
interval_copy[5]: @ 1 year 59 mins
Error parsing interval 6
free(): invalid next size (fast)
Aborted (core dumped)
After patch:
...
interval_copy[5]: @ 1 year 59 mins
Error parsing interval 6
Success parsing large string
--
Maria Sivirilova
-----Original Message-----
From: Daniel Gustafsson <daniel@yesql.se>
Sent: Wednesday, August 19, 2026 3:12 PM
To: Сивирилова Мария Константиновна <m.sivirilova@ftdata.ru>
Cc: pgsql-hackers@lists.postgresql.org
Subject: Re: [PATCH] Fix heap-buffer-overflow in PGTYPEStimestamp_defmt_scan()
On 19 Aug 2026, at 08:55, Sivirilova Marija <m.sivirilova@ftdata.ru> wrote:
Hello, hackers!
We used the Clang Static Analyzer and found a heap-buffer-overflow in the PGTYPEStimestamp_defmt_scan() function inside src/interfaces/ecpg/pgtypeslib/dt_common.c. When processing template tokens like '%D', '%r', '%R', or '%T', the code allocates a temporary buffer based on the length of the remaining input string (pstr). However, it later concatenates the remaining format string (pfmt) into this buffer using strcat(). If an application attempts to parse a short or truncated time string using a longer, complex format pattern, the format string suffix will exceed the allocated memory, causing a heap-buffer-overflow.
The issue can be reproduced with a minimal test case (compiling this with AddressSanitizer):
Can you please add testcases to the patch, to make sure we cover these edgecases in the regression tests.
--
Daniel Gustafsson
On 19 Aug 2026, at 11:13, Sivirilova Marija <m.sivirilova@ftdata.ru> wrote:
I'm sending you an updated patch. A test has been added to src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc. It works without compiling AddressSanitizer.
Thanks. For anyone reviewing (I at least won't have time for a few days):
there is also an earlier patch submitted for fixing this bug which should be
considered to make sure we pick the best fix.
/messages/by-id/CAB8bMiuv0T175FkbcFi_jGN1kp_0S_cYLyHXFiL7RvyuqqQrjg@mail.gmail.com
--
Daniel Gustafsson
Hello!
The fix itself looks good to me, I only seem some issues in the test.
--- a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
+++ b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
If the test produces additional output, you should also update the output file. (but also see my later comment about this)
+ char large_fmt[10000] = {
+ [0] = '%',
+ [1] = 'D',
+ [2 ... 9998] = 'A'
+ };
+
2...9998 is a GNU extension, it won't compile on MSVC.
+ PGTYPEStimestamp_defmt_asc("1 minute", large_fmt, &ts1);
+ printf("Success parsing large string\n");
Won't this fail parsing? I am not saying that it wouldn't trigger an asan/valgrind report when executed with that and the original code, but that printed message is misleading. (it won't succeed ; we aren't parsing a large string, it's a small string parsed with a large format string). It also only tests 1 of the 4 fixed locations.
I probably wouldn't print anything for these tests, as the output won't help deciding if the test failed or passed, it is always the same. Maybe a comment explaining that these calls can trigger asan/valgrind would be more useful?
For anyone reviewing (I at least won't have time for a few days):
there is also an earlier patch submitted for fixing this bug which should be
considered to make sure we pick the best fix.
These seems to be similar but different issue to me.