minidump: Migrate the rest of the tests to

MinidumpWritableAtLocationDescriptor<>().

TEST=minidump_test
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/670853002
This commit is contained in:
Mark Mentovai 2014-10-22 18:35:18 -04:00
parent 8a6a4c68e4
commit 20f95a2f5b
14 changed files with 516 additions and 176 deletions

View File

@ -19,6 +19,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "minidump/minidump_context.h" #include "minidump/minidump_context.h"
#include "minidump/test/minidump_context_test_util.h" #include "minidump/test/minidump_context_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
@ -39,7 +40,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size()); ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size());
const MinidumpContextX86* observed = const MinidumpContextX86* observed =
reinterpret_cast<const MinidumpContextX86*>(&file_writer.string()[0]); MinidumpWritableAtRVA<MinidumpContextX86>(file_writer.string(), 0);
ExpectMinidumpContextX86(0, observed); ExpectMinidumpContextX86(0, observed);
} }
@ -56,7 +57,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size()); ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size());
const MinidumpContextX86* observed = const MinidumpContextX86* observed =
reinterpret_cast<const MinidumpContextX86*>(&file_writer.string()[0]); MinidumpWritableAtRVA<MinidumpContextX86>(file_writer.string(), 0);
ExpectMinidumpContextX86(kSeed, observed); ExpectMinidumpContextX86(kSeed, observed);
} }
} }
@ -75,7 +76,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size()); ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size());
const MinidumpContextAMD64* observed = const MinidumpContextAMD64* observed =
reinterpret_cast<const MinidumpContextAMD64*>(&file_writer.string()[0]); MinidumpWritableAtRVA<MinidumpContextAMD64>(file_writer.string(), 0);
ExpectMinidumpContextAMD64(0, observed); ExpectMinidumpContextAMD64(0, observed);
} }
@ -92,7 +93,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size()); ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size());
const MinidumpContextAMD64* observed = const MinidumpContextAMD64* observed =
reinterpret_cast<const MinidumpContextAMD64*>(&file_writer.string()[0]); MinidumpWritableAtRVA<MinidumpContextAMD64>(file_writer.string(), 0);
ExpectMinidumpContextAMD64(kSeed, observed); ExpectMinidumpContextAMD64(kSeed, observed);
} }
} }

View File

@ -22,6 +22,7 @@
#include "minidump/minidump_simple_string_dictionary_writer.h" #include "minidump/minidump_simple_string_dictionary_writer.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
@ -55,20 +56,19 @@ void GetCrashpadInfoStream(
ASSERT_TRUE(directory); ASSERT_TRUE(directory);
ASSERT_EQ(kMinidumpStreamTypeCrashpadInfo, directory[0].StreamType); ASSERT_EQ(kMinidumpStreamTypeCrashpadInfo, directory[0].StreamType);
ASSERT_EQ(sizeof(MinidumpCrashpadInfo), directory[0].Location.DataSize); EXPECT_EQ(kCrashpadInfoStreamOffset, directory[0].Location.Rva);
ASSERT_EQ(kCrashpadInfoStreamOffset, directory[0].Location.Rva);
*crashpad_info = reinterpret_cast<const MinidumpCrashpadInfo*>( *crashpad_info = MinidumpWritableAtLocationDescriptor<MinidumpCrashpadInfo>(
&file_contents[kCrashpadInfoStreamOffset]); file_contents, directory[0].Location);
ASSERT_TRUE(*crashpad_info);
if (simple_annotations) { if (simple_annotations) {
ASSERT_GE((*crashpad_info)->simple_annotations.DataSize, EXPECT_EQ(kSimpleAnnotationsOffset,
sizeof(MinidumpSimpleStringDictionary));
ASSERT_EQ(kSimpleAnnotationsOffset,
(*crashpad_info)->simple_annotations.Rva); (*crashpad_info)->simple_annotations.Rva);
*simple_annotations = *simple_annotations =
reinterpret_cast<const MinidumpSimpleStringDictionary*>( MinidumpWritableAtLocationDescriptor<MinidumpSimpleStringDictionary>(
&file_contents[kSimpleAnnotationsOffset]); file_contents, (*crashpad_info)->simple_annotations);
ASSERT_TRUE(*simple_annotations);
} else { } else {
ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.DataSize); ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.DataSize);
ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.Rva); ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.Rva);

View File

@ -27,6 +27,7 @@
#include "minidump/minidump_file_writer.h" #include "minidump/minidump_file_writer.h"
#include "minidump/test/minidump_context_test_util.h" #include "minidump/test/minidump_context_test_util.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
@ -50,11 +51,12 @@ void GetExceptionStream(const std::string& file_contents,
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0));
ASSERT_EQ(kMinidumpStreamTypeException, directory[0].StreamType); ASSERT_EQ(kMinidumpStreamTypeException, directory[0].StreamType);
ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_EXCEPTION_STREAM)); EXPECT_EQ(kExceptionStreamOffset, directory[0].Location.Rva);
ASSERT_EQ(kExceptionStreamOffset, directory[0].Location.Rva);
*exception_stream = reinterpret_cast<const MINIDUMP_EXCEPTION_STREAM*>( *exception_stream =
&file_contents[kExceptionStreamOffset]); MinidumpWritableAtLocationDescriptor<MINIDUMP_EXCEPTION_STREAM>(
file_contents, directory[0].Location);
ASSERT_TRUE(exception_stream);
} }
// The MINIDUMP_EXCEPTION_STREAMs |expected| and |observed| are compared against // The MINIDUMP_EXCEPTION_STREAMs |expected| and |observed| are compared against
@ -83,13 +85,9 @@ void ExpectExceptionStream(const MINIDUMP_EXCEPTION_STREAM* expected,
EXPECT_EQ(expected->ExceptionRecord.ExceptionInformation[index], EXPECT_EQ(expected->ExceptionRecord.ExceptionInformation[index],
observed->ExceptionRecord.ExceptionInformation[index]); observed->ExceptionRecord.ExceptionInformation[index]);
} }
EXPECT_EQ(expected->ThreadContext.DataSize, observed->ThreadContext.DataSize); *context = MinidumpWritableAtLocationDescriptor<MinidumpContextX86>(
ASSERT_NE(0u, observed->ThreadContext.DataSize); file_contents, observed->ThreadContext);
ASSERT_NE(0u, observed->ThreadContext.Rva); ASSERT_TRUE(context);
ASSERT_GE(file_contents.size(),
observed->ThreadContext.Rva + observed->ThreadContext.DataSize);
*context = reinterpret_cast<const MinidumpContextX86*>(
&file_contents[observed->ThreadContext.Rva]);
} }
TEST(MinidumpExceptionWriter, Minimal) { TEST(MinidumpExceptionWriter, Minimal) {

View File

@ -23,6 +23,7 @@
#include "minidump/minidump_stream_writer.h" #include "minidump/minidump_stream_writer.h"
#include "minidump/minidump_writable.h" #include "minidump/minidump_writable.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/file_writer.h" #include "util/file/file_writer.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
@ -106,8 +107,9 @@ TEST(MinidumpFileWriter, OneStream) {
EXPECT_EQ(kStreamSize, directory[0].Location.DataSize); EXPECT_EQ(kStreamSize, directory[0].Location.DataSize);
EXPECT_EQ(kStreamOffset, directory[0].Location.Rva); EXPECT_EQ(kStreamOffset, directory[0].Location.Rva);
const uint8_t* stream_data = const uint8_t* stream_data = MinidumpWritableAtLocationDescriptor<uint8_t>(
reinterpret_cast<const uint8_t*>(&file_writer.string()[kStreamOffset]); file_writer.string(), directory[0].Location);
ASSERT_TRUE(stream_data);
std::string expected_stream(kStreamSize, kStreamValue); std::string expected_stream(kStreamSize, kStreamValue);
EXPECT_EQ(0, memcmp(stream_data, expected_stream.c_str(), kStreamSize)); EXPECT_EQ(0, memcmp(stream_data, expected_stream.c_str(), kStreamSize));
@ -118,38 +120,38 @@ TEST(MinidumpFileWriter, ThreeStreams) {
const time_t kTimestamp = 0x155d2fb8; const time_t kTimestamp = 0x155d2fb8;
minidump_file.SetTimestamp(kTimestamp); minidump_file.SetTimestamp(kTimestamp);
const size_t kStream1Size = 5; const size_t kStream0Size = 5;
const MinidumpStreamType kStream1Type = static_cast<MinidumpStreamType>(0x6d); const MinidumpStreamType kStream0Type = static_cast<MinidumpStreamType>(0x6d);
const uint8_t kStream1Value = 0x5a; const uint8_t kStream0Value = 0x5a;
TestStream stream1(kStream1Type, kStream1Size, kStream1Value); TestStream stream0(kStream0Type, kStream0Size, kStream0Value);
minidump_file.AddStream(&stream1); minidump_file.AddStream(&stream0);
// Make the second streams type be a smaller quantity than the first streams // Make the second streams type be a smaller quantity than the first streams
// to test that the streams show up in the order that they were added, not in // to test that the streams show up in the order that they were added, not in
// numeric order. // numeric order.
const size_t kStream2Size = 3; const size_t kStream1Size = 3;
const MinidumpStreamType kStream2Type = static_cast<MinidumpStreamType>(0x4d); const MinidumpStreamType kStream1Type = static_cast<MinidumpStreamType>(0x4d);
const uint8_t kStream2Value = 0xa5; const uint8_t kStream1Value = 0xa5;
TestStream stream1(kStream1Type, kStream1Size, kStream1Value);
minidump_file.AddStream(&stream1);
const size_t kStream2Size = 1;
const MinidumpStreamType kStream2Type = static_cast<MinidumpStreamType>(0x7e);
const uint8_t kStream2Value = 0x36;
TestStream stream2(kStream2Type, kStream2Size, kStream2Value); TestStream stream2(kStream2Type, kStream2Size, kStream2Value);
minidump_file.AddStream(&stream2); minidump_file.AddStream(&stream2);
const size_t kStream3Size = 1;
const MinidumpStreamType kStream3Type = static_cast<MinidumpStreamType>(0x7e);
const uint8_t kStream3Value = 0x36;
TestStream stream3(kStream3Type, kStream3Size, kStream3Value);
minidump_file.AddStream(&stream3);
StringFileWriter file_writer; StringFileWriter file_writer;
ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); ASSERT_TRUE(minidump_file.WriteEverything(&file_writer));
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kStream1Offset = const size_t kStream0Offset =
kDirectoryOffset + 3 * sizeof(MINIDUMP_DIRECTORY); kDirectoryOffset + 3 * sizeof(MINIDUMP_DIRECTORY);
const size_t kStream2Padding = 3; const size_t kStream1Padding = 3;
const size_t kStream1Offset = kStream0Offset + kStream0Size + kStream1Padding;
const size_t kStream2Padding = 1;
const size_t kStream2Offset = kStream1Offset + kStream1Size + kStream2Padding; const size_t kStream2Offset = kStream1Offset + kStream1Size + kStream2Padding;
const size_t kStream3Padding = 1; const size_t kFileSize = kStream2Offset + kStream2Size;
const size_t kStream3Offset = kStream2Offset + kStream2Size + kStream3Padding;
const size_t kFileSize = kStream3Offset + kStream3Size;
ASSERT_EQ(kFileSize, file_writer.string().size()); ASSERT_EQ(kFileSize, file_writer.string().size());
@ -159,40 +161,43 @@ TEST(MinidumpFileWriter, ThreeStreams) {
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 3, kTimestamp)); ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 3, kTimestamp));
ASSERT_TRUE(directory); ASSERT_TRUE(directory);
EXPECT_EQ(kStream1Type, directory[0].StreamType); EXPECT_EQ(kStream0Type, directory[0].StreamType);
EXPECT_EQ(kStream1Size, directory[0].Location.DataSize); EXPECT_EQ(kStream0Size, directory[0].Location.DataSize);
EXPECT_EQ(kStream1Offset, directory[0].Location.Rva); EXPECT_EQ(kStream0Offset, directory[0].Location.Rva);
EXPECT_EQ(kStream2Type, directory[1].StreamType); EXPECT_EQ(kStream1Type, directory[1].StreamType);
EXPECT_EQ(kStream2Size, directory[1].Location.DataSize); EXPECT_EQ(kStream1Size, directory[1].Location.DataSize);
EXPECT_EQ(kStream2Offset, directory[1].Location.Rva); EXPECT_EQ(kStream1Offset, directory[1].Location.Rva);
EXPECT_EQ(kStream3Type, directory[2].StreamType); EXPECT_EQ(kStream2Type, directory[2].StreamType);
EXPECT_EQ(kStream3Size, directory[2].Location.DataSize); EXPECT_EQ(kStream2Size, directory[2].Location.DataSize);
EXPECT_EQ(kStream3Offset, directory[2].Location.Rva); EXPECT_EQ(kStream2Offset, directory[2].Location.Rva);
const uint8_t* stream1_data = const uint8_t* stream0_data = MinidumpWritableAtLocationDescriptor<uint8_t>(
reinterpret_cast<const uint8_t*>(&file_writer.string()[kStream1Offset]); file_writer.string(), directory[0].Location);
ASSERT_TRUE(stream0_data);
std::string expected_stream0(kStream0Size, kStream0Value);
EXPECT_EQ(0, memcmp(stream0_data, expected_stream0.c_str(), kStream0Size));
const int kZeroes[16] = {};
ASSERT_GE(sizeof(kZeroes), kStream1Padding);
EXPECT_EQ(0, memcmp(stream0_data + kStream0Size, kZeroes, kStream1Padding));
const uint8_t* stream1_data = MinidumpWritableAtLocationDescriptor<uint8_t>(
file_writer.string(), directory[1].Location);
ASSERT_TRUE(stream1_data);
std::string expected_stream1(kStream1Size, kStream1Value); std::string expected_stream1(kStream1Size, kStream1Value);
EXPECT_EQ(0, memcmp(stream1_data, expected_stream1.c_str(), kStream1Size)); EXPECT_EQ(0, memcmp(stream1_data, expected_stream1.c_str(), kStream1Size));
const int kZeroes[16] = {};
ASSERT_GE(sizeof(kZeroes), kStream2Padding); ASSERT_GE(sizeof(kZeroes), kStream2Padding);
EXPECT_EQ(0, memcmp(stream1_data + kStream1Size, kZeroes, kStream2Padding)); EXPECT_EQ(0, memcmp(stream1_data + kStream1Size, kZeroes, kStream2Padding));
const uint8_t* stream2_data = const uint8_t* stream2_data = MinidumpWritableAtLocationDescriptor<uint8_t>(
reinterpret_cast<const uint8_t*>(&file_writer.string()[kStream2Offset]); file_writer.string(), directory[2].Location);
ASSERT_TRUE(stream2_data);
std::string expected_stream2(kStream2Size, kStream2Value); std::string expected_stream2(kStream2Size, kStream2Value);
EXPECT_EQ(0, memcmp(stream2_data, expected_stream2.c_str(), kStream2Size)); EXPECT_EQ(0, memcmp(stream2_data, expected_stream2.c_str(), kStream2Size));
ASSERT_GE(sizeof(kZeroes), kStream3Padding);
EXPECT_EQ(0, memcmp(stream2_data + kStream2Size, kZeroes, kStream3Padding));
const uint8_t* stream3_data =
reinterpret_cast<const uint8_t*>(&file_writer.string()[kStream3Offset]);
std::string expected_stream3(kStream3Size, kStream3Value);
EXPECT_EQ(0, memcmp(stream3_data, expected_stream3.c_str(), kStream3Size));
} }
TEST(MinidumpFileWriter, ZeroLengthStream) { TEST(MinidumpFileWriter, ZeroLengthStream) {
@ -226,18 +231,18 @@ TEST(MinidumpFileWriter, ZeroLengthStream) {
TEST(MinidumpFileWriterDeathTest, SameStreamType) { TEST(MinidumpFileWriterDeathTest, SameStreamType) {
MinidumpFileWriter minidump_file; MinidumpFileWriter minidump_file;
const size_t kStream1Size = 5; const size_t kStream0Size = 5;
const MinidumpStreamType kStream1Type = static_cast<MinidumpStreamType>(0x4d); const MinidumpStreamType kStream0Type = static_cast<MinidumpStreamType>(0x4d);
const uint8_t kStream1Value = 0x5a; const uint8_t kStream0Value = 0x5a;
TestStream stream1(kStream1Type, kStream1Size, kStream1Value); TestStream stream0(kStream0Type, kStream0Size, kStream0Value);
minidump_file.AddStream(&stream1); minidump_file.AddStream(&stream0);
// It is an error to add a second stream of the same type. // It is an error to add a second stream of the same type.
const size_t kStream2Size = 3; const size_t kStream1Size = 3;
const MinidumpStreamType kStream2Type = static_cast<MinidumpStreamType>(0x4d); const MinidumpStreamType kStream1Type = static_cast<MinidumpStreamType>(0x4d);
const uint8_t kStream2Value = 0xa5; const uint8_t kStream1Value = 0xa5;
TestStream stream2(kStream2Type, kStream2Size, kStream2Value); TestStream stream1(kStream1Type, kStream1Size, kStream1Value);
ASSERT_DEATH(minidump_file.AddStream(&stream2), "already present"); ASSERT_DEATH(minidump_file.AddStream(&stream1), "already present");
} }
} // namespace } // namespace

View File

@ -24,6 +24,7 @@
#include "minidump/minidump_stream_writer.h" #include "minidump/minidump_stream_writer.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_memory_writer_test_util.h" #include "minidump/test/minidump_memory_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
@ -63,17 +64,11 @@ void GetMemoryListStream(const std::string& file_contents,
ASSERT_EQ(kMinidumpStreamTypeMemoryList, ASSERT_EQ(kMinidumpStreamTypeMemoryList,
directory[directory_index].StreamType); directory[directory_index].StreamType);
ASSERT_GE(directory[directory_index].Location.DataSize, EXPECT_EQ(kMemoryListStreamOffset, directory[directory_index].Location.Rva);
sizeof(MINIDUMP_MEMORY_LIST));
ASSERT_EQ(kMemoryListStreamOffset, directory[directory_index].Location.Rva);
*memory_list = reinterpret_cast<const MINIDUMP_MEMORY_LIST*>( *memory_list = MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
&file_contents[kMemoryListStreamOffset]); file_contents, directory[directory_index].Location);
ASSERT_TRUE(memory_list);
ASSERT_EQ(sizeof(MINIDUMP_MEMORY_LIST) +
(*memory_list)->NumberOfMemoryRanges *
sizeof(MINIDUMP_MEMORY_DESCRIPTOR),
directory[directory_index].Location.DataSize);
} }
TEST(MinidumpMemoryWriter, EmptyMemoryList) { TEST(MinidumpMemoryWriter, EmptyMemoryList) {

View File

@ -25,6 +25,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "minidump/minidump_file_writer.h" #include "minidump/minidump_file_writer.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
#include "util/stdlib/strlcpy.h" #include "util/stdlib/strlcpy.h"
@ -49,13 +50,11 @@ void GetMiscInfoStream(const std::string& file_contents, const T** misc_info) {
ASSERT_TRUE(directory); ASSERT_TRUE(directory);
ASSERT_EQ(kMinidumpStreamTypeMiscInfo, directory[0].StreamType); ASSERT_EQ(kMinidumpStreamTypeMiscInfo, directory[0].StreamType);
ASSERT_EQ(kMiscInfoStreamSize, directory[0].Location.DataSize); EXPECT_EQ(kMiscInfoStreamOffset, directory[0].Location.Rva);
ASSERT_EQ(kMiscInfoStreamOffset, directory[0].Location.Rva);
*misc_info = *misc_info = MinidumpWritableAtLocationDescriptor<T>(file_contents,
reinterpret_cast<const T*>(&file_contents[kMiscInfoStreamOffset]); directory[0].Location);
ASSERT_TRUE(misc_info);
ASSERT_EQ(kMiscInfoStreamSize, (*misc_info)->SizeOfInfo);
} }
void ExpectNULPaddedString16Equal(const char16* expected, void ExpectNULPaddedString16Equal(const char16* expected,

View File

@ -24,6 +24,7 @@
#include "minidump/minidump_file_writer.h" #include "minidump/minidump_file_writer.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
#include "util/misc/uuid.h" #include "util/misc/uuid.h"
@ -48,15 +49,11 @@ void GetModuleListStream(const std::string& file_contents,
ASSERT_TRUE(directory); ASSERT_TRUE(directory);
ASSERT_EQ(kMinidumpStreamTypeModuleList, directory[0].StreamType); ASSERT_EQ(kMinidumpStreamTypeModuleList, directory[0].StreamType);
ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_MODULE_LIST)); EXPECT_EQ(kModuleListStreamOffset, directory[0].Location.Rva);
ASSERT_EQ(kModuleListStreamOffset, directory[0].Location.Rva);
*module_list = reinterpret_cast<const MINIDUMP_MODULE_LIST*>( *module_list = MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>(
&file_contents[kModuleListStreamOffset]); file_contents, directory[0].Location);
ASSERT_TRUE(module_list);
ASSERT_EQ(sizeof(MINIDUMP_MODULE_LIST) +
(*module_list)->NumberOfModules * sizeof(MINIDUMP_MODULE),
directory[0].Location.DataSize);
} }
TEST(MinidumpModuleWriter, EmptyModuleList) { TEST(MinidumpModuleWriter, EmptyModuleList) {
@ -92,19 +89,15 @@ void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record,
uint32_t expected_pdb_age) { uint32_t expected_pdb_age) {
if (expected_pdb_name) { if (expected_pdb_name) {
EXPECT_NE(0u, codeview_record->Rva); EXPECT_NE(0u, codeview_record->Rva);
ASSERT_LE(codeview_record->Rva + codeview_record->DataSize,
file_contents.size());
std::string observed_pdb_name; std::string observed_pdb_name;
if (expected_pdb_uuid) { if (expected_pdb_uuid) {
// The CodeView record should be a PDB 7.0 link. // The CodeView record should be a PDB 7.0 link.
EXPECT_GE(codeview_record->DataSize,
sizeof(MinidumpModuleCodeViewRecordPDB70));
const MinidumpModuleCodeViewRecordPDB70* codeview_pdb70_record = const MinidumpModuleCodeViewRecordPDB70* codeview_pdb70_record =
reinterpret_cast<const MinidumpModuleCodeViewRecordPDB70*>( MinidumpWritableAtLocationDescriptor<
&file_contents[codeview_record->Rva]); MinidumpModuleCodeViewRecordPDB70>(file_contents,
EXPECT_EQ(MinidumpModuleCodeViewRecordPDB70::kSignature, *codeview_record);
codeview_pdb70_record->signature); ASSERT_TRUE(codeview_pdb70_record);
EXPECT_EQ(0, EXPECT_EQ(0,
memcmp(expected_pdb_uuid, memcmp(expected_pdb_uuid,
&codeview_pdb70_record->uuid, &codeview_pdb70_record->uuid,
@ -117,13 +110,11 @@ void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record,
offsetof(MinidumpModuleCodeViewRecordPDB70, pdb_name)); offsetof(MinidumpModuleCodeViewRecordPDB70, pdb_name));
} else { } else {
// The CodeView record should be a PDB 2.0 link. // The CodeView record should be a PDB 2.0 link.
EXPECT_GE(codeview_record->DataSize,
sizeof(MinidumpModuleCodeViewRecordPDB20));
const MinidumpModuleCodeViewRecordPDB20* codeview_pdb20_record = const MinidumpModuleCodeViewRecordPDB20* codeview_pdb20_record =
reinterpret_cast<const MinidumpModuleCodeViewRecordPDB20*>( MinidumpWritableAtLocationDescriptor<
&file_contents[codeview_record->Rva]); MinidumpModuleCodeViewRecordPDB20>(file_contents,
EXPECT_EQ(MinidumpModuleCodeViewRecordPDB20::kSignature, *codeview_record);
codeview_pdb20_record->signature); ASSERT_TRUE(codeview_pdb20_record);
EXPECT_EQ(static_cast<uint32_t>(expected_pdb_timestamp), EXPECT_EQ(static_cast<uint32_t>(expected_pdb_timestamp),
codeview_pdb20_record->timestamp); codeview_pdb20_record->timestamp);
EXPECT_EQ(expected_pdb_age, codeview_pdb20_record->age); EXPECT_EQ(expected_pdb_age, codeview_pdb20_record->age);
@ -157,14 +148,12 @@ void ExpectMiscellaneousDebugRecord(
uint32_t expected_debug_type, uint32_t expected_debug_type,
bool expected_debug_utf16) { bool expected_debug_utf16) {
if (expected_debug_name) { if (expected_debug_name) {
EXPECT_GE(misc_record->DataSize, sizeof(IMAGE_DEBUG_MISC));
EXPECT_NE(0u, misc_record->Rva); EXPECT_NE(0u, misc_record->Rva);
ASSERT_LE(misc_record->Rva + misc_record->DataSize, file_contents.size());
const IMAGE_DEBUG_MISC* misc_debug_record = const IMAGE_DEBUG_MISC* misc_debug_record =
reinterpret_cast<const IMAGE_DEBUG_MISC*>( MinidumpWritableAtLocationDescriptor<IMAGE_DEBUG_MISC>(file_contents,
&file_contents[misc_record->Rva]); *misc_record);
ASSERT_TRUE(misc_debug_record);
EXPECT_EQ(expected_debug_type, misc_debug_record->DataType); EXPECT_EQ(expected_debug_type, misc_debug_record->DataType);
EXPECT_EQ(misc_record->DataSize, misc_debug_record->Length);
EXPECT_EQ(expected_debug_utf16, misc_debug_record->Unicode); EXPECT_EQ(expected_debug_utf16, misc_debug_record->Unicode);
EXPECT_EQ(0u, misc_debug_record->Reserved[0]); EXPECT_EQ(0u, misc_debug_record->Reserved[0]);
EXPECT_EQ(0u, misc_debug_record->Reserved[1]); EXPECT_EQ(0u, misc_debug_record->Reserved[1]);

View File

@ -19,16 +19,23 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "minidump/minidump_extensions.h" #include "minidump/minidump_extensions.h"
#include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
namespace test { namespace test {
namespace { namespace {
const MinidumpSimpleStringDictionary* MinidumpSimpleStringDictionaryCast( const MinidumpSimpleStringDictionary* MinidumpSimpleStringDictionaryAtStart(
const StringFileWriter& file_writer) { const std::string& file_contents,
return reinterpret_cast<const MinidumpSimpleStringDictionary*>( size_t count) {
&file_writer.string()[0]); MINIDUMP_LOCATION_DESCRIPTOR location_descriptor;
location_descriptor.DataSize =
sizeof(MinidumpSimpleStringDictionary) +
count * sizeof(MinidumpSimpleStringDictionaryEntry);
location_descriptor.Rva = 0;
return MinidumpWritableAtLocationDescriptor<MinidumpSimpleStringDictionary>(
file_contents, location_descriptor);
} }
TEST(MinidumpSimpleStringDictionaryWriter, EmptySimpleStringDictionary) { TEST(MinidumpSimpleStringDictionaryWriter, EmptySimpleStringDictionary) {
@ -41,7 +48,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, EmptySimpleStringDictionary) {
file_writer.string().size()); file_writer.string().size());
const MinidumpSimpleStringDictionary* dictionary = const MinidumpSimpleStringDictionary* dictionary =
MinidumpSimpleStringDictionaryCast(file_writer); MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 0);
ASSERT_TRUE(dictionary);
EXPECT_EQ(0u, dictionary->count); EXPECT_EQ(0u, dictionary->count);
} }
@ -59,7 +67,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, EmptyKeyValue) {
file_writer.string().size()); file_writer.string().size());
const MinidumpSimpleStringDictionary* dictionary = const MinidumpSimpleStringDictionary* dictionary =
MinidumpSimpleStringDictionaryCast(file_writer); MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 1);
ASSERT_TRUE(dictionary);
EXPECT_EQ(1u, dictionary->count); EXPECT_EQ(1u, dictionary->count);
EXPECT_EQ(12u, dictionary->entries[0].key); EXPECT_EQ(12u, dictionary->entries[0].key);
EXPECT_EQ(20u, dictionary->entries[0].value); EXPECT_EQ(20u, dictionary->entries[0].value);
@ -89,7 +98,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, OneKeyValue) {
file_writer.string().size()); file_writer.string().size());
const MinidumpSimpleStringDictionary* dictionary = const MinidumpSimpleStringDictionary* dictionary =
MinidumpSimpleStringDictionaryCast(file_writer); MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 1);
ASSERT_TRUE(dictionary);
EXPECT_EQ(1u, dictionary->count); EXPECT_EQ(1u, dictionary->count);
EXPECT_EQ(12u, dictionary->entries[0].key); EXPECT_EQ(12u, dictionary->entries[0].key);
EXPECT_EQ(20u, dictionary->entries[0].value); EXPECT_EQ(20u, dictionary->entries[0].value);
@ -131,7 +141,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, ThreeKeysValues) {
file_writer.string().size()); file_writer.string().size());
const MinidumpSimpleStringDictionary* dictionary = const MinidumpSimpleStringDictionary* dictionary =
MinidumpSimpleStringDictionaryCast(file_writer); MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 3);
ASSERT_TRUE(dictionary);
EXPECT_EQ(3u, dictionary->count); EXPECT_EQ(3u, dictionary->count);
EXPECT_EQ(28u, dictionary->entries[0].key); EXPECT_EQ(28u, dictionary->entries[0].key);
EXPECT_EQ(36u, dictionary->entries[0].value); EXPECT_EQ(36u, dictionary->entries[0].value);
@ -188,7 +199,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, DuplicateKeyValue) {
file_writer.string().size()); file_writer.string().size());
const MinidumpSimpleStringDictionary* dictionary = const MinidumpSimpleStringDictionary* dictionary =
MinidumpSimpleStringDictionaryCast(file_writer); MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 1);
ASSERT_TRUE(dictionary);
EXPECT_EQ(1u, dictionary->count); EXPECT_EQ(1u, dictionary->count);
EXPECT_EQ(12u, dictionary->entries[0].key); EXPECT_EQ(12u, dictionary->entries[0].key);
EXPECT_EQ(20u, dictionary->entries[0].value); EXPECT_EQ(20u, dictionary->entries[0].value);

View File

@ -23,6 +23,7 @@
#include "minidump/minidump_file_writer.h" #include "minidump/minidump_file_writer.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_string_writer_test_util.h" #include "minidump/test/minidump_string_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
@ -56,17 +57,17 @@ void GetSystemInfoStream(const std::string& file_contents,
ASSERT_TRUE(directory); ASSERT_TRUE(directory);
ASSERT_EQ(kMinidumpStreamTypeSystemInfo, directory[0].StreamType); ASSERT_EQ(kMinidumpStreamTypeSystemInfo, directory[0].StreamType);
ASSERT_EQ(sizeof(MINIDUMP_SYSTEM_INFO), directory[0].Location.DataSize); EXPECT_EQ(kSystemInfoStreamOffset, directory[0].Location.Rva);
ASSERT_EQ(kSystemInfoStreamOffset, directory[0].Location.Rva);
*system_info = reinterpret_cast<const MINIDUMP_SYSTEM_INFO*>( *system_info = MinidumpWritableAtLocationDescriptor<MINIDUMP_SYSTEM_INFO>(
&file_contents[kSystemInfoStreamOffset]); file_contents, directory[0].Location);
ASSERT_TRUE(system_info);
ASSERT_EQ(kCSDVersionOffset, (*system_info)->CSDVersionRva); EXPECT_EQ(kCSDVersionOffset, (*system_info)->CSDVersionRva);
*csd_version = *csd_version =
MinidumpStringAtRVA(file_contents, (*system_info)->CSDVersionRva); MinidumpStringAtRVA(file_contents, (*system_info)->CSDVersionRva);
ASSERT_EQ(kCSDVersionBytes, (*csd_version)->Length); EXPECT_EQ(kCSDVersionBytes, (*csd_version)->Length);
} }
TEST(MinidumpSystemInfoWriter, Empty) { TEST(MinidumpSystemInfoWriter, Empty) {

View File

@ -23,6 +23,7 @@
#include "minidump/test/minidump_context_test_util.h" #include "minidump/test/minidump_context_test_util.h"
#include "minidump/test/minidump_memory_writer_test_util.h" #include "minidump/test/minidump_memory_writer_test_util.h"
#include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_file_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file_writer.h" #include "util/file/string_file_writer.h"
namespace crashpad { namespace crashpad {
@ -51,19 +52,18 @@ void GetThreadListStream(const std::string& file_contents,
ASSERT_TRUE(directory); ASSERT_TRUE(directory);
ASSERT_EQ(kMinidumpStreamTypeThreadList, directory[0].StreamType); ASSERT_EQ(kMinidumpStreamTypeThreadList, directory[0].StreamType);
ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_THREAD_LIST)); EXPECT_EQ(kThreadListStreamOffset, directory[0].Location.Rva);
ASSERT_EQ(kThreadListStreamOffset, directory[0].Location.Rva);
*thread_list = reinterpret_cast<const MINIDUMP_THREAD_LIST*>( *thread_list = MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>(
&file_contents[kThreadListStreamOffset]); file_contents, directory[0].Location);
ASSERT_TRUE(thread_list);
ASSERT_EQ(sizeof(MINIDUMP_THREAD_LIST) +
(*thread_list)->NumberOfThreads * sizeof(MINIDUMP_THREAD),
directory[0].Location.DataSize);
if (memory_list) { if (memory_list) {
*memory_list = reinterpret_cast<const MINIDUMP_MEMORY_LIST*>( ASSERT_EQ(kMinidumpStreamTypeMemoryList, directory[1].StreamType);
&file_contents[directory[1].Location.Rva]);
*memory_list = MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
file_contents, directory[1].Location);
ASSERT_TRUE(*memory_list);
} }
} }

View File

@ -32,15 +32,6 @@ const MINIDUMP_HEADER* MinidumpHeaderAtStart(
file_contents, location_descriptor); file_contents, location_descriptor);
if (header) { if (header) {
if (header->Signature != MINIDUMP_SIGNATURE) {
EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_SIGNATURE), header->Signature);
return nullptr;
}
if (header->Version != MINIDUMP_VERSION) {
EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_VERSION), header->Version);
return nullptr;
}
location_descriptor.DataSize = location_descriptor.DataSize =
header->NumberOfStreams * sizeof(MINIDUMP_DIRECTORY); header->NumberOfStreams * sizeof(MINIDUMP_DIRECTORY);
location_descriptor.Rva = header->StreamDirectoryRva; location_descriptor.Rva = header->StreamDirectoryRva;
@ -57,8 +48,6 @@ void VerifyMinidumpHeader(const MINIDUMP_HEADER* header,
uint32_t streams, uint32_t streams,
uint32_t timestamp) { uint32_t timestamp) {
ASSERT_TRUE(header); ASSERT_TRUE(header);
EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_SIGNATURE), header->Signature);
EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_VERSION), header->Version);
ASSERT_EQ(streams, header->NumberOfStreams); ASSERT_EQ(streams, header->NumberOfStreams);
ASSERT_EQ(streams ? sizeof(MINIDUMP_HEADER) : 0u, header->StreamDirectoryRva); ASSERT_EQ(streams ? sizeof(MINIDUMP_HEADER) : 0u, header->StreamDirectoryRva);
EXPECT_EQ(0u, header->CheckSum); EXPECT_EQ(0u, header->CheckSum);

View File

@ -45,13 +45,15 @@ const MINIDUMP_HEADER* MinidumpHeaderAtStart(
//! \brief Verifies, via gtest assertions, that a MINIDUMP_HEADER contains //! \brief Verifies, via gtest assertions, that a MINIDUMP_HEADER contains
//! expected values. //! expected values.
//! //!
//! All fields in the MINIDUMP_HEADER will be evaluated. Most are compared to //! All fields in the MINIDUMP_HEADER will be evaluated except for the Signature
//! their correct default values. MINIDUMP_HEADER::NumberOfStreams is compared //! and Version fields, because those are checked by MinidumpHeaderAtStart().
//! to \a streams, and MINIDUMP_HEADER::TimeDateStamp is compared to \a //! Most other fields are are compared to their correct default values.
//! timestamp. Most fields are checked with nonfatal EXPECT-style assertions, //! MINIDUMP_HEADER::NumberOfStreams is compared to \a streams, and
//! but MINIDUMP_HEADER::NumberOfStreams and MINIDUMP_HEADER::StreamDirectoryRva //! MINIDUMP_HEADER::TimeDateStamp is compared to \a timestamp. Most fields are
//! are checked with fatal ASSERT-style assertions, because they must be //! checked with nonfatal EXPECT-style assertions, but
//! correct in order for processing of the minidump to continue. //! MINIDUMP_HEADER::NumberOfStreams and MINIDUMP_HEADER::StreamDirectoryRva are
//! checked with fatal ASSERT-style assertions, because they must be correct in
//! order for processing of the minidump to continue.
void VerifyMinidumpHeader(const MINIDUMP_HEADER* header, void VerifyMinidumpHeader(const MINIDUMP_HEADER* header,
uint32_t streams, uint32_t streams,
uint32_t timestamp); uint32_t timestamp);

View File

@ -16,6 +16,7 @@
#include <string> #include <string>
#include "base/strings/string16.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
namespace crashpad { namespace crashpad {
@ -34,12 +35,20 @@ const void* MinidumpWritableAtRVAInternal(const std::string& file_contents,
const void* MinidumpWritableAtLocationDescriptorInternal( const void* MinidumpWritableAtLocationDescriptorInternal(
const std::string& file_contents, const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location, const MINIDUMP_LOCATION_DESCRIPTOR& location,
size_t expected_minimum_size) { size_t expected_size,
bool allow_oversized_data) {
if (location.DataSize == 0) { if (location.DataSize == 0) {
EXPECT_EQ(0u, location.Rva); EXPECT_EQ(0u, location.Rva);
return nullptr; return nullptr;
} else if (location.DataSize < expected_minimum_size) { }
EXPECT_GE(location.DataSize, expected_minimum_size);
if (allow_oversized_data) {
if (location.DataSize < expected_size) {
EXPECT_GE(location.DataSize, expected_size);
return nullptr;
}
} else if (location.DataSize != expected_size) {
EXPECT_EQ(expected_size, location.DataSize);
return nullptr; return nullptr;
} }
@ -54,5 +63,213 @@ const void* MinidumpWritableAtLocationDescriptorInternal(
return rv; return rv;
} }
template <>
const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor<IMAGE_DEBUG_MISC>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
const IMAGE_DEBUG_MISC* misc =
TMinidumpWritableAtLocationDescriptor<IMAGE_DEBUG_MISC>(file_contents,
location);
if (!misc) {
return nullptr;
}
if (misc->DataType != IMAGE_DEBUG_MISC_EXENAME) {
EXPECT_EQ(static_cast<uint32_t>(IMAGE_DEBUG_MISC_EXENAME), misc->DataType);
return nullptr;
}
if (misc->Length != location.DataSize) {
EXPECT_EQ(location.DataSize, misc->Length);
return nullptr;
}
if (misc->Unicode == 0) {
size_t string_length = misc->Length - offsetof(IMAGE_DEBUG_MISC, Data) - 1;
if (misc->Data[string_length] != '\0') {
EXPECT_EQ('\0', misc->Data[string_length]);
return nullptr;
}
} else if (misc->Unicode == 1) {
if (misc->Length % sizeof(char16) != 0) {
EXPECT_EQ(0u, misc->Length % sizeof(char16));
return nullptr;
}
size_t string_length =
(misc->Length - offsetof(IMAGE_DEBUG_MISC, Data)) / sizeof(char16) - 1;
const char16* data16 = reinterpret_cast<const char16*>(misc->Data);
if (data16[string_length] != '\0') {
EXPECT_EQ('\0', data16[string_length]);
return nullptr;
}
} else {
ADD_FAILURE() << "misc->Unicode " << misc->Unicode;
return nullptr;
}
return misc;
}
template <>
const MINIDUMP_HEADER* MinidumpWritableAtLocationDescriptor<MINIDUMP_HEADER>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
const MINIDUMP_HEADER* header =
TMinidumpWritableAtLocationDescriptor<MINIDUMP_HEADER>(file_contents,
location);
if (!header) {
return nullptr;
}
if (header->Signature != MINIDUMP_SIGNATURE) {
EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_SIGNATURE), header->Signature);
return nullptr;
}
if (header->Version != MINIDUMP_VERSION) {
EXPECT_EQ(static_cast<uint32_t>(MINIDUMP_VERSION), header->Version);
return nullptr;
}
return header;
}
namespace {
struct MinidumpMemoryListTraits {
typedef MINIDUMP_MEMORY_LIST ListType;
static constexpr size_t kElementSize = sizeof(MINIDUMP_MEMORY_DESCRIPTOR);
static size_t ElementCount(const ListType* list) {
return list->NumberOfMemoryRanges;
}
};
struct MinidumpModuleListTraits {
typedef MINIDUMP_MODULE_LIST ListType;
static constexpr size_t kElementSize = sizeof(MINIDUMP_MODULE);
static size_t ElementCount(const ListType* list) {
return list->NumberOfModules;
}
};
struct MinidumpThreadListTraits {
typedef MINIDUMP_THREAD_LIST ListType;
static constexpr size_t kElementSize = sizeof(MINIDUMP_THREAD);
static size_t ElementCount(const ListType* list) {
return list->NumberOfThreads;
}
};
struct MinidumpSimpleStringDictionaryListTraits {
typedef MinidumpSimpleStringDictionary ListType;
static constexpr size_t kElementSize =
sizeof(MinidumpSimpleStringDictionaryEntry);
static size_t ElementCount(const ListType* list) {
return list->count;
}
};
template <typename T>
const typename T::ListType* MinidumpListAtLocationDescriptor(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
const typename T::ListType* list =
TMinidumpWritableAtLocationDescriptor<typename T::ListType>(file_contents,
location);
if (!list) {
return nullptr;
}
size_t expected_size =
sizeof(typename T::ListType) + T::ElementCount(list) * T::kElementSize;
if (location.DataSize != expected_size) {
EXPECT_EQ(expected_size, location.DataSize);
return nullptr;
}
return list;
}
} // namespace
template <>
const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor<
MINIDUMP_MEMORY_LIST>(const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return MinidumpListAtLocationDescriptor<MinidumpMemoryListTraits>(
file_contents, location);
}
template <>
const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor<
MINIDUMP_MODULE_LIST>(const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return MinidumpListAtLocationDescriptor<MinidumpModuleListTraits>(
file_contents, location);
}
template <>
const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor<
MINIDUMP_THREAD_LIST>(const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return MinidumpListAtLocationDescriptor<MinidumpThreadListTraits>(
file_contents, location);
}
template <>
const MinidumpSimpleStringDictionary*
MinidumpWritableAtLocationDescriptor<MinidumpSimpleStringDictionary>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return MinidumpListAtLocationDescriptor<
MinidumpSimpleStringDictionaryListTraits>(file_contents, location);
}
namespace {
template <typename T>
const T* MinidumpCVPDBAtLocationDescriptor(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
const T* cv_pdb =
TMinidumpWritableAtLocationDescriptor<T>(file_contents, location);
if (!cv_pdb) {
return nullptr;
}
if (cv_pdb->signature != T::kSignature) {
EXPECT_EQ(T::kSignature, cv_pdb->signature);
return nullptr;
}
size_t string_length = location.DataSize - offsetof(T, pdb_name) - 1;
if (cv_pdb->pdb_name[string_length] != '\0') {
EXPECT_EQ('\0', cv_pdb->pdb_name[string_length]);
return nullptr;
}
return cv_pdb;
}
} // namespace
template <>
const MinidumpModuleCodeViewRecordPDB20*
MinidumpWritableAtLocationDescriptor<MinidumpModuleCodeViewRecordPDB20>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return MinidumpCVPDBAtLocationDescriptor<MinidumpModuleCodeViewRecordPDB20>(
file_contents, location);
}
template <>
const MinidumpModuleCodeViewRecordPDB70*
MinidumpWritableAtLocationDescriptor<MinidumpModuleCodeViewRecordPDB70>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return MinidumpCVPDBAtLocationDescriptor<MinidumpModuleCodeViewRecordPDB70>(
file_contents, location);
}
} // namespace test } // namespace test
} // namespace crashpad } // namespace crashpad

View File

@ -16,10 +16,12 @@
#define CRASHPAD_MINIDUMP_TEST_MINIDUMP_WRITABLE_TEST_UTIL_H_ #define CRASHPAD_MINIDUMP_TEST_MINIDUMP_WRITABLE_TEST_UTIL_H_
#include <dbghelp.h> #include <dbghelp.h>
#include <stdint.h>
#include <string> #include <string>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "minidump/minidump_extensions.h"
namespace crashpad { namespace crashpad {
namespace test { namespace test {
@ -47,12 +49,18 @@ const void* MinidumpWritableAtRVAInternal(const std::string& file_contents,
//! \param[in] file_contents The contents of the minidump file. //! \param[in] file_contents The contents of the minidump file.
//! \param[in] location A MINIDUMP_LOCATION_DESCRIPTOR giving the offset within //! \param[in] location A MINIDUMP_LOCATION_DESCRIPTOR giving the offset within
//! the minidump file of the desired object, as well as its size. //! the minidump file of the desired object, as well as its size.
//! \param[in] expected_minimum_size The minimum size allowable for the object. //! \param[in] expected_size The expected size of the object. If \a
//! allow_oversized_data is `true`, \a expected_size is treated as the
//! minimum size of \a location, but it is permitted to be larger. If \a
//! allow_oversized_data is `false`, the size of \a location must match
//! \a expected_size exactly.
//! \param[in] allow_oversized_data Controls whether \a expected_size is a
//! minimum limit (`true`) or an exact match is required (`false`).
//! //!
//! \return If the size of \a location is at least as big as \a //! \return If the size of \a location is agrees with \a expected_size, and if
//! expected_minimum_size, and if \a location is within the range of \a //! \a location is within the range of \a file_contents, returns a pointer
//! file_contents, returns a pointer into \a file_contents at offset \a rva. //! into \a file_contents at offset \a rva. Otherwise, raises a gtest
//! Otherwise, raises a gtest assertion failure and returns `nullptr`. //! assertion failure and returns `nullptr`.
//! //!
//! Do not call this function. Use the typed version, //! Do not call this function. Use the typed version,
//! MinidumpWritableAtLocationDescriptor<>(), or another type-specific function. //! MinidumpWritableAtLocationDescriptor<>(), or another type-specific function.
@ -61,7 +69,54 @@ const void* MinidumpWritableAtRVAInternal(const std::string& file_contents,
const void* MinidumpWritableAtLocationDescriptorInternal( const void* MinidumpWritableAtLocationDescriptorInternal(
const std::string& file_contents, const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location, const MINIDUMP_LOCATION_DESCRIPTOR& location,
size_t expected_minimum_size); size_t expected_size,
bool allow_oversized_data);
//! \brief A traits class defining whether a minidump object type is required to
//! appear only as a fixed-size object or if it is variable-sized.
//!
//! Variable-sized data is data referenced by a MINIDUMP_LOCATION_DESCRIPTOR
//! whose DataSize field may be larger than the size of the basic object types
//! structure. This can happen for types that appear only as variable-sized
//! lists, or types whose final fields are variable-sized lists or other
//! variable-sized data.
template <typename T>
struct MinidumpWritableTraits {
//! \brief `true` if \a T should be treated as a variable-sized data type,
//! where its base size is used solely as a minimum bound. `false` if \a
//! T is a fixed-sized type, which should only appear at its base size.
static const bool kAllowOversizedData = false;
};
#define MINIDUMP_ALLOW_OVERSIZED_DATA(x) \
template <> \
struct MinidumpWritableTraits<x> { \
static const bool kAllowOversizedData = true; \
}
// This type appears only as a variable-sized list.
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_DIRECTORY);
// These types are permitted to be oversized because their final fields are
// variable-sized lists.
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MEMORY_LIST);
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_MODULE_LIST);
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_THREAD_LIST);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpSimpleStringDictionary);
// These types have final fields carrying variable-sized data (typically string
// data).
MINIDUMP_ALLOW_OVERSIZED_DATA(IMAGE_DEBUG_MISC);
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_STRING);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpModuleCodeViewRecordPDB20);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpModuleCodeViewRecordPDB70);
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpUTF8String);
// minidump_file_writer_test accesses its variable-sized test streams via a
// uint8_t*.
MINIDUMP_ALLOW_OVERSIZED_DATA(uint8_t);
#undef MINIDUMP_ALLOW_OVERSIZED_DATA
//! \brief Returns a typed minidump object located within a minidump files //! \brief Returns a typed minidump object located within a minidump files
//! contents, where the offset of the object is known. //! contents, where the offset of the object is known.
@ -83,6 +138,42 @@ const T* MinidumpWritableAtRVA(const std::string& file_contents, RVA rva) {
//! \brief Returns a typed minidump object located within a minidump files //! \brief Returns a typed minidump object located within a minidump files
//! contents, where the offset and size of the object are known. //! contents, where the offset and size of the object are known.
//! //!
//! This function is similar to MinidumpWritableAtLocationDescriptor<>() and is
//! used to implement that function. It exists independently so that template
//! specializations are able to call this function, which provides the default
//! implementation.
//!
//! Do not call this function directly. Use
//! MinidumpWritableAtLocationDescriptor<>() instead.
template <typename T>
const T* TMinidumpWritableAtLocationDescriptor(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return reinterpret_cast<const T*>(
MinidumpWritableAtLocationDescriptorInternal(
file_contents,
location,
sizeof(T),
MinidumpWritableTraits<T>::kAllowOversizedData));
}
//! \brief Returns a typed minidump object located within a minidump files
//! contents, where the offset and size of the object are known.
//!
//! This function has template specializations that perform more stringent
//! checking than the default implementation:
//! - With a MINIDUMP_HEADER template parameter, a template specialization
//! ensures that the structures magic number and version fields are correct.
//! - With a MINIDUMP_MEMORY_LIST, MINIDUMP_THREAD_LIST, MINIDUMP_MODULE_LIST,
//! or MinidumpSimpleStringDictionary template parameter, template
//! specializations ensure that the size given by \a location matches the
//! size expected of a stream containing the number of elements it claims to
//! have.
//! - With an IMAGE_DEBUG_MISC, MinidumpModuleCodeViewRecordPDB20, or
//! MinidumpModuleCodeViewRecordPDB70 template parameter, template
//! specializations ensure that the structure has the expected format
//! including any magic number and the `NUL`-terminated string.
//!
//! \param[in] file_contents The contents of the minidump file. //! \param[in] file_contents The contents of the minidump file.
//! \param[in] location A MINIDUMP_LOCATION_DESCRIPTOR giving the offset within //! \param[in] location A MINIDUMP_LOCATION_DESCRIPTOR giving the offset within
//! the minidump file of the desired object, as well as its size. //! the minidump file of the desired object, as well as its size.
@ -97,11 +188,52 @@ template <typename T>
const T* MinidumpWritableAtLocationDescriptor( const T* MinidumpWritableAtLocationDescriptor(
const std::string& file_contents, const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location) { const MINIDUMP_LOCATION_DESCRIPTOR& location) {
return reinterpret_cast<const T*>( return TMinidumpWritableAtLocationDescriptor<T>(file_contents, location);
MinidumpWritableAtLocationDescriptorInternal(
file_contents, location, sizeof(T)));
} }
template <>
const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor<IMAGE_DEBUG_MISC>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MINIDUMP_HEADER* MinidumpWritableAtLocationDescriptor<MINIDUMP_HEADER>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor<
MINIDUMP_MEMORY_LIST>(const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor<
MINIDUMP_MODULE_LIST>(const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor<
MINIDUMP_THREAD_LIST>(const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MinidumpModuleCodeViewRecordPDB20*
MinidumpWritableAtLocationDescriptor<MinidumpModuleCodeViewRecordPDB20>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MinidumpModuleCodeViewRecordPDB70*
MinidumpWritableAtLocationDescriptor<MinidumpModuleCodeViewRecordPDB70>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
template <>
const MinidumpSimpleStringDictionary*
MinidumpWritableAtLocationDescriptor<MinidumpSimpleStringDictionary>(
const std::string& file_contents,
const MINIDUMP_LOCATION_DESCRIPTOR& location);
} // namespace test } // namespace test
} // namespace crashpad } // namespace crashpad