Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(540)

Unified Diff: util/mach/mach_message_server_test.cc

Issue 557793002: Enhance the MachMessageServer test to cover large messages (MACH_RCV_LARGE) (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « util/mach/mach_message_server.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: util/mach/mach_message_server_test.cc
diff --git a/util/mach/mach_message_server_test.cc b/util/mach/mach_message_server_test.cc
index fe01cd1fd21f916985d75a7b548d65c7717b0cf0..08c781d14dc992fbfaebfa64d2ed65bc777807f1 100644
--- a/util/mach/mach_message_server_test.cc
+++ b/util/mach/mach_message_server_test.cc
@@ -56,6 +56,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
Options()
: expect_server_interface_method_called(true),
parent_wait_for_child_pipe(false),
+ server_options(MACH_MSG_OPTION_NONE),
server_persistent(MachMessageServer::kOneShot),
server_nonblocking(MachMessageServer::kBlocking),
server_timeout_ms(MACH_MSG_TIMEOUT_NONE),
@@ -63,8 +64,10 @@ class TestMachMessageServer : public MachMessageServer::Interface,
server_destroy_complex(true),
expect_server_destroyed_complex(true),
expect_server_result(KERN_SUCCESS),
+ expect_server_transaction_count(1),
client_send_request_count(1),
client_send_complex(false),
+ client_send_large(false),
client_reply_port_type(kReplyPortNormal),
client_expect_reply(true),
child_send_all_requests_before_receiving_any_replies(false),
@@ -81,6 +84,9 @@ class TestMachMessageServer : public MachMessageServer::Interface,
// receive if the receive is to be successful.
bool parent_wait_for_child_pipe;
+ // Options to pass to MachMessageServer::Run() as the |options| parameter.
+ mach_msg_options_t server_options;
+
// Whether the server should run in one-shot or persistent mode.
MachMessageServer::Persistent server_persistent;
@@ -109,6 +115,9 @@ class TestMachMessageServer : public MachMessageServer::Interface,
// The expected return value from MachMessageServer::Run().
kern_return_t expect_server_result;
+ // The number of transactions that the server is expected to handle.
+ size_t expect_server_transaction_count;
+
// The number of requests that the client should send to the server.
size_t client_send_request_count;
@@ -116,6 +125,12 @@ class TestMachMessageServer : public MachMessageServer::Interface,
// descriptor in its body. Normally false.
bool client_send_complex;
+ // true if the client should send a larger message than the server has
+ // allocated space to receive. If server_options contains MACH_RCV_LARGE,
+ // the server will resize its buffer to receive the message. Otherwise, the
+ // message will be destroyed and the server will return MACH_RCV_TOO_LARGE.
+ bool client_send_large;
+
// The type of reply port that the client should provide in its request’s
// mach_msg_header_t::msgh_local_port, which will appear to the server as
// mach_msg_header_t::msgh_remote_port.
@@ -159,7 +174,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
Run();
EXPECT_EQ(requests_, replies_);
- EXPECT_EQ(options_.client_send_request_count, requests_ - start);
+ EXPECT_EQ(options_.expect_server_transaction_count, requests_ - start);
}
// MachMessageServerInterface:
@@ -179,13 +194,19 @@ class TestMachMessageServer : public MachMessageServer::Interface,
mach_msg_trailer_t trailer;
};
+ struct ReceiveLargeRequestMessage : public LargeRequestMessage {
+ mach_msg_trailer_t trailer;
+ };
+
const ReceiveRequestMessage* request =
reinterpret_cast<ReceiveRequestMessage*>(in);
const mach_msg_bits_t expect_msgh_bits =
MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, MACH_MSG_TYPE_MOVE_SEND) |
(options_.client_send_complex ? MACH_MSGH_BITS_COMPLEX : 0);
EXPECT_EQ(expect_msgh_bits, request->header.msgh_bits);
- EXPECT_EQ(sizeof(RequestMessage), request->header.msgh_size);
+ EXPECT_EQ(options_.client_send_large ? sizeof(LargeRequestMessage) :
+ sizeof(RequestMessage),
+ request->header.msgh_size);
if (options_.client_reply_port_type == Options::kReplyPortNormal) {
EXPECT_EQ(RemotePort(), request->header.msgh_remote_port);
}
@@ -210,10 +231,24 @@ class TestMachMessageServer : public MachMessageServer::Interface,
}
EXPECT_EQ(0, memcmp(&request->ndr, &NDR_record, sizeof(NDR_record)));
EXPECT_EQ(requests_, request->number);
+
+ // Look for the trailer in the right spot, depending on whether the request
+ // message was a RequestMessage or a LargeRequestMessage.
+ const mach_msg_trailer_t* trailer;
+ if (options_.client_send_large) {
+ const ReceiveLargeRequestMessage* large_request =
+ reinterpret_cast<const ReceiveLargeRequestMessage*>(request);
+ for (size_t index = 0; index < sizeof(large_request->data); ++index) {
+ EXPECT_EQ('!', large_request->data[index]);
+ }
+ trailer = &large_request->trailer;
+ } else {
+ trailer = &request->trailer;
+ }
+
EXPECT_EQ(static_cast<mach_msg_trailer_type_t>(MACH_MSG_TRAILER_FORMAT_0),
- request->trailer.msgh_trailer_type);
- EXPECT_EQ(MACH_MSG_TRAILER_MINIMUM_SIZE,
- request->trailer.msgh_trailer_size);
+ trailer->msgh_trailer_type);
+ EXPECT_EQ(MACH_MSG_TRAILER_MINIMUM_SIZE, trailer->msgh_trailer_size);
++requests_;
@@ -240,11 +275,23 @@ class TestMachMessageServer : public MachMessageServer::Interface,
private:
struct RequestMessage : public mach_msg_base_t {
+ // If body.msgh_descriptor_count is 0, port_descriptor will still be
+ // present, but it will be zeroed out. It wouldn’t normally be present in a
+ // message froma MIG-generated interface, but it’s harmless and simpler to
+ // leave it here and just treat it as more data.
mach_msg_port_descriptor_t port_descriptor;
+
NDR_record_t ndr;
uint32_t number;
};
+ // LargeRequestMessage is larger enough than a regular RequestMessage to
+ // ensure that whatever buffer was allocated to receive a RequestMessage is
+ // not large enough to receive a LargeRequestMessage.
+ struct LargeRequestMessage : public RequestMessage {
+ uint8_t data[4 * PAGE_SIZE];
+ };
+
struct ReplyMessage : public mig_reply_error_t {
uint32_t number;
};
@@ -264,7 +311,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
ASSERT_EQ(options_.expect_server_result,
(kr = MachMessageServer::Run(this,
LocalPort(),
- MACH_MSG_OPTION_NONE,
+ options_.server_options,
options_.server_persistent,
options_.server_nonblocking,
options_.server_timeout_ms)))
@@ -361,11 +408,17 @@ class TestMachMessageServer : public MachMessageServer::Interface,
// been carried in a Mach message.
base::mac::ScopedMachReceiveRight local_receive_port_owner;
- RequestMessage request = {};
+ // A LargeRequestMessage is always allocated, but the message that will be
+ // sent will be a normal RequestMessage due to the msgh_size field
+ // indicating the size of the smaller base structure unless
+ // options_.client_send_large is true.
+ LargeRequestMessage request = {};
+
request.header.msgh_bits =
MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND) |
(options_.client_send_complex ? MACH_MSGH_BITS_COMPLEX : 0);
- request.header.msgh_size = sizeof(request);
+ request.header.msgh_size = options_.client_send_large ?
+ sizeof(LargeRequestMessage) : sizeof(RequestMessage);
request.header.msgh_remote_port = RemotePort();
kern_return_t kr;
switch (options_.client_reply_port_type) {
@@ -412,6 +465,10 @@ class TestMachMessageServer : public MachMessageServer::Interface,
request.ndr = NDR_record;
request.number = requests_++;
+ if (options_.client_send_large) {
+ memset(request.data, '!', sizeof(request.data));
+ }
+
kr = mach_msg(&request.header,
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
request.header.msgh_size,
@@ -534,6 +591,7 @@ TEST(MachMessageServer, NonblockingNoMessage) {
options.expect_server_interface_method_called = false;
options.server_nonblocking = MachMessageServer::kNonblocking;
options.expect_server_result = MACH_RCV_TIMED_OUT;
+ options.expect_server_transaction_count = 0;
options.client_send_request_count = 0;
TestMachMessageServer test_mach_message_server(options);
test_mach_message_server.Test();
@@ -546,6 +604,7 @@ TEST(MachMessageServer, TimeoutNoMessage) {
options.expect_server_interface_method_called = false;
options.server_timeout_ms = 10;
options.expect_server_result = MACH_RCV_TIMED_OUT;
+ options.expect_server_transaction_count = 0;
options.client_send_request_count = 0;
TestMachMessageServer test_mach_message_server(options);
test_mach_message_server.Test();
@@ -580,6 +639,7 @@ TEST(MachMessageServer, PersistentTenMessages) {
options.server_persistent = MachMessageServer::kPersistent;
options.server_timeout_ms = 10;
options.expect_server_result = MACH_RCV_TIMED_OUT;
+ options.expect_server_transaction_count = 10;
options.client_send_request_count = 10;
TestMachMessageServer test_mach_message_server(options);
test_mach_message_server.Test();
@@ -597,12 +657,17 @@ TEST(MachMessageServer, PersistentNonblockingFourMessages) {
// MACH_PORT_QLIMIT_BASIC, or 5). The number of messages sent for this test
// must be below this, because the server does not begin dequeueing request
// messages until the client has finished sending them.
+ const size_t kTransactionCount = 4;
+ COMPILE_ASSERT(kTransactionCount <= MACH_PORT_QLIMIT_DEFAULT,
+ must_not_exceed_queue_limit);
+
TestMachMessageServer::Options options;
options.parent_wait_for_child_pipe = true;
options.server_persistent = MachMessageServer::kPersistent;
options.server_nonblocking = MachMessageServer::kNonblocking;
options.expect_server_result = MACH_RCV_TIMED_OUT;
- options.client_send_request_count = 4;
+ options.expect_server_transaction_count = kTransactionCount;
+ options.client_send_request_count = kTransactionCount;
options.child_send_all_requests_before_receiving_any_replies = true;
TestMachMessageServer test_mach_message_server(options);
test_mach_message_server.Test();
@@ -716,4 +781,30 @@ TEST(MachMessageServer, ComplexNotDestroyedNoReply) {
test_mach_message_server.Test();
}
+TEST(MachMessageServer, LargeUnexpected) {
+ // The client sends a request to the server that is larger than the server is
+ // expecting. The server did not specify MACH_RCV_LARGE in its options, so the
+ // request is destroyed and the server returns a MACH_RCV_TOO_LARGE error. The
+ // client does not receive a reply.
+ TestMachMessageServer::Options options;
+ options.expect_server_result = MACH_RCV_TOO_LARGE;
+ options.expect_server_transaction_count = 0;
+ options.client_send_large = true;
+ options.client_expect_reply = false;
+ TestMachMessageServer test_mach_message_server(options);
+ test_mach_message_server.Test();
+}
+
+TEST(MachMessageServer, LargeExpected) {
+ // The client sends a request to the server that is larger than the server is
+ // initially expecting. The server did specify MACH_RCV_LARGE in its options,
+ // so a new buffer is allocated to receive the message. The server receives
+ // the large request message, processes it, and returns a reply to the client.
+ TestMachMessageServer::Options options;
+ options.server_options = MACH_RCV_LARGE;
+ options.client_send_large = true;
+ TestMachMessageServer test_mach_message_server(options);
+ test_mach_message_server.Test();
+}
+
} // namespace
« no previous file with comments | « util/mach/mach_message_server.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698