blob: c1c95d590f086e9ce7fd20f3de7f57bf642ee2f3 [file]
// 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.
#ifndef LIB_FIDL_LLCPP_MESSAGE_STORAGE_H_
#define LIB_FIDL_LLCPP_MESSAGE_STORAGE_H_
#include <lib/fidl/llcpp/traits.h>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <type_traits>
#if defined(__clang__) && __has_attribute(uninitialized)
// Attribute "uninitialized" disables -ftrivial-auto-var-init=pattern
// (automatic variable initialization) for the specified variable.
// This is a security measure to better reveal memory corruptions and
// reduce leaking sensitive bits, but FIDL generated code/runtime can
// sometimes prove that a buffer is always overwritten. In those cases
// we can use this attribute to disable the compiler-inserted initialization
// and avoid the performance hit of writing to a large buffer.
#define FIDL_INTERNAL_DISABLE_AUTO_VAR_INIT __attribute__((uninitialized))
#else
#define FIDL_INTERNAL_DISABLE_AUTO_VAR_INIT
#endif
namespace fidl {
// Holds a reference to any storage buffer. This is independent of the allocation.
struct BufferSpan {
BufferSpan() = default;
BufferSpan(uint8_t* data, uint32_t capacity) : data(data), capacity(capacity) {}
uint8_t* data = nullptr;
uint32_t capacity = 0;
};
namespace internal {
// A stack allocated uninitialized array of |kSize| bytes, guaranteed to follow
// FIDL alignment.
//
// To properly ensure uninitialization, always declare objects of this type with
// FIDL_INTERNAL_DISABLE_AUTO_VAR_INIT.
template <size_t kSize>
struct InlineMessageBuffer {
static_assert(kSize % FIDL_ALIGNMENT == 0, "kSize must be FIDL-aligned");
// NOLINTNEXTLINE
InlineMessageBuffer() {}
InlineMessageBuffer(InlineMessageBuffer&&) = delete;
InlineMessageBuffer(const InlineMessageBuffer&) = delete;
InlineMessageBuffer& operator=(InlineMessageBuffer&&) = delete;
InlineMessageBuffer& operator=(const InlineMessageBuffer&) = delete;
BufferSpan view() { return BufferSpan(data(), kSize); }
uint8_t* data() { return data_; }
const uint8_t* data() const { return data_; }
constexpr size_t size() const { return kSize; }
private:
FIDL_ALIGNDECL uint8_t data_[kSize];
};
static_assert(sizeof(InlineMessageBuffer<40>) == 40);
static_assert(alignof(std::max_align_t) % FIDL_ALIGNMENT == 0,
"BoxedMessageBuffer should follow FIDL alignment when allocated on the heap.");
// A heap allocated uninitialized array of |kSize| bytes, guaranteed to follow
// FIDL alignment.
template <size_t kSize>
struct BoxedMessageBuffer {
static_assert(kSize % FIDL_ALIGNMENT == 0, "kSize must be FIDL-aligned");
BoxedMessageBuffer() { ZX_DEBUG_ASSERT(FidlIsAligned(bytes_)); }
~BoxedMessageBuffer() { delete[] bytes_; }
BoxedMessageBuffer(BoxedMessageBuffer&&) = delete;
BoxedMessageBuffer(const BoxedMessageBuffer&) = delete;
BoxedMessageBuffer& operator=(BoxedMessageBuffer&&) = delete;
BoxedMessageBuffer& operator=(const BoxedMessageBuffer&) = delete;
BufferSpan view() { return BufferSpan(data(), kSize); }
uint8_t* data() { return bytes_; }
const uint8_t* data() const { return bytes_; }
constexpr size_t size() const { return kSize; }
private:
uint8_t* bytes_ = new uint8_t[kSize];
};
} // namespace internal
} // namespace fidl
#endif // LIB_FIDL_LLCPP_MESSAGE_STORAGE_H_