From 955426ef79ae635b74ff917c2b9ebc1a24c6a3ef Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 26 Jan 2016 18:25:52 -0800 Subject: [PATCH] Fix a sign extension bug in stdio. This also lets us test the EOVERFLOW behavior, which pointed out that the fgetpos/fsetpos return on failure has always been wrong... Bug: http://b/24807045 Change-Id: I35273eb07c8c9155af858adb27569983397580b6 --- libc/stdio/stdio.cpp | 11 ++++++++--- tests/stdio_test.cpp | 13 +++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/libc/stdio/stdio.cpp b/libc/stdio/stdio.cpp index 2139621cc..16cbd555c 100644 --- a/libc/stdio/stdio.cpp +++ b/libc/stdio/stdio.cpp @@ -426,7 +426,12 @@ static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) { if (_EXT(fp)->_seek64 != nullptr) { return (*_EXT(fp)->_seek64)(fp->_cookie, offset, whence); } else if (fp->_seek != nullptr) { - return (*fp->_seek)(fp->_cookie, offset, whence); + off64_t result = (*fp->_seek)(fp->_cookie, offset, whence); +#if !defined(__LP64__) + // Avoid sign extension if off64_t is larger than off_t. + if (result != -1) result &= 0xffffffff; +#endif + return result; } else { errno = ESPIPE; return -1; @@ -531,12 +536,12 @@ off64_t ftello64(FILE* fp) { int fgetpos(FILE* fp, fpos_t* pos) { *pos = ftello(fp); - return (*pos == -1); + return (*pos == -1) ? -1 : 0; } int fgetpos64(FILE* fp, fpos64_t* pos) { *pos = ftello64(fp); - return (*pos == -1); + return (*pos == -1) ? -1 : 0; } static FILE* __funopen(const void* cookie, diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 7f412c13c..b6f652688 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -1116,14 +1116,19 @@ TEST(STDIO_TEST, funopen_seek) { FILE* fp = funopen(nullptr, read_fn, nullptr, seek_fn, nullptr); ASSERT_TRUE(fp != nullptr); fpos_t pos; - ASSERT_EQ(0, fgetpos(fp, &pos)); - ASSERT_EQ(0xfedcba12LL, pos); +#if defined(__LP64__) + EXPECT_EQ(0, fgetpos(fp, &pos)) << strerror(errno); + EXPECT_EQ(0xfedcba12LL, pos); +#else + EXPECT_EQ(-1, fgetpos(fp, &pos)) << strerror(errno); + EXPECT_EQ(EOVERFLOW, errno); +#endif FILE* fp64 = funopen64(nullptr, read_fn, nullptr, seek64_fn, nullptr); ASSERT_TRUE(fp64 != nullptr); fpos64_t pos64; - ASSERT_EQ(0, fgetpos64(fp64, &pos64)); - ASSERT_EQ(0xfedcba12345678, pos64); + EXPECT_EQ(0, fgetpos64(fp64, &pos64)) << strerror(errno); + EXPECT_EQ(0xfedcba12345678, pos64); #else GTEST_LOG_(INFO) << "glibc uses fopencookie instead.\n"; #endif