Skip to content

Commit 4772616

Browse files
paulsemelcopybara-github
authored andcommitted
Refactor asynchronous byte transport test to avoid allocations in the child process.
This change refactors the test helper to perform buffer allocations and transport client creation in the parent process before fork(). In the child process, it now uses pre-allocated spans and RecvTLV instead of RecvBytes to avoid dynamic memory allocation. Additionally, standard CHECK/ASSERT macros in the child process are replaced with SAPI_RAW_CHECK for safer post-fork execution. PiperOrigin-RevId: 965961727 Change-Id: Ic155e97402a43be2f39a28f0091fc55c3b4f4da4
1 parent 30f1bde commit 4772616

3 files changed

Lines changed: 79 additions & 37 deletions

File tree

sandboxed_api/sandbox2/util/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ cc_test(
297297
"//sandboxed_api/sandbox2:buffer",
298298
"//sandboxed_api/sandbox2:comms",
299299
"//sandboxed_api/util:fileops",
300+
"//sandboxed_api/util:raw_logging",
300301
"//sandboxed_api/util:thread",
301302
"@abseil-cpp//absl/log:check",
302303
"@abseil-cpp//absl/status",

sandboxed_api/sandbox2/util/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ if(BUILD_TESTING AND SAPI_BUILD_TESTING)
325325
absl::time
326326
sandbox2::asynchronous_byte_transport
327327
sandbox2::comms
328+
sapi::raw_logging
328329
sapi::testing
329330
sapi::test_main
330331
)

sandboxed_api/sandbox2/util/asynchronous_byte_transport_test.cc

Lines changed: 77 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <sys/prctl.h>
1919
#include <sys/socket.h>
2020
#include <sys/wait.h>
21+
#include <unistd.h>
2122

2223
#include <cstddef>
2324
#include <cstdint>
@@ -39,6 +40,7 @@
3940
#include "sandboxed_api/sandbox2/comms.h"
4041
#include "sandboxed_api/testing.h"
4142
#include "sandboxed_api/util/fileops.h"
43+
#include "sandboxed_api/util/raw_logging.h"
4244
#include "sandboxed_api/util/thread.h"
4345

4446
namespace sandbox2 {
@@ -82,19 +84,41 @@ class TestHelper {
8284
explicit TestHelper() {}
8385

8486
void StartAsync(int memfd, size_t data_size) {
85-
int pipe_fds[2];
86-
pipe(pipe_fds);
87+
int socket_fds[2];
88+
CHECK_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds), 0);
89+
90+
SAPI_ASSERT_OK_AND_ASSIGN(
91+
auto buffer_client,
92+
sandbox2::Buffer::CreateFromFd(
93+
sapi::file_util::fileops::FDCloser(dup(memfd)), data_size));
94+
SAPI_ASSERT_OK_AND_ASSIGN(
95+
auto transport_client,
96+
sandbox2::AsynchronousByteTransport::CreateSandboxeeSide(
97+
std::move(buffer_client)));
98+
99+
std::vector<uint8_t> data_buf(data_size * 4);
100+
std::vector<uint8_t> data_to_send_buf(data_size * 4);
101+
std::vector<uint8_t> data_to_recv_buf(data_size * 4);
102+
std::vector<uint8_t> recv_data_buf(data_size * 4);
103+
104+
sandbox2::Comms comms_child(socket_fds[0], "test_comms_sandboxee");
105+
87106
pid_ = fork();
88107
CHECK_NE(pid_, -1);
89108
if (pid_ == 0) {
90-
CHECK_EQ(prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0), 0);
91-
close(pipe_fds[1]);
92-
Communicate(pipe_fds[0], memfd, data_size);
93-
close(pipe_fds[0]);
109+
// At this point, we should avoid any heap allocations to prevent
110+
// potential deadlocks in TCMalloc.
111+
SAPI_RAW_CHECK(prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) == 0,
112+
"Failed to set PR_SET_PDEATHSIG");
113+
close(socket_fds[1]);
114+
Communicate(&comms_child, transport_client.get(),
115+
absl::MakeSpan(data_buf), absl::MakeSpan(data_to_send_buf),
116+
absl::MakeSpan(data_to_recv_buf),
117+
absl::MakeSpan(recv_data_buf));
118+
close(socket_fds[0]);
94119
_exit(0);
95120
}
96-
close(pipe_fds[0]);
97-
comms_ = std::make_unique<sandbox2::Comms>(pipe_fds[1], "test_comms");
121+
comms_ = std::make_unique<sandbox2::Comms>(socket_fds[1], "test_comms");
98122
}
99123

100124
void Stop() {
@@ -129,39 +153,55 @@ class TestHelper {
129153
}
130154

131155
private:
132-
void Communicate(int socket_fd, int memfd_fd, size_t data_size) {
133-
SAPI_ASSERT_OK_AND_ASSIGN(
134-
auto buffer_client,
135-
sandbox2::Buffer::CreateFromFd(
136-
sapi::file_util::fileops::FDCloser(memfd_fd), data_size));
137-
SAPI_ASSERT_OK_AND_ASSIGN(
138-
auto transport_client,
139-
sandbox2::AsynchronousByteTransport::CreateSandboxeeSide(
140-
std::move(buffer_client)));
141-
sandbox2::Comms comms(socket_fd, "test_comms_sandboxee");
156+
void Communicate(sandbox2::Comms* comms,
157+
sandbox2::AsynchronousByteTransport* transport_client,
158+
absl::Span<uint8_t> data_buf,
159+
absl::Span<uint8_t> data_to_send_buf,
160+
absl::Span<uint8_t> data_to_recv_buf,
161+
absl::Span<uint8_t> recv_data_buf) {
162+
// This function should avoid allocations to avoid any potential deadlocks
163+
// in TCMalloc. This is why we use fixed-size buffers and raw logging.
142164
ActionType action_type;
143-
while (comms.RecvInt32(reinterpret_cast<int32_t*>(&action_type))) {
165+
uint32_t tag;
166+
size_t len;
167+
while (comms->RecvInt32(reinterpret_cast<int32_t*>(&action_type))) {
144168
if (action_type == ActionType::kSend) {
145-
std::vector<uint8_t> data;
146-
CHECK_EQ(comms.RecvBytes(&data), true);
147-
CHECK_OK(transport_client->Send(data));
169+
SAPI_RAW_CHECK(
170+
comms->RecvTLV(&tag, &len, data_buf.data(), data_buf.size(),
171+
sandbox2::Comms::kTagBytes),
172+
"RecvTLV failed");
173+
SAPI_RAW_CHECK(transport_client->Send(data_buf.subspan(0, len)).ok(),
174+
"Send failed");
148175
} else if (action_type == ActionType::kExchange) {
149-
std::vector<uint8_t> data_to_send;
150-
CHECK_EQ(comms.RecvBytes(&data_to_send), true);
151-
std::vector<uint8_t> data_to_recv;
152-
CHECK_EQ(comms.RecvBytes(&data_to_recv), true);
153-
std::vector<uint8_t> recv_data(data_to_recv.size());
154-
CHECK_OK(transport_client->Exchange(
155-
data_to_send,
156-
absl::Span<uint8_t>(recv_data.data(), recv_data.size())));
157-
ASSERT_EQ(recv_data, data_to_recv);
176+
SAPI_RAW_CHECK(
177+
comms->RecvTLV(&tag, &len, data_to_send_buf.data(),
178+
data_to_send_buf.size(), sandbox2::Comms::kTagBytes),
179+
"RecvTLV send_data failed");
180+
size_t send_len = len;
181+
SAPI_RAW_CHECK(
182+
comms->RecvTLV(&tag, &len, data_to_recv_buf.data(),
183+
data_to_recv_buf.size(), sandbox2::Comms::kTagBytes),
184+
"RecvTLV recv_data failed");
185+
size_t recv_len = len;
186+
SAPI_RAW_CHECK(transport_client
187+
->Exchange(data_to_send_buf.subspan(0, send_len),
188+
recv_data_buf.subspan(0, recv_len))
189+
.ok(),
190+
"Exchange failed");
191+
SAPI_RAW_CHECK(recv_data_buf.subspan(0, recv_len) ==
192+
data_to_recv_buf.subspan(0, recv_len),
193+
"Exchange data mismatch");
158194
} else if (action_type == ActionType::kRecv) {
159-
std::vector<uint8_t> data;
160-
CHECK_EQ(comms.RecvBytes(&data), true);
161-
std::vector<uint8_t> data_recv(data.size());
162-
CHECK_OK(transport_client->Recv(
163-
absl::Span<uint8_t>(data_recv.data(), data_recv.size())));
164-
CHECK_EQ(data, data_recv);
195+
SAPI_RAW_CHECK(
196+
comms->RecvTLV(&tag, &len, data_buf.data(), data_buf.size(),
197+
sandbox2::Comms::kTagBytes),
198+
"RecvTLV failed");
199+
SAPI_RAW_CHECK(
200+
transport_client->Recv(recv_data_buf.subspan(0, len)).ok(),
201+
"Recv failed");
202+
SAPI_RAW_CHECK(
203+
recv_data_buf.subspan(0, len) == data_buf.subspan(0, len),
204+
"Recv data mismatch");
165205
} else if (action_type == ActionType::kTerminate) {
166206
transport_client->Terminate();
167207
}

0 commit comments

Comments
 (0)