Since ea9baa4 ("PDC_wcstombs() now returns a null-terminated string if it hits an un-encodeable wide character or runs out of buffer space", #384), PDC_wcstombs() treats an output that exactly fills the buffer as an error and overwrites its first byte:
size_t i = wcstombs(dest, src, n);
...
assert( -1 != (int)i && i < n);
if( (int)i < 0 || i >= n) /* invalid sequence or insufficient space */
*dest = '\0';
else
dest[i] = '\0';
wcstombs() returns n when the converted string fills all n bytes; that is a complete conversion, not a failure, and the previous code handled it by writing the terminator at dest[n]. Now a converted string is destroyed in the common case, and in a build with assertions enabled the assert fails and the program aborts.
winnstr() hits this on every call, since it converts n wide characters into n bytes:
WINDOW *win = newwin(1, 20, 0, 0);
char buf[16];
mvwaddstr(win, 0, 0, "ABCDE");
int rc = mvwinnstr(win, 0, 0, buf, 5);
/* rc == 5, buf == "\0BCDE" -- was "ABCDE" before ea9baa42 */
wgetnstr() is affected the same way, so with a wide build every instr()/getstr() of single-byte text comes back with a NUL first byte (CPython's test_curses shows b'\x00BCDE' for instr() and b'' for getstr(); it passes against d226010).
A second problem is how the failure is detected: i is a size_t and wcstombs() reports an error as (size_t)-1, so (int)i < 0 (and -1 != (int)i in the assert) relies on implementation-defined narrowing, and would also reject a valid result above INT_MAX. The check should be i == (size_t)-1. Since wcstombs() never returns more than n, that is the only case that needs *dest = '\0':
if( i == (size_t)-1) /* invalid sequence */
*dest = '\0';
else
dest[i] = '\0';
Since ea9baa4 ("PDC_wcstombs() now returns a null-terminated string if it hits an un-encodeable wide character or runs out of buffer space", #384),
PDC_wcstombs()treats an output that exactly fills the buffer as an error and overwrites its first byte:wcstombs()returnsnwhen the converted string fills allnbytes; that is a complete conversion, not a failure, and the previous code handled it by writing the terminator atdest[n]. Now a converted string is destroyed in the common case, and in a build with assertions enabled the assert fails and the program aborts.winnstr()hits this on every call, since it convertsnwide characters intonbytes:wgetnstr()is affected the same way, so with a wide build everyinstr()/getstr()of single-byte text comes back with a NUL first byte (CPython'stest_cursesshowsb'\x00BCDE'forinstr()andb''forgetstr(); it passes against d226010).A second problem is how the failure is detected:
iis asize_tandwcstombs()reports an error as(size_t)-1, so(int)i < 0(and-1 != (int)iin the assert) relies on implementation-defined narrowing, and would also reject a valid result aboveINT_MAX. The check should bei == (size_t)-1. Sincewcstombs()never returns more thann, that is the only case that needs*dest = '\0':