Hi Theo, Theo de Raadt wrote on Wed, Jul 26, 2017 at 08:07:53AM -0600: > Ingo Schwarze wrote:
>> The current behaviour of our implementation is to return the number >> of characters printed *and* set errno = ENOMEM. > I expect it should not set errno. As a general rule, errno should > only be set if an error has been indicated. Other short operations > don't set errno. Ooops, i overlooked the last sentence, sorry. Some *do* set errno. For example, the PRINT() macro calls __sprint() which calls __sfvwrite() in fvwrite.c which contains: _base = recallocarray(fp->_bf._base, fp->_bf._size + 1, _size + 1, 1); if (_base == NULL) goto err; and w = (*fp->_write)(fp->_cookie, p, w); if (w <= 0) goto err; and err: fp->_flags |= __SERR; return (EOF); and then PRINT() does if (__sprint(fp, &uio)) \ goto error; \ error: va_end(orgap); if (__sferror(fp)) ret = -1; goto finish; And invalid multibyte sequences in the format string cause short operations, returning -1 and setting EILSEQ. Same for invalid wide character codes in %lc and %ls arguments. __find_arguments() in GETASTER() is yet another example of a case that can cause a short operation by mmap(2) failure, returning -1 and setting errno. Looking through the code, i failed to find any case of a short operation that allows printf to still succeed apart from the four dtoa() instances we are discussing right now, and none at all that do not set errno. (Not absolutely sure because the code is of substantial size.) So not only does errno get set on typical short operations, but -1 gets returned as well, both for malloc(3) and write(3) failure and EILSEQ and EOVERFLOW, even if something was already written earlier. That seems like yet another argument to always return -1 on malloc(3) failure, answering the good question that kettenis@ asked: Should *printf() fail or succeed? I say, fail. Yours, Ingo