crashpad/minidump/minidump_thread_name_list_writer.cc
Ben Hamilton 339b125241 [minidump] Fix unaligned pointer in thread name list
https://crrev.com/c/3671775/ introduced a warning (and thus, a
compilation failure) on 32-bit ARM when taking the address of the RVA64
field MINIDUMP_THREAD_NAME::RvaOfThreadName:

minidump/minidump_thread_name_list_writer.cc:57:23: error: taking address of packed member 'RvaOfThreadName' of class or structure 'MINIDUMP_THREAD_NAME' may result in an unaligned pointer value [-Werror,-Waddress-of-packed-member]
  name_->RegisterRVA(&thread_name_.RvaOfThreadName);
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Indeed, MINIDUMP_THREAD_NAME's RvaOfThreadName field is not aligned,
so the technique used in MinidumpWritable::Register*() of passing in a
rawptr to an arbitrary struct field which is later dereferenced cannot
be used for this field.

This CL replaces the use of MinidumpWritable::Register*() with
overriding MinidumpThreadNameWriter::WillWriteAtOffsetImpl() to
directly calculate and assign thread_name_.RvaOfThreadName.

Change-Id: I71e751a5b5e896b5e7277879bdbdff6e9eefe023
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3693846
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Ben Hamilton <benhamilton@google.com>
Reviewed-by: Ben Hamilton <benhamilton@google.com>
2022-06-08 18:52:32 +00:00

167 lines
5.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2022 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_thread_name_list_writer.h"
#include <utility>
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"
namespace crashpad {
MinidumpThreadNameWriter::MinidumpThreadNameWriter()
: MinidumpWritable(), thread_name_(), name_() {}
MinidumpThreadNameWriter::~MinidumpThreadNameWriter() {}
const MINIDUMP_THREAD_NAME* MinidumpThreadNameWriter::MinidumpThreadName()
const {
DCHECK_EQ(state(), kStateWritable);
return &thread_name_;
}
void MinidumpThreadNameWriter::SetThreadName(const std::string& name) {
DCHECK_EQ(state(), kStateMutable);
if (!name_) {
name_.reset(new internal::MinidumpUTF16StringWriter());
}
name_->SetUTF8(name);
}
size_t MinidumpThreadNameWriter::SizeOfObject() {
DCHECK_GE(state(), kStateFrozen);
// This object doesnt directly write anything itself. Its
// MINIDUMP_THREAD_NAME is written by its parent as part of a
// MINIDUMP_THREAD_NAME_LIST, and its children are responsible for writing
// themselves.
return 0;
}
std::vector<internal::MinidumpWritable*> MinidumpThreadNameWriter::Children() {
DCHECK_GE(state(), kStateFrozen);
DCHECK(name_);
std::vector<MinidumpWritable*> children;
children.emplace_back(name_.get());
return children;
}
bool MinidumpThreadNameWriter::WillWriteAtOffsetImpl(FileOffset offset) {
DCHECK_EQ(state(), kStateFrozen);
// This cannot use RegisterRVA(&thread_name_.RvaOfThreadName), since
// &MINIDUMP_THREAD_NAME_LIST::RvaOfThreadName is not aligned on a pointer
// boundary, so it causes failures on 32-bit ARM.
//
// Instead, manually update the RVA64 to the current file offset since the
// child thread_name_ will write its contents at that offset.
decltype(thread_name_.RvaOfThreadName) local_rva_of_thread_name;
if (!AssignIfInRange(&local_rva_of_thread_name, offset)) {
LOG(ERROR) << "offset " << offset << " out of range";
return false;
}
thread_name_.RvaOfThreadName = local_rva_of_thread_name;
return MinidumpWritable::WillWriteAtOffsetImpl(offset);
}
bool MinidumpThreadNameWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
// This object doesnt directly write anything itself. Its
// MINIDUMP_THREAD_NAME is written by its parent as part of a
// MINIDUMP_THREAD_NAME_LIST, and its children are responsible for writing
// themselves.
return true;
}
MinidumpThreadNameListWriter::MinidumpThreadNameListWriter()
: MinidumpStreamWriter(), thread_names_() {}
MinidumpThreadNameListWriter::~MinidumpThreadNameListWriter() {}
void MinidumpThreadNameListWriter::AddThreadName(
std::unique_ptr<MinidumpThreadNameWriter> thread_name) {
DCHECK_EQ(state(), kStateMutable);
thread_names_.emplace_back(std::move(thread_name));
}
bool MinidumpThreadNameListWriter::Freeze() {
DCHECK_EQ(state(), kStateMutable);
if (!MinidumpStreamWriter::Freeze()) {
return false;
}
size_t thread_name_count = thread_names_.size();
if (!AssignIfInRange(&thread_name_list_.NumberOfThreadNames,
thread_name_count)) {
LOG(ERROR) << "thread_name_count " << thread_name_count << " out of range";
return false;
}
return true;
}
size_t MinidumpThreadNameListWriter::SizeOfObject() {
DCHECK_GE(state(), kStateFrozen);
return sizeof(thread_name_list_) +
thread_names_.size() * sizeof(MINIDUMP_THREAD_NAME);
}
std::vector<internal::MinidumpWritable*>
MinidumpThreadNameListWriter::Children() {
DCHECK_GE(state(), kStateFrozen);
std::vector<MinidumpWritable*> children;
children.reserve(thread_names_.size());
for (const auto& thread_name : thread_names_) {
children.emplace_back(thread_name.get());
}
return children;
}
bool MinidumpThreadNameListWriter::WriteObject(
FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
WritableIoVec iov;
iov.iov_base = &thread_name_list_;
iov.iov_len = sizeof(thread_name_list_);
std::vector<WritableIoVec> iovecs(1, iov);
iovecs.reserve(thread_names_.size() + 1);
for (const auto& thread_name : thread_names_) {
iov.iov_base = thread_name->MinidumpThreadName();
iov.iov_len = sizeof(MINIDUMP_THREAD_NAME);
iovecs.emplace_back(iov);
}
return file_writer->WriteIoVec(&iovecs);
}
MinidumpStreamType MinidumpThreadNameListWriter::StreamType() const {
return kMinidumpStreamTypeThreadNameList;
}
} // namespace crashpad