Re: winsch() recurses without bound when wcwidth() returns -1
Thomas Dickey <[email protected]> Thu, 30 Jul 2026 15:31:53 -0400
| Newsgroups | gmane.comp.lib.ncurses.bugs |
|---|---|
| Message-ID | <[email protected]> |
--Qhqucl5WIQQcm4FU
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Thu, Jul 30, 2026 at 07:19:10PM +0300, Serhiy Storchaka wrote:
> ncurses/widechar/lib_ins_wch.c:
>=20
> int cells =3D _nc_wacs_width(CharOf(CHDEREF(wch)));
>=20
> if (cells < 0) {
> code =3D winsch(win, (chtype) CharOf(CHDEREF(wch)));
> } else {
>=20
> winsch() calls _nc_insert_ch(), which passes a non-control character
> to its wide branch, where _nc_build_wch() builds the same character
> and gives it back to _nc_insert_wch(), which finds the same negative
> width:
>=20
> frame #0: _nc_build_wch + 197
> frame #1: _nc_insert_ch + 395
> frame #2: winsch + 41
> frame #3: _nc_insert_ch + 415
> frame #4: winsch + 41
> ...
>=20
> To repeat:
>=20
> /* cc winsch_recurse.c -lncursesw -o winsch_recurse
> LC_ALL=3Den_US.ISO8859-15 TERM=3Dxterm ./winsch_recurse 0xA4 */
> #include <curses.h>
> #include <locale.h>
> #include <stdio.h>
>=20
> int main(void)
> {
> FILE *f =3D fopen("/dev/null", "w+");
>=20
> setlocale(LC_ALL, "");
> newterm("xterm", f, f);
> winsch(stdscr, (chtype) 0xA4);
> fprintf(stderr, "ok\n");
> endwin();
> return 0;
> }
>=20
> It takes a byte that is not a control character and whose wcwidth() is
> negative. FreeBSD 15.1 has 57 of them in en_US.ISO8859-15 and 54 in
> uk_UA.KOI8-U, because there wchar_t holds the locale value rather than
> a code point; each crashes with the system libncursesw.so.9
> (6.6.20251230) and with the 2026-07-19 snapshot. On glibc such a byte
> does not seem to exist, and the same snapshot does not crash in any
> locale I tried. UTF-8 locales are unaffected on both.
yes... the BSDs differ from glibc (iirc, {Free,Net,Open}BSD don't match
each other, either)
thanks
=20
> Found through Python's curses module, whose test suite calls insstr().
>=20
> A character that the locale cannot represent has no width to insert,
> so returning ERR ends the recursion:
>=20
> --- a/ncurses/widechar/lib_ins_wch.c
> +++ b/ncurses/widechar/lib_ins_wch.c
> @@
> if (cells < 0) {
> - code =3D winsch(win, (chtype) CharOf(CHDEREF(wch)));
> + code =3D ERR;
> } else {
>=20
> With that the reproducer returns for every byte and locale I tried,
> and a byte with a positive width is unaffected. I do not know whether
> ERR is the right return there, or whether such a character should be
> treated as one cell.
probably it should be stored according to its representation with unctrl
(two cells) since this is similar to waddch.
--=20
Thomas E. Dickey <[email protected]>
https://invisible-island.net
--Qhqucl5WIQQcm4FU
Content-Type: application/pgp-signature; name="signature.asc"
-----BEGIN PGP SIGNATURE-----
iQGzBAABCgAdFiEEGYgtkt2kxADCLA1WzCr0RyFnvgMFAmprpqUACgkQzCr0RyFn
vgONnAwAqHPgljbpSEhudcrTfUma81BIDHmx9Q43/hoQ1DRlsCL2VzYJ/I3PgEAx
SLfUSAixIuIgkkWuzdOYwxlbsUKsJt8mXQP750vxPgK6ZS4RUFWjFxWH6h7ZjfCA
5zNfPNMTqGHhcCuaq9PGldj5M9riGexkH3z1qsKGEMN+KHAgLmnj7fnZ300a1mAK
lQP86kQ+Yz/j+pvDYK+CvBZmoB7PMpUFpRYNXcoTezPxRTbE7qay+lowjqAwrprE
iJVFEn432nu6/PQfPfjd7qEDmCC2WkwtHKhbUECNX5ChPC/6zHQ7WyDZmK6t4aSV
suuVQS9TascvaPX4FDMiaxqMcyPBc95wywu3d0WLnLO4/PAIz0igJPqPGrWsTTaW
+cnF2hUhRiIaxUhXyco8UsCpmwdtY/pPvsWXj82QPFQgGTkgPIt3PVbAHgIm9txj
DnAnSMvCcErJpbCSCj8GeAi9TxA3KKoljdeY6NP5NoFvpQIVlw5/gL1CjbVtWDL3
z0E78eTB
=D3sq
-----END PGP SIGNATURE-----
--Qhqucl5WIQQcm4FU--