Date: Fri, 25 Mar 2022 10:50:41 -0400 From: Mark Johnston <markj@freebsd.org> To: Guy Yur <guyyur@gmail.com> Cc: freebsd-current <freebsd-current@freebsd.org>, Konstantin Belousov <kib@freebsd.org> Subject: Re: Interrupted fputc followed by fprintf in _IOLBF mode causes core dump Message-ID: <Yj3WwYBSCvbZJcKo@nuc> In-Reply-To: <CAC67Hz-P9xp-1OSuh8VW8OBTqQJj1zTQHhDxwUqN_%2BVsK1%2BCsg@mail.gmail.com> References: <CAC67Hz-P9xp-1OSuh8VW8OBTqQJj1zTQHhDxwUqN_%2BVsK1%2BCsg@mail.gmail.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, Mar 25, 2022 at 03:18:40PM +0300, Guy Yur wrote: > Hi, > > dhcpcd on head (Mar 24) and 13.1-BETA2 crashes in fprintf/__sfvwrite. > It doesn't crash if If I revert the __sflush/__sfvwrite commits: > 86a16ada1ea608408cec370171d9f59353e97c77 and > bafaa70b6f9098d83d074968c8e6747ecec1e118. > > Stack trace: > 0 memcpy () at /usr/src/lib/libc/amd64/string/memmove.S:314 > #1 0x00000008221c300a in __sfvwrite (fp=<optimized out>, > uio=0x8207ad338) at /usr/src/lib/libc/stdio/fvwrite.c:182 > #2 0x00000008221cc631 in __sprint (fp=0x26fffe, uio=0x8207ad2d7, > locale=<optimized out>) at /usr/src/lib/libc/stdio/vfprintf.c:166 > #3 io_flush (iop=0x8207ad330, locale=<optimized out>) at > /usr/src/lib/libc/stdio/printfcommon.h:157 > #4 __vfprintf (fp=fp@entry=0x8222892d0, locale=locale@entry=0x822288ab8 > <__xlocale_global_locale>, fmt0=<optimized out>, fmt0@entry=0x204182 "%s", > ap=<optimized out>, ap@entry=0x8207ad4e0) at > /usr/src/lib/libc/stdio/vfprintf.c:1033 > #5 0x00000008221c8aea in vfprintf_l (fp=0x8222892d0, locale=0x822288ab8 > <__xlocale_global_locale>, fmt0=0x204182 "%s", ap=0x8207ad4e0) > at /usr/src/lib/libc/stdio/vfprintf.c:285 > #6 0x0000000000222efa in vlogprintf_r (ctx=0x270820 <_logctx>, > stream=0x8222892d0, fmt=0x204182 "%s", args=0x8207adad0) at logerr.c:186 > ... > > (gdb) frame 5 > #5 0x00000008221c8aea in vfprintf_l (fp=0x8222892d0, locale=0x822288ab8 > <__xlocale_global_locale>, fmt0=0x204182 "%s", ap=0x8207ad4e0) > at /usr/src/lib/libc/stdio/vfprintf.c:285 > 285 ret = __vfprintf(fp, locale, fmt0, ap); > (gdb) p *fp > $1 = {_p = 0x27084f <_logctx+47> "e21:3e7c\n42a/64\n", _r = 0, _w = > -1025, _flags = 2057, _file = 2, _bf = {_base = 0x270820 <_logctx> > "*\"", _size = 1024}, > _lbfsize = -1024, _cookie = 0x8222892d0, _close = 0x8221c7b40 > <__sclose>, _read = 0x8221c7af0 <__sread>, _seek = 0x8221c7b30 > <__sseek>, > _write = 0x8221c7b10 <__swrite>, _ub = {_base = 0x0, _size = 0}, _up > = 0x0, _ur = 0, _ubuf = "\000\000", _nbuf = "", _lb = {_base = 0x0, > _size = 0}, > _blksize = 4096, _offset = 0, _fl_mutex = 0x0, _fl_owner = 0x0, > _fl_count = 0, _orientation = -1, _mbstate = {__mbstate8 = '\000' > <repeats 127 times>, > _mbstateL = 0}, _flags2 = 0} > > (gdb) frame 1 > #1 0x00000008221c300a in __sfvwrite (fp=<optimized out>, > uio=0x8207ad338) at /usr/src/lib/libc/stdio/fvwrite.c:182 > 182 COPY(w); > (gdb) p w > $4 = -1 > > > The dhcpcd flow leading to the crash: > 1. init with setvbuf _IOLBF on stderr > https://github.com/NetworkConfiguration/dhcpcd/blob/master/src/logerr.c#L453 > > 2. fputc with newline called on stderr but is interrupted > https://github.com/NetworkConfiguration/dhcpcd/blob/master/src/logerr.c#L187 > > 3. next event received, vfprintf is called on stderr and crashes > https://github.com/NetworkConfiguration/dhcpcd/blob/master/src/logerr.c#L186 > > > Simple program that eventually crashes: Thanks for the reproducer. The bug is akin to that fixed by bafaa70b6f9098d83d074968c8e6747ecec1e118. Could you please verify that the patch below fixes the original bug? commit 11f817e847b2f06bd543d1bd6cfdff53d69842dc Author: Mark Johnston <markj@FreeBSD.org> Date: Fri Mar 25 10:46:24 2022 -0400 libc: Restore fp state upon flush error in fputc diff --git a/lib/libc/stdio/wbuf.c b/lib/libc/stdio/wbuf.c index e1aa70243e94..6cd75145a271 100644 --- a/lib/libc/stdio/wbuf.c +++ b/lib/libc/stdio/wbuf.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); int __swbuf(int c, FILE *fp) { + unsigned char *old_p; int n; /* @@ -87,8 +88,15 @@ __swbuf(int c, FILE *fp) } fp->_w--; *fp->_p++ = c; - if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) - if (__fflush(fp)) + old_p = fp->_p; + if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) { + if (__fflush(fp)) { + if (fp->_p == old_p) { + fp->_p--; + fp->_w++; + } return (EOF); + } + } return (c); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Yj3WwYBSCvbZJcKo>