mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-15 01:57:58 +08:00
6278690abe
sed -i '' -E -e 's/Copyright (.+) The Crashpad Authors\. All rights reserved\.$/Copyright \1 The Crashpad Authors/' $(git grep -El 'Copyright (.+) The Crashpad Authors\. All rights reserved\.$') Bug: chromium:1098010 Change-Id: I8d6138469ddbe3d281a5d83f64cf918ec2491611 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3878262 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
204 lines
6.6 KiB
C++
204 lines
6.6 KiB
C++
// Copyright 2021 The Crashpad Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "util/ios/ios_intermediate_dump_reader.h"
|
|
|
|
#include <memory>
|
|
#include <stack>
|
|
#include <vector>
|
|
|
|
#include "base/logging.h"
|
|
#include "util/file/filesystem.h"
|
|
#include "util/ios/ios_intermediate_dump_data.h"
|
|
#include "util/ios/ios_intermediate_dump_format.h"
|
|
#include "util/ios/ios_intermediate_dump_list.h"
|
|
#include "util/ios/ios_intermediate_dump_object.h"
|
|
#include "util/ios/ios_intermediate_dump_writer.h"
|
|
|
|
namespace crashpad {
|
|
namespace internal {
|
|
|
|
IOSIntermediateDumpReaderInitializeResult IOSIntermediateDumpReader::Initialize(
|
|
const IOSIntermediateDumpInterface& dump_interface) {
|
|
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
|
|
|
// Don't initialize empty files.
|
|
FileOffset size = dump_interface.Size();
|
|
if (size == 0) {
|
|
return IOSIntermediateDumpReaderInitializeResult::kFailure;
|
|
}
|
|
|
|
IOSIntermediateDumpReaderInitializeResult result =
|
|
IOSIntermediateDumpReaderInitializeResult::kSuccess;
|
|
if (!Parse(dump_interface.FileReader(), size)) {
|
|
LOG(ERROR) << "Intermediate dump parsing failed";
|
|
result = IOSIntermediateDumpReaderInitializeResult::kIncomplete;
|
|
}
|
|
|
|
INITIALIZATION_STATE_SET_VALID(initialized_);
|
|
return result;
|
|
}
|
|
|
|
const IOSIntermediateDumpMap* IOSIntermediateDumpReader::RootMap() {
|
|
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
|
return &intermediate_dump_;
|
|
}
|
|
|
|
bool IOSIntermediateDumpReader::Parse(FileReaderInterface* reader,
|
|
FileOffset file_size) {
|
|
std::stack<IOSIntermediateDumpObject*> stack;
|
|
stack.push(&intermediate_dump_);
|
|
using Command = IOSIntermediateDumpWriter::CommandType;
|
|
using Type = IOSIntermediateDumpObject::Type;
|
|
|
|
Command command;
|
|
if (!reader->ReadExactly(&command, sizeof(Command)) ||
|
|
command != Command::kRootMapStart) {
|
|
LOG(ERROR) << "Unexpected start to root map.";
|
|
return false;
|
|
}
|
|
|
|
while (reader->ReadExactly(&command, sizeof(Command))) {
|
|
constexpr int kMaxStackDepth = 10;
|
|
if (stack.size() > kMaxStackDepth) {
|
|
LOG(ERROR) << "Unexpected depth of intermediate dump data.";
|
|
return false;
|
|
}
|
|
|
|
IOSIntermediateDumpObject* parent = stack.top();
|
|
switch (command) {
|
|
case Command::kMapStart: {
|
|
std::unique_ptr<IOSIntermediateDumpMap> new_map(
|
|
new IOSIntermediateDumpMap());
|
|
if (parent->GetType() == Type::kMap) {
|
|
const auto parent_map = static_cast<IOSIntermediateDumpMap*>(parent);
|
|
stack.push(new_map.get());
|
|
IntermediateDumpKey key;
|
|
if (!reader->ReadExactly(&key, sizeof(key)))
|
|
return false;
|
|
if (key == IntermediateDumpKey::kInvalid)
|
|
return false;
|
|
parent_map->map_[key] = std::move(new_map);
|
|
} else if (parent->GetType() == Type::kList) {
|
|
const auto parent_list =
|
|
static_cast<IOSIntermediateDumpList*>(parent);
|
|
stack.push(new_map.get());
|
|
parent_list->push_back(std::move(new_map));
|
|
} else {
|
|
LOG(ERROR) << "Unexpected parent (not a map or list).";
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case Command::kArrayStart: {
|
|
auto new_list = std::make_unique<IOSIntermediateDumpList>();
|
|
if (parent->GetType() != Type::kMap) {
|
|
LOG(ERROR) << "Attempting to push an array not in a map.";
|
|
return false;
|
|
}
|
|
|
|
IntermediateDumpKey key;
|
|
if (!reader->ReadExactly(&key, sizeof(key)))
|
|
return false;
|
|
if (key == IntermediateDumpKey::kInvalid)
|
|
return false;
|
|
|
|
auto parent_map = static_cast<IOSIntermediateDumpMap*>(parent);
|
|
stack.push(new_list.get());
|
|
parent_map->map_[key] = std::move(new_list);
|
|
break;
|
|
}
|
|
case Command::kMapEnd:
|
|
if (stack.size() < 2) {
|
|
LOG(ERROR) << "Attempting to pop off main map.";
|
|
return false;
|
|
}
|
|
|
|
if (parent->GetType() != Type::kMap) {
|
|
LOG(ERROR) << "Unexpected map end not in a map.";
|
|
return false;
|
|
}
|
|
stack.pop();
|
|
break;
|
|
case Command::kArrayEnd:
|
|
if (stack.size() < 2) {
|
|
LOG(ERROR) << "Attempting to pop off main map.";
|
|
return false;
|
|
}
|
|
if (parent->GetType() != Type::kList) {
|
|
LOG(ERROR) << "Unexpected list end not in a list.";
|
|
return false;
|
|
}
|
|
stack.pop();
|
|
break;
|
|
case Command::kProperty: {
|
|
if (parent->GetType() != Type::kMap) {
|
|
LOG(ERROR) << "Attempting to add a property not in a map.";
|
|
return false;
|
|
}
|
|
IntermediateDumpKey key;
|
|
if (!reader->ReadExactly(&key, sizeof(key)))
|
|
return false;
|
|
if (key == IntermediateDumpKey::kInvalid)
|
|
return false;
|
|
|
|
size_t value_length;
|
|
if (!reader->ReadExactly(&value_length, sizeof(value_length))) {
|
|
return false;
|
|
}
|
|
|
|
constexpr int kMaximumPropertyLength = 64 * 1024 * 1024; // 64MB.
|
|
if (value_length > kMaximumPropertyLength) {
|
|
LOG(ERROR) << "Attempting to read a property that's too big: "
|
|
<< value_length;
|
|
return false;
|
|
}
|
|
|
|
std::vector<uint8_t> data(value_length);
|
|
if (!reader->ReadExactly(data.data(), value_length)) {
|
|
return false;
|
|
}
|
|
auto parent_map = static_cast<IOSIntermediateDumpMap*>(parent);
|
|
if (parent_map->map_.find(key) != parent_map->map_.end()) {
|
|
LOG(ERROR) << "Inserting duplicate key";
|
|
}
|
|
parent_map->map_[key] =
|
|
std::make_unique<IOSIntermediateDumpData>(std::move(data));
|
|
break;
|
|
}
|
|
case Command::kRootMapEnd: {
|
|
if (stack.size() != 1) {
|
|
LOG(ERROR) << "Unexpected end of root map.";
|
|
return false;
|
|
}
|
|
|
|
if (reader->Seek(0, SEEK_CUR) != file_size) {
|
|
LOG(ERROR) << "Root map ended before end of file.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
default:
|
|
LOG(ERROR) << "Failed to parse serialized intermediate minidump.";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
LOG(ERROR) << "Unexpected end of root map.";
|
|
return false;
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace crashpad
|