Avoid pathological behavior in OpenBSD's fread.
(cherry picked from commit 20841a137b
)
Bug: https://code.google.com/p/android/issues/detail?id=81155
Bug: 18556607
Change-Id: Ibdfebc20dce4c34ad565014523c9b074e90ea665
This commit is contained in:
parent
152e978f73
commit
27d276f3a6
3 changed files with 49 additions and 2 deletions
|
@ -61,6 +61,7 @@ libc_common_src_files := \
|
|||
bionic/sigsetmask.c \
|
||||
bionic/system_properties_compat.c \
|
||||
stdio/findfp.c \
|
||||
stdio/fread.c \
|
||||
stdio/snprintf.c\
|
||||
stdio/sprintf.c \
|
||||
|
||||
|
@ -396,7 +397,6 @@ libc_upstream_openbsd_src_files := \
|
|||
upstream-openbsd/lib/libc/stdio/fputs.c \
|
||||
upstream-openbsd/lib/libc/stdio/fputwc.c \
|
||||
upstream-openbsd/lib/libc/stdio/fputws.c \
|
||||
upstream-openbsd/lib/libc/stdio/fread.c \
|
||||
upstream-openbsd/lib/libc/stdio/freopen.c \
|
||||
upstream-openbsd/lib/libc/stdio/fscanf.c \
|
||||
upstream-openbsd/lib/libc/stdio/fseek.c \
|
||||
|
|
|
@ -68,7 +68,23 @@ fread(void *buf, size_t size, size_t count, FILE *fp)
|
|||
fp->_r = 0;
|
||||
total = resid;
|
||||
p = buf;
|
||||
while (resid > (r = fp->_r)) {
|
||||
|
||||
// BEGIN android-added
|
||||
// Avoid pathological behavior on unbuffered files. OpenBSD
|
||||
// will loop reading one byte then memcpying one byte!
|
||||
if ((fp->_flags & __SNBF) != 0) {
|
||||
// We know if we're unbuffered that our buffer is empty, so
|
||||
// we can just read directly.
|
||||
while (resid > 0 && (r = (*fp->_read)(fp->_cookie, p, resid)) > 0) {
|
||||
p += r;
|
||||
resid -= r;
|
||||
}
|
||||
FUNLOCKFILE(fp);
|
||||
return ((total - resid) / size);
|
||||
}
|
||||
// END android-added
|
||||
|
||||
while (resid > (size_t)(r = fp->_r)) {
|
||||
(void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
|
||||
fp->_p += r;
|
||||
/* fp->_r = 0 ... done in __srefill */
|
|
@ -694,3 +694,34 @@ TEST(stdio, fpos_t_and_seek) {
|
|||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// https://code.google.com/p/android/issues/detail?id=81155
|
||||
// http://b/18556607
|
||||
TEST(stdio, fread_unbuffered_pathological_performance) {
|
||||
FILE* fp = fopen("/dev/zero", "r");
|
||||
ASSERT_TRUE(fp != NULL);
|
||||
|
||||
// Make this stream unbuffered.
|
||||
setvbuf(fp, 0, _IONBF, 0);
|
||||
|
||||
char buf[65*1024];
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
|
||||
time_t t0 = time(NULL);
|
||||
for (size_t i = 0; i < 1024; ++i) {
|
||||
fread(buf, 64*1024, 1, fp);
|
||||
}
|
||||
time_t t1 = time(NULL);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// 1024 64KiB reads should have been very quick.
|
||||
ASSERT_LE(t1 - t0, 1);
|
||||
|
||||
for (size_t i = 0; i < 64*1024; ++i) {
|
||||
ASSERT_EQ('\0', buf[i]);
|
||||
}
|
||||
for (size_t i = 64*1024; i < 65*1024; ++i) {
|
||||
ASSERT_EQ('\xff', buf[i]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue