Re: Speed up ICU case conversion by using ucasemap_utf8To*()
Andreas Karlsson <andreas@proxel.se>
From: Andreas Karlsson <andreas@proxel.se>
To: Alexander Lakhin <exclusion@gmail.com>, Jeff Davis <pgsql@j-davis.com>,
zengman <zengman@halodbtech.com>,
pgsql-hackers <pgsql-hackers@postgresql.org>
Date: 2026-04-01T00:46:23Z
Lists: pgsql-hackers
Attachments
- v1-0001-Fix-overrun-when-comparing-with-unterminated-ICU-.patch (text/x-patch) patch v1-0001
On 3/12/26 5:00 AM, Alexander Lakhin wrote:
> I've discovered that starting from c4ff35f10, the following query:
> CREATE COLLATION c (provider = icu, locale = 'icu_something');
>
> makes asan detect (maybe dubious, but still..) stack-buffer-overflow:
> ==21963==ERROR: AddressSanitizer: stack-buffer-overflow on address
> 0x7ffd386d4e63 at pc 0x650cd7972a76 bp 0x7ffd386d4e00 sp 0x7ffd386d45a8
> ...
> Address 0x7ffd386d4e63 is located in stack of thread T0 at offset 67 in
> frame
> #0 0x650cd86962ef in foldcase_options (.../usr/local/pgsql/bin/
> postgres+0x12322ef) (BuildId: e441a9634858193e7358e5901e7948606ff5b1b1)
>
> This frame has 2 object(s):
> [48, 52) 'status' (line 993)
> [64, 67) 'lang' (line 992) <== Memory access at offset 67 overflows
> this variable
>
> I use a build made with:
> CC=gcc-13 CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address -
> static-libasan" ./configure --with-icu ...
>
> Could you please have a look?
Thanks for finding this!
Interestingly this bug seems like it would be there even before my
patch, but maybe something I did made it when moving code around made it
possible or easier to trigger. As far as I can tell the issue is that
uloc_getLanguage(locale, lang, 3, &status);
will populate lang with a string which is not zero terminated if the
language is 3 or more characters, e.g. "und". And for some reason which
I am not entirely strcmp("tr", {'u','n','d'}) can cause an overflow.
Maybe due to some optimization?
My proposed fix is that we allocate a ULOC_LANG_CAPACITY buffer for the
language like we do in fix_icu_locale_str() instead of trying to be
clever. An alternative would be to use strncmp("tr", lang, 3) but that
seems too clever for my taste in something which is not performance
critical. A third option would be to check for
U_STRING_NOT_TERMINATED_WARNING but I think that would just be
unnecessarily convoluted code.
I have attached my proposed fix.
Andreas
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Check for unterminated strings when calling uloc_getLanguage().
- dacd8fa6f259 19 (unreleased) landed
- ca938ec213d9 18.4 landed
- a756067a0e3b 17.10 landed
- 8167371704bd 16.14 landed
-
Fix overrun when comparing with unterminated ICU language string.
- 6393259bd49d 18.4 landed
- 06ce97b9994e 19 (unreleased) landed
-
ICU: use UTF8-optimized case conversion API
- c4ff35f10441 19 (unreleased) landed