EXPECT_FALSE(csv->next(row));
}
+// Verifies that VersionedCSVFile::next() propagates CSVFile::next()
+// failures. Closing the stream after a successful read leaves the
+// previous row intact while the base class returns false; the
+// versioned wrapper must not treat that stale row as a new success.
+// See Gitlab #4664.
+TEST_F(VersionedCSVFileTest, nextPropagatesReadFailure) {
+ writeFile("animal,color,age\n"
+ "cat,black,2\n"
+ "lion,yellow,17\n");
+
+ boost::scoped_ptr<VersionedCSVFile> csv(new VersionedCSVFile(testfile_));
+ ASSERT_NO_THROW(csv->addColumn("animal", "2.0", ""));
+ ASSERT_NO_THROW(csv->addColumn("color", "2.0", "grey"));
+ ASSERT_NO_THROW(csv->addColumn("age", "2.0", "0"));
+ ASSERT_NO_THROW(csv->open());
+
+ CSVRow row;
+ ASSERT_TRUE(csv->next(row));
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("black", row.readAt(1));
+ EXPECT_EQ("2", row.readAt(2));
+
+ // Simulate a subsequent read failure: stream is unusable, but
+ // 'row' still holds the previously read valid contents.
+ ASSERT_NO_THROW(csv->close());
+ EXPECT_FALSE(csv->next(row));
+ EXPECT_NE(std::string::npos, csv->getReadMsg().find("NULL stream"));
+
+ // Stale row contents must remain unchanged (base class does not
+ // clear the row on failure).
+ EXPECT_EQ("cat", row.readAt(0));
+ EXPECT_EQ("black", row.readAt(1));
+ EXPECT_EQ("2", row.readAt(2));
+}
+
} // end of anonymous namespace
bool
VersionedCSVFile::next(CSVRow& row) {
setReadMsg("success");
- // Use base class to physical read the row, but skip its row
- // validation
- CSVFile::next(row, true);
+ // Use base class to physically read the row, but skip its row
+ // validation. Propagate I/O and stream failures: on error the
+ // base class leaves 'row' unchanged, so continuing would validate
+ // stale contents and incorrectly report success.
+ if (!CSVFile::next(row, true)) {
+ return (false);
+ }
if (row == CSVFile::EMPTY_ROW()) {
return(true);
}
-// Copyright (C) 2015-2024 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2015-2026 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
///
/// @param [out] row Object receiving the parsed CSV file.
///
- /// @return true if row has been read and validated; false if validation
- /// failed.
+ /// @return true if row has been read and validated; false if the
+ /// underlying read failed or validation failed. On read failure the
+ /// contents of @c row are left unchanged.
bool next(CSVRow& row);
/// @brief Returns the schema version of the physical file