Add memory corruption checking to base::File().
Since we crash on invalid fd in ScopedFD::Close(), memory corruption
in a base::File() object can cause crashes; perhaps long after the memory
is actually corrupt.
This CL puts a checksum in memory near the fd on POSIX systems. The
checksum is different enough to be very unlikely to be correct after a
random memory write, but also very cheap to compute, so we can have
most operations on a file double quickly double check its integrity,
for earlier (and more useful for debugging) crashes.
This is intended to help us debug issue 424562. Once we have found out
if and where memory is being corrupted, this instrumentation code should
be removed.
R=thakis@chromium.org,pasko@chromium.org
BUG=424562
Review URL: https://codereview.chromium.org/702473009
Cr-Commit-Position: refs/heads/master@{#303251}
CrOS-Libchrome-Original-Commit: 32ea7f9a9a2385bd8911bf5bc37748a560a387d5
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 43684b5..3d229e4 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -483,6 +483,49 @@
}
}
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
+ UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
+ UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
+
+// static
+void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
+ unsigned int* out_checksum) const {
+ // Use a single iteration of a linear congruentional generator (lcg) to
+ // provide a cheap checksum unlikely to be accidentally matched by a random
+ // memory corruption.
+
+ // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
+ // length, we insure that each distinct fd value maps to a distinct checksum,
+ // which maximises the utility of our checksum.
+
+ // This code uses "unsigned int" throughout for its defined modular semantics,
+ // which implicitly gives us a divisor that is a power of two.
+
+ const unsigned int kMultiplier = 13035 * 4 + 1;
+ COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
+ const unsigned int kIncrement = 1595649551;
+ COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
+
+ *out_checksum =
+ static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
+}
+
+void File::MemoryCheckingScopedFD::Check() const {
+ unsigned int computed_checksum;
+ ComputeMemoryChecksum(&computed_checksum);
+ CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
+}
+
+void File::MemoryCheckingScopedFD::UpdateChecksum() {
+ ComputeMemoryChecksum(&file_memory_checksum_);
+}
+
void File::SetPlatformFile(PlatformFile file) {
DCHECK(!file_.is_valid());
file_.reset(file);