[mojo] Use base::Pickle for Message storage.
This CL modifies the mojo::Message implementation so that
its storage is always backed by a base::Pickle.
Part of a series of changes to support custom mojom serialization:
1. https://codereview.chromium.org/1515423002
2. https://codereview.chromium.org/1517043004
3. https://codereview.chromium.org/1524693002
4. https://codereview.chromium.org/1520153002
5. This CL
6. https://codereview.chromium.org/1526533002
7. https://codereview.chromium.org/1524703002
BUG=569669
Review URL: https://codereview.chromium.org/1524613002
Cr-Commit-Position: refs/heads/master@{#365766}
diff --git a/base/pickle.cc b/base/pickle.cc
index 6fcdece3..678c425 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -329,6 +329,13 @@
header_ = reinterpret_cast<Header*>(p);
}
+void* Pickle::ClaimBytes(size_t num_bytes) {
+ void* p = ClaimUninitializedBytesInternal(num_bytes);
+ CHECK(p);
+ memset(p, 0, num_bytes);
+ return p;
+}
+
size_t Pickle::GetTotalAllocatedSize() const {
if (capacity_after_header_ == kCapacityReadOnly)
return 0;
@@ -384,10 +391,9 @@
template void Pickle::WriteBytesStatic<4>(const void* data);
template void Pickle::WriteBytesStatic<8>(const void* data);
-inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+inline void* Pickle::ClaimUninitializedBytesInternal(size_t length) {
DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
<< "oops: pickle is readonly";
- MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
size_t data_len = bits::Align(length, sizeof(uint32_t));
DCHECK_GE(data_len, length);
#ifdef ARCH_CPU_64_BITS
@@ -404,10 +410,18 @@
}
char* write = mutable_payload() + write_offset_;
- memcpy(write, data, length);
- memset(write + length, 0, data_len - length);
+ memset(write + length, 0, data_len - length); // Always initialize padding
header_->payload_size = static_cast<uint32_t>(new_size);
write_offset_ = new_size;
+ return write;
+}
+
+inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+ DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
+ << "oops: pickle is readonly";
+ MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
+ void* write = ClaimUninitializedBytesInternal(length);
+ memcpy(write, data, length);
}
} // namespace base
diff --git a/base/pickle.h b/base/pickle.h
index 72b33ddc..8e82c62 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -258,6 +258,13 @@
// of the header.
void Resize(size_t new_capacity);
+ // Claims |num_bytes| bytes of payload. This is similar to Reserve() in that
+ // it may grow the capacity, but it also advances the write offset of the
+ // pickle by |num_bytes|. Claimed memory, including padding, is zeroed.
+ //
+ // Returns the address of the first byte claimed.
+ void* ClaimBytes(size_t num_bytes);
+
// Find the end of the pickled data that starts at range_start. Returns NULL
// if the entire Pickle is not found in the given data range.
static const char* FindNext(size_t header_size,
@@ -299,6 +306,8 @@
WriteBytesStatic<sizeof(data)>(&data);
return true;
}
+
+ inline void* ClaimUninitializedBytesInternal(size_t num_bytes);
inline void WriteBytesCommon(const void* data, size_t length);
FRIEND_TEST_ALL_PREFIXES(PickleTest, DeepCopyResize);
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index f58e7ece..6804614 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -524,4 +524,50 @@
EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header());
}
+namespace {
+
+// Publicly exposes the ClaimBytes interface for testing.
+class TestingPickle : public Pickle {
+ public:
+ TestingPickle() {}
+
+ void* ClaimBytes(size_t num_bytes) { return Pickle::ClaimBytes(num_bytes); }
+};
+
+} // namespace
+
+// Checks that claimed bytes are zero-initialized.
+TEST(PickleTest, ClaimBytesInitialization) {
+ static const int kChunkSize = 64;
+ TestingPickle pickle;
+ const char* bytes = static_cast<const char*>(pickle.ClaimBytes(kChunkSize));
+ for (size_t i = 0; i < kChunkSize; ++i) {
+ EXPECT_EQ(0, bytes[i]);
+ }
+}
+
+// Checks that ClaimBytes properly advances the write offset.
+TEST(PickleTest, ClaimBytes) {
+ std::string data("Hello, world!");
+
+ TestingPickle pickle;
+ pickle.WriteSizeT(data.size());
+ void* bytes = pickle.ClaimBytes(data.size());
+ pickle.WriteInt(42);
+ memcpy(bytes, data.data(), data.size());
+
+ PickleIterator iter(pickle);
+ size_t out_data_length;
+ EXPECT_TRUE(iter.ReadSizeT(&out_data_length));
+ EXPECT_EQ(data.size(), out_data_length);
+
+ const char* out_data = nullptr;
+ EXPECT_TRUE(iter.ReadBytes(&out_data, out_data_length));
+ EXPECT_EQ(data, std::string(out_data, out_data_length));
+
+ int out_value;
+ EXPECT_TRUE(iter.ReadInt(&out_value));
+ EXPECT_EQ(42, out_value);
+}
+
} // namespace base
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 3cc4dbf..f18ad01 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -53,6 +53,8 @@
"lib/multiplex_router.cc",
"lib/multiplex_router.h",
"lib/no_interface.cc",
+ "lib/pickle_buffer.cc",
+ "lib/pickle_buffer.h",
"lib/pipe_control_message_handler.cc",
"lib/pipe_control_message_handler.h",
"lib/pipe_control_message_handler_delegate.h",
@@ -83,6 +85,7 @@
public_deps = [
":callback",
+ "//base",
"//mojo/public/cpp/system",
]
diff --git a/mojo/public/cpp/bindings/lib/buffer.h b/mojo/public/cpp/bindings/lib/buffer.h
index c3b570e..98bbce0e 100644
--- a/mojo/public/cpp/bindings/lib/buffer.h
+++ b/mojo/public/cpp/bindings/lib/buffer.h
@@ -10,12 +10,18 @@
namespace mojo {
namespace internal {
+class PickleBuffer;
+
// Buffer provides a way to allocate memory. Allocations are 8-byte aligned and
// zero-initialized. Allocations remain valid for the lifetime of the Buffer.
class Buffer {
public:
virtual ~Buffer() {}
virtual void* Allocate(size_t num_bytes) = 0;
+
+ // TODO(rockot): Remove this. It's a hack to get a PickleBuffer in
+ // Serialize_ calls without having to update every call site.
+ virtual PickleBuffer* AsPickleBuffer() = 0;
};
} // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.cc b/mojo/public/cpp/bindings/lib/fixed_buffer.cc
index c81fc6e..bfaea59 100644
--- a/mojo/public/cpp/bindings/lib/fixed_buffer.cc
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.cc
@@ -38,6 +38,8 @@
return result;
}
+PickleBuffer* FixedBuffer::AsPickleBuffer() { return nullptr; }
+
FixedBufferForTesting::FixedBufferForTesting(size_t size) {
size_ = internal::Align(size);
// Use calloc here to ensure all message memory is zero'd out.
diff --git a/mojo/public/cpp/bindings/lib/fixed_buffer.h b/mojo/public/cpp/bindings/lib/fixed_buffer.h
index 83eaf97..5e389f1f 100644
--- a/mojo/public/cpp/bindings/lib/fixed_buffer.h
+++ b/mojo/public/cpp/bindings/lib/fixed_buffer.h
@@ -49,6 +49,8 @@
// memory is zero-filled.
void* Allocate(size_t num_bytes) override;
+ PickleBuffer* AsPickleBuffer() override;
+
protected:
char* ptr_;
size_t cursor_;
diff --git a/mojo/public/cpp/bindings/lib/message.cc b/mojo/public/cpp/bindings/lib/message.cc
index 6b563e7..23ef162 100644
--- a/mojo/public/cpp/bindings/lib/message.cc
+++ b/mojo/public/cpp/bindings/lib/message.cc
@@ -13,54 +13,30 @@
namespace mojo {
Message::Message() {
- Initialize();
}
Message::~Message() {
- FreeDataAndCloseHandles();
+ CloseHandles();
}
-void Message::Reset() {
- FreeDataAndCloseHandles();
-
- handles_.clear();
- Initialize();
-}
-
-void Message::AllocData(uint32_t num_bytes) {
- MOJO_DCHECK(!data_);
- data_num_bytes_ = num_bytes;
- data_ = static_cast<internal::MessageData*>(calloc(num_bytes, 1));
-}
-
-void Message::AllocUninitializedData(uint32_t num_bytes) {
- MOJO_DCHECK(!data_);
- data_num_bytes_ = num_bytes;
- data_ = static_cast<internal::MessageData*>(malloc(num_bytes));
+void Message::Initialize(size_t capacity, bool zero_initialized) {
+ DCHECK(!buffer_);
+ buffer_.reset(new internal::PickleBuffer(capacity, zero_initialized));
}
void Message::MoveTo(Message* destination) {
MOJO_DCHECK(this != destination);
- destination->FreeDataAndCloseHandles();
-
// No copy needed.
- destination->data_num_bytes_ = data_num_bytes_;
- destination->data_ = data_;
+ std::swap(destination->buffer_, buffer_);
std::swap(destination->handles_, handles_);
+ CloseHandles();
handles_.clear();
- Initialize();
+ buffer_.reset();
}
-void Message::Initialize() {
- data_num_bytes_ = 0;
- data_ = nullptr;
-}
-
-void Message::FreeDataAndCloseHandles() {
- free(data_);
-
+void Message::CloseHandles() {
for (std::vector<Handle>::iterator it = handles_.begin();
it != handles_.end(); ++it) {
if (it->is_valid())
@@ -84,16 +60,18 @@
return rv;
Message message;
- message.AllocUninitializedData(num_bytes);
+ message.Initialize(num_bytes, false /* zero_initialized */);
+
+ void* mutable_data = message.buffer()->Allocate(num_bytes);
message.mutable_handles()->resize(num_handles);
rv = ReadMessageRaw(
handle,
- message.mutable_data(),
+ mutable_data,
&num_bytes,
message.mutable_handles()->empty()
? nullptr
- : reinterpret_cast<MojoHandle*>(&message.mutable_handles()->front()),
+ : reinterpret_cast<MojoHandle*>(message.mutable_handles()->data()),
&num_handles,
MOJO_READ_MESSAGE_FLAG_NONE);
if (receiver && rv == MOJO_RESULT_OK)
diff --git a/mojo/public/cpp/bindings/lib/message_builder.cc b/mojo/public/cpp/bindings/lib/message_builder.cc
index 25f1862..5319f4b 100644
--- a/mojo/public/cpp/bindings/lib/message_builder.cc
+++ b/mojo/public/cpp/bindings/lib/message_builder.cc
@@ -17,10 +17,10 @@
}
MessageBuilder::MessageBuilder(uint32_t name, size_t payload_size) {
- Initialize(sizeof(MessageHeader) + payload_size);
+ InitializeMessage(sizeof(MessageHeader) + payload_size);
MessageHeader* header;
- Allocate(&buf_, &header);
+ Allocate(message_.buffer(), &header);
header->version = 0;
header->name = name;
}
@@ -30,18 +30,19 @@
MessageBuilder::MessageBuilder() {}
-void MessageBuilder::Initialize(size_t size) {
- message_.AllocData(static_cast<uint32_t>(Align(size)));
- buf_.Initialize(message_.mutable_data(), message_.data_num_bytes());
+void MessageBuilder::InitializeMessage(size_t size) {
+ message_.Initialize(static_cast<uint32_t>(Align(size)),
+ true /* zero_initialized */);
}
MessageWithRequestIDBuilder::MessageWithRequestIDBuilder(uint32_t name,
size_t payload_size,
uint32_t flags,
uint64_t request_id) {
- Initialize(sizeof(MessageHeaderWithRequestID) + payload_size);
+ InitializeMessage(sizeof(MessageHeaderWithRequestID) + payload_size);
+
MessageHeaderWithRequestID* header;
- Allocate(&buf_, &header);
+ Allocate(message_.buffer(), &header);
header->version = 1;
header->name = name;
header->flags = flags;
diff --git a/mojo/public/cpp/bindings/lib/message_builder.h b/mojo/public/cpp/bindings/lib/message_builder.h
index 86ae71db..5fba7453 100644
--- a/mojo/public/cpp/bindings/lib/message_builder.h
+++ b/mojo/public/cpp/bindings/lib/message_builder.h
@@ -7,7 +7,6 @@
#include <stdint.h>
-#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
#include "mojo/public/cpp/bindings/lib/message_internal.h"
#include "mojo/public/cpp/bindings/message.h"
@@ -21,15 +20,14 @@
MessageBuilder(uint32_t name, size_t payload_size);
~MessageBuilder();
- Buffer* buffer() { return &buf_; }
+ Buffer* buffer() { return message_.buffer(); }
Message* message() { return &message_; }
protected:
MessageBuilder();
- void Initialize(size_t size);
+ void InitializeMessage(size_t size);
Message message_;
- FixedBuffer buf_;
MOJO_DISALLOW_COPY_AND_ASSIGN(MessageBuilder);
};
diff --git a/mojo/public/cpp/bindings/lib/message_internal.h b/mojo/public/cpp/bindings/lib/message_internal.h
index 97b9619..8bc2e0da 100644
--- a/mojo/public/cpp/bindings/lib/message_internal.h
+++ b/mojo/public/cpp/bindings/lib/message_internal.h
@@ -35,13 +35,6 @@
static_assert(sizeof(MessageHeaderWithRequestID) == 32,
"Bad sizeof(MessageHeaderWithRequestID)");
-struct MessageData {
- MessageHeader header;
-};
-
-static_assert(sizeof(MessageData) == sizeof(MessageHeader),
- "Bad sizeof(MessageData)");
-
#pragma pack(pop)
} // namespace internal
diff --git a/mojo/public/cpp/bindings/lib/pickle_buffer.cc b/mojo/public/cpp/bindings/lib/pickle_buffer.cc
new file mode 100644
index 0000000..cb481a9
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/pickle_buffer.cc
@@ -0,0 +1,96 @@
+// Copyright 2015 The Chromium 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 "mojo/public/cpp/bindings/lib/pickle_buffer.h"
+
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/pickle.h"
+#include "mojo/public/cpp/bindings/lib/bindings_serialization.h"
+
+namespace mojo {
+namespace internal {
+
+class PickleBuffer::Storage : public base::Pickle {
+ public:
+ explicit Storage(size_t num_bytes);
+ ~Storage() override {}
+
+ size_t available_capacity() const {
+ return capacity_after_header() - payload_size();
+ }
+
+ void* GetData() { return static_cast<void*>(mutable_payload()); }
+ void* Claim(size_t num_bytes) { return ClaimBytes(num_bytes); }
+
+ private:
+ // TODO(rockot): Stop wasting 8 bytes per buffer.
+ //
+ // We don't use Pickle's header at all, but its base header type consumes 4
+ // bytes. We waste another 4 bytes to keep our actual buffer aligned to an
+ // 8-byte boundary.
+ //
+ // The reason we don't use base::Pickle's header is that it stores payload
+ // length in the first 4 bytes. Mojo Messages are packed like mojom structs,
+ // where the first 4 bytes are header size rather than payload size.
+ struct PaddedHeader : public base::Pickle::Header {
+ uint32_t padding;
+ };
+
+ static_assert(sizeof(PaddedHeader) % 8 == 0,
+ "PickleBuffer requires a Pickle header size with 8-byte alignment.");
+
+ DISALLOW_COPY_AND_ASSIGN(Storage);
+};
+
+PickleBuffer::Storage::Storage(size_t num_bytes)
+ : base::Pickle(sizeof(PaddedHeader)) {
+ headerT<PaddedHeader>()->padding = 0;
+ Resize(num_bytes);
+}
+
+PickleBuffer::PickleBuffer(size_t num_bytes, bool zero_initialized)
+ : storage_(new Storage(num_bytes)) {
+ if (zero_initialized)
+ memset(storage_->GetData(), 0, num_bytes);
+}
+
+PickleBuffer::~PickleBuffer() {
+}
+
+const void* PickleBuffer::data() const { return storage_->GetData(); }
+
+size_t PickleBuffer::data_num_bytes() const { return storage_->payload_size(); }
+
+base::Pickle* PickleBuffer::pickle() const {
+ return storage_.get();
+}
+
+void* PickleBuffer::Allocate(size_t num_bytes) {
+ DCHECK(storage_);
+
+ // The last allocation may terminate in between 8-byte boundaries. Pad the
+ // front of this allocation if that's the case.
+ size_t padded_capacity = Align(storage_->payload_size());
+ DCHECK_GE(padded_capacity, storage_->payload_size());
+
+ size_t padding_bytes = padded_capacity - storage_->payload_size();
+ size_t allocation_size = padding_bytes + num_bytes;
+ const void* previous_data_location = storage_->GetData();
+ if (storage_->available_capacity() < allocation_size) {
+ NOTREACHED() <<
+ "Message buffers must be fully allocated before serialization.";
+ return nullptr;
+ }
+ char* p = static_cast<char*>(storage_->Claim(allocation_size));
+ DCHECK_EQ(storage_->GetData(), previous_data_location);
+ return p + padding_bytes;
+}
+
+PickleBuffer* PickleBuffer::AsPickleBuffer() { return this; }
+
+} // namespace internal
+} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/pickle_buffer.h b/mojo/public/cpp/bindings/lib/pickle_buffer.h
new file mode 100644
index 0000000..efbfcc8
--- /dev/null
+++ b/mojo/public/cpp/bindings/lib/pickle_buffer.h
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium 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 MOJO_PUBLIC_CPP_BINDINGS_LIB_PICKLE_BUFFER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_PICKLE_BUFFER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "mojo/public/cpp/bindings/lib/buffer.h"
+
+namespace mojo {
+namespace internal {
+
+// An implementation of Buffer which uses base::Pickle for its backing. Note
+// that this does not use Pickle's header structure at all, instead storing
+// the complete Message (including header) in the Pickle's payload.
+class PickleBuffer : public Buffer {
+ public:
+ PickleBuffer(size_t num_bytes, bool zero_initialized);
+ ~PickleBuffer() override;
+
+ const void* data() const;
+
+ void* data() {
+ return const_cast<void*>(static_cast<const PickleBuffer*>(this)->data());
+ }
+
+ size_t data_num_bytes() const;
+
+ base::Pickle* pickle() const;
+
+ private:
+ class Storage;
+
+ // Buffer implementation. Note that this cannot grow the Pickle's capacity and
+ // it is an error to Allocate() more bytes in total than have been
+ // pre-allocated using ReserveCapacity() or ReserveUninitializedCapacity().
+ //
+ // This guarantees that the returned data is aligned on an 8-byte boundary.
+ void* Allocate(size_t num_bytes) override;
+ PickleBuffer* AsPickleBuffer() override;
+
+ scoped_ptr<Storage> storage_;
+
+ DISALLOW_COPY_AND_ASSIGN(PickleBuffer);
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_PICKLE_BUFFER_H_
diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h
index b0a403b..ed77f310 100644
--- a/mojo/public/cpp/bindings/message.h
+++ b/mojo/public/cpp/bindings/message.h
@@ -5,9 +5,12 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_
#define MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_
+#include <limits>
#include <vector>
+#include "base/memory/scoped_ptr.h"
#include "mojo/public/cpp/bindings/lib/message_internal.h"
+#include "mojo/public/cpp/bindings/lib/pickle_buffer.h"
#include "mojo/public/cpp/environment/logging.h"
namespace mojo {
@@ -21,66 +24,74 @@
Message();
~Message();
- void Reset();
-
- void AllocData(uint32_t num_bytes);
- void AllocUninitializedData(uint32_t num_bytes);
+ void Initialize(size_t capacity, bool zero_initialized);
// Transfers data and handles to |destination|.
void MoveTo(Message* destination);
- uint32_t data_num_bytes() const { return data_num_bytes_; }
+ uint32_t data_num_bytes() const {
+ MOJO_DCHECK(buffer_->data_num_bytes() <=
+ std::numeric_limits<uint32_t>::max());
+ return static_cast<uint32_t>(buffer_->data_num_bytes());
+ }
// Access the raw bytes of the message.
const uint8_t* data() const {
- return reinterpret_cast<const uint8_t*>(data_);
+ return static_cast<const uint8_t*>(buffer_->data());
}
- uint8_t* mutable_data() { return reinterpret_cast<uint8_t*>(data_); }
+
+ uint8_t* mutable_data() { return static_cast<uint8_t*>(buffer_->data()); }
// Access the header.
- const internal::MessageHeader* header() const { return &data_->header; }
+ const internal::MessageHeader* header() const {
+ return static_cast<const internal::MessageHeader*>(buffer_->data());
+ }
- uint32_t interface_id() const { return data_->header.interface_id; }
- void set_interface_id(uint32_t id) { data_->header.interface_id = id; }
+ internal::MessageHeader* header() {
+ return const_cast<internal::MessageHeader*>(
+ static_cast<const Message*>(this)->header());
+ }
- uint32_t name() const { return data_->header.name; }
- bool has_flag(uint32_t flag) const { return !!(data_->header.flags & flag); }
+ uint32_t interface_id() const { return header()->interface_id; }
+ void set_interface_id(uint32_t id) { header()->interface_id = id; }
+
+ uint32_t name() const { return header()->name; }
+ bool has_flag(uint32_t flag) const { return !!(header()->flags & flag); }
// Access the request_id field (if present).
- bool has_request_id() const { return data_->header.version >= 1; }
+ bool has_request_id() const { return header()->version >= 1; }
uint64_t request_id() const {
MOJO_DCHECK(has_request_id());
return static_cast<const internal::MessageHeaderWithRequestID*>(
- &data_->header)->request_id;
+ header())->request_id;
}
void set_request_id(uint64_t request_id) {
MOJO_DCHECK(has_request_id());
- static_cast<internal::MessageHeaderWithRequestID*>(&data_->header)
+ static_cast<internal::MessageHeaderWithRequestID*>(header())
->request_id = request_id;
}
// Access the payload.
- const uint8_t* payload() const {
- return reinterpret_cast<const uint8_t*>(data_) + data_->header.num_bytes;
- }
- uint8_t* mutable_payload() {
- return reinterpret_cast<uint8_t*>(data_) + data_->header.num_bytes;
- }
+ const uint8_t* payload() const { return data() + header()->num_bytes; }
+ uint8_t* mutable_payload() { return const_cast<uint8_t*>(payload()); }
uint32_t payload_num_bytes() const {
- MOJO_DCHECK(data_num_bytes_ >= data_->header.num_bytes);
- return data_num_bytes_ - data_->header.num_bytes;
+ MOJO_DCHECK(buffer_->data_num_bytes() >= header()->num_bytes);
+ size_t num_bytes = buffer_->data_num_bytes() - header()->num_bytes;
+ MOJO_DCHECK(num_bytes <= std::numeric_limits<uint32_t>::max());
+ return static_cast<uint32_t>(num_bytes);
}
// Access the handles.
const std::vector<Handle>* handles() const { return &handles_; }
std::vector<Handle>* mutable_handles() { return &handles_; }
- private:
- void Initialize();
- void FreeDataAndCloseHandles();
+ // Access the underlying Buffer interface.
+ internal::Buffer* buffer() { return buffer_.get(); }
- uint32_t data_num_bytes_;
- internal::MessageData* data_;
+ private:
+ void CloseHandles();
+
+ scoped_ptr<internal::PickleBuffer> buffer_;
std::vector<Handle> handles_;
MOJO_DISALLOW_COPY_AND_ASSIGN(Message);
diff --git a/mojo/public/cpp/bindings/tests/validation_unittest.cc b/mojo/public/cpp/bindings/tests/validation_unittest.cc
index f3ff9ab..7153a59 100644
--- a/mojo/public/cpp/bindings/tests/validation_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/validation_unittest.cc
@@ -148,9 +148,10 @@
return false;
}
- message->AllocUninitializedData(static_cast<uint32_t>(data.size()));
+ message->Initialize(static_cast<uint32_t>(data.size()),
+ false /* zero_initialized */);
if (!data.empty())
- memcpy(message->mutable_data(), &data[0], data.size());
+ memcpy(message->buffer()->Allocate(data.size()), &data[0], data.size());
message->mutable_handles()->resize(num_handles);
return true;
diff --git a/third_party/mojo/mojo_public.gyp b/third_party/mojo/mojo_public.gyp
index d62e57e..d9d77eabf 100644
--- a/third_party/mojo/mojo_public.gyp
+++ b/third_party/mojo/mojo_public.gyp
@@ -147,6 +147,8 @@
'../../mojo/public/cpp/bindings/lib/multiplex_router.cc',
'../../mojo/public/cpp/bindings/lib/multiplex_router.h',
'../../mojo/public/cpp/bindings/lib/no_interface.cc',
+ '../../mojo/public/cpp/bindings/lib/pickle_buffer.cc',
+ '../../mojo/public/cpp/bindings/lib/pickle_buffer.h',
'../../mojo/public/cpp/bindings/lib/pipe_control_message_handler.cc',
'../../mojo/public/cpp/bindings/lib/pipe_control_message_handler.h',
'../../mojo/public/cpp/bindings/lib/pipe_control_message_handler_delegate.h',
@@ -176,6 +178,7 @@
'>@(mojom_generated_sources)',
],
'dependencies': [
+ '../../base/base.gyp:base',
'mojo_interface_bindings_cpp_sources',
],
},