blob: 9e64ca21538606cc91a7d597a62346a0714a7a30 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/llcpptest.flexible.test/cpp/wire.h>
#include <fidl/llcpptest.flexible.test/cpp/wire_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/wait.h>
#include <lib/fidl/cpp/wire/outgoing_message.h>
#include <lib/zx/event.h>
#include <zircon/fidl.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <gtest/gtest.h>
namespace test = ::llcpptest_flexible_test;
// These tests verify that the messaging APIs allocate a bespoke amount of memory
// depending on the shapes of types in the methods in the protocol, but also
// anticipate future bytes/handles size additions to flexible types, and allocate
// the transport maximum in those cases.
namespace {
// The only difference between StrictUnboundedXUnion and StrictBoundedXUnion is that
// StrictBoundedXUnion limits the vector payload length to 200 bytes. Therefore, by observing that
// sizeof(fidl::WireResult<test::ReceiveStrictEnvelope::GetUnboundedXUnion>) is less than 200, we
// can guarantee that the response storage is not inlined. Rather, it is allocated on the heap.
static_assert(sizeof(fidl::WireResult<test::ReceiveStrictEnvelope::GetUnboundedXUnion>) < 200,
"Result of GetUnboundedXUnion should be stored as a pointer to heap allocation");
// GetBoundedXUnion should be inlined, because it is smaller than 512, but bigger than 200, making
// the entire ResultOf object bigger than 200. The assertion triggers when the ResultOf object size
// falls below 200, at which point we know it is physically incapable of holding a GetBoundedXUnion
// inline, so probably used heap allocation. Here we are trying to test this without plumbing extra
// flags which themselves need to be tested.
static_assert(sizeof(fidl::WireResult<test::ReceiveStrictEnvelope::GetBoundedXUnion>) > 200,
"Result of GetBoundedXUnion should be inlined");
// Implement a special server that returns xunion/tables with unknown ordinals.
// This is impossible to do when using the bindings normally. Here we use a normal server to
// set a tag in the response xunion corresponding to the FIDL call, and intercept and rewrite
// the xunion to an unknown ordinal using a special fidl::Transaction implementation.
class RewriteTransaction : public fidl::Transaction {
public:
std::unique_ptr<Transaction> TakeOwnership() override {
ADD_FAILURE() << "Never called";
return {};
}
void Close(zx_status_t epitaph) override {
ADD_FAILURE() << "Transaction::Close called with epitaph " << epitaph;
}
zx_status_t Reply(fidl::OutgoingMessage* indicator_msg,
fidl::WriteOptions write_options) override {
EXPECT_NE(txid_, 0u);
auto indicator_msg_bytes = indicator_msg->CopyBytes();
unsigned char real_msg_bytes[ZX_CHANNEL_MAX_MSG_BYTES] = {};
zx_handle_t real_msg_handles[ZX_CHANNEL_MAX_MSG_HANDLES] = {};
fidl_channel_handle_metadata_t real_msg_handle_metadata[ZX_CHANNEL_MAX_MSG_HANDLES] = {};
// Copy from original header to get magic, flags, and ordinals.
EXPECT_GE(indicator_msg_bytes.size(), sizeof(fidl_message_header_t));
memcpy(real_msg_bytes, indicator_msg_bytes.data(), sizeof(fidl_message_header_t));
fidl_message_header_t* header = reinterpret_cast<fidl_message_header_t*>(real_msg_bytes);
header->txid = txid_;
zx_channel_iovec_t iovec = {
.buffer = real_msg_bytes,
.capacity = 0,
};
uint32_t num_handles = 0;
EXPECT_GE(indicator_msg_bytes.size(),
sizeof(fidl::internal::TransactionalResponse<
test::ReceiveFlexibleEnvelope::GetUnknownXUnionMoreHandles>));
// Determine if |indicator_msg| has a xunion or a table, by inspecting the first few bytes.
auto maybe_vector = reinterpret_cast<const fidl_vector_t*>(indicator_msg_bytes.data() +
sizeof(fidl_message_header_t));
if ((maybe_vector->count == 1 || maybe_vector->count == 2) &&
reinterpret_cast<uintptr_t>(maybe_vector->data) == FIDL_ALLOC_PRESENT) {
// Table
// Manually craft the actual response which has an unknown ordinal
auto real_response =
reinterpret_cast<fidl_table_t*>(&real_msg_bytes[sizeof(fidl_message_header_t)]);
real_response->envelopes.data = reinterpret_cast<void*>(FIDL_ALLOC_PRESENT);
if (maybe_vector->count == 1) {
// The |want_more_than_30_bytes_at_ordinal_3| field was set.
// Create a message with more bytes than expected
constexpr uint32_t kUnknownBytes = 5000;
constexpr uint32_t kUnknownHandles = 0;
real_response->envelopes.count = 3;
const auto envelope_header_offset =
sizeof(fidl_message_header_t) + sizeof(fidl_table_t) + sizeof(fidl_envelope_t) * 2;
const auto envelope_payload_offset = envelope_header_offset + sizeof(fidl_envelope_t);
auto envelope = reinterpret_cast<fidl_envelope_t*>(&real_msg_bytes[envelope_header_offset]);
*envelope = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
iovec.capacity = envelope_payload_offset + kUnknownBytes;
num_handles = kUnknownHandles;
memset(&real_msg_bytes[envelope_payload_offset], 0xAA, kUnknownBytes);
} else {
// The |want_more_than_4_handles_at_ordinal_4| field was set.
// Create a message with more handles than expected
constexpr uint32_t kUnknownBytes = 16;
constexpr uint32_t kUnknownHandles = ZX_CHANNEL_MAX_MSG_HANDLES;
for (uint32_t i = 0; i < kUnknownHandles; i++) {
EXPECT_EQ(zx_event_create(0, &real_msg_handles[i]), ZX_OK);
}
real_response->envelopes.count = 4;
const auto envelope_header_offset =
sizeof(fidl_message_header_t) + sizeof(fidl_table_t) + sizeof(fidl_envelope_t) * 3;
const auto envelope_payload_offset = envelope_header_offset + sizeof(fidl_envelope_t);
auto envelope = reinterpret_cast<fidl_envelope_t*>(&real_msg_bytes[envelope_header_offset]);
*envelope = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
iovec.capacity = envelope_payload_offset + kUnknownBytes;
num_handles = kUnknownHandles;
memset(&real_msg_bytes[envelope_payload_offset], 0xBB, kUnknownBytes);
}
} else {
// Manually craft the actual response which has an unknown ordinal
constexpr uint32_t kBadOrdinal = 0x8badf00d;
static_assert(kBadOrdinal !=
static_cast<uint32_t>(test::wire::FlexibleXUnion::Tag::kWantMoreThan30Bytes));
static_assert(kBadOrdinal !=
static_cast<uint32_t>(test::wire::FlexibleXUnion::Tag::kWantMoreThan4Handles));
auto real_response =
reinterpret_cast<fidl_union_t*>(&real_msg_bytes[sizeof(fidl_message_header_t)]);
real_response->tag = kBadOrdinal;
auto indicator_response = reinterpret_cast<const fidl::internal::TransactionalResponse<
test::ReceiveFlexibleEnvelope::GetUnknownXUnionMoreHandles>*>(indicator_msg_bytes.data());
switch (indicator_response->body.xu.Which()) {
case test::wire::FlexibleXUnion::Tag::kWantMoreThan30Bytes: {
// Create a message with more bytes than expected
constexpr uint32_t kUnknownBytes = 5000;
constexpr uint32_t kUnknownHandles = 0;
real_response->envelope = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
iovec.capacity = sizeof(fidl_message_header_t) + sizeof(fidl_union_t) + kUnknownBytes;
num_handles = kUnknownHandles;
memset(&real_msg_bytes[sizeof(fidl_message_header_t) + sizeof(fidl_union_t)], 0xAA,
kUnknownBytes);
break;
}
case test::wire::FlexibleXUnion::Tag::kWantMoreThan4Handles: {
// Create a message with more handles than expected
constexpr uint32_t kUnknownBytes = 16;
constexpr uint32_t kUnknownHandles = ZX_CHANNEL_MAX_MSG_HANDLES;
for (uint32_t i = 0; i < kUnknownHandles; i++) {
EXPECT_EQ(zx_event_create(0, &real_msg_handles[i]), ZX_OK);
}
real_response->envelope = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
iovec.capacity = sizeof(fidl_message_header_t) + sizeof(fidl_union_t) + kUnknownBytes;
num_handles = kUnknownHandles;
memset(&real_msg_bytes[sizeof(fidl_message_header_t) + sizeof(fidl_union_t)], 0xBB,
kUnknownBytes);
break;
}
default:
ADD_FAILURE() << "Cannot reach here";
}
}
zx_handle_disposition_t handle_dispositions[ZX_CHANNEL_MAX_MSG_HANDLES];
for (uint32_t i = 0; i < num_handles; i++) {
handle_dispositions[i] = {
.operation = ZX_HANDLE_OP_MOVE,
.handle = real_msg_handles[i],
.type = real_msg_handle_metadata[i].obj_type,
.rights = real_msg_handle_metadata[i].rights,
.result = ZX_OK,
};
}
EXPECT_EQ(
channel_->write_etc(0, iovec.buffer, iovec.capacity, handle_dispositions, num_handles),
ZX_OK);
return ZX_OK;
}
RewriteTransaction(zx_txid_t txid, zx::unowned_channel channel)
: txid_(txid), channel_(std::move(channel)) {}
private:
zx_txid_t txid_;
zx::unowned_channel channel_;
};
class Server : fidl::WireServer<test::ReceiveFlexibleEnvelope>, private async_wait_t {
public:
void GetUnknownXUnionMoreBytes(GetUnknownXUnionMoreBytesCompleter::Sync& completer) override {
test::wire::FlexibleXUnion xunion;
fidl::Array<uint8_t, 30> array = {};
completer.Reply(test::wire::FlexibleXUnion::WithWantMoreThan30Bytes(
fidl::ObjectView<fidl::Array<uint8_t, 30>>::FromExternal(&array)));
}
void GetUnknownXUnionMoreHandles(GetUnknownXUnionMoreHandlesCompleter::Sync& completer) override {
test::wire::FlexibleXUnion xunion;
fidl::Array<zx::handle, 4> array = {};
completer.Reply(test::wire::FlexibleXUnion::WithWantMoreThan4Handles(
fidl::ObjectView<fidl::Array<zx::handle, 4>>::FromExternal(&array)));
}
void GetUnknownTableMoreBytes(GetUnknownTableMoreBytesCompleter::Sync& completer) override {
fidl::Arena allocator;
auto flexible_table = test::wire::FlexibleTable::Builder(allocator)
.want_more_than_30_bytes_at_ordinal_3({})
.Build();
completer.Reply(flexible_table);
}
void GetUnknownTableMoreHandles(GetUnknownTableMoreHandlesCompleter::Sync& completer) override {
fidl::Arena allocator;
auto flexible_table = test::wire::FlexibleTable::Builder(allocator)
.want_more_than_4_handles_at_ordinal_4({})
.Build();
completer.Reply(flexible_table);
}
Server(async_dispatcher_t* dispatcher, fidl::ServerEnd<test::ReceiveFlexibleEnvelope> channel)
: async_wait_t({
.state = ASYNC_STATE_INIT,
.handler = &MessageHandler,
.object = channel.TakeChannel().release(),
.trigger = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
.options = 0,
}),
dispatcher_(dispatcher) {
async_begin_wait(dispatcher_, this);
}
~Server() override {
async_cancel_wait(dispatcher_, this);
zx_handle_close(async_wait_t::object);
}
void HandleMessage(async_dispatcher_t* dispatcher, zx_status_t status,
const zx_packet_signal_t* signal) {
if (status != ZX_OK) {
return;
}
if (signal->observed & ZX_CHANNEL_READABLE) {
for (uint64_t i = 0; i < signal->count; i++) {
fidl::IncomingHeaderAndMessage msg =
fidl::MessageRead(zx::unowned_channel(async_wait_t::object),
fidl::ChannelMessageStorageView{
.bytes = fidl::BufferSpan(bytes_->data(), bytes_->size()),
.handles = handles_->data(),
.handle_metadata = handle_metadata_->data(),
.handle_capacity = static_cast<uint32_t>(handles_->size()),
});
if (!msg.ok()) {
return;
}
auto hdr = msg.header();
RewriteTransaction txn(hdr->txid, zx::unowned_channel(async_wait_t::object));
fidl::WireDispatch<test::ReceiveFlexibleEnvelope>(this, std::move(msg), &txn);
}
// Will only get here if every single message was handled synchronously and successfully.
async_begin_wait(dispatcher_, this);
} else {
ASSERT_TRUE(signal->observed & ZX_CHANNEL_PEER_CLOSED);
}
}
// Implement the function required by |async_wait_t|.
static void MessageHandler(async_dispatcher_t* dispatcher, async_wait_t* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
static_cast<Server*>(wait)->HandleMessage(dispatcher, status, signal);
}
private:
async_dispatcher_t* dispatcher_;
std::unique_ptr<std::array<uint8_t, ZX_CHANNEL_MAX_MSG_BYTES>> bytes_ =
std::make_unique<std::array<uint8_t, ZX_CHANNEL_MAX_MSG_BYTES>>();
std::unique_ptr<std::array<zx_handle_t, ZX_CHANNEL_MAX_MSG_HANDLES>> handles_ =
std::make_unique<std::array<zx_handle_t, ZX_CHANNEL_MAX_MSG_HANDLES>>();
std::unique_ptr<std::array<fidl_channel_handle_metadata_t, ZX_CHANNEL_MAX_MSG_HANDLES>>
handle_metadata_ = std::make_unique<
std::array<fidl_channel_handle_metadata_t, ZX_CHANNEL_MAX_MSG_HANDLES>>();
};
class FlexibleEnvelopeTest : public ::testing::Test {
protected:
void SetUp() override {
loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigAttachToCurrentThread);
ASSERT_EQ(loop_->StartThread("test_llcpp_flexible_envelope_server"), ZX_OK);
zx::result server_end = fidl::CreateEndpoints(&client_end_);
ASSERT_EQ(server_end.status_value(), ZX_OK);
server_ = std::make_unique<Server>(loop_->dispatcher(), std::move(*server_end));
}
void TearDown() override {
loop_->Quit();
loop_->JoinThreads();
}
fidl::WireSyncClient<test::ReceiveFlexibleEnvelope> TakeClient() {
EXPECT_TRUE(client_end_.is_valid());
return fidl::WireSyncClient<test::ReceiveFlexibleEnvelope>(std::move(client_end_));
}
private:
std::unique_ptr<async::Loop> loop_;
std::unique_ptr<Server> server_;
fidl::ClientEnd<test::ReceiveFlexibleEnvelope> client_end_;
};
static_assert(fidl::internal::ClampedMessageSize<
fidl::internal::TransactionalResponse<
test::ReceiveFlexibleEnvelope::GetUnknownXUnionMoreBytes>,
fidl::MessageDirection::kReceiving>() == ZX_CHANNEL_MAX_MSG_BYTES,
"Cannot assume any limit on byte size apart from the channel limit");
TEST_F(FlexibleEnvelopeTest, ReceiveUnknownVariantWithMoreBytes) {
auto client = TakeClient();
auto result = client->GetUnknownXUnionMoreBytes();
EXPECT_TRUE(result.ok());
ASSERT_EQ(result.status(), ZX_OK) << zx_status_get_string(result.status());
ASSERT_TRUE(result.value().xu.IsUnknown());
}
static_assert(fidl::internal::ClampedHandleCount<
fidl::internal::TransactionalResponse<
test::ReceiveFlexibleEnvelope::GetUnknownXUnionMoreHandles>,
fidl::MessageDirection::kReceiving>() == ZX_CHANNEL_MAX_MSG_HANDLES,
"Cannot assume any limit on handle count apart from the channel limit");
TEST_F(FlexibleEnvelopeTest, ReceiveUnknownVariantWithMoreHandles) {
auto client = TakeClient();
auto result = client->GetUnknownXUnionMoreHandles();
EXPECT_TRUE(result.ok());
ASSERT_EQ(result.status(), ZX_OK) << zx_status_get_string(result.status());
ASSERT_TRUE(result.value().xu.IsUnknown());
}
static_assert(
fidl::internal::ClampedMessageSize<fidl::internal::TransactionalResponse<
test::ReceiveFlexibleEnvelope::GetUnknownTableMoreBytes>,
fidl::MessageDirection::kReceiving>() ==
ZX_CHANNEL_MAX_MSG_BYTES,
"Cannot assume any limit on byte size apart from the channel limit");
TEST_F(FlexibleEnvelopeTest, ReceiveUnknownTableFieldWithMoreBytes) {
auto client = TakeClient();
auto result = client->GetUnknownTableMoreBytes();
EXPECT_TRUE(result.ok());
ASSERT_EQ(result.status(), ZX_OK) << zx_status_get_string(result.status());
EXPECT_FALSE(result.value().t.has_want_more_than_30_bytes_at_ordinal_3());
EXPECT_FALSE(result.value().t.has_want_more_than_4_handles_at_ordinal_4());
}
static_assert(fidl::internal::ClampedHandleCount<
fidl::internal::TransactionalResponse<
test::ReceiveFlexibleEnvelope::GetUnknownTableMoreHandles>,
fidl::MessageDirection::kReceiving>() == ZX_CHANNEL_MAX_MSG_HANDLES,
"Cannot assume any limit on handle count apart from the channel limit");
TEST_F(FlexibleEnvelopeTest, ReceiveUnknownTableFieldWithMoreHandles) {
auto client = TakeClient();
auto result = client->GetUnknownTableMoreHandles();
EXPECT_TRUE(result.ok());
ASSERT_EQ(result.status(), ZX_OK) << zx_status_get_string(result.status());
EXPECT_FALSE(result.value().t.has_want_more_than_30_bytes_at_ordinal_3());
EXPECT_FALSE(result.value().t.has_want_more_than_4_handles_at_ordinal_4());
}
// Test receiving an event with a flexible envelope that's larger than the types
// described by the FIDL schema.
class FlexibleEnvelopeEventTest : public ::testing::Test {
public:
void SetUp() final {
auto endpoints = fidl::Endpoints<test::ReceiveFlexibleEnvelope>::Create();
client_end_ = std::move(endpoints.client);
server_end_ = std::move(endpoints.server);
}
const fidl::ClientEnd<test::ReceiveFlexibleEnvelope>& client_end() const { return client_end_; }
const fidl::ServerEnd<test::ReceiveFlexibleEnvelope>& server_end() const { return server_end_; }
static constexpr uint32_t kBadOrdinal = 0x8badf00d;
static_assert(kBadOrdinal !=
static_cast<uint32_t>(test::wire::FlexibleXUnion::Tag::kWantMoreThan30Bytes));
static_assert(kBadOrdinal !=
static_cast<uint32_t>(test::wire::FlexibleXUnion::Tag::kWantMoreThan4Handles));
private:
fidl::ClientEnd<test::ReceiveFlexibleEnvelope> client_end_;
fidl::ServerEnd<test::ReceiveFlexibleEnvelope> server_end_;
};
struct MessageStorage {
template <typename FidlType>
void Init() {
FidlType value;
static_assert(fidl::IsFidlTransactionalMessage<FidlType>::value);
memcpy(bytes_, static_cast<void*>(&value), sizeof(value));
}
template <typename T>
T* Build() {
T* ptr = reinterpret_cast<T*>(&bytes_[num_bytes_]);
num_bytes_ += FIDL_ALIGN(sizeof(T));
return ptr;
}
void AddGarbage(uint32_t count) {
memset(&bytes_[num_bytes_], 0xAA, count);
num_bytes_ += FIDL_ALIGN(count);
}
void AddHandles(uint32_t count) {
for (uint32_t i = 0; i < count; i++) {
zx::event e;
ASSERT_EQ(zx::event::create(0, &e), ZX_OK);
handles_[num_handles_] = e.release();
num_handles_++;
}
}
zx_status_t Write(const zx::channel& channel) {
return channel.write(0, bytes_, num_bytes_, handles_, num_handles_);
}
private:
uint8_t bytes_[ZX_CHANNEL_MAX_MSG_BYTES] = {};
zx_handle_t handles_[ZX_CHANNEL_MAX_MSG_HANDLES] = {};
uint32_t num_bytes_ = sizeof(fidl_message_header_t);
uint32_t num_handles_ = 0;
};
static_assert(
fidl::internal::ClampedMessageSize<
fidl::internal::TransactionalEvent<test::ReceiveFlexibleEnvelope::OnUnknownXUnionMoreBytes>,
fidl::MessageDirection::kReceiving>() == ZX_CHANNEL_MAX_MSG_BYTES,
"Cannot assume any limit on byte size apart from the channel limit");
TEST_F(FlexibleEnvelopeEventTest, ReceiveUnknownXUnionFieldWithMoreBytes) {
MessageStorage storage;
storage.Init<fidl::internal::TransactionalEvent<
test::ReceiveFlexibleEnvelope::OnUnknownXUnionMoreBytes>>();
// Manually craft a xunion response with an unknown ordinal that is larger
// than expected.
auto* real_response = storage.Build<fidl_union_t>();
real_response->tag = kBadOrdinal;
constexpr uint32_t kUnknownBytes = 5000;
constexpr uint32_t kUnknownHandles = 0;
real_response->envelope = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
storage.AddGarbage(kUnknownBytes);
ASSERT_EQ(ZX_OK, storage.Write(server_end().channel()));
class EventHandler
: public fidl::testing::WireSyncEventHandlerTestBase<test::ReceiveFlexibleEnvelope> {
public:
void NotImplemented_(const std::string& name) final { ADD_FAILURE() << "Unexpected " << name; }
void OnUnknownXUnionMoreBytes(
fidl::WireEvent<test::ReceiveFlexibleEnvelope::OnUnknownXUnionMoreBytes>* event) final {
EXPECT_FALSE(event->is_want_more_than_30_bytes());
EXPECT_FALSE(event->is_want_more_than_4_handles());
EXPECT_TRUE(event->IsUnknown());
called = true;
}
bool called = false;
};
EventHandler event_handler;
fidl::Status status = event_handler.HandleOneEvent(client_end());
EXPECT_TRUE(status.ok()) << status;
EXPECT_TRUE(event_handler.called);
}
static_assert(fidl::internal::ClampedHandleCount<
fidl::internal::TransactionalEvent<
test::ReceiveFlexibleEnvelope::OnUnknownXUnionMoreHandles>,
fidl::MessageDirection::kReceiving>() == ZX_CHANNEL_MAX_MSG_HANDLES,
"Cannot assume any limit on handle count apart from the channel limit");
TEST_F(FlexibleEnvelopeEventTest, ReceiveUnknownXUnionFieldWithMoreHandles) {
MessageStorage storage;
storage.Init<fidl::internal::TransactionalEvent<
test::ReceiveFlexibleEnvelope::OnUnknownXUnionMoreHandles>>();
// Manually craft a xunion response with an unknown ordinal has more handles
// than expected.
auto* real_response = storage.Build<fidl_union_t>();
real_response->tag = kBadOrdinal;
constexpr uint32_t kUnknownBytes = 16;
constexpr uint32_t kUnknownHandles = ZX_CHANNEL_MAX_MSG_HANDLES;
real_response->envelope = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
storage.AddGarbage(kUnknownBytes);
storage.AddHandles(kUnknownHandles);
ASSERT_EQ(ZX_OK, storage.Write(server_end().channel()));
class EventHandler
: public fidl::testing::WireSyncEventHandlerTestBase<test::ReceiveFlexibleEnvelope> {
public:
void NotImplemented_(const std::string& name) final { ADD_FAILURE() << "Unexpected " << name; }
void OnUnknownXUnionMoreHandles(
fidl::WireEvent<test::ReceiveFlexibleEnvelope::OnUnknownXUnionMoreHandles>* event) final {
EXPECT_FALSE(event->is_want_more_than_30_bytes());
EXPECT_FALSE(event->is_want_more_than_4_handles());
EXPECT_TRUE(event->IsUnknown());
called = true;
}
bool called = false;
};
EventHandler event_handler;
fidl::Status status = event_handler.HandleOneEvent(client_end());
EXPECT_TRUE(status.ok()) << status;
EXPECT_TRUE(event_handler.called);
}
static_assert(
fidl::internal::ClampedMessageSize<
fidl::internal::TransactionalEvent<test::ReceiveFlexibleEnvelope::OnUnknownTableMoreBytes>,
fidl::MessageDirection::kReceiving>() == ZX_CHANNEL_MAX_MSG_BYTES,
"Cannot assume any limit on byte size apart from the channel limit");
TEST_F(FlexibleEnvelopeEventTest, ReceiveUnknownTableFieldWithMoreBytes) {
MessageStorage storage;
storage.Init<
fidl::internal::TransactionalEvent<test::ReceiveFlexibleEnvelope::OnUnknownTableMoreBytes>>();
// Manually craft a table response with an unknown ordinal that is larger
// than expected.
auto* real_response = storage.Build<fidl_table_t>();
real_response->envelopes.count = 4;
auto* envelopes = storage.Build<fidl_envelope_t[4]>();
real_response->envelopes.data = reinterpret_cast<void*>(FIDL_ALLOC_PRESENT); // NOLINT
(*envelopes)[0] = fidl_envelope_t{};
(*envelopes)[1] = fidl_envelope_t{};
(*envelopes)[2] = fidl_envelope_t{};
constexpr uint32_t kUnknownBytes = 5000;
constexpr uint32_t kUnknownHandles = 0;
(*envelopes)[3] = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
storage.AddGarbage(kUnknownBytes);
ASSERT_EQ(ZX_OK, storage.Write(server_end().channel()));
class EventHandler
: public fidl::testing::WireSyncEventHandlerTestBase<test::ReceiveFlexibleEnvelope> {
public:
void NotImplemented_(const std::string& name) final { ADD_FAILURE() << "Unexpected " << name; }
void OnUnknownTableMoreBytes(
fidl::WireEvent<test::ReceiveFlexibleEnvelope::OnUnknownTableMoreBytes>* event) final {
EXPECT_FALSE(event->has_want_more_than_30_bytes_at_ordinal_3());
EXPECT_FALSE(event->has_want_more_than_4_handles_at_ordinal_4());
EXPECT_TRUE(event->HasUnknownData());
called = true;
}
bool called = false;
};
EventHandler event_handler;
fidl::Status status = event_handler.HandleOneEvent(client_end());
EXPECT_TRUE(status.ok()) << status;
EXPECT_TRUE(event_handler.called);
}
static_assert(fidl::internal::ClampedMessageSize<
fidl::internal::TransactionalEvent<
test::ReceiveFlexibleEnvelope::OnUnknownTableMoreHandles>,
fidl::MessageDirection::kReceiving>() == ZX_CHANNEL_MAX_MSG_BYTES,
"Cannot assume any limit on handle count apart from the channel limit");
TEST_F(FlexibleEnvelopeEventTest, ReceiveUnknownTableFieldWithMoreHandles) {
MessageStorage storage;
storage.Init<fidl::internal::TransactionalEvent<
test::ReceiveFlexibleEnvelope::OnUnknownTableMoreHandles>>();
// Manually craft a table response with an unknown ordinal that has more
// handles than expected.
auto* real_response = storage.Build<fidl_table_t>();
real_response->envelopes.count = 4;
auto* envelopes = storage.Build<fidl_envelope_t[4]>();
real_response->envelopes.data = reinterpret_cast<void*>(FIDL_ALLOC_PRESENT); // NOLINT
(*envelopes)[0] = fidl_envelope_t{};
(*envelopes)[1] = fidl_envelope_t{};
(*envelopes)[2] = fidl_envelope_t{};
constexpr uint32_t kUnknownBytes = 16;
constexpr uint32_t kUnknownHandles = ZX_CHANNEL_MAX_MSG_HANDLES;
(*envelopes)[3] = fidl_envelope_t{
.num_bytes = kUnknownBytes,
.num_handles = kUnknownHandles,
};
storage.AddGarbage(kUnknownBytes);
storage.AddHandles(kUnknownHandles);
ASSERT_EQ(ZX_OK, storage.Write(server_end().channel()));
class EventHandler
: public fidl::testing::WireSyncEventHandlerTestBase<test::ReceiveFlexibleEnvelope> {
public:
void NotImplemented_(const std::string& name) final { ADD_FAILURE() << "Unexpected " << name; }
void OnUnknownTableMoreHandles(
fidl::WireEvent<test::ReceiveFlexibleEnvelope::OnUnknownTableMoreHandles>* event) final {
EXPECT_FALSE(event->has_want_more_than_30_bytes_at_ordinal_3());
EXPECT_FALSE(event->has_want_more_than_4_handles_at_ordinal_4());
EXPECT_TRUE(event->HasUnknownData());
called = true;
}
bool called = false;
};
EventHandler event_handler;
fidl::Status status = event_handler.HandleOneEvent(client_end());
EXPECT_TRUE(status.ok()) << status;
EXPECT_TRUE(event_handler.called);
}
} // namespace