Re: Interrupted fputc followed by fprintf in _IOLBF mode causes core dump
Date: Fri, 25 Mar 2022 14:50:41 UTC
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);
}