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

Unified Diff: util/mach/child_port_handshake_test.cc

Issue 1408473002: ChildPortHandshake: allow receive rights to be received (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback Created 5 years, 2 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/child_port_handshake.cc ('k') | util/mach/mach_message.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: util/mach/child_port_handshake_test.cc
diff --git a/util/mach/child_port_handshake_test.cc b/util/mach/child_port_handshake_test.cc
index 12ca424c54cc20b269d3cb5417cac4a79a80d7b3..f77107b53982614c66074238711cb3f372006369 100644
--- a/util/mach/child_port_handshake_test.cc
+++ b/util/mach/child_port_handshake_test.cc
@@ -26,161 +26,355 @@ namespace {
class ChildPortHandshakeTest : public Multiprocess {
public:
- enum TestType {
- kTestTypeChildChecksIn = 0,
- kTestTypeChildDoesNotCheckIn_ReadsPipe,
- kTestTypeChildDoesNotCheckIn,
- kTestTypeTokenIncorrect,
- kTestTypeTokenIncorrectThenCorrect,
+ enum class ClientProcess {
+ // The child runs the client and the parent runs the server.
+ kChildClient = 0,
+
+ // The parent runs the client and the child runs the server.
+ kParentClient,
+ };
+
+ enum class TestType {
+ // The client checks in with the server, transferring a receive right.
+ kClientChecksIn_ReceiveRight = 0,
+
+ // In this test, the client checks in with the server normally. It sends a
+ // copy of its bootstrap port to the server, because both parent and child
+ // should have the same bootstrap port, allowing for verification.
+ kClientChecksIn_SendRight,
+
+ // The client checks in with the server, transferring a send-once right.
+ kClientChecksIn_SendOnceRight,
+
+ // In this test, the client reads from its pipe, and subsequently exits
+ // without checking in. This tests that the server properly detects that it
+ // has lost its client after sending instructions to it via the pipe, while
+ // waiting for a check-in message.
+ kClientDoesNotCheckIn,
+
+ // In this test, the client exits without checking in. This tests that the
+ // server properly detects that it has lost a client. Whether or not the
+ // client closes the pipe before the server writes to it is a race, and the
+ // server needs to be able to detect client loss in both cases, so the
+ // ClientDoesNotCheckIn_ReadsPipe and NoClient tests also exist to test
+ // these individual cases more deterministically.
+ kClientDoesNotCheckIn_ReadsPipe,
+
+ // In this test, the client checks in with the server with an incorrect
+ // token value and a copy of its own task port. The server should reject the
+ // message because of the invalid token, and return MACH_PORT_NULL to its
+ // caller.
+ kTokenIncorrect,
+
+ // In this test, the client checks in with the server with an incorrect
+ // token value and a copy of its own task port, and subsequently, the
+ // correct token value and a copy of its bootstrap port. The server should
+ // reject the first because of the invalid token, but it should continue
+ // waiting for a message with a valid token as long as the pipe remains
+ // open. It should wind wind up returning the bootstrap port, allowing for
+ // verification.
+ kTokenIncorrectThenCorrect,
+
+ // The server dies. The failure should be reported in the client. This test
+ // type is only compatible with ClientProcess::kParentClient.
+ kServerDies,
};
- explicit ChildPortHandshakeTest(TestType test_type)
- : Multiprocess(), child_port_handshake_(), test_type_(test_type) {}
- ~ChildPortHandshakeTest() {}
+ ChildPortHandshakeTest(ClientProcess client_process, TestType test_type)
+ : Multiprocess(),
+ child_port_handshake_(),
+ client_process_(client_process),
+ test_type_(test_type) {
+ }
+
+ ~ChildPortHandshakeTest() {
+ }
private:
- // Multiprocess:
+ void RunServer() {
+ if (test_type_ == TestType::kServerDies) {
+ return;
+ }
+
+ base::mac::ScopedMachReceiveRight receive_right;
+ base::mac::ScopedMachSendRight send_right;
+ if (test_type_ == TestType::kClientChecksIn_ReceiveRight) {
+ receive_right.reset(child_port_handshake_.RunServer(
+ ChildPortHandshake::PortRightType::kReceiveRight));
+ } else {
+ send_right.reset(child_port_handshake_.RunServer(
+ ChildPortHandshake::PortRightType::kSendRight));
+ }
- void MultiprocessParent() override {
- base::mac::ScopedMachSendRight child_port(
- child_port_handshake_.RunServer());
switch (test_type_) {
- case kTestTypeChildChecksIn:
- case kTestTypeTokenIncorrectThenCorrect:
- EXPECT_EQ(bootstrap_port, child_port);
+ case TestType::kClientChecksIn_ReceiveRight:
+ EXPECT_TRUE(receive_right.is_valid());
+ break;
+
+ case TestType::kClientChecksIn_SendRight:
+ case TestType::kTokenIncorrectThenCorrect:
+ EXPECT_EQ(bootstrap_port, send_right);
+ break;
+
+ case TestType::kClientChecksIn_SendOnceRight:
+ EXPECT_TRUE(send_right.is_valid());
+ EXPECT_NE(bootstrap_port, send_right);
+ break;
+
+ case TestType::kClientDoesNotCheckIn:
+ case TestType::kClientDoesNotCheckIn_ReadsPipe:
+ case TestType::kTokenIncorrect:
+ EXPECT_FALSE(send_right.is_valid());
break;
- case kTestTypeChildDoesNotCheckIn_ReadsPipe:
- case kTestTypeChildDoesNotCheckIn:
- case kTestTypeTokenIncorrect:
- EXPECT_EQ(kMachPortNull, child_port);
+ case TestType::kServerDies:
+ // This was special-cased as an early return above.
+ FAIL();
break;
}
}
- void MultiprocessChild() override {
- int read_pipe = child_port_handshake_.ReadPipeFD();
+ void RunClient() {
switch (test_type_) {
- case kTestTypeChildChecksIn:
- ChildPortHandshake::RunClient(
- read_pipe, bootstrap_port, MACH_MSG_TYPE_COPY_SEND);
+ case TestType::kClientChecksIn_SendRight: {
+ ASSERT_TRUE(child_port_handshake_.RunClient(bootstrap_port,
+ MACH_MSG_TYPE_COPY_SEND));
+ break;
+ }
+
+ case TestType::kClientChecksIn_ReceiveRight: {
+ mach_port_t receive_right = NewMachPort(MACH_PORT_RIGHT_RECEIVE);
+ ASSERT_TRUE(child_port_handshake_.RunClient(
+ receive_right, MACH_MSG_TYPE_MOVE_RECEIVE));
+ break;
+ }
+
+ case TestType::kClientChecksIn_SendOnceRight: {
+ base::mac::ScopedMachReceiveRight receive_right(
+ NewMachPort(MACH_PORT_RIGHT_RECEIVE));
+ ASSERT_TRUE(child_port_handshake_.RunClient(
+ receive_right.get(), MACH_MSG_TYPE_MAKE_SEND_ONCE));
+ break;
+ }
+
+ case TestType::kClientDoesNotCheckIn: {
+ child_port_handshake_.ServerWriteFD().reset();
+ child_port_handshake_.ClientReadFD().reset();
break;
+ }
- case kTestTypeChildDoesNotCheckIn_ReadsPipe: {
+ case TestType::kClientDoesNotCheckIn_ReadsPipe: {
// Don’t run the standard client routine. Instead, drain the pipe, which
// will get the parent to the point that it begins waiting for a
// check-in message. Then, exit. The pipe is drained using the same
// implementation that the real client would use.
+ child_port_handshake_.ServerWriteFD().reset();
+ base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD();
child_port_token_t token;
std::string service_name;
- ChildPortHandshake::RunClientInternal_ReadPipe(
- read_pipe, &token, &service_name);
+ ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe(
+ client_read_fd.get(), &token, &service_name));
break;
}
- case kTestTypeChildDoesNotCheckIn:
- break;
-
- case kTestTypeTokenIncorrect: {
+ case TestType::kTokenIncorrect: {
// Don’t run the standard client routine. Instead, read the token and
// service name, mutate the token, and then check in with the bad token.
// The parent should reject the message.
+ child_port_handshake_.ServerWriteFD().reset();
+ base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD();
child_port_token_t token;
std::string service_name;
- ChildPortHandshake::RunClientInternal_ReadPipe(
- read_pipe, &token, &service_name);
+ ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe(
+ client_read_fd.get(), &token, &service_name));
child_port_token_t bad_token = ~token;
- ChildPortHandshake::RunClientInternal_SendCheckIn(
- service_name, bad_token, mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
+ ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn(
+ service_name,
+ bad_token,
+ mach_task_self(),
+ MACH_MSG_TYPE_COPY_SEND));
break;
}
- case kTestTypeTokenIncorrectThenCorrect: {
+ case TestType::kTokenIncorrectThenCorrect: {
// Don’t run the standard client routine. Instead, read the token and
// service name. Mutate the token, and check in with the bad token,
// expecting the parent to reject the message. Then, check in with the
// correct token, expecting the parent to accept it.
+ child_port_handshake_.ServerWriteFD().reset();
+ base::ScopedFD client_read_fd = child_port_handshake_.ClientReadFD();
child_port_token_t token;
std::string service_name;
- ChildPortHandshake::RunClientInternal_ReadPipe(
- read_pipe, &token, &service_name);
+ ASSERT_TRUE(ChildPortHandshake::RunClientInternal_ReadPipe(
+ client_read_fd.release(), &token, &service_name));
child_port_token_t bad_token = ~token;
- ChildPortHandshake::RunClientInternal_SendCheckIn(
- service_name, bad_token, mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
- ChildPortHandshake::RunClientInternal_SendCheckIn(
- service_name, token, bootstrap_port, MACH_MSG_TYPE_COPY_SEND);
+ ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn(
+ service_name,
+ bad_token,
+ mach_task_self(),
+ MACH_MSG_TYPE_COPY_SEND));
+ ASSERT_TRUE(ChildPortHandshake::RunClientInternal_SendCheckIn(
+ service_name, token, bootstrap_port, MACH_MSG_TYPE_COPY_SEND));
+ break;
+ }
+
+ case TestType::kServerDies: {
+ ASSERT_EQ(ClientProcess::kParentClient, client_process_);
+ ASSERT_FALSE(child_port_handshake_.RunClient(bootstrap_port,
+ MACH_MSG_TYPE_COPY_SEND));
break;
}
}
}
+ // Multiprocess:
+
+ void MultiprocessParent() override {
+ switch (client_process_) {
+ case ClientProcess::kChildClient:
+ RunServer();
+ break;
+ case ClientProcess::kParentClient:
+ RunClient();
+ break;
+ }
+ }
+
+ void MultiprocessChild() override {
+ switch (client_process_) {
+ case ClientProcess::kChildClient:
+ RunClient();
+ break;
+ case ClientProcess::kParentClient:
+ RunServer();
+ break;
+ }
+ }
+
private:
ChildPortHandshake child_port_handshake_;
+ ClientProcess client_process_;
TestType test_type_;
DISALLOW_COPY_AND_ASSIGN(ChildPortHandshakeTest);
};
-TEST(ChildPortHandshake, ChildChecksIn) {
- // In this test, the client checks in with the server normally. It sends a
- // copy of its bootstrap port to the server, because both parent and child
- // should have the same bootstrap port, allowing for verification.
- ChildPortHandshakeTest test(ChildPortHandshakeTest::kTestTypeChildChecksIn);
+TEST(ChildPortHandshake, ChildClientChecksIn_ReceiveRight) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kChildClient,
+ ChildPortHandshakeTest::TestType::kClientChecksIn_ReceiveRight);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ChildClientChecksIn_SendRight) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kChildClient,
+ ChildPortHandshakeTest::TestType::kClientChecksIn_SendRight);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ChildClientChecksIn_SendOnceRight) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kChildClient,
+ ChildPortHandshakeTest::TestType::kClientChecksIn_SendOnceRight);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ChildClientDoesNotCheckIn) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kChildClient,
+ ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ChildClientDoesNotCheckIn_ReadsPipe) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kChildClient,
+ ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn_ReadsPipe);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ChildClientTokenIncorrect) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kChildClient,
+ ChildPortHandshakeTest::TestType::kTokenIncorrect);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ChildClientTokenIncorrectThenCorrect) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kChildClient,
+ ChildPortHandshakeTest::TestType::kTokenIncorrectThenCorrect);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ParentClientChecksIn_ReceiveRight) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kClientChecksIn_ReceiveRight);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ParentClientChecksIn_SendRight) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kClientChecksIn_SendRight);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ParentClientChecksIn_SendOnceRight) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kClientChecksIn_SendOnceRight);
+ test.Run();
+}
+
+TEST(ChildPortHandshake, ParentClientDoesNotCheckIn) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn);
test.Run();
}
-TEST(ChildPortHandshake, ChildDoesNotCheckIn) {
- // In this test, the client exits without checking in. This tests that the
- // server properly detects that it has lost a client. Whether or not the
- // client closes the pipe before the server writes to it is a race, and the
- // server needs to be able to detect client loss in both cases, so the
- // ChildDoesNotCheckIn_ReadsPipe and NoChild tests also exist to test these
- // individual cases more deterministically.
+TEST(ChildPortHandshake, ParentClientDoesNotCheckIn_ReadsPipe) {
ChildPortHandshakeTest test(
- ChildPortHandshakeTest::kTestTypeChildDoesNotCheckIn);
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kClientDoesNotCheckIn_ReadsPipe);
test.Run();
}
-TEST(ChildPortHandshake, ChildDoesNotCheckIn_ReadsPipe) {
- // In this test, the client reads from its pipe, and subsequently exits
- // without checking in. This tests that the server properly detects that it
- // has lost its client after sending instructions to it via the pipe, while
- // waiting for a check-in message.
+TEST(ChildPortHandshake, ParentClientTokenIncorrect) {
ChildPortHandshakeTest test(
- ChildPortHandshakeTest::kTestTypeChildDoesNotCheckIn_ReadsPipe);
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kTokenIncorrect);
test.Run();
}
-TEST(ChildPortHandshake, TokenIncorrect) {
- // In this test, the client checks in with the server with an incorrect token
- // value and a copy of its own task port. The server should reject the message
- // because of the invalid token, and return MACH_PORT_NULL to its caller.
- ChildPortHandshakeTest test(ChildPortHandshakeTest::kTestTypeTokenIncorrect);
+TEST(ChildPortHandshake, ParentClientTokenIncorrectThenCorrect) {
+ ChildPortHandshakeTest test(
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kTokenIncorrectThenCorrect);
test.Run();
}
-TEST(ChildPortHandshake, TokenIncorrectThenCorrect) {
- // In this test, the client checks in with the server with an incorrect token
- // value and a copy of its own task port, and subsequently, the correct token
- // value and a copy of its bootstrap port. The server should reject the first
- // because of the invalid token, but it should continue waiting for a message
- // with a valid token as long as the pipe remains open. It should wind wind up
- // returning the bootstrap port, allowing for verification.
+TEST(ChildPortHandshake, ParentClientServerDies) {
ChildPortHandshakeTest test(
- ChildPortHandshakeTest::kTestTypeTokenIncorrectThenCorrect);
+ ChildPortHandshakeTest::ClientProcess::kParentClient,
+ ChildPortHandshakeTest::TestType::kServerDies);
test.Run();
}
-TEST(ChildPortHandshake, NoChild) {
- // In this test, the client never checks in with the parent because the child
- // never even runs. This tests that the server properly detects that it has
- // no client at all, and does not terminate execution with an error such as
+TEST(ChildPortHandshake, NoClient) {
+ // In this test, the client never checks in with the server because it never
+ // even runs. This tests that the server properly detects that it has no
+ // client at all, and does not terminate execution with an error such as
// “broken pipe” when attempting to send instructions to the client. This test
- // is similar to ChildDoesNotCheckIn, but because there’s no child at all, the
- // server is guaranteed to see that its pipe partner is gone.
+ // is similar to kClientDoesNotCheckIn, but because there’s no client at all,
+ // the server is guaranteed to see that its pipe partner is gone.
ChildPortHandshake child_port_handshake;
- base::mac::ScopedMachSendRight child_port(child_port_handshake.RunServer());
- EXPECT_EQ(kMachPortNull, child_port);
+ base::mac::ScopedMachSendRight child_port(child_port_handshake.RunServer(
+ ChildPortHandshake::PortRightType::kSendRight));
+ EXPECT_FALSE(child_port.is_valid());
}
} // namespace
« no previous file with comments | « util/mach/child_port_handshake.cc ('k') | util/mach/mach_message.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698