am cc7e28f1: am 432f763c: Merge "Avoid pathological behavior in OpenBSD\'s fread."

* commit 'cc7e28f111bfa5cd859ab7ac4eac8f98d9f10af3':
  Avoid pathological behavior in OpenBSD's fread.
This commit is contained in:
Elliott Hughes 2014-12-02 22:49:36 +00:00 committed by Android Git Automerger
commit c28e2797a7
3 changed files with 49 additions and 2 deletions

View File

@ -58,6 +58,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 \
stdio/stdio_ext.cpp \
@ -406,7 +407,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 \

View File

@ -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 */

View File

@ -813,3 +813,34 @@ TEST(stdio, freopen_CLOEXEC) {
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]);
}
}