mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-31 01:43:03 +08:00
c8a016b99d
BUG=837308 R=mark@chromium.org Change-Id: Ibecbfc7bc2d61ee54bc1114e4b20978adbc77db2 Reviewed-on: https://chromium-review.googlesource.com/c/1393921 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Avi Drissman <avi@chromium.org>
308 lines
10 KiB
C++
308 lines
10 KiB
C++
// Copyright 2014 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 "util/mach/composite_mach_message_server.h"
|
||
|
||
#include <sys/types.h>
|
||
|
||
#include "base/strings/stringprintf.h"
|
||
#include "gtest/gtest.h"
|
||
#include "test/gtest_death.h"
|
||
#include "util/mach/mach_message.h"
|
||
#include "util/misc/arraysize.h"
|
||
|
||
namespace crashpad {
|
||
namespace test {
|
||
namespace {
|
||
|
||
TEST(CompositeMachMessageServer, Empty) {
|
||
CompositeMachMessageServer server;
|
||
|
||
EXPECT_TRUE(server.MachMessageServerRequestIDs().empty());
|
||
|
||
mach_msg_empty_rcv_t request = {};
|
||
EXPECT_EQ(server.MachMessageServerRequestSize(), sizeof(request.header));
|
||
|
||
mig_reply_error_t reply = {};
|
||
EXPECT_EQ(server.MachMessageServerReplySize(), sizeof(reply));
|
||
|
||
bool destroy_complex_request = false;
|
||
EXPECT_FALSE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, MIG_BAD_ID);
|
||
}
|
||
|
||
class TestMachMessageHandler : public MachMessageServer::Interface {
|
||
public:
|
||
TestMachMessageHandler()
|
||
: MachMessageServer::Interface(),
|
||
request_ids_(),
|
||
request_size_(0),
|
||
reply_size_(0),
|
||
return_code_(KERN_FAILURE),
|
||
return_value_(false),
|
||
destroy_complex_request_(false) {
|
||
}
|
||
|
||
~TestMachMessageHandler() {
|
||
}
|
||
|
||
void SetReturnCodes(bool return_value,
|
||
kern_return_t return_code,
|
||
bool destroy_complex_request) {
|
||
return_value_ = return_value;
|
||
return_code_ = return_code;
|
||
destroy_complex_request_ = destroy_complex_request;
|
||
}
|
||
|
||
void AddRequestID(mach_msg_id_t request_id) {
|
||
request_ids_.insert(request_id);
|
||
}
|
||
|
||
void SetRequestSize(mach_msg_size_t request_size) {
|
||
request_size_ = request_size;
|
||
}
|
||
|
||
void SetReplySize(mach_msg_size_t reply_size) {
|
||
reply_size_ = reply_size;
|
||
}
|
||
|
||
// MachMessageServer::Interface:
|
||
|
||
bool MachMessageServerFunction(const mach_msg_header_t* in,
|
||
mach_msg_header_t* out,
|
||
bool* destroy_complex_request) override {
|
||
EXPECT_NE(request_ids_.find(in->msgh_id), request_ids_.end());
|
||
|
||
*destroy_complex_request = destroy_complex_request_;
|
||
PrepareMIGReplyFromRequest(in, out);
|
||
SetMIGReplyError(out, return_code_);
|
||
return return_value_;
|
||
}
|
||
|
||
std::set<mach_msg_id_t> MachMessageServerRequestIDs() override {
|
||
return request_ids_;
|
||
}
|
||
|
||
mach_msg_size_t MachMessageServerRequestSize() override {
|
||
return request_size_;
|
||
}
|
||
|
||
mach_msg_size_t MachMessageServerReplySize() override {
|
||
return reply_size_;
|
||
}
|
||
|
||
private:
|
||
std::set<mach_msg_id_t> request_ids_;
|
||
mach_msg_size_t request_size_;
|
||
mach_msg_size_t reply_size_;
|
||
kern_return_t return_code_;
|
||
bool return_value_;
|
||
bool destroy_complex_request_;
|
||
|
||
DISALLOW_COPY_AND_ASSIGN(TestMachMessageHandler);
|
||
};
|
||
|
||
TEST(CompositeMachMessageServer, HandlerDoesNotHandle) {
|
||
TestMachMessageHandler handler;
|
||
|
||
CompositeMachMessageServer server;
|
||
server.AddHandler(&handler);
|
||
|
||
EXPECT_TRUE(server.MachMessageServerRequestIDs().empty());
|
||
|
||
mach_msg_empty_rcv_t request = {};
|
||
EXPECT_EQ(server.MachMessageServerRequestSize(), sizeof(request.header));
|
||
|
||
mig_reply_error_t reply = {};
|
||
EXPECT_EQ(server.MachMessageServerReplySize(), sizeof(reply));
|
||
|
||
bool destroy_complex_request = false;
|
||
EXPECT_FALSE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, MIG_BAD_ID);
|
||
EXPECT_FALSE(destroy_complex_request);
|
||
}
|
||
|
||
TEST(CompositeMachMessageServer, OneHandler) {
|
||
constexpr mach_msg_id_t kRequestID = 100;
|
||
constexpr mach_msg_size_t kRequestSize = 256;
|
||
constexpr mach_msg_size_t kReplySize = 128;
|
||
constexpr kern_return_t kReturnCode = KERN_SUCCESS;
|
||
|
||
TestMachMessageHandler handler;
|
||
handler.AddRequestID(kRequestID);
|
||
handler.SetRequestSize(kRequestSize);
|
||
handler.SetReplySize(kReplySize);
|
||
handler.SetReturnCodes(true, kReturnCode, true);
|
||
|
||
CompositeMachMessageServer server;
|
||
|
||
// The chosen request and reply sizes must be larger than the defaults for
|
||
// that portion fo the test to be valid.
|
||
EXPECT_GT(kRequestSize, server.MachMessageServerRequestSize());
|
||
EXPECT_GT(kReplySize, server.MachMessageServerReplySize());
|
||
|
||
server.AddHandler(&handler);
|
||
|
||
std::set<mach_msg_id_t> expect_request_ids;
|
||
expect_request_ids.insert(kRequestID);
|
||
EXPECT_EQ(server.MachMessageServerRequestIDs(), expect_request_ids);
|
||
|
||
EXPECT_EQ(server.MachMessageServerRequestSize(), kRequestSize);
|
||
EXPECT_EQ(server.MachMessageServerReplySize(), kReplySize);
|
||
|
||
mach_msg_empty_rcv_t request = {};
|
||
mig_reply_error_t reply = {};
|
||
|
||
// Send a message with an unknown request ID.
|
||
request.header.msgh_id = 0;
|
||
bool destroy_complex_request = false;
|
||
EXPECT_FALSE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, MIG_BAD_ID);
|
||
EXPECT_FALSE(destroy_complex_request);
|
||
|
||
// Send a message with a known request ID.
|
||
request.header.msgh_id = kRequestID;
|
||
EXPECT_TRUE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, kReturnCode);
|
||
EXPECT_TRUE(destroy_complex_request);
|
||
}
|
||
|
||
TEST(CompositeMachMessageServer, ThreeHandlers) {
|
||
static constexpr mach_msg_id_t kRequestIDs0[] = {5};
|
||
constexpr kern_return_t kReturnCode0 = KERN_SUCCESS;
|
||
|
||
static constexpr mach_msg_id_t kRequestIDs1[] = {4, 7};
|
||
constexpr kern_return_t kReturnCode1 = KERN_PROTECTION_FAILURE;
|
||
|
||
static constexpr mach_msg_id_t kRequestIDs2[] = {10, 0, 20};
|
||
constexpr mach_msg_size_t kRequestSize2 = 6144;
|
||
constexpr mach_msg_size_t kReplySize2 = 16384;
|
||
constexpr kern_return_t kReturnCode2 = KERN_NOT_RECEIVER;
|
||
|
||
TestMachMessageHandler handlers[3];
|
||
std::set<mach_msg_id_t> expect_request_ids;
|
||
|
||
for (size_t index = 0; index < ArraySize(kRequestIDs0); ++index) {
|
||
const mach_msg_id_t request_id = kRequestIDs0[index];
|
||
handlers[0].AddRequestID(request_id);
|
||
expect_request_ids.insert(request_id);
|
||
}
|
||
handlers[0].SetRequestSize(sizeof(mach_msg_header_t));
|
||
handlers[0].SetReplySize(sizeof(mig_reply_error_t));
|
||
handlers[0].SetReturnCodes(true, kReturnCode0, false);
|
||
|
||
for (size_t index = 0; index < ArraySize(kRequestIDs1); ++index) {
|
||
const mach_msg_id_t request_id = kRequestIDs1[index];
|
||
handlers[1].AddRequestID(request_id);
|
||
expect_request_ids.insert(request_id);
|
||
}
|
||
handlers[1].SetRequestSize(100);
|
||
handlers[1].SetReplySize(200);
|
||
handlers[1].SetReturnCodes(false, kReturnCode1, true);
|
||
|
||
for (size_t index = 0; index < ArraySize(kRequestIDs2); ++index) {
|
||
const mach_msg_id_t request_id = kRequestIDs2[index];
|
||
handlers[2].AddRequestID(request_id);
|
||
expect_request_ids.insert(request_id);
|
||
}
|
||
handlers[2].SetRequestSize(kRequestSize2);
|
||
handlers[2].SetReplySize(kReplySize2);
|
||
handlers[2].SetReturnCodes(true, kReturnCode2, true);
|
||
|
||
CompositeMachMessageServer server;
|
||
|
||
// The chosen request and reply sizes must be larger than the defaults for
|
||
// that portion fo the test to be valid.
|
||
EXPECT_GT(kRequestSize2, server.MachMessageServerRequestSize());
|
||
EXPECT_GT(kReplySize2, server.MachMessageServerReplySize());
|
||
|
||
server.AddHandler(&handlers[0]);
|
||
server.AddHandler(&handlers[1]);
|
||
server.AddHandler(&handlers[2]);
|
||
|
||
EXPECT_EQ(server.MachMessageServerRequestIDs(), expect_request_ids);
|
||
|
||
EXPECT_EQ(server.MachMessageServerRequestSize(), kRequestSize2);
|
||
EXPECT_EQ(server.MachMessageServerReplySize(), kReplySize2);
|
||
|
||
mach_msg_empty_rcv_t request = {};
|
||
mig_reply_error_t reply = {};
|
||
|
||
// Send a message with an unknown request ID.
|
||
request.header.msgh_id = 100;
|
||
bool destroy_complex_request = false;
|
||
EXPECT_FALSE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, MIG_BAD_ID);
|
||
EXPECT_FALSE(destroy_complex_request);
|
||
|
||
// Send messages with known request IDs.
|
||
|
||
for (size_t index = 0; index < ArraySize(kRequestIDs0); ++index) {
|
||
request.header.msgh_id = kRequestIDs0[index];
|
||
SCOPED_TRACE(base::StringPrintf(
|
||
"handler 0, index %zu, id %d", index, request.header.msgh_id));
|
||
|
||
EXPECT_TRUE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, kReturnCode0);
|
||
EXPECT_FALSE(destroy_complex_request);
|
||
}
|
||
|
||
for (size_t index = 0; index < ArraySize(kRequestIDs1); ++index) {
|
||
request.header.msgh_id = kRequestIDs1[index];
|
||
SCOPED_TRACE(base::StringPrintf(
|
||
"handler 1, index %zu, id %d", index, request.header.msgh_id));
|
||
|
||
EXPECT_FALSE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, kReturnCode1);
|
||
EXPECT_TRUE(destroy_complex_request);
|
||
}
|
||
|
||
for (size_t index = 0; index < ArraySize(kRequestIDs2); ++index) {
|
||
request.header.msgh_id = kRequestIDs2[index];
|
||
SCOPED_TRACE(base::StringPrintf(
|
||
"handler 2, index %zu, id %d", index, request.header.msgh_id));
|
||
|
||
EXPECT_TRUE(server.MachMessageServerFunction(
|
||
&request.header, &reply.Head, &destroy_complex_request));
|
||
EXPECT_EQ(reply.RetCode, kReturnCode2);
|
||
EXPECT_TRUE(destroy_complex_request);
|
||
}
|
||
}
|
||
|
||
// CompositeMachMessageServer can’t deal with two handlers that want to handle
|
||
// the same request ID.
|
||
TEST(CompositeMachMessageServerDeathTest, DuplicateRequestID) {
|
||
constexpr mach_msg_id_t kRequestID = 400;
|
||
|
||
TestMachMessageHandler handlers[2];
|
||
handlers[0].AddRequestID(kRequestID);
|
||
handlers[1].AddRequestID(kRequestID);
|
||
|
||
CompositeMachMessageServer server;
|
||
|
||
server.AddHandler(&handlers[0]);
|
||
EXPECT_DEATH_CHECK(server.AddHandler(&handlers[1]), "duplicate request ID");
|
||
}
|
||
|
||
} // namespace
|
||
} // namespace test
|
||
} // namespace crashpad
|