Skip to content

PDC_wcstombs() zeroes the first byte when the output exactly fills the buffer (regression in ea9baa42) #390

Description

@serhiy-storchaka

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';

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions