From e2f4172643968b3623cf24ae2f00fbd1be252e09 Mon Sep 17 00:00:00 2001 From: Karl Williamson Date: Sun, 7 Mar 2021 07:33:33 -0700 Subject: [PATCH] locale.c: Add check that strxfrm didn't fail The code failed to take into account that strxfrm() can fail for reasons besides buffer length. It does not return errors, and the only way to check is to set errno to 0 beforehand, and check that it is still 0 afterwards. --- locale.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/locale.c b/locale.c index d21c8ecd40f1..d36db3279055 100644 --- a/locale.c +++ b/locale.c @@ -5439,16 +5439,25 @@ Perl__mem_collxfrm(pTHX_ const char *input_string, * give up */ for (;;) { + errno = 0; *xlen = strxfrm(xbuf + COLLXFRM_HDR_LEN, s, xAlloc - COLLXFRM_HDR_LEN); /* If the transformed string occupies less space than we told strxfrm() - * was available, it means it successfully transformed the whole - * string. */ + * was available, it means it transformed the whole string. */ if (*xlen < xAlloc - COLLXFRM_HDR_LEN) { - /* Some systems include a trailing NUL in the returned length. - * Ignore it, using a loop in case multiple trailing NULs are - * returned. */ + /* But there still could have been a problem */ + if (errno != 0) { + DEBUG_L(PerlIO_printf(Perl_debug_log, + "strxfrm failed for LC_COLLATE=%s; errno=%d, input=%s\n", + PL_collation_name, errno, + _byte_dump_string((U8 *) s, len, 1))); + goto bad; + } + + /* Here, the transformation was successful. Some systems include a + * trailing NUL in the returned length. Ignore it, using a loop in + * case multiple trailing NULs are returned. */ while ( (*xlen) > 0 && *(xbuf + COLLXFRM_HDR_LEN + (*xlen) - 1) == '\0') {