diff --git a/minidump/minidump_context_writer_test.cc b/minidump/minidump_context_writer_test.cc index 43f6476..9359514 100644 --- a/minidump/minidump_context_writer_test.cc +++ b/minidump/minidump_context_writer_test.cc @@ -19,6 +19,7 @@ #include "gtest/gtest.h" #include "minidump/minidump_context.h" #include "minidump/test/minidump_context_test_util.h" +#include "minidump/test/minidump_writable_test_util.h" #include "util/file/string_file_writer.h" namespace crashpad { @@ -39,7 +40,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) { ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size()); const MinidumpContextX86* observed = - reinterpret_cast(&file_writer.string()[0]); + MinidumpWritableAtRVA(file_writer.string(), 0); ExpectMinidumpContextX86(0, observed); } @@ -56,7 +57,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) { ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size()); const MinidumpContextX86* observed = - reinterpret_cast(&file_writer.string()[0]); + MinidumpWritableAtRVA(file_writer.string(), 0); ExpectMinidumpContextX86(kSeed, observed); } } @@ -75,7 +76,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size()); const MinidumpContextAMD64* observed = - reinterpret_cast(&file_writer.string()[0]); + MinidumpWritableAtRVA(file_writer.string(), 0); ExpectMinidumpContextAMD64(0, observed); } @@ -92,7 +93,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size()); const MinidumpContextAMD64* observed = - reinterpret_cast(&file_writer.string()[0]); + MinidumpWritableAtRVA(file_writer.string(), 0); ExpectMinidumpContextAMD64(kSeed, observed); } } diff --git a/minidump/minidump_crashpad_info_writer_test.cc b/minidump/minidump_crashpad_info_writer_test.cc index 3cbbfb6..b59301b 100644 --- a/minidump/minidump_crashpad_info_writer_test.cc +++ b/minidump/minidump_crashpad_info_writer_test.cc @@ -22,6 +22,7 @@ #include "minidump/minidump_simple_string_dictionary_writer.h" #include "minidump/test/minidump_file_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" namespace crashpad { @@ -55,20 +56,19 @@ void GetCrashpadInfoStream( ASSERT_TRUE(directory); ASSERT_EQ(kMinidumpStreamTypeCrashpadInfo, directory[0].StreamType); - ASSERT_EQ(sizeof(MinidumpCrashpadInfo), directory[0].Location.DataSize); - ASSERT_EQ(kCrashpadInfoStreamOffset, directory[0].Location.Rva); + EXPECT_EQ(kCrashpadInfoStreamOffset, directory[0].Location.Rva); - *crashpad_info = reinterpret_cast( - &file_contents[kCrashpadInfoStreamOffset]); + *crashpad_info = MinidumpWritableAtLocationDescriptor( + file_contents, directory[0].Location); + ASSERT_TRUE(*crashpad_info); if (simple_annotations) { - ASSERT_GE((*crashpad_info)->simple_annotations.DataSize, - sizeof(MinidumpSimpleStringDictionary)); - ASSERT_EQ(kSimpleAnnotationsOffset, + EXPECT_EQ(kSimpleAnnotationsOffset, (*crashpad_info)->simple_annotations.Rva); *simple_annotations = - reinterpret_cast( - &file_contents[kSimpleAnnotationsOffset]); + MinidumpWritableAtLocationDescriptor( + file_contents, (*crashpad_info)->simple_annotations); + ASSERT_TRUE(*simple_annotations); } else { ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.DataSize); ASSERT_EQ(0u, (*crashpad_info)->simple_annotations.Rva); diff --git a/minidump/minidump_exception_writer_test.cc b/minidump/minidump_exception_writer_test.cc index e1cad61..2b51327 100644 --- a/minidump/minidump_exception_writer_test.cc +++ b/minidump/minidump_exception_writer_test.cc @@ -27,6 +27,7 @@ #include "minidump/minidump_file_writer.h" #include "minidump/test/minidump_context_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" namespace crashpad { @@ -50,11 +51,12 @@ void GetExceptionStream(const std::string& file_contents, ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_EQ(kMinidumpStreamTypeException, directory[0].StreamType); - ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_EXCEPTION_STREAM)); - ASSERT_EQ(kExceptionStreamOffset, directory[0].Location.Rva); + EXPECT_EQ(kExceptionStreamOffset, directory[0].Location.Rva); - *exception_stream = reinterpret_cast( - &file_contents[kExceptionStreamOffset]); + *exception_stream = + MinidumpWritableAtLocationDescriptor( + file_contents, directory[0].Location); + ASSERT_TRUE(exception_stream); } // 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], observed->ExceptionRecord.ExceptionInformation[index]); } - EXPECT_EQ(expected->ThreadContext.DataSize, observed->ThreadContext.DataSize); - ASSERT_NE(0u, observed->ThreadContext.DataSize); - ASSERT_NE(0u, observed->ThreadContext.Rva); - ASSERT_GE(file_contents.size(), - observed->ThreadContext.Rva + observed->ThreadContext.DataSize); - *context = reinterpret_cast( - &file_contents[observed->ThreadContext.Rva]); + *context = MinidumpWritableAtLocationDescriptor( + file_contents, observed->ThreadContext); + ASSERT_TRUE(context); } TEST(MinidumpExceptionWriter, Minimal) { diff --git a/minidump/minidump_file_writer_test.cc b/minidump/minidump_file_writer_test.cc index 51369f5..cda9356 100644 --- a/minidump/minidump_file_writer_test.cc +++ b/minidump/minidump_file_writer_test.cc @@ -23,6 +23,7 @@ #include "minidump/minidump_stream_writer.h" #include "minidump/minidump_writable.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/string_file_writer.h" @@ -106,8 +107,9 @@ TEST(MinidumpFileWriter, OneStream) { EXPECT_EQ(kStreamSize, directory[0].Location.DataSize); EXPECT_EQ(kStreamOffset, directory[0].Location.Rva); - const uint8_t* stream_data = - reinterpret_cast(&file_writer.string()[kStreamOffset]); + const uint8_t* stream_data = MinidumpWritableAtLocationDescriptor( + file_writer.string(), directory[0].Location); + ASSERT_TRUE(stream_data); std::string expected_stream(kStreamSize, kStreamValue); EXPECT_EQ(0, memcmp(stream_data, expected_stream.c_str(), kStreamSize)); @@ -118,38 +120,38 @@ TEST(MinidumpFileWriter, ThreeStreams) { const time_t kTimestamp = 0x155d2fb8; minidump_file.SetTimestamp(kTimestamp); - const size_t kStream1Size = 5; - const MinidumpStreamType kStream1Type = static_cast(0x6d); - const uint8_t kStream1Value = 0x5a; - TestStream stream1(kStream1Type, kStream1Size, kStream1Value); - minidump_file.AddStream(&stream1); + const size_t kStream0Size = 5; + const MinidumpStreamType kStream0Type = static_cast(0x6d); + const uint8_t kStream0Value = 0x5a; + TestStream stream0(kStream0Type, kStream0Size, kStream0Value); + minidump_file.AddStream(&stream0); // Make the second stream’s type be a smaller quantity than the first stream’s // to test that the streams show up in the order that they were added, not in // numeric order. - const size_t kStream2Size = 3; - const MinidumpStreamType kStream2Type = static_cast(0x4d); - const uint8_t kStream2Value = 0xa5; + const size_t kStream1Size = 3; + const MinidumpStreamType kStream1Type = static_cast(0x4d); + const uint8_t kStream1Value = 0xa5; + TestStream stream1(kStream1Type, kStream1Size, kStream1Value); + minidump_file.AddStream(&stream1); + + const size_t kStream2Size = 1; + const MinidumpStreamType kStream2Type = static_cast(0x7e); + const uint8_t kStream2Value = 0x36; TestStream stream2(kStream2Type, kStream2Size, kStream2Value); minidump_file.AddStream(&stream2); - const size_t kStream3Size = 1; - const MinidumpStreamType kStream3Type = static_cast(0x7e); - const uint8_t kStream3Value = 0x36; - TestStream stream3(kStream3Type, kStream3Size, kStream3Value); - minidump_file.AddStream(&stream3); - StringFileWriter file_writer; ASSERT_TRUE(minidump_file.WriteEverything(&file_writer)); const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); - const size_t kStream1Offset = + const size_t kStream0Offset = 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 kStream3Padding = 1; - const size_t kStream3Offset = kStream2Offset + kStream2Size + kStream3Padding; - const size_t kFileSize = kStream3Offset + kStream3Size; + const size_t kFileSize = kStream2Offset + kStream2Size; ASSERT_EQ(kFileSize, file_writer.string().size()); @@ -159,40 +161,43 @@ TEST(MinidumpFileWriter, ThreeStreams) { ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 3, kTimestamp)); ASSERT_TRUE(directory); - EXPECT_EQ(kStream1Type, directory[0].StreamType); - EXPECT_EQ(kStream1Size, directory[0].Location.DataSize); - EXPECT_EQ(kStream1Offset, directory[0].Location.Rva); - EXPECT_EQ(kStream2Type, directory[1].StreamType); - EXPECT_EQ(kStream2Size, directory[1].Location.DataSize); - EXPECT_EQ(kStream2Offset, directory[1].Location.Rva); - EXPECT_EQ(kStream3Type, directory[2].StreamType); - EXPECT_EQ(kStream3Size, directory[2].Location.DataSize); - EXPECT_EQ(kStream3Offset, directory[2].Location.Rva); + EXPECT_EQ(kStream0Type, directory[0].StreamType); + EXPECT_EQ(kStream0Size, directory[0].Location.DataSize); + EXPECT_EQ(kStream0Offset, directory[0].Location.Rva); + EXPECT_EQ(kStream1Type, directory[1].StreamType); + EXPECT_EQ(kStream1Size, directory[1].Location.DataSize); + EXPECT_EQ(kStream1Offset, directory[1].Location.Rva); + EXPECT_EQ(kStream2Type, directory[2].StreamType); + EXPECT_EQ(kStream2Size, directory[2].Location.DataSize); + EXPECT_EQ(kStream2Offset, directory[2].Location.Rva); - const uint8_t* stream1_data = - reinterpret_cast(&file_writer.string()[kStream1Offset]); + const uint8_t* stream0_data = MinidumpWritableAtLocationDescriptor( + 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( + file_writer.string(), directory[1].Location); + ASSERT_TRUE(stream1_data); std::string expected_stream1(kStream1Size, kStream1Value); EXPECT_EQ(0, memcmp(stream1_data, expected_stream1.c_str(), kStream1Size)); - const int kZeroes[16] = {}; ASSERT_GE(sizeof(kZeroes), kStream2Padding); EXPECT_EQ(0, memcmp(stream1_data + kStream1Size, kZeroes, kStream2Padding)); - const uint8_t* stream2_data = - reinterpret_cast(&file_writer.string()[kStream2Offset]); + const uint8_t* stream2_data = MinidumpWritableAtLocationDescriptor( + file_writer.string(), directory[2].Location); + ASSERT_TRUE(stream2_data); std::string expected_stream2(kStream2Size, kStream2Value); 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(&file_writer.string()[kStream3Offset]); - - std::string expected_stream3(kStream3Size, kStream3Value); - EXPECT_EQ(0, memcmp(stream3_data, expected_stream3.c_str(), kStream3Size)); } TEST(MinidumpFileWriter, ZeroLengthStream) { @@ -226,18 +231,18 @@ TEST(MinidumpFileWriter, ZeroLengthStream) { TEST(MinidumpFileWriterDeathTest, SameStreamType) { MinidumpFileWriter minidump_file; - const size_t kStream1Size = 5; - const MinidumpStreamType kStream1Type = static_cast(0x4d); - const uint8_t kStream1Value = 0x5a; - TestStream stream1(kStream1Type, kStream1Size, kStream1Value); - minidump_file.AddStream(&stream1); + const size_t kStream0Size = 5; + const MinidumpStreamType kStream0Type = static_cast(0x4d); + const uint8_t kStream0Value = 0x5a; + TestStream stream0(kStream0Type, kStream0Size, kStream0Value); + minidump_file.AddStream(&stream0); // It is an error to add a second stream of the same type. - const size_t kStream2Size = 3; - const MinidumpStreamType kStream2Type = static_cast(0x4d); - const uint8_t kStream2Value = 0xa5; - TestStream stream2(kStream2Type, kStream2Size, kStream2Value); - ASSERT_DEATH(minidump_file.AddStream(&stream2), "already present"); + const size_t kStream1Size = 3; + const MinidumpStreamType kStream1Type = static_cast(0x4d); + const uint8_t kStream1Value = 0xa5; + TestStream stream1(kStream1Type, kStream1Size, kStream1Value); + ASSERT_DEATH(minidump_file.AddStream(&stream1), "already present"); } } // namespace diff --git a/minidump/minidump_memory_writer_test.cc b/minidump/minidump_memory_writer_test.cc index 66a3fc6..8060db7 100644 --- a/minidump/minidump_memory_writer_test.cc +++ b/minidump/minidump_memory_writer_test.cc @@ -24,6 +24,7 @@ #include "minidump/minidump_stream_writer.h" #include "minidump/test/minidump_file_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" namespace crashpad { @@ -63,17 +64,11 @@ void GetMemoryListStream(const std::string& file_contents, ASSERT_EQ(kMinidumpStreamTypeMemoryList, directory[directory_index].StreamType); - ASSERT_GE(directory[directory_index].Location.DataSize, - sizeof(MINIDUMP_MEMORY_LIST)); - ASSERT_EQ(kMemoryListStreamOffset, directory[directory_index].Location.Rva); + EXPECT_EQ(kMemoryListStreamOffset, directory[directory_index].Location.Rva); - *memory_list = reinterpret_cast( - &file_contents[kMemoryListStreamOffset]); - - ASSERT_EQ(sizeof(MINIDUMP_MEMORY_LIST) + - (*memory_list)->NumberOfMemoryRanges * - sizeof(MINIDUMP_MEMORY_DESCRIPTOR), - directory[directory_index].Location.DataSize); + *memory_list = MinidumpWritableAtLocationDescriptor( + file_contents, directory[directory_index].Location); + ASSERT_TRUE(memory_list); } TEST(MinidumpMemoryWriter, EmptyMemoryList) { diff --git a/minidump/minidump_misc_info_writer_test.cc b/minidump/minidump_misc_info_writer_test.cc index 5960685..a342f27 100644 --- a/minidump/minidump_misc_info_writer_test.cc +++ b/minidump/minidump_misc_info_writer_test.cc @@ -25,6 +25,7 @@ #include "gtest/gtest.h" #include "minidump/minidump_file_writer.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/stdlib/strlcpy.h" @@ -49,13 +50,11 @@ void GetMiscInfoStream(const std::string& file_contents, const T** misc_info) { ASSERT_TRUE(directory); ASSERT_EQ(kMinidumpStreamTypeMiscInfo, directory[0].StreamType); - ASSERT_EQ(kMiscInfoStreamSize, directory[0].Location.DataSize); - ASSERT_EQ(kMiscInfoStreamOffset, directory[0].Location.Rva); + EXPECT_EQ(kMiscInfoStreamOffset, directory[0].Location.Rva); - *misc_info = - reinterpret_cast(&file_contents[kMiscInfoStreamOffset]); - - ASSERT_EQ(kMiscInfoStreamSize, (*misc_info)->SizeOfInfo); + *misc_info = MinidumpWritableAtLocationDescriptor(file_contents, + directory[0].Location); + ASSERT_TRUE(misc_info); } void ExpectNULPaddedString16Equal(const char16* expected, diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index 6aba549..1aef0f1 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -24,6 +24,7 @@ #include "minidump/minidump_file_writer.h" #include "minidump/test/minidump_file_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/misc/uuid.h" @@ -48,15 +49,11 @@ void GetModuleListStream(const std::string& file_contents, ASSERT_TRUE(directory); ASSERT_EQ(kMinidumpStreamTypeModuleList, directory[0].StreamType); - ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_MODULE_LIST)); - ASSERT_EQ(kModuleListStreamOffset, directory[0].Location.Rva); + EXPECT_EQ(kModuleListStreamOffset, directory[0].Location.Rva); - *module_list = reinterpret_cast( - &file_contents[kModuleListStreamOffset]); - - ASSERT_EQ(sizeof(MINIDUMP_MODULE_LIST) + - (*module_list)->NumberOfModules * sizeof(MINIDUMP_MODULE), - directory[0].Location.DataSize); + *module_list = MinidumpWritableAtLocationDescriptor( + file_contents, directory[0].Location); + ASSERT_TRUE(module_list); } TEST(MinidumpModuleWriter, EmptyModuleList) { @@ -92,19 +89,15 @@ void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record, uint32_t expected_pdb_age) { if (expected_pdb_name) { EXPECT_NE(0u, codeview_record->Rva); - ASSERT_LE(codeview_record->Rva + codeview_record->DataSize, - file_contents.size()); std::string observed_pdb_name; if (expected_pdb_uuid) { // The CodeView record should be a PDB 7.0 link. - EXPECT_GE(codeview_record->DataSize, - sizeof(MinidumpModuleCodeViewRecordPDB70)); const MinidumpModuleCodeViewRecordPDB70* codeview_pdb70_record = - reinterpret_cast( - &file_contents[codeview_record->Rva]); - EXPECT_EQ(MinidumpModuleCodeViewRecordPDB70::kSignature, - codeview_pdb70_record->signature); + MinidumpWritableAtLocationDescriptor< + MinidumpModuleCodeViewRecordPDB70>(file_contents, + *codeview_record); + ASSERT_TRUE(codeview_pdb70_record); EXPECT_EQ(0, memcmp(expected_pdb_uuid, &codeview_pdb70_record->uuid, @@ -117,13 +110,11 @@ void ExpectCodeViewRecord(const MINIDUMP_LOCATION_DESCRIPTOR* codeview_record, offsetof(MinidumpModuleCodeViewRecordPDB70, pdb_name)); } else { // The CodeView record should be a PDB 2.0 link. - EXPECT_GE(codeview_record->DataSize, - sizeof(MinidumpModuleCodeViewRecordPDB20)); const MinidumpModuleCodeViewRecordPDB20* codeview_pdb20_record = - reinterpret_cast( - &file_contents[codeview_record->Rva]); - EXPECT_EQ(MinidumpModuleCodeViewRecordPDB20::kSignature, - codeview_pdb20_record->signature); + MinidumpWritableAtLocationDescriptor< + MinidumpModuleCodeViewRecordPDB20>(file_contents, + *codeview_record); + ASSERT_TRUE(codeview_pdb20_record); EXPECT_EQ(static_cast(expected_pdb_timestamp), codeview_pdb20_record->timestamp); EXPECT_EQ(expected_pdb_age, codeview_pdb20_record->age); @@ -157,14 +148,12 @@ void ExpectMiscellaneousDebugRecord( uint32_t expected_debug_type, bool expected_debug_utf16) { if (expected_debug_name) { - EXPECT_GE(misc_record->DataSize, sizeof(IMAGE_DEBUG_MISC)); EXPECT_NE(0u, misc_record->Rva); - ASSERT_LE(misc_record->Rva + misc_record->DataSize, file_contents.size()); const IMAGE_DEBUG_MISC* misc_debug_record = - reinterpret_cast( - &file_contents[misc_record->Rva]); + MinidumpWritableAtLocationDescriptor(file_contents, + *misc_record); + ASSERT_TRUE(misc_debug_record); 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(0u, misc_debug_record->Reserved[0]); EXPECT_EQ(0u, misc_debug_record->Reserved[1]); diff --git a/minidump/minidump_simple_string_dictionary_writer_test.cc b/minidump/minidump_simple_string_dictionary_writer_test.cc index bbe2476..7ab62a8 100644 --- a/minidump/minidump_simple_string_dictionary_writer_test.cc +++ b/minidump/minidump_simple_string_dictionary_writer_test.cc @@ -19,16 +19,23 @@ #include "gtest/gtest.h" #include "minidump/minidump_extensions.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" namespace crashpad { namespace test { namespace { -const MinidumpSimpleStringDictionary* MinidumpSimpleStringDictionaryCast( - const StringFileWriter& file_writer) { - return reinterpret_cast( - &file_writer.string()[0]); +const MinidumpSimpleStringDictionary* MinidumpSimpleStringDictionaryAtStart( + const std::string& file_contents, + size_t count) { + MINIDUMP_LOCATION_DESCRIPTOR location_descriptor; + location_descriptor.DataSize = + sizeof(MinidumpSimpleStringDictionary) + + count * sizeof(MinidumpSimpleStringDictionaryEntry); + location_descriptor.Rva = 0; + return MinidumpWritableAtLocationDescriptor( + file_contents, location_descriptor); } TEST(MinidumpSimpleStringDictionaryWriter, EmptySimpleStringDictionary) { @@ -41,7 +48,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, EmptySimpleStringDictionary) { file_writer.string().size()); const MinidumpSimpleStringDictionary* dictionary = - MinidumpSimpleStringDictionaryCast(file_writer); + MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 0); + ASSERT_TRUE(dictionary); EXPECT_EQ(0u, dictionary->count); } @@ -59,7 +67,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, EmptyKeyValue) { file_writer.string().size()); const MinidumpSimpleStringDictionary* dictionary = - MinidumpSimpleStringDictionaryCast(file_writer); + MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 1); + ASSERT_TRUE(dictionary); EXPECT_EQ(1u, dictionary->count); EXPECT_EQ(12u, dictionary->entries[0].key); EXPECT_EQ(20u, dictionary->entries[0].value); @@ -89,7 +98,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, OneKeyValue) { file_writer.string().size()); const MinidumpSimpleStringDictionary* dictionary = - MinidumpSimpleStringDictionaryCast(file_writer); + MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 1); + ASSERT_TRUE(dictionary); EXPECT_EQ(1u, dictionary->count); EXPECT_EQ(12u, dictionary->entries[0].key); EXPECT_EQ(20u, dictionary->entries[0].value); @@ -131,7 +141,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, ThreeKeysValues) { file_writer.string().size()); const MinidumpSimpleStringDictionary* dictionary = - MinidumpSimpleStringDictionaryCast(file_writer); + MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 3); + ASSERT_TRUE(dictionary); EXPECT_EQ(3u, dictionary->count); EXPECT_EQ(28u, dictionary->entries[0].key); EXPECT_EQ(36u, dictionary->entries[0].value); @@ -188,7 +199,8 @@ TEST(MinidumpSimpleStringDictionaryWriter, DuplicateKeyValue) { file_writer.string().size()); const MinidumpSimpleStringDictionary* dictionary = - MinidumpSimpleStringDictionaryCast(file_writer); + MinidumpSimpleStringDictionaryAtStart(file_writer.string(), 1); + ASSERT_TRUE(dictionary); EXPECT_EQ(1u, dictionary->count); EXPECT_EQ(12u, dictionary->entries[0].key); EXPECT_EQ(20u, dictionary->entries[0].value); diff --git a/minidump/minidump_system_info_writer_test.cc b/minidump/minidump_system_info_writer_test.cc index 28c91df..da7895b 100644 --- a/minidump/minidump_system_info_writer_test.cc +++ b/minidump/minidump_system_info_writer_test.cc @@ -23,6 +23,7 @@ #include "minidump/minidump_file_writer.h" #include "minidump/test/minidump_file_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" namespace crashpad { @@ -56,17 +57,17 @@ void GetSystemInfoStream(const std::string& file_contents, ASSERT_TRUE(directory); ASSERT_EQ(kMinidumpStreamTypeSystemInfo, directory[0].StreamType); - ASSERT_EQ(sizeof(MINIDUMP_SYSTEM_INFO), directory[0].Location.DataSize); - ASSERT_EQ(kSystemInfoStreamOffset, directory[0].Location.Rva); + EXPECT_EQ(kSystemInfoStreamOffset, directory[0].Location.Rva); - *system_info = reinterpret_cast( - &file_contents[kSystemInfoStreamOffset]); + *system_info = MinidumpWritableAtLocationDescriptor( + file_contents, directory[0].Location); + ASSERT_TRUE(system_info); - ASSERT_EQ(kCSDVersionOffset, (*system_info)->CSDVersionRva); + EXPECT_EQ(kCSDVersionOffset, (*system_info)->CSDVersionRva); *csd_version = MinidumpStringAtRVA(file_contents, (*system_info)->CSDVersionRva); - ASSERT_EQ(kCSDVersionBytes, (*csd_version)->Length); + EXPECT_EQ(kCSDVersionBytes, (*csd_version)->Length); } TEST(MinidumpSystemInfoWriter, Empty) { diff --git a/minidump/minidump_thread_writer_test.cc b/minidump/minidump_thread_writer_test.cc index fb2baff..74fc7fe 100644 --- a/minidump/minidump_thread_writer_test.cc +++ b/minidump/minidump_thread_writer_test.cc @@ -23,6 +23,7 @@ #include "minidump/test/minidump_context_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_writable_test_util.h" #include "util/file/string_file_writer.h" namespace crashpad { @@ -51,19 +52,18 @@ void GetThreadListStream(const std::string& file_contents, ASSERT_TRUE(directory); ASSERT_EQ(kMinidumpStreamTypeThreadList, directory[0].StreamType); - ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_THREAD_LIST)); - ASSERT_EQ(kThreadListStreamOffset, directory[0].Location.Rva); + EXPECT_EQ(kThreadListStreamOffset, directory[0].Location.Rva); - *thread_list = reinterpret_cast( - &file_contents[kThreadListStreamOffset]); - - ASSERT_EQ(sizeof(MINIDUMP_THREAD_LIST) + - (*thread_list)->NumberOfThreads * sizeof(MINIDUMP_THREAD), - directory[0].Location.DataSize); + *thread_list = MinidumpWritableAtLocationDescriptor( + file_contents, directory[0].Location); + ASSERT_TRUE(thread_list); if (memory_list) { - *memory_list = reinterpret_cast( - &file_contents[directory[1].Location.Rva]); + ASSERT_EQ(kMinidumpStreamTypeMemoryList, directory[1].StreamType); + + *memory_list = MinidumpWritableAtLocationDescriptor( + file_contents, directory[1].Location); + ASSERT_TRUE(*memory_list); } } diff --git a/minidump/test/minidump_file_writer_test_util.cc b/minidump/test/minidump_file_writer_test_util.cc index e87c099..723e97d 100644 --- a/minidump/test/minidump_file_writer_test_util.cc +++ b/minidump/test/minidump_file_writer_test_util.cc @@ -32,15 +32,6 @@ const MINIDUMP_HEADER* MinidumpHeaderAtStart( file_contents, location_descriptor); if (header) { - if (header->Signature != MINIDUMP_SIGNATURE) { - EXPECT_EQ(static_cast(MINIDUMP_SIGNATURE), header->Signature); - return nullptr; - } - if (header->Version != MINIDUMP_VERSION) { - EXPECT_EQ(static_cast(MINIDUMP_VERSION), header->Version); - return nullptr; - } - location_descriptor.DataSize = header->NumberOfStreams * sizeof(MINIDUMP_DIRECTORY); location_descriptor.Rva = header->StreamDirectoryRva; @@ -57,8 +48,6 @@ void VerifyMinidumpHeader(const MINIDUMP_HEADER* header, uint32_t streams, uint32_t timestamp) { ASSERT_TRUE(header); - EXPECT_EQ(static_cast(MINIDUMP_SIGNATURE), header->Signature); - EXPECT_EQ(static_cast(MINIDUMP_VERSION), header->Version); ASSERT_EQ(streams, header->NumberOfStreams); ASSERT_EQ(streams ? sizeof(MINIDUMP_HEADER) : 0u, header->StreamDirectoryRva); EXPECT_EQ(0u, header->CheckSum); diff --git a/minidump/test/minidump_file_writer_test_util.h b/minidump/test/minidump_file_writer_test_util.h index 846fa12..9b561e0 100644 --- a/minidump/test/minidump_file_writer_test_util.h +++ b/minidump/test/minidump_file_writer_test_util.h @@ -45,13 +45,15 @@ const MINIDUMP_HEADER* MinidumpHeaderAtStart( //! \brief Verifies, via gtest assertions, that a MINIDUMP_HEADER contains //! expected values. //! -//! All fields in the MINIDUMP_HEADER will be evaluated. Most are compared to -//! their correct default values. MINIDUMP_HEADER::NumberOfStreams is compared -//! to \a streams, and MINIDUMP_HEADER::TimeDateStamp is compared to \a -//! timestamp. Most fields are checked with nonfatal EXPECT-style assertions, -//! but 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. +//! All fields in the MINIDUMP_HEADER will be evaluated except for the Signature +//! and Version fields, because those are checked by MinidumpHeaderAtStart(). +//! Most other fields are are compared to their correct default values. +//! MINIDUMP_HEADER::NumberOfStreams is compared to \a streams, and +//! MINIDUMP_HEADER::TimeDateStamp is compared to \a timestamp. Most fields are +//! checked with nonfatal EXPECT-style assertions, but +//! 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, uint32_t streams, uint32_t timestamp); diff --git a/minidump/test/minidump_writable_test_util.cc b/minidump/test/minidump_writable_test_util.cc index 7466d7c..3e98a03 100644 --- a/minidump/test/minidump_writable_test_util.cc +++ b/minidump/test/minidump_writable_test_util.cc @@ -16,6 +16,7 @@ #include +#include "base/strings/string16.h" #include "gtest/gtest.h" namespace crashpad { @@ -34,12 +35,20 @@ const void* MinidumpWritableAtRVAInternal(const std::string& file_contents, const void* MinidumpWritableAtLocationDescriptorInternal( const std::string& file_contents, const MINIDUMP_LOCATION_DESCRIPTOR& location, - size_t expected_minimum_size) { + size_t expected_size, + bool allow_oversized_data) { if (location.DataSize == 0) { EXPECT_EQ(0u, location.Rva); 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; } @@ -54,5 +63,213 @@ const void* MinidumpWritableAtLocationDescriptorInternal( return rv; } +template <> +const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + const IMAGE_DEBUG_MISC* misc = + TMinidumpWritableAtLocationDescriptor(file_contents, + location); + if (!misc) { + return nullptr; + } + + if (misc->DataType != IMAGE_DEBUG_MISC_EXENAME) { + EXPECT_EQ(static_cast(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(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( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + const MINIDUMP_HEADER* header = + TMinidumpWritableAtLocationDescriptor(file_contents, + location); + if (!header) { + return nullptr; + } + + if (header->Signature != MINIDUMP_SIGNATURE) { + EXPECT_EQ(static_cast(MINIDUMP_SIGNATURE), header->Signature); + return nullptr; + } + if (header->Version != MINIDUMP_VERSION) { + EXPECT_EQ(static_cast(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 +const typename T::ListType* MinidumpListAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + const typename T::ListType* list = + TMinidumpWritableAtLocationDescriptor(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( + file_contents, location); +} + +template <> +const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor< + MINIDUMP_MODULE_LIST>(const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + return MinidumpListAtLocationDescriptor( + file_contents, location); +} + +template <> +const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor< + MINIDUMP_THREAD_LIST>(const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + return MinidumpListAtLocationDescriptor( + file_contents, location); +} + +template <> +const MinidumpSimpleStringDictionary* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + return MinidumpListAtLocationDescriptor< + MinidumpSimpleStringDictionaryListTraits>(file_contents, location); +} + +namespace { + +template +const T* MinidumpCVPDBAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + const T* cv_pdb = + TMinidumpWritableAtLocationDescriptor(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( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + return MinidumpCVPDBAtLocationDescriptor( + file_contents, location); +} + +template <> +const MinidumpModuleCodeViewRecordPDB70* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + return MinidumpCVPDBAtLocationDescriptor( + file_contents, location); +} + } // namespace test } // namespace crashpad diff --git a/minidump/test/minidump_writable_test_util.h b/minidump/test/minidump_writable_test_util.h index a637f19..8b5ddba 100644 --- a/minidump/test/minidump_writable_test_util.h +++ b/minidump/test/minidump_writable_test_util.h @@ -16,10 +16,12 @@ #define CRASHPAD_MINIDUMP_TEST_MINIDUMP_WRITABLE_TEST_UTIL_H_ #include +#include #include #include "gtest/gtest.h" +#include "minidump/minidump_extensions.h" namespace crashpad { 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] location A MINIDUMP_LOCATION_DESCRIPTOR giving the offset within //! 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 -//! expected_minimum_size, and if \a location is within the range of \a -//! file_contents, returns a pointer into \a file_contents at offset \a rva. -//! Otherwise, raises a gtest assertion failure and returns `nullptr`. +//! \return If the size of \a location is agrees with \a expected_size, and if +//! \a location is within the range of \a file_contents, returns a pointer +//! into \a file_contents at offset \a rva. Otherwise, raises a gtest +//! assertion failure and returns `nullptr`. //! //! Do not call this function. Use the typed version, //! MinidumpWritableAtLocationDescriptor<>(), or another type-specific function. @@ -61,7 +69,54 @@ const void* MinidumpWritableAtRVAInternal(const std::string& file_contents, const void* MinidumpWritableAtLocationDescriptorInternal( const std::string& file_contents, 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 type’s +//! 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 +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 { \ + 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 file’s //! 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 file’s //! 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 +const T* TMinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + return reinterpret_cast( + MinidumpWritableAtLocationDescriptorInternal( + file_contents, + location, + sizeof(T), + MinidumpWritableTraits::kAllowOversizedData)); +} + +//! \brief Returns a typed minidump object located within a minidump file’s +//! 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 structure’s 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] location A MINIDUMP_LOCATION_DESCRIPTOR giving the offset within //! the minidump file of the desired object, as well as its size. @@ -97,11 +188,52 @@ template const T* MinidumpWritableAtLocationDescriptor( const std::string& file_contents, const MINIDUMP_LOCATION_DESCRIPTOR& location) { - return reinterpret_cast( - MinidumpWritableAtLocationDescriptorInternal( - file_contents, location, sizeof(T))); + return TMinidumpWritableAtLocationDescriptor(file_contents, location); } +template <> +const IMAGE_DEBUG_MISC* MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); + +template <> +const MINIDUMP_HEADER* MinidumpWritableAtLocationDescriptor( + 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( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); + +template <> +const MinidumpModuleCodeViewRecordPDB70* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); + +template <> +const MinidumpSimpleStringDictionary* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); + } // namespace test } // namespace crashpad