mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-28 07:48:14 +08:00
Make file_io reads more rational and predictable
ReadFile() attempted to continue reading after a short read. In most cases, this is fine. However, ReadFile() would keep trying to fill a partially-filled buffer until experiencing a 0-length read(), signaling end-of-file. For certain weird file descriptors like terminal input, EOF is an ephemeral condition, and attempting to read beyond EOF doesn’t actually return 0 (EOF) provided that they remain open, it will block waiting for more input. Consequently, ReadFile() and anything based on ReadFile() had an undocumented and quirky interface, which was that any short read that it returned (not an underlying short read) actually indicated EOF. This facet of ReadFile() was unexpected, so it’s being removed. The new behavior is that ReadFile() will return an underlying short read. The behavior of FileReaderInterface::Read() is updated in accordance with this change. Upon experiencing a short read, the caller can determine the best action. Most callers were already prepared for this behavior. Outside of util/file, only crashpad_database_util properly implemented EOF detection according to previous semantics, and adapting it to new semantics is trivial. Callers who require an exact-length read can use the new ReadFileExactly(), or the newly renamed LoggingReadFileExactly() or CheckedReadFileExactly(). These functions will retry following a short read. The renamed functions were previously called LoggingReadFile() and CheckedReadFile(), but those names implied that they were simply wrapping ReadFile(), which is not the case. They wrapped ReadFile() and further, insisted on a full read. Since ReadFile()’s semantics are now changing but these functions’ are not, they’re now even more distinct from ReadFile(), and must be renamed to avoid confusion. Test: * Change-Id: I06b77e0d6ad8719bd2eb67dab93a8740542dd908 Reviewed-on: https://chromium-review.googlesource.com/456676 Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
parent
51b21d8874
commit
00b6442752
@ -77,8 +77,8 @@ std::string ReadRestOfFileAsString(FileHandle file) {
|
|||||||
DCHECK_GT(end, read_from);
|
DCHECK_GT(end, read_from);
|
||||||
size_t data_length = static_cast<size_t>(end - read_from);
|
size_t data_length = static_cast<size_t>(end - read_from);
|
||||||
std::string buffer(data_length, '\0');
|
std::string buffer(data_length, '\0');
|
||||||
return LoggingReadFile(file, &buffer[0], data_length) ? buffer
|
return LoggingReadFileExactly(file, &buffer[0], data_length) ? buffer
|
||||||
: std::string();
|
: std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper structures, and conversions ------------------------------------------
|
// Helper structures, and conversions ------------------------------------------
|
||||||
@ -417,7 +417,7 @@ void Metadata::Read() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MetadataFileHeader header;
|
MetadataFileHeader header;
|
||||||
if (!LoggingReadFile(handle_.get(), &header, sizeof(header))) {
|
if (!LoggingReadFileExactly(handle_.get(), &header, sizeof(header))) {
|
||||||
LOG(ERROR) << "failed to read header";
|
LOG(ERROR) << "failed to read header";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -438,7 +438,7 @@ void Metadata::Read() {
|
|||||||
std::vector<ReportDisk> reports;
|
std::vector<ReportDisk> reports;
|
||||||
if (header.num_records > 0) {
|
if (header.num_records > 0) {
|
||||||
std::vector<MetadataFileReportRecord> records(header.num_records);
|
std::vector<MetadataFileReportRecord> records(header.num_records);
|
||||||
if (!LoggingReadFile(
|
if (!LoggingReadFileExactly(
|
||||||
handle_.get(), &records[0], records_size.ValueOrDie())) {
|
handle_.get(), &records[0], records_size.ValueOrDie())) {
|
||||||
LOG(ERROR) << "failed to read records";
|
LOG(ERROR) << "failed to read records";
|
||||||
return;
|
return;
|
||||||
|
@ -246,13 +246,10 @@ bool Settings::ReadSettings(FileHandle handle,
|
|||||||
if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
|
if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool read_result;
|
bool read_result =
|
||||||
if (log_read_error) {
|
log_read_error
|
||||||
read_result = LoggingReadFile(handle, out_data, sizeof(*out_data));
|
? LoggingReadFileExactly(handle, out_data, sizeof(*out_data))
|
||||||
} else {
|
: ReadFileExactly(handle, out_data, sizeof(*out_data));
|
||||||
read_result =
|
|
||||||
ReadFile(handle, out_data, sizeof(*out_data)) == sizeof(*out_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!read_result)
|
if (!read_result)
|
||||||
return false;
|
return false;
|
||||||
|
@ -90,7 +90,8 @@ int CrashOtherProgram(int argc, wchar_t* argv[]) {
|
|||||||
|
|
||||||
// Wait until it's ready.
|
// Wait until it's ready.
|
||||||
char c;
|
char c;
|
||||||
if (!LoggingReadFile(child.stdout_read_handle(), &c, sizeof(c)) || c != ' ') {
|
if (!LoggingReadFileExactly(child.stdout_read_handle(), &c, sizeof(c)) ||
|
||||||
|
c != ' ') {
|
||||||
LOG(ERROR) << "failed child communication";
|
LOG(ERROR) << "failed child communication";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ class ModuleAnnotationsMultiprocessTest final : public WinMultiprocess {
|
|||||||
void WinMultiprocessParent() override {
|
void WinMultiprocessParent() override {
|
||||||
// Read the child executable module.
|
// Read the child executable module.
|
||||||
HMODULE module = nullptr;
|
HMODULE module = nullptr;
|
||||||
CheckedReadFile(ReadPipeHandle(), &module, sizeof(module));
|
CheckedReadFileExactly(ReadPipeHandle(), &module, sizeof(module));
|
||||||
|
|
||||||
// Reopen the child process with necessary access.
|
// Reopen the child process with necessary access.
|
||||||
HANDLE process_handle =
|
HANDLE process_handle =
|
||||||
@ -70,7 +70,7 @@ class ModuleAnnotationsMultiprocessTest final : public WinMultiprocess {
|
|||||||
|
|
||||||
// Wait until a signal from the parent process to terminate.
|
// Wait until a signal from the parent process to terminate.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
|
CheckedReadFileExactly(ReadPipeHandle(), &c, sizeof(c));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ class TestMachOImageAnnotationsReader final
|
|||||||
// Wait for the child process to indicate that it’s done setting up its
|
// Wait for the child process to indicate that it’s done setting up its
|
||||||
// annotations via the CrashpadInfo interface.
|
// annotations via the CrashpadInfo interface.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
|
CheckedReadFileExactly(ReadPipeHandle(), &c, sizeof(c));
|
||||||
|
|
||||||
// Verify the “simple map” annotations set via the CrashpadInfo interface.
|
// Verify the “simple map” annotations set via the CrashpadInfo interface.
|
||||||
const std::vector<ProcessReader::Module>& modules =
|
const std::vector<ProcessReader::Module>& modules =
|
||||||
@ -333,7 +333,7 @@ class TestMachOImageAnnotationsReader final
|
|||||||
CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
|
CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
|
||||||
|
|
||||||
// Wait for the parent to indicate that it’s safe to crash.
|
// Wait for the parent to indicate that it’s safe to crash.
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
|
CheckedReadFileExactly(ReadPipeHandle(), &c, sizeof(c));
|
||||||
|
|
||||||
// Direct an exception message to the exception server running in the
|
// Direct an exception message to the exception server running in the
|
||||||
// parent.
|
// parent.
|
||||||
|
@ -105,7 +105,7 @@ class ProcessReaderChild final : public MachMultiprocess {
|
|||||||
FileHandle read_handle = ReadPipeHandle();
|
FileHandle read_handle = ReadPipeHandle();
|
||||||
|
|
||||||
mach_vm_address_t address;
|
mach_vm_address_t address;
|
||||||
CheckedReadFile(read_handle, &address, sizeof(address));
|
CheckedReadFileExactly(read_handle, &address, sizeof(address));
|
||||||
|
|
||||||
std::string read_string;
|
std::string read_string;
|
||||||
ASSERT_TRUE(process_reader.Memory()->ReadCString(address, &read_string));
|
ASSERT_TRUE(process_reader.Memory()->ReadCString(address, &read_string));
|
||||||
@ -448,15 +448,15 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
|
|||||||
thread_index < thread_count_ + 1;
|
thread_index < thread_count_ + 1;
|
||||||
++thread_index) {
|
++thread_index) {
|
||||||
uint64_t thread_id;
|
uint64_t thread_id;
|
||||||
CheckedReadFile(read_handle, &thread_id, sizeof(thread_id));
|
CheckedReadFileExactly(read_handle, &thread_id, sizeof(thread_id));
|
||||||
|
|
||||||
TestThreadPool::ThreadExpectation expectation;
|
TestThreadPool::ThreadExpectation expectation;
|
||||||
CheckedReadFile(read_handle,
|
CheckedReadFileExactly(read_handle,
|
||||||
&expectation.stack_address,
|
&expectation.stack_address,
|
||||||
sizeof(expectation.stack_address));
|
sizeof(expectation.stack_address));
|
||||||
CheckedReadFile(read_handle,
|
CheckedReadFileExactly(read_handle,
|
||||||
&expectation.suspend_count,
|
&expectation.suspend_count,
|
||||||
sizeof(expectation.suspend_count));
|
sizeof(expectation.suspend_count));
|
||||||
|
|
||||||
// There can’t be any duplicate thread IDs.
|
// There can’t be any duplicate thread IDs.
|
||||||
EXPECT_EQ(0u, thread_map.count(thread_id));
|
EXPECT_EQ(0u, thread_map.count(thread_id));
|
||||||
@ -730,7 +730,8 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
|||||||
FileHandle read_handle = ReadPipeHandle();
|
FileHandle read_handle = ReadPipeHandle();
|
||||||
|
|
||||||
uint32_t expect_modules;
|
uint32_t expect_modules;
|
||||||
CheckedReadFile(read_handle, &expect_modules, sizeof(expect_modules));
|
CheckedReadFileExactly(
|
||||||
|
read_handle, &expect_modules, sizeof(expect_modules));
|
||||||
|
|
||||||
ASSERT_EQ(expect_modules, modules.size());
|
ASSERT_EQ(expect_modules, modules.size());
|
||||||
|
|
||||||
@ -740,16 +741,17 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
|||||||
"index %zu, name %s", index, modules[index].name.c_str()));
|
"index %zu, name %s", index, modules[index].name.c_str()));
|
||||||
|
|
||||||
uint32_t expect_name_length;
|
uint32_t expect_name_length;
|
||||||
CheckedReadFile(
|
CheckedReadFileExactly(
|
||||||
read_handle, &expect_name_length, sizeof(expect_name_length));
|
read_handle, &expect_name_length, sizeof(expect_name_length));
|
||||||
|
|
||||||
// The NUL terminator is not read.
|
// The NUL terminator is not read.
|
||||||
std::string expect_name(expect_name_length, '\0');
|
std::string expect_name(expect_name_length, '\0');
|
||||||
CheckedReadFile(read_handle, &expect_name[0], expect_name_length);
|
CheckedReadFileExactly(read_handle, &expect_name[0], expect_name_length);
|
||||||
EXPECT_EQ(expect_name, modules[index].name);
|
EXPECT_EQ(expect_name, modules[index].name);
|
||||||
|
|
||||||
mach_vm_address_t expect_address;
|
mach_vm_address_t expect_address;
|
||||||
CheckedReadFile(read_handle, &expect_address, sizeof(expect_address));
|
CheckedReadFileExactly(
|
||||||
|
read_handle, &expect_address, sizeof(expect_address));
|
||||||
ASSERT_TRUE(modules[index].reader);
|
ASSERT_TRUE(modules[index].reader);
|
||||||
EXPECT_EQ(expect_address, modules[index].reader->Address());
|
EXPECT_EQ(expect_address, modules[index].reader->Address());
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ int wmain(int argc, wchar_t* argv[]) {
|
|||||||
|
|
||||||
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
PCHECK(in != INVALID_HANDLE_VALUE) << "GetStdHandle";
|
PCHECK(in != INVALID_HANDLE_VALUE) << "GetStdHandle";
|
||||||
CheckedReadFile(in, &c, sizeof(c));
|
CheckedReadFileExactly(in, &c, sizeof(c));
|
||||||
CHECK(c == 'd' || c == ' ');
|
CHECK(c == 'd' || c == ' ');
|
||||||
|
|
||||||
// If 'd' we crash with a debug break, otherwise exit normally.
|
// If 'd' we crash with a debug break, otherwise exit normally.
|
||||||
|
@ -42,7 +42,7 @@ int wmain(int argc, wchar_t* argv[]) {
|
|||||||
|
|
||||||
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
PCHECK(in != INVALID_HANDLE_VALUE) << "GetStdHandle";
|
PCHECK(in != INVALID_HANDLE_VALUE) << "GetStdHandle";
|
||||||
crashpad::CheckedReadFile(in, &c, sizeof(c));
|
crashpad::CheckedReadFileExactly(in, &c, sizeof(c));
|
||||||
CHECK(c == 'd' || c == ' ');
|
CHECK(c == 'd' || c == ' ');
|
||||||
|
|
||||||
// If 'd' we crash with a debug break, otherwise exit normally.
|
// If 'd' we crash with a debug break, otherwise exit normally.
|
||||||
|
@ -148,9 +148,9 @@ void TestCrashingChild(const base::string16& directory_modification) {
|
|||||||
|
|
||||||
// The child tells us (approximately) where it will crash.
|
// The child tells us (approximately) where it will crash.
|
||||||
WinVMAddress break_near_address;
|
WinVMAddress break_near_address;
|
||||||
LoggingReadFile(child.stdout_read_handle(),
|
LoggingReadFileExactly(child.stdout_read_handle(),
|
||||||
&break_near_address,
|
&break_near_address,
|
||||||
sizeof(break_near_address));
|
sizeof(break_near_address));
|
||||||
delegate.set_break_near(break_near_address);
|
delegate.set_break_near(break_near_address);
|
||||||
|
|
||||||
// Wait for the child to crash and the exception information to be validated.
|
// Wait for the child to crash and the exception information to be validated.
|
||||||
@ -250,9 +250,9 @@ void TestDumpWithoutCrashingChild(
|
|||||||
|
|
||||||
// The child tells us (approximately) where it will capture a dump.
|
// The child tells us (approximately) where it will capture a dump.
|
||||||
WinVMAddress dump_near_address;
|
WinVMAddress dump_near_address;
|
||||||
LoggingReadFile(child.stdout_read_handle(),
|
LoggingReadFileExactly(child.stdout_read_handle(),
|
||||||
&dump_near_address,
|
&dump_near_address,
|
||||||
sizeof(dump_near_address));
|
sizeof(dump_near_address));
|
||||||
delegate.set_dump_near(dump_near_address);
|
delegate.set_dump_near(dump_near_address);
|
||||||
|
|
||||||
// Wait for the child to crash and the exception information to be validated.
|
// Wait for the child to crash and the exception information to be validated.
|
||||||
|
@ -58,7 +58,7 @@ void TestExtraMemoryRanges(TestType type,
|
|||||||
// Wait for the child process to indicate that it's done setting up its
|
// Wait for the child process to indicate that it's done setting up its
|
||||||
// annotations via the CrashpadInfo interface.
|
// annotations via the CrashpadInfo interface.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(child.stdout_read_handle(), &c, sizeof(c));
|
CheckedReadFileExactly(child.stdout_read_handle(), &c, sizeof(c));
|
||||||
|
|
||||||
ProcessSnapshotWin snapshot;
|
ProcessSnapshotWin snapshot;
|
||||||
ASSERT_TRUE(snapshot.Initialize(
|
ASSERT_TRUE(snapshot.Initialize(
|
||||||
|
@ -62,7 +62,7 @@ void TestAnnotationsOnCrash(TestType type,
|
|||||||
// Wait for the child process to indicate that it's done setting up its
|
// Wait for the child process to indicate that it's done setting up its
|
||||||
// annotations via the CrashpadInfo interface.
|
// annotations via the CrashpadInfo interface.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(child.stdout_read_handle(), &c, sizeof(c));
|
CheckedReadFileExactly(child.stdout_read_handle(), &c, sizeof(c));
|
||||||
|
|
||||||
ProcessReaderWin process_reader;
|
ProcessReaderWin process_reader;
|
||||||
ASSERT_TRUE(process_reader.Initialize(child.process_handle(),
|
ASSERT_TRUE(process_reader.Initialize(child.process_handle(),
|
||||||
|
@ -69,7 +69,7 @@ class ProcessReaderChild final : public WinMultiprocess {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
WinVMAddress address;
|
WinVMAddress address;
|
||||||
CheckedReadFile(ReadPipeHandle(), &address, sizeof(address));
|
CheckedReadFileExactly(ReadPipeHandle(), &address, sizeof(address));
|
||||||
|
|
||||||
char buffer[sizeof(kTestMemory)];
|
char buffer[sizeof(kTestMemory)];
|
||||||
ASSERT_TRUE(
|
ASSERT_TRUE(
|
||||||
@ -142,7 +142,7 @@ class ProcessReaderChildThreadSuspendCount final : public WinMultiprocess {
|
|||||||
|
|
||||||
void WinMultiprocessParent() override {
|
void WinMultiprocessParent() override {
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
|
CheckedReadFileExactly(ReadPipeHandle(), &c, sizeof(c));
|
||||||
ASSERT_EQ(' ', c);
|
ASSERT_EQ(' ', c);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,8 @@ void TestImageReaderChild(const base::string16& directory_modification) {
|
|||||||
child.Start();
|
child.Start();
|
||||||
|
|
||||||
char c;
|
char c;
|
||||||
ASSERT_TRUE(LoggingReadFile(child.stdout_read_handle(), &c, sizeof(c)));
|
ASSERT_TRUE(
|
||||||
|
LoggingReadFileExactly(child.stdout_read_handle(), &c, sizeof(c)));
|
||||||
ASSERT_EQ(' ', c);
|
ASSERT_EQ(' ', c);
|
||||||
|
|
||||||
ScopedProcessSuspend suspend(child.process_handle());
|
ScopedProcessSuspend suspend(child.process_handle());
|
||||||
|
@ -39,7 +39,7 @@ class TestMultiprocessExec final : public MultiprocessExec {
|
|||||||
char c = 'z';
|
char c = 'z';
|
||||||
ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), &c, 1));
|
ASSERT_TRUE(LoggingWriteFile(WritePipeHandle(), &c, 1));
|
||||||
|
|
||||||
ASSERT_TRUE(LoggingReadFile(ReadPipeHandle(), &c, 1));
|
ASSERT_TRUE(LoggingReadFileExactly(ReadPipeHandle(), &c, 1));
|
||||||
EXPECT_EQ('Z', c);
|
EXPECT_EQ('Z', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +39,11 @@ class TestMultiprocess final : public Multiprocess {
|
|||||||
void MultiprocessParent() override {
|
void MultiprocessParent() override {
|
||||||
FileHandle read_handle = ReadPipeHandle();
|
FileHandle read_handle = ReadPipeHandle();
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(read_handle, &c, 1);
|
CheckedReadFileExactly(read_handle, &c, 1);
|
||||||
EXPECT_EQ('M', c);
|
EXPECT_EQ('M', c);
|
||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
CheckedReadFile(read_handle, &pid, sizeof(pid));
|
CheckedReadFileExactly(read_handle, &pid, sizeof(pid));
|
||||||
EXPECT_EQ(pid, ChildPID());
|
EXPECT_EQ(pid, ChildPID());
|
||||||
|
|
||||||
c = 'm';
|
c = 'm';
|
||||||
@ -63,7 +63,7 @@ class TestMultiprocess final : public Multiprocess {
|
|||||||
pid_t pid = getpid();
|
pid_t pid = getpid();
|
||||||
CheckedWriteFile(write_handle, &pid, sizeof(pid));
|
CheckedWriteFile(write_handle, &pid, sizeof(pid));
|
||||||
|
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, 1);
|
CheckedReadFileExactly(ReadPipeHandle(), &c, 1);
|
||||||
EXPECT_EQ('m', c);
|
EXPECT_EQ('m', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ std::unique_ptr<WinChildProcess::Handles> WinChildProcess::Launch() {
|
|||||||
// immediately, and test code expects process initialization to have
|
// immediately, and test code expects process initialization to have
|
||||||
// completed so it can, for example, read the process memory.
|
// completed so it can, for example, read the process memory.
|
||||||
char c;
|
char c;
|
||||||
if (!LoggingReadFile(handles_for_parent->read.get(), &c, sizeof(c))) {
|
if (!LoggingReadFileExactly(handles_for_parent->read.get(), &c, sizeof(c))) {
|
||||||
ADD_FAILURE() << "LoggedReadFile";
|
ADD_FAILURE() << "LoggedReadFile";
|
||||||
return std::unique_ptr<Handles>();
|
return std::unique_ptr<Handles>();
|
||||||
}
|
}
|
||||||
|
@ -597,7 +597,7 @@ int DatabaseUtilMain(int argc, char* argv[]) {
|
|||||||
!LoggingWriteFile(new_report->handle, buf, read_result)) {
|
!LoggingWriteFile(new_report->handle, buf, read_result)) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
} while (read_result == sizeof(buf));
|
} while (read_result > 0);
|
||||||
|
|
||||||
call_error_writing_crash_report.Disarm();
|
call_error_writing_crash_report.Disarm();
|
||||||
|
|
||||||
|
@ -19,38 +19,71 @@
|
|||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
bool LoggingReadFile(FileHandle file, void* buffer, size_t size) {
|
namespace {
|
||||||
|
|
||||||
|
bool ReadFileExactlyInternal(FileHandle file,
|
||||||
|
void* buffer,
|
||||||
|
size_t size,
|
||||||
|
bool can_log) {
|
||||||
FileOperationResult expect = base::checked_cast<FileOperationResult>(size);
|
FileOperationResult expect = base::checked_cast<FileOperationResult>(size);
|
||||||
FileOperationResult rv = ReadFile(file, buffer, size);
|
char* buffer_c = static_cast<char*>(buffer);
|
||||||
if (rv < 0) {
|
|
||||||
PLOG(ERROR) << "read";
|
FileOperationResult total_bytes = 0;
|
||||||
return false;
|
while (size > 0) {
|
||||||
|
FileOperationResult bytes = ReadFile(file, buffer, size);
|
||||||
|
if (bytes < 0) {
|
||||||
|
PLOG_IF(ERROR, can_log) << kNativeReadFunctionName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_LE(static_cast<size_t>(bytes), size);
|
||||||
|
|
||||||
|
if (bytes == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_c += bytes;
|
||||||
|
size -= bytes;
|
||||||
|
total_bytes += bytes;
|
||||||
}
|
}
|
||||||
if (rv != expect) {
|
|
||||||
LOG(ERROR) << "read: expected " << expect << ", observed " << rv;
|
if (total_bytes != expect) {
|
||||||
|
LOG_IF(ERROR, can_log) << kNativeReadFunctionName << ": expected " << expect
|
||||||
|
<< ", observed " << total_bytes;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool ReadFileExactly(FileHandle file, void* buffer, size_t size) {
|
||||||
|
return ReadFileExactlyInternal(file, buffer, size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoggingReadFileExactly(FileHandle file, void* buffer, size_t size) {
|
||||||
|
return ReadFileExactlyInternal(file, buffer, size, true);
|
||||||
|
}
|
||||||
|
|
||||||
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size) {
|
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||||
FileOperationResult expect = base::checked_cast<FileOperationResult>(size);
|
FileOperationResult expect = base::checked_cast<FileOperationResult>(size);
|
||||||
FileOperationResult rv = WriteFile(file, buffer, size);
|
FileOperationResult rv = WriteFile(file, buffer, size);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
PLOG(ERROR) << "write";
|
PLOG(ERROR) << kNativeWriteFunctionName;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (rv != expect) {
|
if (rv != expect) {
|
||||||
LOG(ERROR) << "write: expected " << expect << ", observed " << rv;
|
LOG(ERROR) << kNativeWriteFunctionName << ": expected " << expect
|
||||||
|
<< ", observed " << rv;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckedReadFile(FileHandle file, void* buffer, size_t size) {
|
void CheckedReadFileExactly(FileHandle file, void* buffer, size_t size) {
|
||||||
CHECK(LoggingReadFile(file, buffer, size));
|
CHECK(LoggingReadFileExactly(file, buffer, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size) {
|
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||||
@ -61,9 +94,9 @@ void CheckedReadFileAtEOF(FileHandle file) {
|
|||||||
char c;
|
char c;
|
||||||
FileOperationResult rv = ReadFile(file, &c, 1);
|
FileOperationResult rv = ReadFile(file, &c, 1);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
PCHECK(rv == 0) << "read";
|
PCHECK(rv == 0) << kNativeReadFunctionName;
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(rv, 0) << "read";
|
CHECK_EQ(rv, 0) << kNativeReadFunctionName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,20 +114,33 @@ enum class FileLocking : bool {
|
|||||||
kExclusive,
|
kExclusive,
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \brief Reads from a file, retrying when interrupted on POSIX or following a
|
//! \brief The name of the native read function used by ReadFile().
|
||||||
//! short read.
|
|
||||||
//!
|
//!
|
||||||
//! This function reads into \a buffer, stopping only when \a size bytes have
|
//! This value may be useful for logging.
|
||||||
//! been read or when end-of-file has been reached. On Windows, reading from
|
//!
|
||||||
//! sockets is not currently supported.
|
//! \sa kNativeWriteFunctionName
|
||||||
|
extern const char kNativeReadFunctionName[];
|
||||||
|
|
||||||
|
//! \brief The name of the native write function used by WriteFile().
|
||||||
|
//!
|
||||||
|
//! This value may be useful for logging.
|
||||||
|
//!
|
||||||
|
//! \sa kNativeReadFunctionName
|
||||||
|
extern const char kNativeWriteFunctionName[];
|
||||||
|
|
||||||
|
//! \brief Reads from a file, retrying when interrupted on POSIX.
|
||||||
|
//!
|
||||||
|
//! This function reads into \a buffer. Fewer than \a size bytes may be read.
|
||||||
|
//! On Windows, reading from sockets is not currently supported.
|
||||||
//!
|
//!
|
||||||
//! \return The number of bytes read and placed into \a buffer, or `-1` on
|
//! \return The number of bytes read and placed into \a buffer, or `-1` on
|
||||||
//! error, with `errno` or `GetLastError()` set appropriately. On error, a
|
//! error, with `errno` or `GetLastError()` set appropriately. On error, a
|
||||||
//! portion of \a file may have been read into \a buffer.
|
//! portion of \a file may have been read into \a buffer.
|
||||||
//!
|
//!
|
||||||
//! \sa WriteFile
|
//! \sa WriteFile
|
||||||
//! \sa LoggingReadFile
|
//! \sa ReadFileExactly
|
||||||
//! \sa CheckedReadFile
|
//! \sa LoggingReadFileExactly
|
||||||
|
//! \sa CheckedReadFileExactly
|
||||||
//! \sa CheckedReadFileAtEOF
|
//! \sa CheckedReadFileAtEOF
|
||||||
FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size);
|
FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size);
|
||||||
|
|
||||||
@ -146,27 +159,50 @@ FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size);
|
|||||||
//! \sa CheckedWriteFile
|
//! \sa CheckedWriteFile
|
||||||
FileOperationResult WriteFile(FileHandle file, const void* buffer, size_t size);
|
FileOperationResult WriteFile(FileHandle file, const void* buffer, size_t size);
|
||||||
|
|
||||||
//! \brief Wraps ReadFile(), ensuring that exactly \a size bytes are read.
|
//! \brief Wraps ReadFile(), retrying following a short read, ensuring that
|
||||||
|
//! exactly \a size bytes are read.
|
||||||
//!
|
//!
|
||||||
//! \return `true` on success. If \a size is out of the range of possible
|
//! If \a size is out of the range of possible ReadFile() return values, this
|
||||||
//! ReadFile() return values, if the underlying ReadFile() fails, or if
|
//! function causes execution to terminate without returning.
|
||||||
//! other than \a size bytes were read, this function logs a message and
|
//!
|
||||||
|
//! \return `true` on success. If the underlying ReadFile() fails, or if fewer
|
||||||
|
//! than \a size bytes were read, this function logs a message and
|
||||||
//! returns `false`.
|
//! returns `false`.
|
||||||
//!
|
//!
|
||||||
//! \sa LoggingWriteFile
|
//! \sa LoggingWriteFile
|
||||||
//! \sa ReadFile
|
//! \sa ReadFile
|
||||||
//! \sa CheckedReadFile
|
//! \sa LoggingReadFileExactly
|
||||||
|
//! \sa CheckedReadFileExactly
|
||||||
//! \sa CheckedReadFileAtEOF
|
//! \sa CheckedReadFileAtEOF
|
||||||
bool LoggingReadFile(FileHandle file, void* buffer, size_t size);
|
bool ReadFileExactly(FileHandle file, void* buffer, size_t size);
|
||||||
|
|
||||||
|
//! \brief Wraps ReadFile(), retrying following a short read, ensuring that
|
||||||
|
//! exactly \a size bytes are read.
|
||||||
|
//!
|
||||||
|
//! If \a size is out of the range of possible ReadFile() return values, this
|
||||||
|
//! function causes execution to terminate without returning.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success. If the underlying ReadFile() fails, or if fewer
|
||||||
|
//! than \a size bytes were read, this function logs a message and
|
||||||
|
//! returns `false`.
|
||||||
|
//!
|
||||||
|
//! \sa LoggingWriteFile
|
||||||
|
//! \sa ReadFile
|
||||||
|
//! \sa ReadFileExactly
|
||||||
|
//! \sa CheckedReadFileExactly
|
||||||
|
//! \sa CheckedReadFileAtEOF
|
||||||
|
bool LoggingReadFileExactly(FileHandle file, void* buffer, size_t size);
|
||||||
|
|
||||||
//! \brief Wraps WriteFile(), ensuring that exactly \a size bytes are written.
|
//! \brief Wraps WriteFile(), ensuring that exactly \a size bytes are written.
|
||||||
//!
|
//!
|
||||||
//! \return `true` on success. If \a size is out of the range of possible
|
//! If \a size is out of the range of possible WriteFile() return values, this
|
||||||
//! WriteFile() return values, if the underlying WriteFile() fails, or if
|
//! function causes execution to terminate without returning.
|
||||||
//! other than \a size bytes were written, this function logs a message and
|
//!
|
||||||
|
//! \return `true` on success. If the underlying WriteFile() fails, or if fewer
|
||||||
|
//! than \a size bytes were written, this function logs a message and
|
||||||
//! returns `false`.
|
//! returns `false`.
|
||||||
//!
|
//!
|
||||||
//! \sa LoggingReadFile
|
//! \sa LoggingReadFileExactly
|
||||||
//! \sa WriteFile
|
//! \sa WriteFile
|
||||||
//! \sa CheckedWriteFile
|
//! \sa CheckedWriteFile
|
||||||
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size);
|
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size);
|
||||||
@ -174,22 +210,22 @@ bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size);
|
|||||||
//! \brief Wraps ReadFile(), ensuring that exactly \a size bytes are read.
|
//! \brief Wraps ReadFile(), ensuring that exactly \a size bytes are read.
|
||||||
//!
|
//!
|
||||||
//! If \a size is out of the range of possible ReadFile() return values, if the
|
//! If \a size is out of the range of possible ReadFile() return values, if the
|
||||||
//! underlying ReadFile() fails, or if other than \a size bytes were read, this
|
//! underlying ReadFile() fails, or if fewer than \a size bytes were read, this
|
||||||
//! function causes execution to terminate without returning.
|
//! function causes execution to terminate without returning.
|
||||||
//!
|
//!
|
||||||
//! \sa CheckedWriteFile
|
//! \sa CheckedWriteFile
|
||||||
//! \sa ReadFile
|
//! \sa ReadFile
|
||||||
//! \sa LoggingReadFile
|
//! \sa LoggingReadFileExactly
|
||||||
//! \sa CheckedReadFileAtEOF
|
//! \sa CheckedReadFileAtEOF
|
||||||
void CheckedReadFile(FileHandle file, void* buffer, size_t size);
|
void CheckedReadFileExactly(FileHandle file, void* buffer, size_t size);
|
||||||
|
|
||||||
//! \brief Wraps WriteFile(), ensuring that exactly \a size bytes are written.
|
//! \brief Wraps WriteFile(), ensuring that exactly \a size bytes are written.
|
||||||
//!
|
//!
|
||||||
//! If \a size is out of the range of possible WriteFile() return values, if the
|
//! If \a size is out of the range of possible WriteFile() return values, if the
|
||||||
//! underlying WriteFile() fails, or if other than \a size bytes were written,
|
//! underlying WriteFile() fails, or if fewer than \a size bytes were written,
|
||||||
//! this function causes execution to terminate without returning.
|
//! this function causes execution to terminate without returning.
|
||||||
//!
|
//!
|
||||||
//! \sa CheckedReadFile
|
//! \sa CheckedReadFileExactly
|
||||||
//! \sa WriteFile
|
//! \sa WriteFile
|
||||||
//! \sa LoggingWriteFile
|
//! \sa LoggingWriteFile
|
||||||
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size);
|
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size);
|
||||||
@ -200,7 +236,7 @@ void CheckedWriteFile(FileHandle file, const void* buffer, size_t size);
|
|||||||
//! If the underlying ReadFile() fails, or if a byte actually is read, this
|
//! If the underlying ReadFile() fails, or if a byte actually is read, this
|
||||||
//! function causes execution to terminate without returning.
|
//! function causes execution to terminate without returning.
|
||||||
//!
|
//!
|
||||||
//! \sa CheckedReadFile
|
//! \sa CheckedReadFileExactly
|
||||||
//! \sa ReadFile
|
//! \sa ReadFile
|
||||||
void CheckedReadFileAtEOF(FileHandle file);
|
void CheckedReadFileAtEOF(FileHandle file);
|
||||||
|
|
||||||
|
@ -24,54 +24,6 @@
|
|||||||
#include "base/numerics/safe_conversions.h"
|
#include "base/numerics/safe_conversions.h"
|
||||||
#include "base/posix/eintr_wrapper.h"
|
#include "base/posix/eintr_wrapper.h"
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct ReadTraits {
|
|
||||||
using VoidBufferType = void*;
|
|
||||||
using CharBufferType = char*;
|
|
||||||
static crashpad::FileOperationResult Operate(int fd,
|
|
||||||
CharBufferType buffer,
|
|
||||||
size_t size) {
|
|
||||||
return read(fd, buffer, size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WriteTraits {
|
|
||||||
using VoidBufferType = const void*;
|
|
||||||
using CharBufferType = const char*;
|
|
||||||
static crashpad::FileOperationResult Operate(int fd,
|
|
||||||
CharBufferType buffer,
|
|
||||||
size_t size) {
|
|
||||||
return write(fd, buffer, size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Traits>
|
|
||||||
crashpad::FileOperationResult
|
|
||||||
ReadOrWrite(int fd, typename Traits::VoidBufferType buffer, size_t size) {
|
|
||||||
typename Traits::CharBufferType buffer_c =
|
|
||||||
reinterpret_cast<typename Traits::CharBufferType>(buffer);
|
|
||||||
|
|
||||||
crashpad::FileOperationResult total_bytes = 0;
|
|
||||||
while (size > 0) {
|
|
||||||
crashpad::FileOperationResult bytes =
|
|
||||||
HANDLE_EINTR(Traits::Operate(fd, buffer_c, size));
|
|
||||||
if (bytes < 0) {
|
|
||||||
return bytes;
|
|
||||||
} else if (bytes == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_c += bytes;
|
|
||||||
size -= bytes;
|
|
||||||
total_bytes += bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return total_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace crashpad {
|
namespace crashpad {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -108,14 +60,44 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly,
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
const char kNativeReadFunctionName[] = "read";
|
||||||
|
const char kNativeWriteFunctionName[] = "write";
|
||||||
|
|
||||||
|
// TODO(mark): Handle > ssize_t-sized reads and writes if necessary. The
|
||||||
|
// standard leaves this implementation-defined. Some systems return EINVAL in
|
||||||
|
// this case. ReadFile() and WriteFile() could enforce this behavior.
|
||||||
|
|
||||||
FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size) {
|
FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size) {
|
||||||
return ReadOrWrite<ReadTraits>(file, buffer, size);
|
FileOperationResult bytes = HANDLE_EINTR(read(file, buffer, size));
|
||||||
|
if (bytes < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_LE(static_cast<size_t>(bytes), size);
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileOperationResult WriteFile(FileHandle file,
|
FileOperationResult WriteFile(FileHandle file,
|
||||||
const void* buffer,
|
const void* buffer,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
return ReadOrWrite<WriteTraits>(file, buffer, size);
|
const char* buffer_c = static_cast<const char*>(buffer);
|
||||||
|
|
||||||
|
FileOperationResult total_bytes = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
FileOperationResult bytes = HANDLE_EINTR(write(file, buffer_c, size));
|
||||||
|
if (bytes < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_NE(bytes, 0);
|
||||||
|
DCHECK_LE(static_cast<size_t>(bytes), size);
|
||||||
|
|
||||||
|
buffer_c += bytes;
|
||||||
|
size -= bytes;
|
||||||
|
total_bytes += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileHandle OpenFileForRead(const base::FilePath& path) {
|
FileHandle OpenFileForRead(const base::FilePath& path) {
|
||||||
|
@ -70,37 +70,37 @@ FileHandle OpenFileForOutput(DWORD access,
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// TODO(scottmg): Handle > DWORD sized writes if necessary.
|
const char kNativeReadFunctionName[] = "ReadFile";
|
||||||
|
const char kNativeWriteFunctionName[] = "WriteFile";
|
||||||
|
|
||||||
|
// TODO(scottmg): Handle > DWORD-sized reads and writes if necessary.
|
||||||
|
|
||||||
FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size) {
|
FileOperationResult ReadFile(FileHandle file, void* buffer, size_t size) {
|
||||||
DCHECK(!IsSocketHandle(file));
|
DCHECK(!IsSocketHandle(file));
|
||||||
DWORD size_dword = base::checked_cast<DWORD>(size);
|
|
||||||
DWORD total_read = 0;
|
while (true) {
|
||||||
char* buffer_c = reinterpret_cast<char*>(buffer);
|
DWORD size_dword = base::checked_cast<DWORD>(size);
|
||||||
while (size_dword > 0) {
|
|
||||||
DWORD bytes_read;
|
DWORD bytes_read;
|
||||||
BOOL success = ::ReadFile(file, buffer_c, size_dword, &bytes_read, nullptr);
|
BOOL success = ::ReadFile(file, buffer, size_dword, &bytes_read, nullptr);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
||||||
// When reading a pipe and the write handle has been closed, ReadFile
|
// When reading a pipe and the write handle has been closed, ReadFile
|
||||||
// fails with ERROR_BROKEN_PIPE, but only once all pending data has been
|
// fails with ERROR_BROKEN_PIPE, but only once all pending data has been
|
||||||
// read.
|
// read. Treat this as EOF.
|
||||||
break;
|
return 0;
|
||||||
} else if (GetLastError() != ERROR_MORE_DATA) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
} else if (bytes_read == 0 && GetFileType(file) != FILE_TYPE_PIPE) {
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK_NE(bytes_read, static_cast<DWORD>(-1));
|
||||||
|
DCHECK_LE(bytes_read, size_dword);
|
||||||
|
if (bytes_read != 0 || GetFileType(file) != FILE_TYPE_PIPE) {
|
||||||
// Zero bytes read for a file indicates reaching EOF. Zero bytes read from
|
// Zero bytes read for a file indicates reaching EOF. Zero bytes read from
|
||||||
// a pipe indicates only that there was a zero byte WriteFile issued on
|
// a pipe indicates only that there was a zero byte WriteFile issued on
|
||||||
// the other end, so continue reading.
|
// the other end, so continue reading.
|
||||||
break;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_c += bytes_read;
|
|
||||||
size_dword -= bytes_read;
|
|
||||||
total_read += bytes_read;
|
|
||||||
}
|
}
|
||||||
return total_read;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileOperationResult WriteFile(FileHandle file,
|
FileOperationResult WriteFile(FileHandle file,
|
||||||
@ -113,6 +113,7 @@ FileOperationResult WriteFile(FileHandle file,
|
|||||||
BOOL rv = ::WriteFile(file, buffer, size_dword, &bytes_written, nullptr);
|
BOOL rv = ::WriteFile(file, buffer, size_dword, &bytes_written, nullptr);
|
||||||
if (!rv)
|
if (!rv)
|
||||||
return -1;
|
return -1;
|
||||||
|
CHECK_NE(bytes_written, static_cast<DWORD>(-1));
|
||||||
CHECK_EQ(bytes_written, size_dword);
|
CHECK_EQ(bytes_written, size_dword);
|
||||||
return bytes_written;
|
return bytes_written;
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,30 @@ namespace crashpad {
|
|||||||
|
|
||||||
bool FileReaderInterface::ReadExactly(void* data, size_t size) {
|
bool FileReaderInterface::ReadExactly(void* data, size_t size) {
|
||||||
FileOperationResult expect = base::checked_cast<FileOperationResult>(size);
|
FileOperationResult expect = base::checked_cast<FileOperationResult>(size);
|
||||||
FileOperationResult rv = Read(data, size);
|
char* data_c = static_cast<char*>(data);
|
||||||
if (rv < 0) {
|
|
||||||
// Read() will have logged its own error.
|
FileOperationResult total_bytes = 0;
|
||||||
return false;
|
while (size > 0) {
|
||||||
} else if (rv != expect) {
|
FileOperationResult bytes = Read(data, size);
|
||||||
LOG(ERROR) << "ReadExactly(): expected " << expect << ", observed " << rv;
|
if (bytes < 0) {
|
||||||
|
// Read() will have logged its own error.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_LE(static_cast<size_t>(bytes), size);
|
||||||
|
|
||||||
|
if (bytes == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_c += bytes;
|
||||||
|
size -= bytes;
|
||||||
|
total_bytes += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_bytes != expect) {
|
||||||
|
LOG(ERROR) << "ReadExactly(): expected " << expect << ", observed "
|
||||||
|
<< total_bytes;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,13 +62,10 @@ WeakFileHandleFileReader::~WeakFileHandleFileReader() {
|
|||||||
FileOperationResult WeakFileHandleFileReader::Read(void* data, size_t size) {
|
FileOperationResult WeakFileHandleFileReader::Read(void* data, size_t size) {
|
||||||
DCHECK_NE(file_handle_, kInvalidFileHandle);
|
DCHECK_NE(file_handle_, kInvalidFileHandle);
|
||||||
|
|
||||||
// Don’t use LoggingReadFile(), which insists on a full read and only returns
|
|
||||||
// a bool. This method permits short reads and returns the number of bytes
|
|
||||||
// read.
|
|
||||||
base::checked_cast<FileOperationResult>(size);
|
base::checked_cast<FileOperationResult>(size);
|
||||||
FileOperationResult rv = ReadFile(file_handle_, data, size);
|
FileOperationResult rv = ReadFile(file_handle_, data, size);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
PLOG(ERROR) << "read";
|
PLOG(ERROR) << kNativeReadFunctionName;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class FileReaderInterface : public virtual FileSeekerInterface {
|
|||||||
//! \brief Wraps Read(), ensuring that the read succeeded and exactly \a size
|
//! \brief Wraps Read(), ensuring that the read succeeded and exactly \a size
|
||||||
//! bytes were read.
|
//! bytes were read.
|
||||||
//!
|
//!
|
||||||
//! Semantically, this behaves as LoggingReadFile().
|
//! Semantically, this behaves as LoggingReadFileExactly().
|
||||||
//!
|
//!
|
||||||
//! \return `true` if the operation succeeded, `false` if it failed, with an
|
//! \return `true` if the operation succeeded, `false` if it failed, with an
|
||||||
//! error message logged. Short reads are treated as failures.
|
//! error message logged. Short reads are treated as failures.
|
||||||
|
@ -403,20 +403,20 @@ bool ChildPortHandshake::RunClientInternal_ReadPipe(int client_read_fd,
|
|||||||
child_port_token_t* token,
|
child_port_token_t* token,
|
||||||
std::string* service_name) {
|
std::string* service_name) {
|
||||||
// Read the token from the pipe.
|
// Read the token from the pipe.
|
||||||
if (!LoggingReadFile(client_read_fd, token, sizeof(*token))) {
|
if (!LoggingReadFileExactly(client_read_fd, token, sizeof(*token))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the service name from the pipe.
|
// Read the service name from the pipe.
|
||||||
uint32_t service_name_length;
|
uint32_t service_name_length;
|
||||||
if (!LoggingReadFile(
|
if (!LoggingReadFileExactly(
|
||||||
client_read_fd, &service_name_length, sizeof(service_name_length))) {
|
client_read_fd, &service_name_length, sizeof(service_name_length))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
service_name->resize(service_name_length);
|
service_name->resize(service_name_length);
|
||||||
if (!service_name->empty() &&
|
if (!service_name->empty() &&
|
||||||
!LoggingReadFile(
|
!LoggingReadFileExactly(
|
||||||
client_read_fd, &(*service_name)[0], service_name_length)) {
|
client_read_fd, &(*service_name)[0], service_name_length)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
|||||||
CheckedWriteFile(test_exception_ports_->WritePipeHandle(), &c, 1);
|
CheckedWriteFile(test_exception_ports_->WritePipeHandle(), &c, 1);
|
||||||
|
|
||||||
// Wait for the parent process to say that its end is set up.
|
// Wait for the parent process to say that its end is set up.
|
||||||
CheckedReadFile(test_exception_ports_->ReadPipeHandle(), &c, 1);
|
CheckedReadFileExactly(test_exception_ports_->ReadPipeHandle(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
|
|
||||||
// Regardless of where ExceptionPorts::SetExceptionPort() ran,
|
// Regardless of where ExceptionPorts::SetExceptionPort() ran,
|
||||||
@ -352,7 +352,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
|||||||
// Wait for the child process to be ready. It needs to have all of its
|
// Wait for the child process to be ready. It needs to have all of its
|
||||||
// threads set up before proceeding if in kSetOutOfProcess mode.
|
// threads set up before proceeding if in kSetOutOfProcess mode.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, 1);
|
CheckedReadFileExactly(ReadPipeHandle(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
|
|
||||||
mach_port_t local_port = LocalPort();
|
mach_port_t local_port = LocalPort();
|
||||||
|
@ -344,7 +344,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
if (options_.parent_wait_for_child_pipe) {
|
if (options_.parent_wait_for_child_pipe) {
|
||||||
// Wait until the child is done sending what it’s going to send.
|
// Wait until the child is done sending what it’s going to send.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, 1);
|
CheckedReadFileExactly(ReadPipeHandle(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +397,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
if (options_.child_wait_for_parent_pipe_early) {
|
if (options_.child_wait_for_parent_pipe_early) {
|
||||||
// Wait until the parent is done setting things up on its end.
|
// Wait until the parent is done setting things up on its end.
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, 1);
|
CheckedReadFileExactly(ReadPipeHandle(), &c, 1);
|
||||||
EXPECT_EQ('\0', c);
|
EXPECT_EQ('\0', c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +431,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
|||||||
|
|
||||||
if (options_.child_wait_for_parent_pipe_late) {
|
if (options_.child_wait_for_parent_pipe_late) {
|
||||||
char c;
|
char c;
|
||||||
CheckedReadFile(ReadPipeHandle(), &c, 1);
|
CheckedReadFileExactly(ReadPipeHandle(), &c, 1);
|
||||||
ASSERT_EQ('\0', c);
|
ASSERT_EQ('\0', c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
|||||||
// The child will write the HTTP server port number as a packed unsigned
|
// The child will write the HTTP server port number as a packed unsigned
|
||||||
// short to stdout.
|
// short to stdout.
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
ASSERT_TRUE(LoggingReadFile(ReadPipeHandle(), &port, sizeof(port)));
|
ASSERT_TRUE(LoggingReadFileExactly(ReadPipeHandle(), &port, sizeof(port)));
|
||||||
|
|
||||||
// Then the parent will tell the web server what response code to send
|
// Then the parent will tell the web server what response code to send
|
||||||
// for the HTTP request.
|
// for the HTTP request.
|
||||||
|
@ -396,7 +396,8 @@ bool ExceptionHandlerServer::ServiceClientConnection(
|
|||||||
const internal::PipeServiceContext& service_context) {
|
const internal::PipeServiceContext& service_context) {
|
||||||
ClientToServerMessage message;
|
ClientToServerMessage message;
|
||||||
|
|
||||||
if (!LoggingReadFile(service_context.pipe(), &message, sizeof(message)))
|
if (!LoggingReadFileExactly(
|
||||||
|
service_context.pipe(), &message, sizeof(message)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
|
@ -143,10 +143,11 @@ TEST_F(ExceptionHandlerServerTest, StopWhileConnected) {
|
|||||||
|
|
||||||
std::wstring ReadWString(FileHandle handle) {
|
std::wstring ReadWString(FileHandle handle) {
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
EXPECT_TRUE(LoggingReadFile(handle, &length, sizeof(length)));
|
EXPECT_TRUE(LoggingReadFileExactly(handle, &length, sizeof(length)));
|
||||||
std::wstring str(length, L'\0');
|
std::wstring str(length, L'\0');
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
EXPECT_TRUE(LoggingReadFile(handle, &str[0], length * sizeof(str[0])));
|
EXPECT_TRUE(
|
||||||
|
LoggingReadFileExactly(handle, &str[0], length * sizeof(str[0])));
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ void TestOtherProcess(const base::string16& directory_modification) {
|
|||||||
|
|
||||||
// The child sends us a code address we can look up in the memory map.
|
// The child sends us a code address we can look up in the memory map.
|
||||||
WinVMAddress code_address;
|
WinVMAddress code_address;
|
||||||
CheckedReadFile(
|
CheckedReadFileExactly(
|
||||||
child.stdout_read_handle(), &code_address, sizeof(code_address));
|
child.stdout_read_handle(), &code_address, sizeof(code_address));
|
||||||
|
|
||||||
ASSERT_TRUE(process_info.Initialize(child.process_handle()));
|
ASSERT_TRUE(process_info.Initialize(child.process_handle()));
|
||||||
|
@ -80,7 +80,7 @@ class ScopedProcessSuspendTest final : public WinChildProcess {
|
|||||||
int Run() override {
|
int Run() override {
|
||||||
char c;
|
char c;
|
||||||
// Wait for notification from parent.
|
// Wait for notification from parent.
|
||||||
EXPECT_TRUE(LoggingReadFile(ReadPipeHandle(), &c, sizeof(c)));
|
EXPECT_TRUE(LoggingReadFileExactly(ReadPipeHandle(), &c, sizeof(c)));
|
||||||
EXPECT_EQ(' ', c);
|
EXPECT_EQ(' ', c);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user