Skip to content

Commit dec5ee1

Browse files
davidbenBoringssl LUCI CQ
authored andcommitted
Tolerate feof returning arbitrary non-zero values
feof apparently does not promise EOF returns 1, just a non-zero value. See [0]. We very much do not care about the impacted platform, but it is probably prudent to handle this, in case some platform we do care about uses this leeway. While I'm here, add a test for EOF in file BIOs. In writing this test, I noticed that BIO_reset's return value convention, like BIO_seek, is completely inconsistent. Document the problem for now. (OpenSSL's documentation[1] also mentions this, though they seem to have missed that fds are also impacted.) [0] openssl/openssl#30395 [1] https://docs.openssl.org/master/man3/BIO_ctrl/#description:~:text=%C2%B6-,BIO_reset()%20normally%20returns%201%20for%20success%20and%20%3C%3D0%20for%20failure.%20File%20BIOs%20are%20an%20exception%2C%20they%20return%200%20for%20success%20and%20%2D1%20for%20failure.,-BIO_seek()%20and%20BIO_tell Change-Id: I2df1925b157bb34897174143d74ca9e5e86a673c Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/90888 Reviewed-by: Lily Chen <chlily@google.com> Commit-Queue: Lily Chen <chlily@google.com> Auto-Submit: David Benjamin <davidben@google.com>
1 parent d2c7ec9 commit dec5ee1

File tree

3 files changed

+43
-7
lines changed

3 files changed

+43
-7
lines changed

crypto/bio/bio_test.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,37 @@ TEST(BIOTest, Gets) {
704704
EXPECT_EQ(c, 'a');
705705
}
706706

707+
TEST(BIOTest, FileEOF) {
708+
if (SkipTempFileTests()) {
709+
GTEST_SKIP();
710+
}
711+
712+
TemporaryFile file;
713+
ASSERT_TRUE(file.Init("abcd"));
714+
UniquePtr<BIO> bio(BIO_new_file(file.path().c_str(), "rb"));
715+
ASSERT_TRUE(bio);
716+
EXPECT_EQ(BIO_eof(bio.get()), 0);
717+
// Read everything.
718+
char buf[4];
719+
ASSERT_EQ(4, BIO_read(bio.get(), buf, sizeof(buf)));
720+
EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes("abcd"));
721+
EXPECT_EQ(BIO_eof(bio.get()), 0);
722+
// Try to keep reading. The BIO should now signal EOF.
723+
ASSERT_EQ(0, BIO_read(bio.get(), buf, sizeof(buf)));
724+
EXPECT_EQ(BIO_eof(bio.get()), 1);
725+
// Reset the BIO. File BIOs have an unusual return value convention for
726+
// |BIO_reset|.
727+
EXPECT_EQ(BIO_reset(bio.get()), 0);
728+
// This should clear the EOF indicator for the stream.
729+
EXPECT_EQ(BIO_eof(bio.get()), 0);
730+
// Repeat the test.
731+
ASSERT_EQ(4, BIO_read(bio.get(), buf, sizeof(buf)));
732+
EXPECT_EQ(Bytes(buf, sizeof(buf)), Bytes("abcd"));
733+
EXPECT_EQ(BIO_eof(bio.get()), 0);
734+
ASSERT_EQ(0, BIO_read(bio.get(), buf, sizeof(buf)));
735+
EXPECT_EQ(BIO_eof(bio.get()), 1);
736+
}
737+
707738
// Test that, on Windows, file BIOs correctly handle text vs binary mode.
708739
TEST(BIOTest, FileMode) {
709740
if (SkipTempFileTests()) {

crypto/bio/file.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
147147
case BIO_C_FILE_SEEK:
148148
return fseek(fp, num, 0);
149149
case BIO_CTRL_EOF:
150-
return feof(fp);
150+
// feof may return any non-zero value for EOF, but we must return 1.
151+
return feof(fp) != 0;
151152
case BIO_C_FILE_TELL:
152153
case BIO_CTRL_INFO:
153154
return ftell(fp);

include/openssl/bio.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ OPENSSL_EXPORT char *BIO_ptr_ctrl(BIO *bp, int cmd, long larg);
118118
OPENSSL_EXPORT long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg);
119119

120120
// BIO_reset resets |bio| to its initial state, the precise meaning of which
121-
// depends on the concrete type of |bio|. It returns one on success and zero
122-
// otherwise.
121+
// depends on the concrete type of |bio|. It normally returns one on success and
122+
// <= 0 otherwise. However, for file and fd BIOs, it returns zero on success and
123+
// a negative number on error.
124+
//
125+
// WARNING: This function's return value conventions differs from most functions
126+
// in this library.
123127
OPENSSL_EXPORT int BIO_reset(BIO *bio);
124128

125129
// BIO_eof returns non-zero when |bio| has reached end-of-file. The precise
@@ -496,8 +500,8 @@ OPENSSL_EXPORT int BIO_rw_filename(BIO *bio, const char *filename);
496500
// BIO_tell returns the file offset of |bio|, or a negative number on error or
497501
// if |bio| does not support the operation.
498502
//
499-
// TODO(https://crbug.com/boringssl/465): On platforms where |long| is 32-bit,
500-
// this function cannot report 64-bit offsets.
503+
// TODO(crbug.com/42290329): On platforms where |long| is 32-bit, this function
504+
// cannot report 64-bit offsets.
501505
OPENSSL_EXPORT long BIO_tell(BIO *bio);
502506

503507
// BIO_seek sets the file offset of |bio| to |offset|. It returns a non-negative
@@ -508,8 +512,8 @@ OPENSSL_EXPORT long BIO_tell(BIO *bio);
508512
// WARNING: This function's return value conventions differs from most functions
509513
// in this library.
510514
//
511-
// TODO(https://crbug.com/boringssl/465): On platforms where |long| is 32-bit,
512-
// this function cannot handle 64-bit offsets.
515+
// TODO(crbug.com/42290329): On platforms where |long| is 32-bit, this function
516+
// cannot handle 64-bit offsets.
513517
OPENSSL_EXPORT long BIO_seek(BIO *bio, long offset);
514518

515519

0 commit comments

Comments
 (0)