diff options
Diffstat (limited to 'src/common/linux')
36 files changed, 778 insertions, 138 deletions
diff --git a/src/common/linux/breakpad_getcontext.h b/src/common/linux/breakpad_getcontext.h index c553219f..d64784d4 100644 --- a/src/common/linux/breakpad_getcontext.h +++ b/src/common/linux/breakpad_getcontext.h @@ -29,10 +29,6 @@ #ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H #define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifndef HAVE_GETCONTEXT #include <signal.h> diff --git a/src/common/linux/breakpad_getcontext_unittest.cc b/src/common/linux/breakpad_getcontext_unittest.cc index 573ddd88..5b340eb7 100644 --- a/src/common/linux/breakpad_getcontext_unittest.cc +++ b/src/common/linux/breakpad_getcontext_unittest.cc @@ -29,6 +29,10 @@ // asm/sigcontext.h can't be included with signal.h on glibc or // musl, so only compare _libc_fpstate and _fpstate on Android. #if defined(__ANDROID__) && defined(__x86_64__) +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <asm/sigcontext.h> #endif diff --git a/src/common/linux/crc32.cc b/src/common/linux/crc32.cc index c02f06c4..cf386a24 100644 --- a/src/common/linux/crc32.cc +++ b/src/common/linux/crc32.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/crc32.h" namespace google_breakpad { diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index b436f765..b693fc9e 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -31,6 +31,10 @@ // dump_symbols.cc: implement google_breakpad::WriteSymbolFile: // Find all the debugging info in a file and dump it as a Breakpad symbol file. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/dump_symbols.h" #include <assert.h> @@ -47,6 +51,9 @@ #include <sys/stat.h> #include <unistd.h> #include <zlib.h> +#ifdef HAVE_LIBZSTD +#include <zstd.h> +#endif #include <set> #include <string> @@ -104,6 +111,11 @@ using google_breakpad::wasteful_vector; #define EM_AARCH64 183 #endif +// Define ZStd compression if host machine does not include this define. +#ifndef ELFCOMPRESS_ZSTD +#define ELFCOMPRESS_ZSTD 2 +#endif + // // FDWrapper // @@ -301,7 +313,7 @@ uint32_t GetCompressionHeader( return sizeof (*header); } -std::pair<uint8_t *, uint64_t> UncompressSectionContents( +std::pair<uint8_t *, uint64_t> UncompressZlibSectionContents( const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) { z_stream stream; memset(&stream, 0, sizeof stream); @@ -330,6 +342,90 @@ std::pair<uint8_t *, uint64_t> UncompressSectionContents( : std::make_pair(uncompressed_buffer.release(), uncompressed_size); } +#ifdef HAVE_LIBZSTD +std::pair<uint8_t *, uint64_t> UncompressZstdSectionContents( + const uint8_t* compressed_buffer, uint64_t compressed_size,uint64_t uncompressed_size) { + + google_breakpad::scoped_array<uint8_t> uncompressed_buffer(new uint8_t[uncompressed_size]); + size_t out_size = ZSTD_decompress(uncompressed_buffer.get(), uncompressed_size, + compressed_buffer, compressed_size); + if (ZSTD_isError(out_size)) { + return std::make_pair(nullptr, 0); + } + assert(out_size == uncompressed_size); + return std::make_pair(uncompressed_buffer.release(), uncompressed_size); +} +#endif + +std::pair<uint8_t *, uint64_t> UncompressSectionContents( + uint64_t compression_type, const uint8_t* compressed_buffer, + uint64_t compressed_size, uint64_t uncompressed_size) { + if (compression_type == ELFCOMPRESS_ZLIB) { + return UncompressZlibSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } + +#ifdef HAVE_LIBZSTD + if (compression_type == ELFCOMPRESS_ZSTD) { + return UncompressZstdSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } +#endif + + return std::make_pair(nullptr, 0); +} + +void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (!reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + template<typename ElfClass> bool LoadDwarf(const string& dwarf_filename, const typename ElfClass::Ehdr* elf_header, @@ -380,7 +476,7 @@ bool LoadDwarf(const string& dwarf_filename, size -= compression_header_size; std::pair<uint8_t *, uint64_t> uncompressed = - UncompressSectionContents(contents, size, chdr.ch_size); + UncompressSectionContents(chdr.ch_type, contents, size, chdr.ch_size); if (uncompressed.first != nullptr && uncompressed.second != 0) { file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second); @@ -417,6 +513,11 @@ bool LoadDwarf(const string& dwarf_filename, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. offset += reader.Start(); + // Start to process split dwarf file. + if (reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&reader, module, endianness, handle_inter_cu_refs, + handle_inline); + } } return true; } @@ -445,6 +546,9 @@ bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header, case EM_X86_64: *register_names = DwarfCFIToModule::RegisterNames::X86_64(); return true; + case EM_RISCV: + *register_names = DwarfCFIToModule::RegisterNames::RISCV(); + return true; default: return false; } @@ -522,7 +626,7 @@ bool LoadDwarfCFI(const string& dwarf_filename, cfi_size -= compression_header_size; std::pair<uint8_t *, uint64_t> uncompressed = - UncompressSectionContents(cfi, cfi_size, chdr.ch_size); + UncompressSectionContents(chdr.ch_type, cfi, cfi_size, chdr.ch_size); if (uncompressed.first == nullptr || uncompressed.second == 0) { fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str()); @@ -1018,6 +1122,7 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) { case EM_SPARC: return "sparc"; case EM_SPARCV9: return "sparcv9"; case EM_X86_64: return "x86_64"; + case EM_RISCV: return "riscv"; default: return NULL; } } diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index 97d5827e..55dcdeed 100644 --- a/src/common/linux/dump_symbols_unittest.cc +++ b/src/common/linux/dump_symbols_unittest.cc @@ -31,6 +31,10 @@ // dump_symbols_unittest.cc: // Unittests for google_breakpad::DumpSymbols +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include <link.h> #include <stdio.h> diff --git a/src/common/linux/elf_core_dump.cc b/src/common/linux/elf_core_dump.cc index f5ee3033..67257fd2 100644 --- a/src/common/linux/elf_core_dump.cc +++ b/src/common/linux/elf_core_dump.cc @@ -29,6 +29,10 @@ // elf_core_dump.cc: Implement google_breakpad::ElfCoreDump. // See elf_core_dump.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/elf_core_dump.h" #include <stddef.h> diff --git a/src/common/linux/elf_core_dump_unittest.cc b/src/common/linux/elf_core_dump_unittest.cc index 6789dd84..25cab99f 100644 --- a/src/common/linux/elf_core_dump_unittest.cc +++ b/src/common/linux/elf_core_dump_unittest.cc @@ -28,6 +28,10 @@ // elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <sys/procfs.h> #include <set> diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc index 3c33be99..70d50f89 100644 --- a/src/common/linux/elf_symbols_to_module.cc +++ b/src/common/linux/elf_symbols_to_module.cc @@ -30,6 +30,10 @@ // Original author: Ted Mielczarek <ted.mielczarek@gmail.com> +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/elf_symbols_to_module.h" #include <cxxabi.h> diff --git a/src/common/linux/elf_symbols_to_module_unittest.cc b/src/common/linux/elf_symbols_to_module_unittest.cc index 17eb670f..a74b29f0 100644 --- a/src/common/linux/elf_symbols_to_module_unittest.cc +++ b/src/common/linux/elf_symbols_to_module_unittest.cc @@ -31,6 +31,10 @@ // elf_symbols_to_module_unittest.cc: // Unittests for google_breakpad::ELFSymbolsToModule +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include <string> diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc index a68cc0af..95b5db82 100644 --- a/src/common/linux/elfutils.cc +++ b/src/common/linux/elfutils.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/elfutils.h" #include <assert.h> diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc index 0bd2a759..d8fcbd8d 100644 --- a/src/common/linux/file_id.cc +++ b/src/common/linux/file_id.cc @@ -31,6 +31,10 @@ // See file_id.h for documentation // +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/file_id.h" #include <arpa/inet.h> diff --git a/src/common/linux/file_id_unittest.cc b/src/common/linux/file_id_unittest.cc index 74bf9e1b..0ef45353 100644 --- a/src/common/linux/file_id_unittest.cc +++ b/src/common/linux/file_id_unittest.cc @@ -28,6 +28,10 @@ // Unit tests for FileID +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include <spawn.h> #include <stdlib.h> diff --git a/src/common/linux/google_crashdump_uploader.cc b/src/common/linux/google_crashdump_uploader.cc index 6242e6d2..8c5e0492 100644 --- a/src/common/linux/google_crashdump_uploader.cc +++ b/src/common/linux/google_crashdump_uploader.cc @@ -27,6 +27,10 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/google_crashdump_uploader.h" #include <sys/types.h> diff --git a/src/common/linux/google_crashdump_uploader_test.cc b/src/common/linux/google_crashdump_uploader_test.cc index 39aab65d..e81f21d6 100644 --- a/src/common/linux/google_crashdump_uploader_test.cc +++ b/src/common/linux/google_crashdump_uploader_test.cc @@ -28,6 +28,10 @@ // Unit test for crash dump uploader. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string> #include "common/linux/google_crashdump_uploader.h" diff --git a/src/common/linux/guid_creator.cc b/src/common/linux/guid_creator.cc index 31a326c7..8635f9dc 100644 --- a/src/common/linux/guid_creator.cc +++ b/src/common/linux/guid_creator.cc @@ -27,7 +27,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef HAVE_CONFIG_H -#include <config.h> +#include <config.h> // Must come first #endif #include "common/linux/eintr_wrapper.h" diff --git a/src/common/linux/http_upload.cc b/src/common/linux/http_upload.cc index 1b576ea6..0a5bdb50 100644 --- a/src/common/linux/http_upload.cc +++ b/src/common/linux/http_upload.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/http_upload.h" #include <assert.h> diff --git a/src/common/linux/libcurl_wrapper.cc b/src/common/linux/libcurl_wrapper.cc index a53087d9..2b639098 100644 --- a/src/common/linux/libcurl_wrapper.cc +++ b/src/common/linux/libcurl_wrapper.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <dlfcn.h> #include <iostream> @@ -303,12 +307,10 @@ bool LibcurlWrapper::SendRequestInner(const string& url, (*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); } -#ifndef NDEBUG if (err_code != CURLE_OK) fprintf(stderr, "Failed to send http request to %s, error: %s\n", url.c_str(), (*easy_strerror_)(err_code)); -#endif Reset(); diff --git a/src/common/linux/linux_libc_support.cc b/src/common/linux/linux_libc_support.cc index 10cbeaef..abcbfde8 100644 --- a/src/common/linux/linux_libc_support.cc +++ b/src/common/linux/linux_libc_support.cc @@ -30,6 +30,10 @@ // we call the libc functions directly we risk crashing in the dynamic linker // as it tries to resolve uncached PLT entries. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/linux_libc_support.h" #include <stddef.h> diff --git a/src/common/linux/linux_libc_support_unittest.cc b/src/common/linux/linux_libc_support_unittest.cc index 449f995f..30dd1430 100644 --- a/src/common/linux/linux_libc_support_unittest.cc +++ b/src/common/linux/linux_libc_support_unittest.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/linux/linux_libc_support.h" diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc index 7e444607..a7b96eb5 100644 --- a/src/common/linux/memory_mapped_file.cc +++ b/src/common/linux/memory_mapped_file.cc @@ -29,6 +29,10 @@ // memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile. // See memory_mapped_file.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/memory_mapped_file.h" #include <fcntl.h> @@ -57,8 +61,11 @@ MemoryMappedFile::~MemoryMappedFile() { bool MemoryMappedFile::Map(const char* path, size_t offset) { Unmap(); - - int fd = sys_open(path, O_RDONLY, 0); + // Based on https://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html + // If O_NONBLOCK is set: The open() function will return without blocking + // for the device to be ready or available. Setting this value will provent + // hanging if file is not avilable. + int fd = sys_open(path, O_RDONLY | O_NONBLOCK, 0); if (fd == -1) { return false; } diff --git a/src/common/linux/memory_mapped_file.h b/src/common/linux/memory_mapped_file.h index d4a85051..462e116e 100644 --- a/src/common/linux/memory_mapped_file.h +++ b/src/common/linux/memory_mapped_file.h @@ -33,7 +33,7 @@ #define COMMON_LINUX_MEMORY_MAPPED_FILE_H_ #include <stddef.h> -#include "common/basictypes.h" + #include "common/memory_range.h" namespace google_breakpad { @@ -49,6 +49,9 @@ class MemoryMappedFile { // If Map() fails, the object behaves as if it is default constructed. MemoryMappedFile(const char* path, size_t offset); + MemoryMappedFile(const MemoryMappedFile&) = delete; + void operator=(const MemoryMappedFile&) = delete; + ~MemoryMappedFile(); // Maps a file at |path| into memory, which can then be accessed via @@ -77,8 +80,6 @@ class MemoryMappedFile { private: // Mapped file content as a MemoryRange object. MemoryRange content_; - - DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); }; } // namespace google_breakpad diff --git a/src/common/linux/memory_mapped_file_unittest.cc b/src/common/linux/memory_mapped_file_unittest.cc index 5ed677df..b7a61a70 100644 --- a/src/common/linux/memory_mapped_file_unittest.cc +++ b/src/common/linux/memory_mapped_file_unittest.cc @@ -29,6 +29,10 @@ // memory_mapped_file_unittest.cc: // Unit tests for google_breakpad::MemoryMappedFile. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <fcntl.h> #include <string.h> #include <unistd.h> diff --git a/src/common/linux/safe_readlink.cc b/src/common/linux/safe_readlink.cc index 97ea62c0..a42b01a5 100644 --- a/src/common/linux/safe_readlink.cc +++ b/src/common/linux/safe_readlink.cc @@ -29,6 +29,10 @@ // safe_readlink.cc: Implement google_breakpad::SafeReadLink. // See safe_readlink.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stddef.h> #include "third_party/lss/linux_syscall_support.h" diff --git a/src/common/linux/safe_readlink_unittest.cc b/src/common/linux/safe_readlink_unittest.cc index 6f5f9d75..8fa6d065 100644 --- a/src/common/linux/safe_readlink_unittest.cc +++ b/src/common/linux/safe_readlink_unittest.cc @@ -28,6 +28,10 @@ // safe_readlink_unittest.cc: Unit tests for google_breakpad::SafeReadLink. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/linux/safe_readlink.h" diff --git a/src/common/linux/scoped_pipe.cc b/src/common/linux/scoped_pipe.cc new file mode 100644 index 00000000..8de04ce9 --- /dev/null +++ b/src/common/linux/scoped_pipe.cc @@ -0,0 +1,132 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_pipe.h" + +#include <unistd.h> + +#include "common/linux/eintr_wrapper.h" + +namespace google_breakpad { + +ScopedPipe::ScopedPipe() { + fds_[0] = -1; + fds_[1] = -1; +} + +ScopedPipe::~ScopedPipe() { + CloseReadFd(); + CloseWriteFd(); +} + +bool ScopedPipe::Init() { + return pipe(fds_) == 0; +} + +void ScopedPipe::CloseReadFd() { + if (fds_[0] != -1) { + close(fds_[0]); + fds_[0] = -1; + } +} + +void ScopedPipe::CloseWriteFd() { + if (fds_[1] != -1) { + close(fds_[1]); + fds_[1] = -1; + } +} + +bool ScopedPipe::ReadLine(std::string& line) { + // Simple buffered file read. `read_buffer_` stores previously read bytes, and + // we either return a line from this buffer, or we append blocks of read bytes + // to the buffer until we have a complete line. + size_t eol_index = read_buffer_.find('\n'); + + // While we don't have a full line, and read pipe is valid. + while (eol_index == std::string::npos && GetReadFd() != -1) { + // Read a block of 128 bytes from the read pipe. + char read_buf[128]; + ssize_t read_len = HANDLE_EINTR( + read(GetReadFd(), read_buf, sizeof(read_buf))); + if (read_len <= 0) { + // Pipe error, or pipe has been closed. + CloseReadFd(); + break; + } + + // Append the block, and check if we have a full line now. + read_buffer_.append(read_buf, read_len); + eol_index = read_buffer_.find('\n'); + } + + if (eol_index != std::string::npos) { + // We have a full line to output. + line = read_buffer_.substr(0, eol_index); + if (eol_index < read_buffer_.size()) { + read_buffer_ = read_buffer_.substr(eol_index + 1); + } else { + read_buffer_ = ""; + } + + return true; + } + + if (read_buffer_.size()) { + // We don't have a full line to output, but we can only reach here if the + // pipe has closed and there are some bytes left at the end, so we should + // return those bytes. + line = std::move(read_buffer_); + read_buffer_ = ""; + + return true; + } + + // We don't have any buffered data left, and the pipe has closed. + return false; +} + +int ScopedPipe::Dup2WriteFd(int new_fd) const { + return dup2(fds_[1], new_fd); +} + +bool ScopedPipe::WriteForTesting(const void* bytes, size_t bytes_len) { + ssize_t r = HANDLE_EINTR(write(GetWriteFd(), bytes, bytes_len)); + if (r != static_cast<ssize_t>(bytes_len)) { + CloseWriteFd(); + return false; + } + + return true; +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_pipe.h b/src/common/linux/scoped_pipe.h new file mode 100644 index 00000000..25394c2a --- /dev/null +++ b/src/common/linux/scoped_pipe.h @@ -0,0 +1,115 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_LINUX_SCOPED_PIPE_H_ +#define COMMON_LINUX_SCOPED_PIPE_H_ + +#include <stdint.h> +#include <string> + +namespace google_breakpad { + +// Small RAII wrapper for a pipe pair. +// +// Example (both ends of pipe in same process): +// ScopedPipe tmp; +// std::string line; +// if (tmp.Init() && tmp.Write(bytes, bytes_len)) { +// tmp.CloseWriteFd(); +// while (tmp.ReadLine(&line)) { +// std::cerr << line << std::endl; +// } +// } +// +// Example (reading output from a child process): +// ScopedPipe tmp; +// if (fork()) { +// // Parent process, read from the read end of the pipe. +// std::string line; +// while (tmp.ReadLine(line)) { +// // Process output... +// } +// // Close read pipe once done processing the output that we wanted, this +// // should ensure that the child process exits even if we didn't read all +// // of the output. +// tmp.CloseReadFd(); +// // Parent process should handle waiting for child to exit here... +// } else { +// // Child process, close the read fd and dup the write fd before exec'ing. +// tmp.CloseReadFd(); +// tmp.Dup2WriteFd(STDOUT_FILENO); +// tmp.Dup2WriteFd(STDERR_FILENO); +// execl("some-command", "some-arguments"); +// } +class ScopedPipe { + public: + ScopedPipe(); + ~ScopedPipe(); + + // Creates the pipe pair - returns false on error. + bool Init(); + + // Close the read pipe. This only needs to be used when the read pipe needs to + // be closed earlier. + void CloseReadFd(); + + // Close the write pipe. This only needs to be used when the write pipe needs + // to be closed earlier. + void CloseWriteFd(); + + // Reads characters until newline or end of pipe. On read failure this will + // close the read pipe, but continue to return true and read buffered lines + // until the internal buffering is exhausted. This will block if there is no + // data available on the read pipe. + bool ReadLine(std::string& line); + + // Writes bytes to the write end of the pipe, returns false and closes write + // pipe on failure. + bool WriteForTesting(const void* bytes, size_t bytes_len); + + // Calls the dup2 system call to replace any existing open file descriptor + // with number new_fd with a copy of the current write end file descriptor + // for the pipe. + int Dup2WriteFd(int new_fd) const; + + private: + int GetReadFd() const { + return fds_[0]; + } + + int GetWriteFd() const { + return fds_[1]; + } + + int fds_[2]; + std::string read_buffer_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SCOPED_PIPE_H_ diff --git a/src/common/linux/scoped_pipe_unittest.cc b/src/common/linux/scoped_pipe_unittest.cc new file mode 100644 index 00000000..4daa5c25 --- /dev/null +++ b/src/common/linux/scoped_pipe_unittest.cc @@ -0,0 +1,75 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// scoped_pipe_unittest.cc: Unit tests for google_breakpad::ScopedPipe. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_pipe.h" + +#include "breakpad_googletest_includes.h" + +namespace google_breakpad { + +TEST(ScopedPipeTest, WriteAndClose) { + const char kTestData[] = "One\nTwo\nThree"; + ScopedPipe pipe; + std::string line; + + ASSERT_TRUE(pipe.Init()); + ASSERT_TRUE(pipe.WriteForTesting(kTestData, strlen(kTestData))); + pipe.CloseWriteFd(); + + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "One"); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Two"); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Three"); + ASSERT_FALSE(pipe.ReadLine(line)); +} + +TEST(ScopedPipeTest, MultipleWrites) { + const char kTestDataOne[] = "One\n"; + const char kTestDataTwo[] = "Two\n"; + ScopedPipe pipe; + std::string line; + + ASSERT_TRUE(pipe.Init()); + ASSERT_TRUE(pipe.WriteForTesting(kTestDataOne, strlen(kTestDataOne))); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "One"); + + ASSERT_TRUE(pipe.WriteForTesting(kTestDataTwo, strlen(kTestDataTwo))); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Two"); +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_tmpfile.cc b/src/common/linux/scoped_tmpfile.cc new file mode 100644 index 00000000..2395a64e --- /dev/null +++ b/src/common/linux/scoped_tmpfile.cc @@ -0,0 +1,103 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility class for creating a temporary file that is deleted in the +// destructor. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_tmpfile.h" + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include "common/linux/eintr_wrapper.h" + +#if !defined(__ANDROID__) +#define TEMPDIR "/tmp" +#else +#define TEMPDIR "/data/local/tmp" +#endif + +namespace google_breakpad { + +ScopedTmpFile::ScopedTmpFile() = default; + +ScopedTmpFile::~ScopedTmpFile() { + if (fd_ >= 0) { + close(fd_); + fd_ = -1; + } +} + +bool ScopedTmpFile::InitEmpty() { + // Prevent calling Init when fd_ is already valid, leaking the file. + if (fd_ != -1) { + return false; + } + + // Respect the TMPDIR environment variable. + const char* tempdir = getenv("TMPDIR"); + if (!tempdir) { + tempdir = TEMPDIR; + } + + // Create a temporary file that is not linked in to the filesystem, and that + // is only accessible by the current user. + fd_ = open(tempdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); + + return fd_ >= 0; +} + +bool ScopedTmpFile::InitString(const char* text) { + return InitData(text, strlen(text)); +} + +bool ScopedTmpFile::InitData(const void* data, size_t data_len) { + if (!InitEmpty()) { + return false; + } + + return SetContents(data, data_len); +} + +bool ScopedTmpFile::SetContents(const void* data, size_t data_len) { + ssize_t r = HANDLE_EINTR(write(fd_, data, data_len)); + if (r != static_cast<ssize_t>(data_len)) { + return false; + } + + return 0 == lseek(fd_, 0, SEEK_SET); +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_tmpfile.h b/src/common/linux/scoped_tmpfile.h new file mode 100644 index 00000000..dffec182 --- /dev/null +++ b/src/common/linux/scoped_tmpfile.h @@ -0,0 +1,85 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility class for creating a temporary file for that is deleted in the +// destructor. + +#ifndef COMMON_LINUX_SCOPED_TMPFILE_H_ +#define COMMON_LINUX_SCOPED_TMPFILE_H_ + +#include <string> + +namespace google_breakpad { + +// Small RAII wrapper for temporary files. +// +// Example: +// ScopedTmpFile tmp; +// if (tmp.Init("Some file contents")) { +// ... +// } +class ScopedTmpFile { + public: + // Initialize the ScopedTmpFile object - this does not create the temporary + // file until Init is called. + ScopedTmpFile(); + + // Destroy temporary file on scope exit. + ~ScopedTmpFile(); + + // Creates the empty temporary file - returns true iff the temporary file was + // created successfully. Should always be checked before using the file. + bool InitEmpty(); + + // Creates the temporary file with the provided C string. The terminating null + // is not written. Returns true iff the temporary file was created + // successfully and the contents were written successfully. + bool InitString(const char* text); + + // Creates the temporary file with the provided data. Returns true iff the + // temporary file was created successfully and the contents were written + // successfully. + bool InitData(const void* data, size_t data_len); + + // Returns the Posix file descriptor for the test file, or -1 if Init() + // returned false. Note: on Windows, this always returns -1. + int GetFd() const { + return fd_; + } + + private: + // Set the contents of the temporary file, and seek back to the start of the + // file. On failure, returns false. + bool SetContents(const void* data, size_t data_len); + + int fd_ = -1; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SCOPED_TMPFILE_H_ diff --git a/src/common/linux/scoped_tmpfile_unittest.cc b/src/common/linux/scoped_tmpfile_unittest.cc new file mode 100644 index 00000000..f0bb2bbb --- /dev/null +++ b/src/common/linux/scoped_tmpfile_unittest.cc @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// scoped_tmpfile_unittest.cc: Unit tests for google_breakpad::ScopedTmpfile. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_tmpfile.h" + +#include <unistd.h> + +#include "breakpad_googletest_includes.h" + +using google_breakpad::ScopedTmpFile; + +TEST(ScopedTmpFileTest, CheckContentsMatch) { + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("Test")); + + char file_contents[5] = {0}; + ASSERT_EQ(4, read(file.GetFd(), file_contents, sizeof(file_contents))); + EXPECT_STREQ(file_contents, "Test"); +} diff --git a/src/common/linux/symbol_collector_client.cc b/src/common/linux/symbol_collector_client.cc index 1c1dc97a..e9a1893c 100644 --- a/src/common/linux/symbol_collector_client.cc +++ b/src/common/linux/symbol_collector_client.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/symbol_collector_client.h" #include <stdio.h> diff --git a/src/common/linux/symbol_upload.cc b/src/common/linux/symbol_upload.cc index c080533a..8ab143c6 100644 --- a/src/common/linux/symbol_upload.cc +++ b/src/common/linux/symbol_upload.cc @@ -29,6 +29,10 @@ // symbol_upload.cc: implemented google_breakpad::sym_upload::Start, a helper // function for linux symbol upload tool. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/symbol_upload.h" #include <assert.h> diff --git a/src/common/linux/synth_elf.cc b/src/common/linux/synth_elf.cc index 2ba25e61..8e9170e7 100644 --- a/src/common/linux/synth_elf.cc +++ b/src/common/linux/synth_elf.cc @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/synth_elf.h" #include <assert.h> diff --git a/src/common/linux/synth_elf_unittest.cc b/src/common/linux/synth_elf_unittest.cc index 44ef6ef3..578f6a26 100644 --- a/src/common/linux/synth_elf_unittest.cc +++ b/src/common/linux/synth_elf_unittest.cc @@ -31,6 +31,10 @@ // synth_elf_unittest.cc: // Unittests for google_breakpad::synth_elf::ELF +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include "breakpad_googletest_includes.h" diff --git a/src/common/linux/tests/auto_testfile.h b/src/common/linux/tests/auto_testfile.h deleted file mode 100644 index e2d2ff23..00000000 --- a/src/common/linux/tests/auto_testfile.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2013 Google LLC -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google LLC nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Utility class for creating a temporary file for unit tests -// that is deleted in the destructor. - -#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE -#define GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE - -#include <unistd.h> -#include <sys/types.h> - -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/linux/eintr_wrapper.h" -#include "common/tests/auto_tempdir.h" - -namespace google_breakpad { - -class AutoTestFile { - public: - // Create a new empty test file. - // test_prefix: (input) test-specific prefix, can't be NULL. - explicit AutoTestFile(const char* test_prefix) { - Init(test_prefix); - } - - // Create a new test file, and fill it with initial data from a C string. - // The terminating zero is not written. - // test_prefix: (input) test-specific prefix, can't be NULL. - // text: (input) initial content. - AutoTestFile(const char* test_prefix, const char* text) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, static_cast<size_t>(strlen(text))); - } - - AutoTestFile(const char* test_prefix, const char* text, size_t text_len) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, text_len); - } - - // Destroy test file on scope exit. - ~AutoTestFile() { - if (fd_ >= 0) { - close(fd_); - fd_ = -1; - } - } - - // Returns true iff the test file could be created properly. - // Useful in tests inside EXPECT_TRUE(file.IsOk()); - bool IsOk() { - return fd_ >= 0; - } - - // Returns the Posix file descriptor for the test file, or -1 - // If IsOk() returns false. Note: on Windows, this always returns -1. - int GetFd() { - return fd_; - } - - private: - void Init(const char* test_prefix) { - fd_ = -1; - char path_templ[PATH_MAX]; - int ret = snprintf(path_templ, sizeof(path_templ), - TEMPDIR "/%s-unittest.XXXXXX", - test_prefix); - if (ret >= static_cast<int>(sizeof(path_templ))) - return; - - fd_ = mkstemp(path_templ); - if (fd_ < 0) - return; - - unlink(path_templ); - } - - void WriteText(const char* text, size_t text_len) { - ssize_t r = HANDLE_EINTR(write(fd_, text, text_len)); - if (r != static_cast<ssize_t>(text_len)) { - close(fd_); - fd_ = -1; - return; - } - - lseek(fd_, 0, SEEK_SET); - } - - int fd_; -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE diff --git a/src/common/linux/tests/crash_generator.cc b/src/common/linux/tests/crash_generator.cc index 0db0c4a2..1cad9ae2 100644 --- a/src/common/linux/tests/crash_generator.cc +++ b/src/common/linux/tests/crash_generator.cc @@ -29,6 +29,10 @@ // crash_generator.cc: Implement google_breakpad::CrashGenerator. // See crash_generator.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/tests/crash_generator.h" #include <pthread.h> |