// Copyright 2016 The Crashpad Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "minidump/minidump_user_stream_writer.h" #include #include #include "gtest/gtest.h" #include "minidump/minidump_file_writer.h" #include "minidump/test/minidump_file_writer_test_util.h" #include "minidump/test/minidump_user_extension_stream_util.h" #include "minidump/test/minidump_writable_test_util.h" #include "snapshot/test/test_memory_snapshot.h" #include "util/file/string_file.h" namespace crashpad { namespace test { namespace { // The user stream is expected to be the only stream. void GetUserStream(const std::string& file_contents, MINIDUMP_LOCATION_DESCRIPTOR* user_stream_location, uint32_t stream_type, size_t stream_size) { constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER); constexpr size_t kUserStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY); const MINIDUMP_DIRECTORY* directory; const MINIDUMP_HEADER* header = MinidumpHeaderAtStart(file_contents, &directory); ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0)); ASSERT_TRUE(directory); constexpr size_t kDirectoryIndex = 0; ASSERT_EQ(directory[kDirectoryIndex].StreamType, stream_type); EXPECT_EQ(directory[kDirectoryIndex].Location.Rva, kUserStreamOffset); EXPECT_EQ(directory[kDirectoryIndex].Location.DataSize, stream_size); *user_stream_location = directory[kDirectoryIndex].Location; } constexpr MinidumpStreamType kTestStreamId = static_cast(0x123456); TEST(MinidumpUserStreamWriter, InitializeFromSnapshotNoData) { MinidumpFileWriter minidump_file_writer; auto user_stream_writer = std::make_unique(); auto stream = std::make_unique(kTestStreamId, nullptr); user_stream_writer->InitializeFromSnapshot(stream.get()); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(user_stream_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); ASSERT_EQ(string_file.string().size(), sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY)); MINIDUMP_LOCATION_DESCRIPTOR user_stream_location; ASSERT_NO_FATAL_FAILURE(GetUserStream( string_file.string(), &user_stream_location, kTestStreamId, 0u)); } TEST(MinidumpUserStreamWriter, InitializeFromUserExtensionStreamNoData) { MinidumpFileWriter minidump_file_writer; auto data_source = std::make_unique( kTestStreamId, nullptr, 0); auto user_stream_writer = std::make_unique(); user_stream_writer->InitializeFromUserExtensionStream(std::move(data_source)); minidump_file_writer.AddStream(std::move(user_stream_writer)); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); ASSERT_EQ(string_file.string().size(), sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY)); MINIDUMP_LOCATION_DESCRIPTOR user_stream_location; ASSERT_NO_FATAL_FAILURE(GetUserStream( string_file.string(), &user_stream_location, kTestStreamId, 0u)); } TEST(MinidumpUserStreamWriter, InitializeFromSnapshotOneStream) { MinidumpFileWriter minidump_file_writer; auto user_stream_writer = std::make_unique(); TestMemorySnapshot* test_data = new TestMemorySnapshot(); test_data->SetAddress(97865); constexpr size_t kStreamSize = 128; test_data->SetSize(kStreamSize); test_data->SetValue('c'); auto stream = std::make_unique(kTestStreamId, test_data); user_stream_writer->InitializeFromSnapshot(stream.get()); ASSERT_TRUE(minidump_file_writer.AddStream(std::move(user_stream_writer))); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); ASSERT_EQ(string_file.string().size(), sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + kStreamSize); MINIDUMP_LOCATION_DESCRIPTOR user_stream_location = {}; ASSERT_NO_FATAL_FAILURE(GetUserStream( string_file.string(), &user_stream_location, kTestStreamId, kStreamSize)); const std::string stream_data = string_file.string().substr( user_stream_location.Rva, user_stream_location.DataSize); EXPECT_EQ(stream_data, std::string(kStreamSize, 'c')); } TEST(MinidumpUserStreamWriter, InitializeFromBufferOneStream) { MinidumpFileWriter minidump_file_writer; constexpr size_t kStreamSize = 128; std::vector data(kStreamSize, 'c'); auto data_source = std::make_unique( kTestStreamId, &data[0], data.size()); auto user_stream_writer = std::make_unique(); user_stream_writer->InitializeFromUserExtensionStream(std::move(data_source)); minidump_file_writer.AddStream(std::move(user_stream_writer)); StringFile string_file; ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file)); ASSERT_EQ(string_file.string().size(), sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + kStreamSize); MINIDUMP_LOCATION_DESCRIPTOR user_stream_location = {}; ASSERT_NO_FATAL_FAILURE(GetUserStream( string_file.string(), &user_stream_location, kTestStreamId, kStreamSize)); const std::string stream_data = string_file.string().substr( user_stream_location.Rva, user_stream_location.DataSize); EXPECT_EQ(stream_data, std::string(kStreamSize, 'c')); } } // namespace } // namespace test } // namespace crashpad