Ingo Schwarze <[email protected]> writes:

> Hi,
>
> did i mention already that libc wide character code is buggy as hell?
> I looked at another very simple function of only 30 lines of code
> and promptly found another bug.
>
> The fgetwln(3) manual is quite explicit that the "fgetwln() function
> may also fail ... for any of the errors specified for ... mbrtowc(3)"
> and that it must return NULL in case of failure.  That's sensible;
> we shouldn't expect programmers to inspect ferror(3) or errno(2)
> after getting a function return value indicating success.
>
> However, after reading a single valid character, fgetwln(3) will
> mistreat all subsequent encoding errors as newlines - returning
> success when encountering an invalid encoding, but still setting
> both errno(3) and the stdio error indicator.
>
> OK to commit the following patch?

Makes sense to me.

> Note that it will make programs using fgetwln(3), in particular in
> ports, error out more frequently, and no longer permit reading of
> streams containing encoding errors with this function.  But trying
> to do so wasn't reliable in the past anyway, because encoding errors
> right after newlines already caused the function to error out.
>
> Also note that FreeBSD and NetBSD contain the same bug.
> Actually, i found the bug because i played with FreeBSD rev(1) code
> on OpenBSD and was surprised by its absurd behaviour when fed input
> containing encoding errors.
>
> Yours,
>   Ingo
>
>
> Index: stdio/fgetwln.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/stdio/fgetwln.c,v
> retrieving revision 1.1
> diff -p -U11 -r1.1 fgetwln.c
> --- stdio/fgetwln.c   12 Jan 2015 20:58:07 -0000      1.1
> +++ stdio/fgetwln.c   21 Aug 2016 14:00:32 -0000
> @@ -59,23 +59,23 @@ fgetwln(FILE * __restrict fp, size_t *le
>  
>       len = 0;
>       while ((wc = __fgetwc_unlock(fp)) != WEOF) {
>  #define      GROW    512
>               if (len >= fp->_lb._size / sizeof(wchar_t) &&
>                   __slbexpand(fp, len + GROW))
>                       goto error;
>               *((wchar_t *)fp->_lb._base + len++) = wc;
>               if (wc == L'\n')
>                       break;
>       }
> -     if (len == 0)
> +     if (len == 0 || fp->_flags & __SERR)
>               goto error;
>  
>       FUNLOCKFILE(fp);
>       *lenp = len;
>       return (wchar_t *)fp->_lb._base;
>  
>  error:
>       FUNLOCKFILE(fp);
>       *lenp = 0;
>       return NULL;
>  }
>

-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to