Fix crash introduced by incorrect backport 806555e300.

Commit 7f007e4a04 in master depends on 1476028225, but the latter was
not backported. Therefore 806555e300 (the backport of commit
7f007e4a04) incorrectly used pg_strfold() in a locale where
ctype_is_c.

The fix is to simply have the callers check for ctype_is_c.

Because 7f007e4a04 was only backported to version 18, and because the
commit in master is fine, this fix only exists in version 18.

Reported-by: Александр Кожемякин <a.kozhemyakin@postgrespro.ru>
Discussion: https://postgr.es/m/456f7143-51ea-4342-b4a1-85f0d9b6c79f@postgrespro.ru
This commit is contained in:
Jeff Davis 2026-01-27 08:16:07 -08:00
parent 919c9fa13c
commit 8993bf0991
2 changed files with 43 additions and 12 deletions

View file

@ -30,20 +30,34 @@ ltree_crc32_sz(const char *buf, int size)
locale = pg_newlocale_from_collation(DEFAULT_COLLATION_OID);
INIT_TRADITIONAL_CRC32(crc);
while (size > 0)
if (locale->ctype_is_c)
{
char foldstr[UNICODE_CASEMAP_BUFSZ];
int srclen = pg_mblen(p);
size_t foldlen;
while (size > 0)
{
char c = pg_ascii_tolower(*p);
/* fold one codepoint at a time */
foldlen = pg_strfold(foldstr, UNICODE_CASEMAP_BUFSZ, p, srclen,
locale);
COMP_TRADITIONAL_CRC32(crc, &c, 1);
size--;
p++;
}
}
else
{
while (size > 0)
{
char foldstr[UNICODE_CASEMAP_BUFSZ];
int srclen = pg_mblen(p);
size_t foldlen;
COMP_TRADITIONAL_CRC32(crc, foldstr, foldlen);
/* fold one codepoint at a time */
foldlen = pg_strfold(foldstr, UNICODE_CASEMAP_BUFSZ, p, srclen,
locale);
size -= srclen;
p += srclen;
COMP_TRADITIONAL_CRC32(crc, foldstr, foldlen);
size -= srclen;
p += srclen;
}
}
FIN_TRADITIONAL_CRC32(crc);
return (unsigned int) crc;

View file

@ -96,15 +96,32 @@ ltree_prefix_eq_ci(const char *a, size_t a_sz, const char *b, size_t b_sz)
static pg_locale_t locale = NULL;
size_t al_sz = a_sz + 1;
size_t al_len;
char *al = palloc(al_sz);
char *al;
size_t bl_sz = b_sz + 1;
size_t bl_len;
char *bl = palloc(bl_sz);
char *bl;
bool res;
if (!locale)
locale = pg_newlocale_from_collation(DEFAULT_COLLATION_OID);
if (locale->ctype_is_c)
{
if (a_sz > b_sz)
return false;
for (int i = 0; i < a_sz; i++)
{
if (pg_ascii_tolower(a[i]) != pg_ascii_tolower(b[i]))
return false;
}
return true;
}
al = palloc(al_sz);
bl = palloc(bl_sz);
/* casefold both a and b */
al_len = pg_strfold(al, al_sz, a, a_sz, locale);