<feed xmlns='http://www.w3.org/2005/Atom'>
<title>musl/src/stdio, branch v1.1.15</title>
<subtitle>musl - an implementation of the standard library for Linux-based systems</subtitle>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/'/>
<entry>
<title>fix FILE buffer underflow in ungetwc</title>
<updated>2016-04-26T19:26:40+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2016-04-26T19:26:40+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=6ed791e768d83b40ed56c99dbb1ed72c1e49aae7'/>
<id>6ed791e768d83b40ed56c99dbb1ed72c1e49aae7</id>
<content type='text'>
commit 7e816a6487932cbb3cb71d94b609e50e81f4e5bf (version 1.1.11
release cycle) moved the code that performs wchar_t to multibyte
conversion across code that used the resulting length in bytes,
thereby breaking the unget buffer space check in ungetwc and
clobbering up to three bytes below the start of the buffer.

for allocated FILEs (all read-enabled FILEs except stdin), the
underflow clobbers at most the FILE-specific locale pointer. no stores
are performed through this pointer, but subsequent loads may result in
a crash or mismatching encoding rule (UTF-8 multibyte vs byte-based).

for stdin, the buffer lies in .bss and the underflow may clobber
another object. in practice, for libc.so the adjacent object seems to
be stderr's buffer, which is completely unused, but this could vary
with linking options, or when static linking.

applications which do not attempt to use more than one character of
ungetwc pushback, or which do not use ungetwc, are not affected.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
commit 7e816a6487932cbb3cb71d94b609e50e81f4e5bf (version 1.1.11
release cycle) moved the code that performs wchar_t to multibyte
conversion across code that used the resulting length in bytes,
thereby breaking the unget buffer space check in ungetwc and
clobbering up to three bytes below the start of the buffer.

for allocated FILEs (all read-enabled FILEs except stdin), the
underflow clobbers at most the FILE-specific locale pointer. no stores
are performed through this pointer, but subsequent loads may result in
a crash or mismatching encoding rule (UTF-8 multibyte vs byte-based).

for stdin, the buffer lies in .bss and the underflow may clobber
another object. in practice, for libc.so the adjacent object seems to
be stderr's buffer, which is completely unused, but this could vary
with linking options, or when static linking.

applications which do not attempt to use more than one character of
ungetwc pushback, or which do not use ungetwc, are not affected.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix undefined pointer comparison in stdio-internal __toread</title>
<updated>2016-03-29T03:41:17+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2016-03-29T03:41:17+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=6d1a3dfeaf2caac4033a3c65822fb4e7e14866c7'/>
<id>6d1a3dfeaf2caac4033a3c65822fb4e7e14866c7</id>
<content type='text'>
the comparison f-&gt;wpos &gt; f-&gt;buf has undefined behavior when f-&gt;wpos is
a null pointer, despite the intuition (and actual compiler behavior,
for all known compilers) being that NULL &gt; ptr is false for all valid
pointers ptr.

the purpose of the comparison is to determine if the write buffer is
non-empty, and the idiom used elsewhere for that is comparison against
f-&gt;wbase, which is either a null pointer when not writing, or equal to
f-&gt;buf when writing. in the former case, both f-&gt;wpos and f-&gt;wbase are
null; in the latter they are both non-null and point into the same
array.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
the comparison f-&gt;wpos &gt; f-&gt;buf has undefined behavior when f-&gt;wpos is
a null pointer, despite the intuition (and actual compiler behavior,
for all known compilers) being that NULL &gt; ptr is false for all valid
pointers ptr.

the purpose of the comparison is to determine if the write buffer is
non-empty, and the idiom used elsewhere for that is comparison against
f-&gt;wbase, which is either a null pointer when not writing, or equal to
f-&gt;buf when writing. in the former case, both f-&gt;wpos and f-&gt;wbase are
null; in the latter they are both non-null and point into the same
array.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix padding string formats to width in wide printf variants</title>
<updated>2016-03-16T20:35:22+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2016-03-16T20:35:22+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=4aac019a0efd59011a48d031ad046c934c7e8365'/>
<id>4aac019a0efd59011a48d031ad046c934c7e8365</id>
<content type='text'>
the idiom fprintf(f, "%.*s", n, "") was wrongly used in vfwprintf as a
means of producing n spaces; instead it produces no output. the
correct form is fprintf(f, "%*s", n, ""), using width instead of
precision, since for %s the later is a maximum rather than a minimum.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
the idiom fprintf(f, "%.*s", n, "") was wrongly used in vfwprintf as a
means of producing n spaces; instead it produces no output. the
correct form is fprintf(f, "%*s", n, ""), using width instead of
precision, since for %s the later is a maximum rather than a minimum.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix assumption in fputs that fwrite returning 0 implies an error</title>
<updated>2016-02-16T18:26:16+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2016-02-16T18:26:16+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=10a17dfbad2c267d885817abc9c7589fc7ff630b'/>
<id>10a17dfbad2c267d885817abc9c7589fc7ff630b</id>
<content type='text'>
internally, the idiom of passing nmemb=1 to fwrite and interpreting
the return value of fwrite (which is necessarily 0 or 1) as
failure/success is fairly widely used. this is not correct, however,
when the size argument is unknown and may be zero, since C requires
fwrite to return 0 in that special case. previously fwrite always
returned nmemb on success, but this was changed for conformance with
ISO C by commit 500c6886c654fd45e4926990fee2c61d816be197.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
internally, the idiom of passing nmemb=1 to fwrite and interpreting
the return value of fwrite (which is necessarily 0 or 1) as
failure/success is fairly widely used. this is not correct, however,
when the size argument is unknown and may be zero, since C requires
fwrite to return 0 in that special case. previously fwrite always
returned nmemb on success, but this was changed for conformance with
ISO C by commit 500c6886c654fd45e4926990fee2c61d816be197.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix return value for fread/fwrite when size argument is 0</title>
<updated>2016-02-11T00:44:19+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2016-02-11T00:44:19+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=500c6886c654fd45e4926990fee2c61d816be197'/>
<id>500c6886c654fd45e4926990fee2c61d816be197</id>
<content type='text'>
when the size argument was zero but nmemb was nonzero, these functions
were returning nmemb, despite no data having been written.
conceptually this is not wrong, but the standard requires a return
value of zero in this case.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
when the size argument was zero but nmemb was nonzero, these functions
were returning nmemb, despite no data having been written.
conceptually this is not wrong, but the standard requires a return
value of zero in this case.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix failed write reporting by fwrite in line-buffered mode</title>
<updated>2016-02-10T18:51:05+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2016-02-10T18:51:05+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=5a6e8d098abfef67028e6c3edbac39e0bbaf8bd8'/>
<id>5a6e8d098abfef67028e6c3edbac39e0bbaf8bd8</id>
<content type='text'>
when a write error occurred while flushing output due to a newline,
fwrite falsely reported all bytes up to and including the newline as
successfully written. in general, due to buffering such "spurious
success" returns are acceptable for stdio; however for line-buffered
mode it was subtly wrong. errors were still visible via ferror() or as
a short-write return if there was more data past the newline that
should have been written, but since the contract for line-buffered
mode is that everything up through the newline be written out
immediately, a discrepency was observable in the actual file contents.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
when a write error occurred while flushing output due to a newline,
fwrite falsely reported all bytes up to and including the newline as
successfully written. in general, due to buffering such "spurious
success" returns are acceptable for stdio; however for line-buffered
mode it was subtly wrong. errors were still visible via ferror() or as
a short-write return if there was more data past the newline that
should have been written, but since the contract for line-buffered
mode is that everything up through the newline be written out
immediately, a discrepency was observable in the actual file contents.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix overly pessimistic realloc strategy in getdelim</title>
<updated>2015-12-20T05:39:35+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2015-12-20T05:32:46+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=c673158d91ad995ed59dd910777cd6464f61fe8e'/>
<id>c673158d91ad995ed59dd910777cd6464f61fe8e</id>
<content type='text'>
previously, getdelim was allocating twice the space needed every time
it expanded its buffer to implement exponential buffer growth (in
order to avoid quadratic run time). however, this doubling was
performed even when the final buffer length needed was already known,
which is the common case that occurs whenever the delimiter is in the
FILE's buffer.

this patch makes two changes to remedy the situation:

1. over-allocation is no longer performed if the delimiter has already
been found when realloc is needed.

2. growth factor is reduced from 2x to 1.5x to reduce the relative
excess allocation in cases where the delimiter is not initially in the
buffer, including unbuffered streams.

in theory these changes could lead to quadratic time if the same
buffer is reused to process a sequence of lines successively
increasing in length, but once this length exceeds the stdio buffer
size, the delimiter will not be found in the buffer right away and
exponential growth will still kick in.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
previously, getdelim was allocating twice the space needed every time
it expanded its buffer to implement exponential buffer growth (in
order to avoid quadratic run time). however, this doubling was
performed even when the final buffer length needed was already known,
which is the common case that occurs whenever the delimiter is in the
FILE's buffer.

this patch makes two changes to remedy the situation:

1. over-allocation is no longer performed if the delimiter has already
been found when realloc is needed.

2. growth factor is reduced from 2x to 1.5x to reduce the relative
excess allocation in cases where the delimiter is not initially in the
buffer, including unbuffered streams.

in theory these changes could lead to quadratic time if the same
buffer is reused to process a sequence of lines successively
increasing in length, but once this length exceeds the stdio buffer
size, the delimiter will not be found in the buffer right away and
exponential growth will still kick in.
</pre>
</div>
</content>
</entry>
<entry>
<title>avoid updating caller's size when getdelim fails to realloc</title>
<updated>2015-12-20T04:43:31+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2015-12-20T04:43:31+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=d87f0a9a95f0a1228ee5579e5822a8c93bc96823'/>
<id>d87f0a9a95f0a1228ee5579e5822a8c93bc96823</id>
<content type='text'>
getdelim was updating *n, the caller's stored buffer size, before
calling realloc. if getdelim then failed due to realloc failure, the
caller would see in *n a value larger than the actual size of the
allocated block, and use of that value is unsafe. in particular,
passing it again to getdelim is unsafe.

now, temporary storage is used for the desired new size, and *n is not
written until realloc succeeds.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
getdelim was updating *n, the caller's stored buffer size, before
calling realloc. if getdelim then failed due to realloc failure, the
caller would see in *n a value larger than the actual size of the
allocated block, and use of that value is unsafe. in particular,
passing it again to getdelim is unsafe.

now, temporary storage is used for the desired new size, and *n is not
written until realloc succeeds.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix single-byte overflow of malloc'd buffer in getdelim</title>
<updated>2015-10-25T02:42:10+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2015-10-25T02:42:10+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=b114190b29417fff6f701eea3a3b3b6030338280'/>
<id>b114190b29417fff6f701eea3a3b3b6030338280</id>
<content type='text'>
the buffer enlargement logic here accounted for the terminating null
byte, but not for the possibility of hitting the delimiter in the
buffer-refill code path that uses getc_unlocked, in which case two
additional bytes (the delimiter and the null termination) are written
without another chance to enlarge the buffer.

this patch and the corresponding bug report are by Felix Janda.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
the buffer enlargement logic here accounted for the terminating null
byte, but not for the possibility of hitting the delimiter in the
buffer-refill code path that uses getc_unlocked, in which case two
additional bytes (the delimiter and the null termination) are written
without another chance to enlarge the buffer.

this patch and the corresponding bug report are by Felix Janda.
</pre>
</div>
</content>
</entry>
<entry>
<title>fix open_[w]memstream behavior when no writes take place</title>
<updated>2015-10-08T22:10:09+00:00</updated>
<author>
<name>Rich Felker</name>
<email>dalias@aerifal.cx</email>
</author>
<published>2015-10-08T22:03:53+00:00</published>
<link rel='alternate' type='text/html' href='http://git.musl-libc.org/cgit/musl/commit/?id=7b9f57f207b51132f188f750161953b7baf32154'/>
<id>7b9f57f207b51132f188f750161953b7baf32154</id>
<content type='text'>
the specification for these functions requires that the buffer/size
exposed to the caller be valid after any successful call to fflush or
fclose on the stream. the implementation's approach is to update them
only at flush time, but that misses the case where fflush or fclose is
called without any writes having taken place, in which case the write
flushing callback will not be called.

to fix both the observable bug and the desired invariant, setup empty
buffers at open time and fail the open operation if no memory is
available.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
the specification for these functions requires that the buffer/size
exposed to the caller be valid after any successful call to fflush or
fclose on the stream. the implementation's approach is to update them
only at flush time, but that misses the case where fflush or fclose is
called without any writes having taken place, in which case the write
flushing callback will not be called.

to fix both the observable bug and the desired invariant, setup empty
buffers at open time and fail the open operation if no memory is
available.
</pre>
</div>
</content>
</entry>
</feed>
