The mem_iconveh functions is documented to return an offsets[] array: If OFFSETS is not NULL, it should point to an array of SRCLEN integers; this array is filled with offsets into the result, i.e. the character starting at SRC[i] corresponds to the character starting at (*RESULTP)[OFFSETS[i]], and other offsets are set to (size_t)(-1).
In a couple of cases, OFFSETS[i] can point to the end of the result string: - When the input ends in an invalid character and handler == iconveh_error, - When the input is in a stateful encoding and ends in a shift sequence, - When the input ends in one or more Unicode LANGUAGE TAG characters. None of these leads to a bug in libunistring. But it's worth fixing anyway. 2026-08-16 Bruno Haible <[email protected]> striconveh: Ensure that none of the offsets[] are out-of-range. Reported by AISLE via Mike Fabian <[email protected]>. * lib/striconveh.c (mem_cd_iconveh_internal): Ensure that no offsets[i] is == length. * tests/test-striconveh.c (main): Adjust expected contents of the offsets[] array. * lib/striconveh.c (main): Likewise. * tests/test-striconveh.c (main): Likewise. * tests/test-striconveha.c (main): Likewise. * tests/uniconv/test-u8-conv-from-enc.c (main): Likewise. * tests/uniconv/test-u16-conv-from-enc.c (main): Likewise. * tests/uniconv/test-u32-conv-from-enc.c (main): Likewise. * tests/uniconv/test-u8-conv-to-enc.c (main): Likewise. * tests/uniconv/test-u16-conv-to-enc.c (main): Likewise. striconveh tests: Add some more test cases. * tests/test-striconveh.c (main): Add some more test cases for mem_iconveh() with offsets.
From e42d012275045cfa68c857fa648ab94c653fea0e Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sun, 16 Aug 2026 14:34:27 +0200 Subject: [PATCH 1/2] striconveh tests: Add some more test cases. * tests/test-striconveh.c (main): Add some more test cases for mem_iconveh() with offsets. --- ChangeLog | 6 +++ tests/test-striconveh.c | 83 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/ChangeLog b/ChangeLog index b2e2619314..a82a816666 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2026-08-16 Bruno Haible <[email protected]> + + striconveh tests: Add some more test cases. + * tests/test-striconveh.c (main): Add some more test cases for + mem_iconveh() with offsets. + 2026-08-16 Bruno Haible <[email protected]> malloc-posix: Fix file list (regression 2026-07-27). diff --git a/tests/test-striconveh.c b/tests/test-striconveh.c index ebb0a775c0..d4c45383ad 100644 --- a/tests/test-striconveh.c +++ b/tests/test-striconveh.c @@ -1367,6 +1367,89 @@ main () } } +# if (defined _LIBICONV_VERSION && !(_LIBICONV_VERSION == 0x10b && defined __APPLE__)) || (defined __GLIBC__ && !defined __UCLIBC__) + /* Test conversion from ISO-2022-JP-2 to UTF-8 with no errors, + but a trailing shift sequence. */ + { + static const char input[] = "Sch" "\033$(D+S\033(B" "ner Gru" "\033$(D)N\033(B"; /* "Schöner Gruß" */ + static const char expected[] = "Sch\303\266ner Gru\303\237"; + size_t *offsets = new_offsets (strlen (input)); + char *result = NULL; + size_t length = 0; + int retval = mem_iconveh (input, strlen (input), + "ISO-2022-JP-2", "UTF-8", + iconveh_question_mark, + offsets, + &result, &length); + ASSERT (retval == 0); + ASSERT (length == strlen (expected)); + ASSERT (result != NULL && memeq (result, expected, strlen (expected))); + for (size_t i = 0; i < 28; i++) + ASSERT (offsets[i] == (i <= 3 ? i : + i == 9 ? 5 : + i >= 13 && i <= 19 ? i - 7 : + i == 25 ? 14 : + (size_t)(-1))); + ASSERT (offsets[28] == MAGIC); + free (offsets); + free (result); + } + + /* Test conversion from UTF-8 to ISO-2022-JP-2 with no errors, + but a trailing shift sequence. */ + { + static const char input[] = "Sch\303\266ner Gru\303\237"; /* "Schöner Gruß" */ + static const char expected[] = "Sch" "\033$(D+S\033(B" "ner Gru" "\033$(D)N\033(B"; + size_t *offsets = new_offsets (strlen (input)); + char *result = NULL; + size_t length = 0; + int retval = mem_iconveh (input, strlen (input), + "UTF-8", "ISO-2022-JP-2", + iconveh_question_mark, + offsets, + &result, &length); + ASSERT (retval == 0); + ASSERT (length == strlen (expected)); + ASSERT (result != NULL && memeq (result, expected, strlen (expected))); + for (size_t i = 0; i < 14; i++) + ASSERT (offsets[i] == (i <= 3 ? i : + i == 5 ? 9 : + i >= 6 && i <= 12 ? i + 7 : + (size_t)(-1))); + ASSERT (offsets[14] == MAGIC); + free (offsets); + free (result); + } +# endif + +# if (defined __GLIBC__ && !defined __UCLIBC__) + /* Test conversion from UTF-8 to ASCII with no errors, + but some discarded characters. */ + { + static const char input[] = "a\363\240\201\270bc\363\240\201\246\363\240\201\262"; /* "a<U+E0078>bc<U+E0066><U+E0072>" */ + static const char expected[] = "abc"; + size_t *offsets = new_offsets (strlen (input)); + char *result = NULL; + size_t length = 0; + int retval = mem_iconveh (input, strlen (input), + "UTF-8", "ASCII", + iconveh_question_mark, + offsets, + &result, &length); + ASSERT (retval == 0); + ASSERT (length == strlen (expected)); + ASSERT (result != NULL && memeq (result, expected, strlen (expected))); + for (size_t i = 0; i < 15; i++) + ASSERT (offsets[i] == (i <= 1 ? i : + i == 6 ? 2 : + i == 7 ? 3 : + (size_t)(-1))); + ASSERT (offsets[15] == MAGIC); + free (offsets); + free (result); + } +# endif + /* ------------------------- Test str_iconveh() ------------------------- */ /* Test conversion from ISO-8859-2 to ISO-8859-1 with no errors. */ -- 2.53.0
>From 5f1137d6ba2f64dd9c1cf2eb05f0cac3172f210b Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sun, 16 Aug 2026 15:21:13 +0200 Subject: [PATCH 2/2] striconveh: Ensure that none of the offsets[] are out-of-range. Reported by AISLE via Mike Fabian <[email protected]>. * lib/striconveh.c (mem_cd_iconveh_internal): Ensure that no offsets[i] is == length. * tests/test-striconveh.c (main): Adjust expected contents of the offsets[] array. * lib/striconveh.c (main): Likewise. * tests/test-striconveh.c (main): Likewise. * tests/test-striconveha.c (main): Likewise. * tests/uniconv/test-u8-conv-from-enc.c (main): Likewise. * tests/uniconv/test-u16-conv-from-enc.c (main): Likewise. * tests/uniconv/test-u32-conv-from-enc.c (main): Likewise. * tests/uniconv/test-u8-conv-to-enc.c (main): Likewise. * tests/uniconv/test-u16-conv-to-enc.c (main): Likewise. --- ChangeLog | 15 +++++++++++++++ lib/striconveh.c | 17 +++++++++++++++++ tests/test-striconveh.c | 6 ++---- tests/test-striconveha.c | 3 +-- tests/uniconv/test-u16-conv-from-enc.c | 1 - tests/uniconv/test-u16-conv-to-enc.c | 2 +- tests/uniconv/test-u32-conv-from-enc.c | 1 - tests/uniconv/test-u8-conv-from-enc.c | 1 - tests/uniconv/test-u8-conv-to-enc.c | 2 +- 9 files changed, 37 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index a82a816666..f4efbc514b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ 2026-08-16 Bruno Haible <[email protected]> + striconveh: Ensure that none of the offsets[] are out-of-range. + Reported by AISLE via Mike Fabian <[email protected]>. + * lib/striconveh.c (mem_cd_iconveh_internal): Ensure that no offsets[i] + is == length. + * tests/test-striconveh.c (main): Adjust expected contents of the + offsets[] array. + * lib/striconveh.c (main): Likewise. + * tests/test-striconveh.c (main): Likewise. + * tests/test-striconveha.c (main): Likewise. + * tests/uniconv/test-u8-conv-from-enc.c (main): Likewise. + * tests/uniconv/test-u16-conv-from-enc.c (main): Likewise. + * tests/uniconv/test-u32-conv-from-enc.c (main): Likewise. + * tests/uniconv/test-u8-conv-to-enc.c (main): Likewise. + * tests/uniconv/test-u16-conv-to-enc.c (main): Likewise. + striconveh tests: Add some more test cases. * tests/test-striconveh.c (main): Add some more test cases for mem_iconveh() with offsets. diff --git a/lib/striconveh.c b/lib/striconveh.c index b345923d4e..cac2ce2d57 100644 --- a/lib/striconveh.c +++ b/lib/striconveh.c @@ -976,6 +976,23 @@ mem_cd_iconveh_internal (const char *src, size_t srclen, } done: + if (offsets != NULL) + { + /* Ensure that the last assigned offsets[i] is < length. + (We know that the sequence of assigned offsets[i] is strictly + monotonically increasing.) */ + for (size_t i = srclen; i > 0; ) + { + i--; + if (offsets[i] != (size_t)(-1)) + { + if (offsets[i] == length) + offsets[i] = (size_t)(-1); + break; + } + } + } + /* Now the final memory allocation. */ if (result == tmpbuf) { diff --git a/tests/test-striconveh.c b/tests/test-striconveh.c index d4c45383ad..71d0871e44 100644 --- a/tests/test-striconveh.c +++ b/tests/test-striconveh.c @@ -606,7 +606,7 @@ main () ASSERT (length == 0); if (o) { - ASSERT (offsets[0] == 0); + ASSERT (offsets[0] == (size_t)(-1)); ASSERT (offsets[1] == MAGIC); free (offsets); } @@ -1359,7 +1359,7 @@ main () ASSERT (length == 0); if (o) { - ASSERT (offsets[0] == 0); + ASSERT (offsets[0] == (size_t)(-1)); ASSERT (offsets[1] == MAGIC); free (offsets); } @@ -1388,7 +1388,6 @@ main () ASSERT (offsets[i] == (i <= 3 ? i : i == 9 ? 5 : i >= 13 && i <= 19 ? i - 7 : - i == 25 ? 14 : (size_t)(-1))); ASSERT (offsets[28] == MAGIC); free (offsets); @@ -1442,7 +1441,6 @@ main () for (size_t i = 0; i < 15; i++) ASSERT (offsets[i] == (i <= 1 ? i : i == 6 ? 2 : - i == 7 ? 3 : (size_t)(-1))); ASSERT (offsets[15] == MAGIC); free (offsets); diff --git a/tests/test-striconveha.c b/tests/test-striconveha.c index 52d8434b15..1626db9204 100644 --- a/tests/test-striconveha.c +++ b/tests/test-striconveha.c @@ -297,7 +297,7 @@ main () ASSERT (length == 0); if (o) { - ASSERT (offsets[0] == 0); + ASSERT (offsets[0] == (size_t)(-1)); ASSERT (offsets[1] == MAGIC); free (offsets); } @@ -393,7 +393,6 @@ main () i == 7 ? 6 : i == 9 ? 9 : i == 11 ? 12 : - i == 13 ? 15 : (size_t)(-1))); ASSERT (offsets[16] == MAGIC); free (offsets); diff --git a/tests/uniconv/test-u16-conv-from-enc.c b/tests/uniconv/test-u16-conv-from-enc.c index ef19ed98ec..49ffc8bbba 100644 --- a/tests/uniconv/test-u16-conv-from-enc.c +++ b/tests/uniconv/test-u16-conv-from-enc.c @@ -205,7 +205,6 @@ main () i == 7 ? 2 : i == 9 ? 3 : i == 11 ? 4 : - i == 13 ? 5 : (size_t)(-1))); ASSERT (offsets[16] == MAGIC); free (offsets); diff --git a/tests/uniconv/test-u16-conv-to-enc.c b/tests/uniconv/test-u16-conv-to-enc.c index 5a5abd5e8d..15700da2c9 100644 --- a/tests/uniconv/test-u16-conv-to-enc.c +++ b/tests/uniconv/test-u16-conv-to-enc.c @@ -162,7 +162,7 @@ main () ASSERT (length == strlen ("")); if (o) { - ASSERT (offsets[0] == 0); + ASSERT (offsets[0] == (size_t)(-1)); ASSERT (offsets[1] == MAGIC); free (offsets); } diff --git a/tests/uniconv/test-u32-conv-from-enc.c b/tests/uniconv/test-u32-conv-from-enc.c index 597005dad6..70c8005a2a 100644 --- a/tests/uniconv/test-u32-conv-from-enc.c +++ b/tests/uniconv/test-u32-conv-from-enc.c @@ -205,7 +205,6 @@ main () i == 7 ? 2 : i == 9 ? 3 : i == 11 ? 4 : - i == 13 ? 5 : (size_t)(-1))); ASSERT (offsets[16] == MAGIC); free (offsets); diff --git a/tests/uniconv/test-u8-conv-from-enc.c b/tests/uniconv/test-u8-conv-from-enc.c index c3f679bacb..cd98f82564 100644 --- a/tests/uniconv/test-u8-conv-from-enc.c +++ b/tests/uniconv/test-u8-conv-from-enc.c @@ -191,7 +191,6 @@ main () i == 7 ? 6 : i == 9 ? 9 : i == 11 ? 12 : - i == 13 ? 15 : (size_t)(-1))); ASSERT (offsets[16] == MAGIC); free (offsets); diff --git a/tests/uniconv/test-u8-conv-to-enc.c b/tests/uniconv/test-u8-conv-to-enc.c index 362a280531..f02d9181e9 100644 --- a/tests/uniconv/test-u8-conv-to-enc.c +++ b/tests/uniconv/test-u8-conv-to-enc.c @@ -166,7 +166,7 @@ main () ASSERT (length == strlen ("")); if (o) { - ASSERT (offsets[0] == 0); + ASSERT (offsets[0] == (size_t)(-1)); ASSERT (offsets[1] == MAGIC); free (offsets); } -- 2.53.0
