aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLioncash <mathew1800@gmail.com>2020-04-15 14:21:22 -0400
committerLioncash <mathew1800@gmail.com>2020-04-15 14:43:37 -0400
commite77337588e75adc6e6b8477a8dbe9d1ea8f25c8c (patch)
tree0b6d9732e5276abf734e64dcd708a18da1e931a4
parent64b5985f0a034fb2b1988d960b009985f9929922 (diff)
file_util: Early-exit in WriteArray and ReadArray if specified lengths are zero
It's undefined behavior to pass a null pointer to std::fread and std::fwrite, even if the length passed in is zero, so we must perform the precondition checking ourselves. A common case where this can occur is when passing in the data of an empty std::vector and size, as an empty vector will typically have a null internal buffer. While we're at it, we can move the implementation out of line and add debug checks against passing in nullptr to std::fread and std::fwrite.
-rw-r--r--src/common/file_util.cpp28
-rw-r--r--src/common/file_util.h14
2 files changed, 33 insertions, 9 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 35eee0096c..7f613891b3 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -967,6 +967,34 @@ bool IOFile::Flush() {
return IsOpen() && 0 == std::fflush(m_file);
}
+std::size_t IOFile::ReadImpl(void* data, std::size_t length, std::size_t data_size) const {
+ if (!IsOpen()) {
+ return std::numeric_limits<std::size_t>::max();
+ }
+
+ if (length == 0) {
+ return 0;
+ }
+
+ DEBUG_ASSERT(data != nullptr);
+
+ return std::fread(data, data_size, length, m_file);
+}
+
+std::size_t IOFile::WriteImpl(const void* data, std::size_t length, std::size_t data_size) {
+ if (!IsOpen()) {
+ return std::numeric_limits<std::size_t>::max();
+ }
+
+ if (length == 0) {
+ return 0;
+ }
+
+ DEBUG_ASSERT(data != nullptr);
+
+ return std::fwrite(data, data_size, length, m_file);
+}
+
bool IOFile::Resize(u64 size) {
return IsOpen() && 0 ==
#ifdef _WIN32
diff --git a/src/common/file_util.h b/src/common/file_util.h
index cde7ddf2d1..f7a0c33fae 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -222,22 +222,15 @@ public:
static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
- if (!IsOpen()) {
- return std::numeric_limits<std::size_t>::max();
- }
-
- return std::fread(data, sizeof(T), length, m_file);
+ return ReadImpl(data, length, sizeof(T));
}
template <typename T>
std::size_t WriteArray(const T* data, std::size_t length) {
static_assert(std::is_trivially_copyable_v<T>,
"Given array does not consist of trivially copyable objects");
- if (!IsOpen()) {
- return std::numeric_limits<std::size_t>::max();
- }
- return std::fwrite(data, sizeof(T), length, m_file);
+ return WriteImpl(data, length, sizeof(T));
}
template <typename T>
@@ -278,6 +271,9 @@ public:
}
private:
+ std::size_t ReadImpl(void* data, std::size_t length, std::size_t data_size) const;
+ std::size_t WriteImpl(const void* data, std::size_t length, std::size_t data_size);
+
std::FILE* m_file = nullptr;
};