mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Cross platform low level file IO wrappers
Rename fd_io to file_io, and ReadFD to ReadFile, etc. file_io.cc is the higher level versions that call the basic ReadFile/WriteFile and then file_io_posix.cc and file_io_win.cc are the implementations of those functions. The Windows path is as yet untested, lacking the ability to link the test binary. R=cpu@chromium.org, mark@chromium.org BUG=crashpad:1 Review URL: https://codereview.chromium.org/811823003
This commit is contained in:
parent
3d84a738d0
commit
10165ce449
@ -30,7 +30,7 @@
|
||||
#include "client/simple_string_dictionary.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/mac/process_reader.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/mac/mac_util.h"
|
||||
#include "util/mach/exc_server_variants.h"
|
||||
#include "util/mach/exception_ports.h"
|
||||
@ -193,7 +193,7 @@ class TestMachOImageAnnotationsReader final
|
||||
// Wait for the child process to indicate that it’s done setting up its
|
||||
// annotations via the CrashpadInfo interface.
|
||||
char c;
|
||||
CheckedReadFD(ReadPipeFD(), &c, sizeof(c));
|
||||
CheckedReadFile(ReadPipeFD(), &c, sizeof(c));
|
||||
|
||||
// Verify the “simple map” annotations set via the CrashpadInfo interface.
|
||||
const std::vector<ProcessReader::Module>& modules =
|
||||
@ -216,7 +216,7 @@ class TestMachOImageAnnotationsReader final
|
||||
EXPECT_EQ("", all_annotations_simple_map["#TEST# empty_value"]);
|
||||
|
||||
// Tell the child process that it’s permitted to crash.
|
||||
CheckedWriteFD(WritePipeFD(), &c, sizeof(c));
|
||||
CheckedWriteFile(WritePipeFD(), &c, sizeof(c));
|
||||
|
||||
if (test_type_ != kDontCrash) {
|
||||
// Handle the child’s crash. Further validation will be done in
|
||||
@ -268,10 +268,10 @@ class TestMachOImageAnnotationsReader final
|
||||
|
||||
// Tell the parent that the environment has been set up.
|
||||
char c = '\0';
|
||||
CheckedWriteFD(WritePipeFD(), &c, sizeof(c));
|
||||
CheckedWriteFile(WritePipeFD(), &c, sizeof(c));
|
||||
|
||||
// Wait for the parent to indicate that it’s safe to crash.
|
||||
CheckedReadFD(ReadPipeFD(), &c, sizeof(c));
|
||||
CheckedReadFile(ReadPipeFD(), &c, sizeof(c));
|
||||
|
||||
// Direct an exception message to the exception server running in the
|
||||
// parent.
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/mac/mach_o_image_reader.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/stdlib/pointer_container.h"
|
||||
#include "util/synchronization/semaphore.h"
|
||||
@ -91,7 +91,7 @@ class ProcessReaderChild final : public MachMultiprocess {
|
||||
int read_fd = ReadPipeFD();
|
||||
|
||||
mach_vm_address_t address;
|
||||
CheckedReadFD(read_fd, &address, sizeof(address));
|
||||
CheckedReadFile(read_fd, &address, sizeof(address));
|
||||
|
||||
std::string read_string;
|
||||
ASSERT_TRUE(process_reader.Memory()->ReadCString(address, &read_string));
|
||||
@ -103,11 +103,11 @@ class ProcessReaderChild final : public MachMultiprocess {
|
||||
|
||||
mach_vm_address_t address =
|
||||
reinterpret_cast<mach_vm_address_t>(kTestMemory);
|
||||
CheckedWriteFD(write_fd, &address, sizeof(address));
|
||||
CheckedWriteFile(write_fd, &address, sizeof(address));
|
||||
|
||||
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
||||
// the pipe.
|
||||
CheckedReadFDAtEOF(ReadPipeFD());
|
||||
CheckedReadFileAtEOF(ReadPipeFD());
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessReaderChild);
|
||||
@ -434,13 +434,13 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
|
||||
thread_index < thread_count_ + 1;
|
||||
++thread_index) {
|
||||
uint64_t thread_id;
|
||||
CheckedReadFD(read_fd, &thread_id, sizeof(thread_id));
|
||||
CheckedReadFile(read_fd, &thread_id, sizeof(thread_id));
|
||||
|
||||
TestThreadPool::ThreadExpectation expectation;
|
||||
CheckedReadFD(read_fd,
|
||||
CheckedReadFile(read_fd,
|
||||
&expectation.stack_address,
|
||||
sizeof(expectation.stack_address));
|
||||
CheckedReadFD(read_fd,
|
||||
CheckedReadFile(read_fd,
|
||||
&expectation.suspend_count,
|
||||
sizeof(expectation.suspend_count));
|
||||
|
||||
@ -467,16 +467,16 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
|
||||
// to inspect it. Write an entry for it.
|
||||
uint64_t thread_id = PthreadToThreadID(pthread_self());
|
||||
|
||||
CheckedWriteFD(write_fd, &thread_id, sizeof(thread_id));
|
||||
CheckedWriteFile(write_fd, &thread_id, sizeof(thread_id));
|
||||
|
||||
TestThreadPool::ThreadExpectation expectation;
|
||||
expectation.stack_address = reinterpret_cast<mach_vm_address_t>(&thread_id);
|
||||
expectation.suspend_count = 0;
|
||||
|
||||
CheckedWriteFD(write_fd,
|
||||
CheckedWriteFile(write_fd,
|
||||
&expectation.stack_address,
|
||||
sizeof(expectation.stack_address));
|
||||
CheckedWriteFD(write_fd,
|
||||
CheckedWriteFile(write_fd,
|
||||
&expectation.suspend_count,
|
||||
sizeof(expectation.suspend_count));
|
||||
|
||||
@ -487,18 +487,18 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
|
||||
uint64_t thread_id =
|
||||
thread_pool.GetThreadInfo(thread_index, &expectation);
|
||||
|
||||
CheckedWriteFD(write_fd, &thread_id, sizeof(thread_id));
|
||||
CheckedWriteFD(write_fd,
|
||||
CheckedWriteFile(write_fd, &thread_id, sizeof(thread_id));
|
||||
CheckedWriteFile(write_fd,
|
||||
&expectation.stack_address,
|
||||
sizeof(expectation.stack_address));
|
||||
CheckedWriteFD(write_fd,
|
||||
CheckedWriteFile(write_fd,
|
||||
&expectation.suspend_count,
|
||||
sizeof(expectation.suspend_count));
|
||||
}
|
||||
|
||||
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
||||
// the pipe.
|
||||
CheckedReadFDAtEOF(ReadPipeFD());
|
||||
CheckedReadFileAtEOF(ReadPipeFD());
|
||||
}
|
||||
|
||||
size_t thread_count_;
|
||||
@ -597,7 +597,7 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
||||
int read_fd = ReadPipeFD();
|
||||
|
||||
uint32_t expect_modules;
|
||||
CheckedReadFD(read_fd, &expect_modules, sizeof(expect_modules));
|
||||
CheckedReadFile(read_fd, &expect_modules, sizeof(expect_modules));
|
||||
|
||||
ASSERT_EQ(expect_modules, modules.size());
|
||||
|
||||
@ -606,16 +606,16 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
||||
"index %zu, name %s", index, modules[index].name.c_str()));
|
||||
|
||||
uint32_t expect_name_length;
|
||||
CheckedReadFD(
|
||||
CheckedReadFile(
|
||||
read_fd, &expect_name_length, sizeof(expect_name_length));
|
||||
|
||||
// The NUL terminator is not read.
|
||||
std::string expect_name(expect_name_length, '\0');
|
||||
CheckedReadFD(read_fd, &expect_name[0], expect_name_length);
|
||||
CheckedReadFile(read_fd, &expect_name[0], expect_name_length);
|
||||
EXPECT_EQ(expect_name, modules[index].name);
|
||||
|
||||
mach_vm_address_t expect_address;
|
||||
CheckedReadFD(read_fd, &expect_address, sizeof(expect_address));
|
||||
CheckedReadFile(read_fd, &expect_address, sizeof(expect_address));
|
||||
EXPECT_EQ(expect_address, modules[index].reader->Address());
|
||||
|
||||
if (index == 0 || index == modules.size() - 1) {
|
||||
@ -648,7 +648,7 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
||||
++write_image_count;
|
||||
}
|
||||
|
||||
CheckedWriteFD(write_fd, &write_image_count, sizeof(write_image_count));
|
||||
CheckedWriteFile(write_fd, &write_image_count, sizeof(write_image_count));
|
||||
|
||||
for (size_t index = 0; index < write_image_count; ++index) {
|
||||
const char* dyld_image_name;
|
||||
@ -665,18 +665,19 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
||||
}
|
||||
|
||||
uint32_t dyld_image_name_length = strlen(dyld_image_name);
|
||||
CheckedWriteFD(
|
||||
CheckedWriteFile(
|
||||
write_fd, &dyld_image_name_length, sizeof(dyld_image_name_length));
|
||||
|
||||
// The NUL terminator is not written.
|
||||
CheckedWriteFD(write_fd, dyld_image_name, dyld_image_name_length);
|
||||
CheckedWriteFile(write_fd, dyld_image_name, dyld_image_name_length);
|
||||
|
||||
CheckedWriteFD(write_fd, &dyld_image_address, sizeof(dyld_image_address));
|
||||
CheckedWriteFile(
|
||||
write_fd, &dyld_image_address, sizeof(dyld_image_address));
|
||||
}
|
||||
|
||||
// Wait for the parent to signal that it’s OK to exit by closing its end of
|
||||
// the pipe.
|
||||
CheckedReadFDAtEOF(ReadPipeFD());
|
||||
CheckedReadFileAtEOF(ReadPipeFD());
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessReaderModulesChild);
|
||||
|
@ -1,125 +0,0 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_FILE_FD_IO_H_
|
||||
#define CRASHPAD_UTIL_FILE_FD_IO_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief Wraps `read()`, retrying when interrupted or following a short read.
|
||||
//!
|
||||
//! This function reads into \a buffer, stopping only when \a size bytes have
|
||||
//! been read or when `read()` returns 0, indicating that end-of-file has been
|
||||
//! reached.
|
||||
//!
|
||||
//! \return The number of bytes read and placed into \a buffer, or `-1` on
|
||||
//! error, with `errno` set appropriately. On error, a portion of \a fd may
|
||||
//! have been read into \a buffer.
|
||||
//!
|
||||
//! \sa WriteFD
|
||||
//! \sa LoggingReadFD
|
||||
//! \sa CheckedReadFD
|
||||
//! \sa CheckedReadFDAtEOF
|
||||
ssize_t ReadFD(int fd, void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps `write()`, retrying when interrupted or following a short
|
||||
//! write.
|
||||
//!
|
||||
//! This function writes to \a fd, stopping only when \a size bytes have been
|
||||
//! written.
|
||||
//!
|
||||
//! \return The number of bytes written from \a buffer, or `-1` on error, with
|
||||
//! `errno` set appropriately. On error, a portion of \a buffer may have
|
||||
//! been written to \a fd.
|
||||
//!
|
||||
//! \sa ReadFD
|
||||
//! \sa LoggingWriteFD
|
||||
//! \sa CheckedWriteFD
|
||||
ssize_t WriteFD(int fd, const void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps ReadFD(), ensuring that exactly \a size bytes are read.
|
||||
//!
|
||||
//! \return `true` on success. If \a size is out of the range of possible
|
||||
//! `read()` return values, if the underlying ReadFD() fails, or if other
|
||||
//! than \a size bytes were read, this function logs a message and returns
|
||||
//! `false`.
|
||||
//!
|
||||
//! \sa LoggingWriteFD
|
||||
//! \sa ReadFD
|
||||
//! \sa CheckedReadFD
|
||||
//! \sa CheckedReadFDAtEOF
|
||||
bool LoggingReadFD(int fd, void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps WriteFD(), ensuring that exactly \a size bytes are written.
|
||||
//!
|
||||
//! \return `true` on success. If \a size is out of the range of possible
|
||||
//! `write()` return values, if the underlying WriteFD() fails, or if other
|
||||
//! than \a size bytes were written, this function logs a message and
|
||||
//! returns `false`.
|
||||
//!
|
||||
//! \sa LoggingReadFD
|
||||
//! \sa WriteFD
|
||||
//! \sa CheckedWriteFD
|
||||
bool LoggingWriteFD(int fd, const void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps ReadFD(), ensuring that exactly \a size bytes are read.
|
||||
//!
|
||||
//! If \a size is out of the range of possible `read()` return values, if the
|
||||
//! underlying ReadFD() fails, or if other than \a size bytes were read, this
|
||||
//! function causes execution to terminate without returning.
|
||||
//!
|
||||
//! \sa CheckedWriteFD
|
||||
//! \sa ReadFD
|
||||
//! \sa LoggingReadFD
|
||||
//! \sa CheckedReadFDAtEOF
|
||||
void CheckedReadFD(int fd, void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps WriteFD(), ensuring that exactly \a size bytes are written.
|
||||
//!
|
||||
//! If \a size is out of the range of possible `write()` return values, if the
|
||||
//! underlying WriteFD() fails, or if other than \a size bytes were written,
|
||||
//! this function causes execution to terminate without returning.
|
||||
//!
|
||||
//! \sa CheckedReadFD
|
||||
//! \sa WriteFD
|
||||
//! \sa LoggingWriteFD
|
||||
void CheckedWriteFD(int fd, const void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps ReadFD(), ensuring that it indicates end-of-file.
|
||||
//!
|
||||
//! Attempts to read a single byte from \a fd, expecting no data to be read. If
|
||||
//! the underlying ReadFD() fails, or if a byte actually is read, this function
|
||||
//! causes execution to terminate without returning.
|
||||
//!
|
||||
//! \sa CheckedReadFD
|
||||
//! \sa ReadFD
|
||||
void CheckedReadFDAtEOF(int fd);
|
||||
|
||||
//! \brief Wraps `close()`, logging an error if the operation fails.
|
||||
//!
|
||||
//! \return On success, `true` is returned. On failure, an error is logged and
|
||||
//! `false` is returned.
|
||||
bool LoggingCloseFD(int fd);
|
||||
|
||||
//! \brief Wraps `close()`, ensuring that it succeeds.
|
||||
//!
|
||||
//! If `close()` fails, this function causes execution to terminate without
|
||||
//! returning.
|
||||
void CheckedCloseFD(int fd);
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_FILE_FD_IO_H_
|
74
util/file/file_io.cc
Normal file
74
util/file/file_io.cc
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
bool LoggingReadFile(FileHandle file, void* buffer, size_t size) {
|
||||
ssize_t expect = base::checked_cast<ssize_t>(size);
|
||||
ssize_t rv = ReadFile(file, buffer, size);
|
||||
if (rv < 0) {
|
||||
PLOG(ERROR) << "read";
|
||||
return false;
|
||||
}
|
||||
if (rv != expect) {
|
||||
LOG(ERROR) << "read: expected " << expect << ", observed " << rv;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||
ssize_t expect = base::checked_cast<ssize_t>(size);
|
||||
ssize_t rv = WriteFile(file, buffer, size);
|
||||
if (rv < 0) {
|
||||
PLOG(ERROR) << "write";
|
||||
return false;
|
||||
}
|
||||
if (rv != expect) {
|
||||
LOG(ERROR) << "write: expected " << expect << ", observed " << rv;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckedReadFile(FileHandle file, void* buffer, size_t size) {
|
||||
CHECK(LoggingReadFile(file, buffer, size));
|
||||
}
|
||||
|
||||
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||
CHECK(LoggingWriteFile(file, buffer, size));
|
||||
}
|
||||
|
||||
void CheckedReadFileAtEOF(FileHandle file) {
|
||||
char c;
|
||||
ssize_t rv = ReadFile(file, &c, 1);
|
||||
if (rv < 0) {
|
||||
PCHECK(rv == 0) << "read";
|
||||
} else {
|
||||
CHECK_EQ(rv, 0) << "read";
|
||||
}
|
||||
}
|
||||
|
||||
void CheckedCloseFile(FileHandle file) {
|
||||
CHECK(LoggingCloseFile(file));
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
139
util/file/file_io.h
Normal file
139
util/file/file_io.h
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_FILE_FILE_IO_H_
|
||||
#define CRASHPAD_UTIL_FILE_FILE_IO_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
using FileHandle = int;
|
||||
#elif defined(OS_WIN)
|
||||
using FileHandle = HANDLE;
|
||||
#endif
|
||||
|
||||
//! \brief Reads from a file, retrying when interrupted on POSIX or following a
|
||||
//! short read.
|
||||
//!
|
||||
//! This function reads into \a buffer, stopping only when \a size bytes have
|
||||
//! been read or when end-of-file has been reached. On Windows, reading from
|
||||
//! sockets is not currently supported.
|
||||
//!
|
||||
//! \return The number of bytes read and placed into \a buffer, or `-1` on
|
||||
//! error, with `errno` or `GetLastError()` set appropriately. On error, a
|
||||
//! portion of \a file may have been read into \a buffer.
|
||||
//!
|
||||
//! \sa WriteFile
|
||||
//! \sa LoggingReadFile
|
||||
//! \sa CheckedReadFile
|
||||
//! \sa CheckedReadFileAtEOF
|
||||
ssize_t ReadFile(FileHandle file, void* buffer, size_t size);
|
||||
|
||||
//! \brief Writes to a file, retrying when interrupted or following a short
|
||||
//! write on POSIX.
|
||||
//!
|
||||
//! This function writes to \a file, stopping only when \a size bytes have been
|
||||
//! written.
|
||||
//!
|
||||
//! \return The number of bytes written from \a buffer, or `-1` on error, with
|
||||
//! `errno` or `GetLastError()` set appropriately. On error, a portion of
|
||||
//! \a buffer may have been written to \a file.
|
||||
//!
|
||||
//! \sa ReadFile
|
||||
//! \sa LoggingWriteFile
|
||||
//! \sa CheckedWriteFile
|
||||
ssize_t WriteFile(FileHandle file, const void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps ReadFile(), ensuring that exactly \a size bytes are read.
|
||||
//!
|
||||
//! \return `true` on success. 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 function logs a message and
|
||||
//! returns `false`.
|
||||
//!
|
||||
//! \sa LoggingWriteFile
|
||||
//! \sa ReadFile
|
||||
//! \sa CheckedReadFile
|
||||
//! \sa CheckedReadFileAtEOF
|
||||
bool LoggingReadFile(FileHandle file, void* buffer, size_t size);
|
||||
|
||||
//! \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
|
||||
//! WriteFile() return values, if the underlying WriteFile() fails, or if
|
||||
//! other than \a size bytes were written, this function logs a message and
|
||||
//! returns `false`.
|
||||
//!
|
||||
//! \sa LoggingReadFile
|
||||
//! \sa WriteFile
|
||||
//! \sa CheckedWriteFile
|
||||
bool LoggingWriteFile(FileHandle file, const void* buffer, size_t size);
|
||||
|
||||
//! \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
|
||||
//! underlying ReadFile() fails, or if other than \a size bytes were read, this
|
||||
//! function causes execution to terminate without returning.
|
||||
//!
|
||||
//! \sa CheckedWriteFile
|
||||
//! \sa ReadFile
|
||||
//! \sa LoggingReadFile
|
||||
//! \sa CheckedReadFileAtEOF
|
||||
void CheckedReadFile(FileHandle file, void* buffer, size_t size);
|
||||
|
||||
//! \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
|
||||
//! underlying WriteFile() fails, or if other than \a size bytes were written,
|
||||
//! this function causes execution to terminate without returning.
|
||||
//!
|
||||
//! \sa CheckedReadFile
|
||||
//! \sa WriteFile
|
||||
//! \sa LoggingWriteFile
|
||||
void CheckedWriteFile(FileHandle file, const void* buffer, size_t size);
|
||||
|
||||
//! \brief Wraps ReadFile(), ensuring that it indicates end-of-file.
|
||||
//!
|
||||
//! Attempts to read a single byte from \a file, expecting no data to be read.
|
||||
//! If the underlying ReadFile() fails, or if a byte actually is read, this
|
||||
//! function causes execution to terminate without returning.
|
||||
//!
|
||||
//! \sa CheckedReadFile
|
||||
//! \sa ReadFile
|
||||
void CheckedReadFileAtEOF(FileHandle file);
|
||||
|
||||
//! \brief Wraps `close()` or `CloseHandle()`, logging an error if the operation
|
||||
//! fails.
|
||||
//!
|
||||
//! \return On success, `true` is returned. On failure, an error is logged and
|
||||
//! `false` is returned.
|
||||
bool LoggingCloseFile(FileHandle file);
|
||||
|
||||
//! \brief Wraps `close()` or `CloseHandle()`, ensuring that it succeeds.
|
||||
//!
|
||||
//! If the underlying function fails, this function causes execution to
|
||||
//! terminate without returning.
|
||||
void CheckedCloseFile(FileHandle file);
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_FILE_FILE_IO_H_
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
@ -66,70 +66,18 @@ ssize_t ReadOrWrite(int fd,
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
ssize_t ReadFD(int fd, void* buffer, size_t size) {
|
||||
return ReadOrWrite<ReadTraits>(fd, buffer, size);
|
||||
ssize_t ReadFile(FileHandle file, void* buffer, size_t size) {
|
||||
return ReadOrWrite<ReadTraits>(file, buffer, size);
|
||||
}
|
||||
|
||||
ssize_t WriteFD(int fd, const void* buffer, size_t size) {
|
||||
return ReadOrWrite<WriteTraits>(fd, buffer, size);
|
||||
ssize_t WriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||
return ReadOrWrite<WriteTraits>(file, buffer, size);
|
||||
}
|
||||
|
||||
bool LoggingReadFD(int fd, void* buffer, size_t size) {
|
||||
ssize_t expect = base::checked_cast<ssize_t>(size);
|
||||
ssize_t rv = ReadFD(fd, buffer, size);
|
||||
if (rv < 0) {
|
||||
PLOG(ERROR) << "read";
|
||||
return false;
|
||||
}
|
||||
if (rv != expect) {
|
||||
LOG(ERROR) << "read: expected " << expect << ", observed " << rv;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoggingWriteFD(int fd, const void* buffer, size_t size) {
|
||||
ssize_t expect = base::checked_cast<ssize_t>(size);
|
||||
ssize_t rv = WriteFD(fd, buffer, size);
|
||||
if (rv < 0) {
|
||||
PLOG(ERROR) << "write";
|
||||
return false;
|
||||
}
|
||||
if (rv != expect) {
|
||||
LOG(ERROR) << "write: expected " << expect << ", observed " << rv;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CheckedReadFD(int fd, void* buffer, size_t size) {
|
||||
CHECK(LoggingReadFD(fd, buffer, size));
|
||||
}
|
||||
|
||||
void CheckedWriteFD(int fd, const void* buffer, size_t size) {
|
||||
CHECK(LoggingWriteFD(fd, buffer, size));
|
||||
}
|
||||
|
||||
void CheckedReadFDAtEOF(int fd) {
|
||||
char c;
|
||||
ssize_t rv = ReadFD(fd, &c, 1);
|
||||
if (rv < 0) {
|
||||
PCHECK(rv == 0) << "read";
|
||||
} else {
|
||||
CHECK_EQ(rv, 0) << "read";
|
||||
}
|
||||
}
|
||||
|
||||
bool LoggingCloseFD(int fd) {
|
||||
int rv = IGNORE_EINTR(close(fd));
|
||||
bool LoggingCloseFile(FileHandle file) {
|
||||
int rv = IGNORE_EINTR(close(file));
|
||||
PLOG_IF(ERROR, rv != 0) << "close";
|
||||
return rv == 0;
|
||||
}
|
||||
|
||||
void CheckedCloseFD(int fd) {
|
||||
CHECK(LoggingCloseFD(fd));
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
81
util/file/file_io_win.cc
Normal file
81
util/file/file_io_win.cc
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsSocketHandle(HANDLE file) {
|
||||
if (GetFileType(file) == FILE_TYPE_PIPE) {
|
||||
// FILE_TYPE_PIPE means that it's a socket, a named pipe, or an anonymous
|
||||
// pipe. If we are unable to retrieve the pipe information, we know it's a
|
||||
// socket.
|
||||
return !GetNamedPipeInfo(file, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
// TODO(scottmg): Handle > DWORD sized writes if necessary.
|
||||
|
||||
ssize_t ReadFile(FileHandle file, void* buffer, size_t size) {
|
||||
DCHECK(!IsSocketHandle(file));
|
||||
DWORD size_dword = base::checked_cast<DWORD>(size);
|
||||
DWORD total_read = 0;
|
||||
char* buffer_c = reinterpret_cast<char*>(buffer);
|
||||
while (size_dword > 0) {
|
||||
DWORD bytes_read;
|
||||
BOOL success = ::ReadFile(file, buffer_c, size_dword, &bytes_read, nullptr);
|
||||
if (!success && GetLastError() != ERROR_MORE_DATA) {
|
||||
return -1;
|
||||
} else if (success && bytes_read == 0 &&
|
||||
GetFileType(file) != FILE_TYPE_PIPE) {
|
||||
// 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
|
||||
// the other end, so continue reading.
|
||||
break;
|
||||
}
|
||||
|
||||
buffer_c += bytes_read;
|
||||
size_dword -= bytes_read;
|
||||
total_read += bytes_read;
|
||||
}
|
||||
return total_read;
|
||||
}
|
||||
|
||||
ssize_t WriteFile(FileHandle file, const void* buffer, size_t size) {
|
||||
// TODO(scottmg): This might need to handle the limit for pipes across a
|
||||
// network in the future.
|
||||
DWORD size_dword = base::checked_cast<DWORD>(size);
|
||||
DWORD bytes_written;
|
||||
BOOL rv = ::WriteFile(file, buffer, size_dword, &bytes_written, nullptr);
|
||||
if (!rv)
|
||||
return -1;
|
||||
CHECK_EQ(bytes_written, size_dword);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
bool LoggingCloseFile(FileHandle file) {
|
||||
BOOL rv = CloseHandle(file);
|
||||
PLOG_IF(ERROR, !rv) << "CloseHandle";
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
@ -61,7 +61,7 @@ bool FileWriter::Write(const void* data, size_t size) {
|
||||
DCHECK(fd_.is_valid());
|
||||
|
||||
// TODO(mark): Write no more than SSIZE_MAX bytes in a single call.
|
||||
ssize_t written = WriteFD(fd_.get(), data, size);
|
||||
ssize_t written = WriteFile(fd_.get(), data, size);
|
||||
if (written < 0) {
|
||||
PLOG(ERROR) << "write";
|
||||
return false;
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/mach/child_port.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/mach/mach_message.h"
|
||||
@ -85,7 +85,7 @@ mach_port_t ChildPortHandshake::RunServer() {
|
||||
// Initialize the token and share it with the client via the pipe.
|
||||
token_ = base::RandUint64();
|
||||
int pipe_write = pipe_write_owner.get();
|
||||
if (!LoggingWriteFD(pipe_write, &token_, sizeof(token_))) {
|
||||
if (!LoggingWriteFile(pipe_write, &token_, sizeof(token_))) {
|
||||
LOG(WARNING) << "no client check-in";
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
@ -113,13 +113,14 @@ mach_port_t ChildPortHandshake::RunServer() {
|
||||
|
||||
// Share the service name with the client via the pipe.
|
||||
uint32_t service_name_length = service_name.size();
|
||||
if (!LoggingWriteFD(
|
||||
if (!LoggingWriteFile(
|
||||
pipe_write, &service_name_length, sizeof(service_name_length))) {
|
||||
LOG(WARNING) << "no client check-in";
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
if (!LoggingWriteFD(pipe_write, service_name.c_str(), service_name_length)) {
|
||||
if (!LoggingWriteFile(
|
||||
pipe_write, service_name.c_str(), service_name_length)) {
|
||||
LOG(WARNING) << "no client check-in";
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
@ -310,17 +311,17 @@ void ChildPortHandshake::RunClientInternal_ReadPipe(int pipe_read,
|
||||
child_port_token_t* token,
|
||||
std::string* service_name) {
|
||||
// Read the token from the pipe.
|
||||
CheckedReadFD(pipe_read, token, sizeof(*token));
|
||||
CheckedReadFile(pipe_read, token, sizeof(*token));
|
||||
|
||||
// Read the service name from the pipe.
|
||||
uint32_t service_name_length;
|
||||
CheckedReadFD(pipe_read, &service_name_length, sizeof(service_name_length));
|
||||
CheckedReadFile(pipe_read, &service_name_length, sizeof(service_name_length));
|
||||
DCHECK_LT(service_name_length,
|
||||
implicit_cast<uint32_t>(BOOTSTRAP_MAX_NAME_LEN));
|
||||
|
||||
if (service_name_length > 0) {
|
||||
service_name->resize(service_name_length);
|
||||
CheckedReadFD(pipe_read, &(*service_name)[0], service_name_length);
|
||||
CheckedReadFile(pipe_read, &(*service_name)[0], service_name_length);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/mach/exc_server_variants.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/mach/mach_message.h"
|
||||
@ -242,10 +242,10 @@ class TestExceptionPorts : public MachMultiprocess,
|
||||
|
||||
// Tell the parent process that everything is set up.
|
||||
char c = '\0';
|
||||
CheckedWriteFD(test_exception_ports_->WritePipeFD(), &c, 1);
|
||||
CheckedWriteFile(test_exception_ports_->WritePipeFD(), &c, 1);
|
||||
|
||||
// Wait for the parent process to say that its end is set up.
|
||||
CheckedReadFD(test_exception_ports_->ReadPipeFD(), &c, 1);
|
||||
CheckedReadFile(test_exception_ports_->ReadPipeFD(), &c, 1);
|
||||
EXPECT_EQ('\0', c);
|
||||
|
||||
// Regardless of where ExceptionPorts::SetExceptionPort() ran,
|
||||
@ -359,7 +359,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
||||
// Wait for the child process to be ready. It needs to have all of its
|
||||
// threads set up before proceeding if in kSetOutOfProcess mode.
|
||||
char c;
|
||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
||||
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||
EXPECT_EQ('\0', c);
|
||||
|
||||
mach_port_t local_port = LocalPort();
|
||||
@ -442,7 +442,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
||||
// Let the child process know that everything in the parent process is set
|
||||
// up.
|
||||
c = '\0';
|
||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
||||
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||
|
||||
if (who_crashes_ != kNobodyCrashes) {
|
||||
UniversalMachExcServer universal_mach_exc_server(this);
|
||||
@ -463,7 +463,7 @@ class TestExceptionPorts : public MachMultiprocess,
|
||||
// Wait for the child process to exit or terminate, as indicated by it
|
||||
// closing its pipe. This keeps LocalPort() alive in the child as
|
||||
// RemotePort(), for the child’s use in its TestGetExceptionPorts().
|
||||
CheckedReadFDAtEOF(ReadPipeFD());
|
||||
CheckedReadFileAtEOF(ReadPipeFD());
|
||||
}
|
||||
|
||||
void MachMultiprocessChild() override {
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/mach/mach_message.h"
|
||||
#include "util/test/mac/mach_errors.h"
|
||||
@ -335,13 +335,13 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
if (options_.child_wait_for_parent_pipe_early) {
|
||||
// Tell the child to begin sending messages.
|
||||
char c = '\0';
|
||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
||||
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||
}
|
||||
|
||||
if (options_.parent_wait_for_child_pipe) {
|
||||
// Wait until the child is done sending what it’s going to send.
|
||||
char c;
|
||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
||||
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||
EXPECT_EQ('\0', c);
|
||||
}
|
||||
|
||||
@ -386,7 +386,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
if (options_.child_wait_for_parent_pipe_late) {
|
||||
// Let the child know it’s safe to exit.
|
||||
char c = '\0';
|
||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
||||
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,7 +394,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
if (options_.child_wait_for_parent_pipe_early) {
|
||||
// Wait until the parent is done setting things up on its end.
|
||||
char c;
|
||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
||||
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||
EXPECT_EQ('\0', c);
|
||||
}
|
||||
|
||||
@ -428,7 +428,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
|
||||
if (options_.child_wait_for_parent_pipe_late) {
|
||||
char c;
|
||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
||||
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||
ASSERT_EQ('\0', c);
|
||||
}
|
||||
}
|
||||
@ -550,7 +550,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
// running MachMessageServer() once it’s received.
|
||||
void ChildNotifyParentViaPipe() {
|
||||
char c = '\0';
|
||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
||||
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||
}
|
||||
|
||||
// In the child process, sends a request message to the server and then
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/test/mac/mach_errors.h"
|
||||
#include "util/test/mac/mach_multiprocess.h"
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
@ -55,7 +55,7 @@ FileHTTPBodyStream::FileHTTPBodyStream(const base::FilePath& path)
|
||||
|
||||
FileHTTPBodyStream::~FileHTTPBodyStream() {
|
||||
if (fd_ >= 0) {
|
||||
LoggingCloseFD(fd_);
|
||||
LoggingCloseFile(fd_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,9 +77,9 @@ ssize_t FileHTTPBodyStream::GetBytesBuffer(uint8_t* buffer, size_t max_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
ssize_t rv = ReadFD(fd_, buffer, max_len);
|
||||
ssize_t rv = ReadFile(fd_, buffer, max_len);
|
||||
if (rv == 0) {
|
||||
LoggingCloseFD(fd_);
|
||||
LoggingCloseFile(fd_);
|
||||
fd_ = kClosedAtEOF;
|
||||
} else if (rv < 0) {
|
||||
PLOG(ERROR) << "read";
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/net/http_body.h"
|
||||
#include "util/net/http_headers.h"
|
||||
#include "util/net/http_multipart_builder.h"
|
||||
@ -63,12 +63,12 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
||||
// The child will write the HTTP server port number as a packed unsigned
|
||||
// short to stdout.
|
||||
uint16_t port;
|
||||
ASSERT_TRUE(LoggingReadFD(ReadPipeFD(), &port, sizeof(port)));
|
||||
ASSERT_TRUE(LoggingReadFile(ReadPipeFD(), &port, sizeof(port)));
|
||||
|
||||
// Then the parent will tell the web server what response code to send
|
||||
// for the HTTP request.
|
||||
ASSERT_TRUE(
|
||||
LoggingWriteFD(WritePipeFD(), &response_code_, sizeof(response_code_)));
|
||||
ASSERT_TRUE(LoggingWriteFile(
|
||||
WritePipeFD(), &response_code_, sizeof(response_code_)));
|
||||
|
||||
// Now execute the HTTP request.
|
||||
scoped_ptr<HTTPTransport> transport(HTTPTransport::Create());
|
||||
@ -85,7 +85,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
||||
std::string request;
|
||||
char buf[32];
|
||||
ssize_t bytes_read;
|
||||
while ((bytes_read = ReadFD(ReadPipeFD(), buf, sizeof(buf))) != 0) {
|
||||
while ((bytes_read = ReadFile(ReadPipeFD(), buf, sizeof(buf))) != 0) {
|
||||
ASSERT_GE(bytes_read, 0);
|
||||
request.append(buf, bytes_read);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/misc/scoped_forbid_return.h"
|
||||
#include "util/test/errors.h"
|
||||
@ -262,7 +262,7 @@ void MachMultiprocess::MultiprocessChild() {
|
||||
// Wait for the parent process to close its end of the pipe. The child process
|
||||
// needs to remain alive until then because the parent process will attempt to
|
||||
// verify it using the task port it has access to via ChildTask().
|
||||
CheckedReadFDAtEOF(ReadPipeFD());
|
||||
CheckedReadFileAtEOF(ReadPipeFD());
|
||||
|
||||
if (testing::Test::HasFailure()) {
|
||||
// Trigger the ScopedForbidReturn destructor.
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/test/executable_path.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -37,9 +37,9 @@ class TestMultiprocessExec final : public MultiprocessExec {
|
||||
// gracefully with a gtest assertion if the child does not execute properly.
|
||||
|
||||
char c = 'z';
|
||||
ASSERT_TRUE(LoggingWriteFD(WritePipeFD(), &c, 1));
|
||||
ASSERT_TRUE(LoggingWriteFile(WritePipeFD(), &c, 1));
|
||||
|
||||
ASSERT_TRUE(LoggingReadFD(ReadPipeFD(), &c, 1));
|
||||
ASSERT_TRUE(LoggingReadFile(ReadPipeFD(), &c, 1));
|
||||
EXPECT_EQ('Z', c);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/file/file_io.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
@ -38,31 +38,31 @@ class TestMultiprocess final : public Multiprocess {
|
||||
void MultiprocessParent() override {
|
||||
int read_fd = ReadPipeFD();
|
||||
char c;
|
||||
CheckedReadFD(read_fd, &c, 1);
|
||||
CheckedReadFile(read_fd, &c, 1);
|
||||
EXPECT_EQ('M', c);
|
||||
|
||||
pid_t pid;
|
||||
CheckedReadFD(read_fd, &pid, sizeof(pid));
|
||||
CheckedReadFile(read_fd, &pid, sizeof(pid));
|
||||
EXPECT_EQ(pid, ChildPID());
|
||||
|
||||
c = 'm';
|
||||
CheckedWriteFD(WritePipeFD(), &c, 1);
|
||||
CheckedWriteFile(WritePipeFD(), &c, 1);
|
||||
|
||||
// The child will close its end of the pipe and exit. Make sure that the
|
||||
// parent sees EOF.
|
||||
CheckedReadFDAtEOF(read_fd);
|
||||
CheckedReadFileAtEOF(read_fd);
|
||||
}
|
||||
|
||||
void MultiprocessChild() override {
|
||||
int write_fd = WritePipeFD();
|
||||
|
||||
char c = 'M';
|
||||
CheckedWriteFD(write_fd, &c, 1);
|
||||
CheckedWriteFile(write_fd, &c, 1);
|
||||
|
||||
pid_t pid = getpid();
|
||||
CheckedWriteFD(write_fd, &pid, sizeof(pid));
|
||||
CheckedWriteFile(write_fd, &pid, sizeof(pid));
|
||||
|
||||
CheckedReadFD(ReadPipeFD(), &c, 1);
|
||||
CheckedReadFile(ReadPipeFD(), &c, 1);
|
||||
EXPECT_EQ('m', c);
|
||||
}
|
||||
|
||||
@ -178,18 +178,18 @@ class TestMultiprocessClosePipe final : public Multiprocess {
|
||||
// the read pipe in this process to show end-of-file.
|
||||
void VerifyPartner() {
|
||||
if (what_closes_ == kWriteCloses) {
|
||||
CheckedReadFDAtEOF(ReadPipeFD());
|
||||
CheckedReadFileAtEOF(ReadPipeFD());
|
||||
} else if (what_closes_ == kReadAndWriteClose) {
|
||||
CheckedReadFDAtEOF(ReadPipeFD());
|
||||
CheckedReadFileAtEOF(ReadPipeFD());
|
||||
char c = '\0';
|
||||
|
||||
// This will raise SIGPIPE. If fatal (the normal case), that will cause
|
||||
// process termination. If SIGPIPE is being handled somewhere, the write
|
||||
// will still fail and set errno to EPIPE, and CheckedWriteFD() will abort
|
||||
// execution. Regardless of how SIGPIPE is handled, the process will be
|
||||
// terminated. Because the actual termination mechanism is not known, no
|
||||
// regex can be specified.
|
||||
EXPECT_DEATH(CheckedWriteFD(WritePipeFD(), &c, 1), "");
|
||||
// will still fail and set errno to EPIPE, and CheckedWriteFile() will
|
||||
// abort execution. Regardless of how SIGPIPE is handled, the process will
|
||||
// be terminated. Because the actual termination mechanism is not known,
|
||||
// no regex can be specified.
|
||||
EXPECT_DEATH(CheckedWriteFile(WritePipeFD(), &c, 1), "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,10 @@
|
||||
'<(INTERMEDIATE_DIR)',
|
||||
],
|
||||
'sources': [
|
||||
'file/fd_io.cc',
|
||||
'file/fd_io.h',
|
||||
'file/file_io.cc',
|
||||
'file/file_io.h',
|
||||
'file/file_io_posix.cc',
|
||||
'file/file_io_win.cc',
|
||||
'file/file_writer.cc',
|
||||
'file/file_writer.h',
|
||||
'file/string_file_writer.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user