summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrockot <rockot@chromium.org>2016-02-04 18:12:32 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-05 02:14:00 +0000
commit0457af10a70c2ecf0e0b11a54881fe129232b739 (patch)
treef6382c744d7c8269d3de3c1c4d8f35dc3d832dbf
parentc469cac201cc21a97b38d7bf6b5e23cac14d814f (diff)
downloadchromium_src-0457af10a70c2ecf0e0b11a54881fe129232b739.zip
chromium_src-0457af10a70c2ecf0e0b11a54881fe129232b739.tar.gz
chromium_src-0457af10a70c2ecf0e0b11a54881fe129232b739.tar.bz2
Add message sizing to basic IPC traits and struct macros.
BUG=577685 Review URL: https://codereview.chromium.org/1655333002 Cr-Commit-Position: refs/heads/master@{#373720}
-rw-r--r--base/files/file_path.cc8
-rw-r--r--base/files/file_path.h2
-rw-r--r--base/pickle.cc33
-rw-r--r--base/pickle.h36
-rw-r--r--base/pickle_unittest.cc102
-rw-r--r--ipc/ipc_message_macros.h5
-rw-r--r--ipc/ipc_message_utils.cc168
-rw-r--r--ipc/ipc_message_utils.h123
-rw-r--r--ipc/ipc_message_utils_unittest.cc26
-rw-r--r--ipc/param_traits_macros.h4
-rw-r--r--ipc/param_traits_size_macros.h40
-rw-r--r--mojo/public/cpp/bindings/lib/native_serialization.h20
-rw-r--r--mojo/public/cpp/bindings/tests/pickled_struct_blink.cc7
-rw-r--r--mojo/public/cpp/bindings/tests/pickled_struct_blink.h3
-rw-r--r--mojo/public/cpp/bindings/tests/pickled_struct_chromium.cc7
-rw-r--r--mojo/public/cpp/bindings/tests/pickled_struct_chromium.h3
16 files changed, 584 insertions, 3 deletions
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
index 5756dfc..fdaa46b 100644
--- a/base/files/file_path.cc
+++ b/base/files/file_path.cc
@@ -657,6 +657,14 @@ FilePath FilePath::FromUTF16Unsafe(const string16& utf16) {
}
#endif
+void FilePath::GetSizeForPickle(PickleSizer* sizer) const {
+#if defined(OS_WIN)
+ sizer->AddString16(path_);
+#else
+ sizer->AddString(path_);
+#endif
+}
+
void FilePath::WriteToPickle(Pickle* pickle) const {
#if defined(OS_WIN)
pickle->WriteString16(path_);
diff --git a/base/files/file_path.h b/base/files/file_path.h
index 89e9cbf..4eb712a 100644
--- a/base/files/file_path.h
+++ b/base/files/file_path.h
@@ -138,6 +138,7 @@ namespace base {
class Pickle;
class PickleIterator;
+class PickleSizer;
// An abstraction to isolate users from the differences between native
// pathnames on different platforms.
@@ -377,6 +378,7 @@ class BASE_EXPORT FilePath {
// Similar to FromUTF8Unsafe, but accepts UTF-16 instead.
static FilePath FromUTF16Unsafe(const string16& utf16);
+ void GetSizeForPickle(PickleSizer* sizer) const;
void WriteToPickle(Pickle* pickle) const;
bool ReadFromPickle(PickleIterator* iter);
diff --git a/base/pickle.cc b/base/pickle.cc
index 8aa9f62..b12ec9a 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -208,6 +208,39 @@ bool PickleIterator::ReadBytes(const char** data, int length) {
return true;
}
+PickleSizer::PickleSizer() {}
+
+PickleSizer::~PickleSizer() {}
+
+void PickleSizer::AddString(const StringPiece& value) {
+ AddInt();
+ AddBytes(static_cast<int>(value.size()));
+}
+
+void PickleSizer::AddString16(const StringPiece16& value) {
+ AddInt();
+ AddBytes(static_cast<int>(value.size() * sizeof(char16)));
+}
+
+void PickleSizer::AddData(int length) {
+ CHECK_GE(length, 0);
+ AddInt();
+ AddBytes(length);
+}
+
+void PickleSizer::AddBytes(int length) {
+ payload_size_ += bits::Align(length, sizeof(uint32_t));
+}
+
+template <size_t length> void PickleSizer::AddBytesStatic() {
+ DCHECK_LE(length, static_cast<size_t>(std::numeric_limits<int>::max()));
+ AddBytes(length);
+}
+
+template void PickleSizer::AddBytesStatic<2>();
+template void PickleSizer::AddBytesStatic<4>();
+template void PickleSizer::AddBytesStatic<8>();
+
Pickle::Attachment::Attachment() {}
Pickle::Attachment::~Attachment() {}
diff --git a/base/pickle.h b/base/pickle.h
index e50fd68..18d8afe 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -109,6 +109,42 @@ class BASE_EXPORT PickleIterator {
FRIEND_TEST_ALL_PREFIXES(PickleTest, GetReadPointerAndAdvance);
};
+// This class provides an interface analogous to base::Pickle's WriteFoo()
+// methods and can be used to accurately compute the size of a hypothetical
+// Pickle's payload without having to reference the Pickle implementation.
+class BASE_EXPORT PickleSizer {
+ public:
+ PickleSizer();
+ ~PickleSizer();
+
+ // Returns the computed size of the payload.
+ size_t payload_size() const { return payload_size_; }
+
+ void AddBool() { return AddInt(); }
+ void AddInt() { AddPOD<int>(); }
+ void AddLongUsingDangerousNonPortableLessPersistableForm() { AddPOD<long>(); }
+ void AddUInt16() { return AddPOD<uint16_t>(); }
+ void AddUInt32() { return AddPOD<uint32_t>(); }
+ void AddInt64() { return AddPOD<int64_t>(); }
+ void AddUInt64() { return AddPOD<uint64_t>(); }
+ void AddSizeT() { return AddPOD<uint64_t>(); }
+ void AddFloat() { return AddPOD<float>(); }
+ void AddDouble() { return AddPOD<double>(); }
+ void AddString(const StringPiece& value);
+ void AddString16(const StringPiece16& value);
+ void AddData(int length);
+ void AddBytes(int length);
+
+ private:
+ // Just like AddBytes() but with a compile-time size for performance.
+ template<size_t length> void BASE_EXPORT AddBytesStatic();
+
+ template <typename T>
+ void AddPOD() { AddBytesStatic<sizeof(T)>(); }
+
+ size_t payload_size_ = 0;
+};
+
// This class provides facilities for basic binary value packing and unpacking.
//
// The Pickle class supports appending primitive values (ints, strings, etc.)
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index b195a81..6dae177 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -575,4 +575,106 @@ TEST(PickleTest, ClaimBytes) {
EXPECT_EQ(42, out_value);
}
+// Checks that PickleSizer and Pickle agree on the size of things.
+TEST(PickleTest, PickleSizer) {
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteBool(true);
+ sizer.AddBool();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteInt(42);
+ sizer.AddInt();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteLongUsingDangerousNonPortableLessPersistableForm(42);
+ sizer.AddLongUsingDangerousNonPortableLessPersistableForm();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteUInt16(42);
+ sizer.AddUInt16();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteUInt32(42);
+ sizer.AddUInt32();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteInt64(42);
+ sizer.AddInt64();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteUInt64(42);
+ sizer.AddUInt64();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteSizeT(42);
+ sizer.AddSizeT();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteFloat(42.0f);
+ sizer.AddFloat();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteDouble(42.0);
+ sizer.AddDouble();
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteString(teststring);
+ sizer.AddString(teststring);
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteString16(teststring16);
+ sizer.AddString16(teststring16);
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteData(testdata, testdatalen);
+ sizer.AddData(testdatalen);
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+ {
+ TestingPickle pickle;
+ base::PickleSizer sizer;
+ pickle.WriteBytes(testdata, testdatalen);
+ sizer.AddBytes(testdatalen);
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+ }
+}
+
} // namespace base
diff --git a/ipc/ipc_message_macros.h b/ipc/ipc_message_macros.h
index 7365b6c..9e9b3e0 100644
--- a/ipc/ipc_message_macros.h
+++ b/ipc/ipc_message_macros.h
@@ -45,6 +45,11 @@
// // Generate destructors.
// #include "ipc/struct_destructor_macros.h"
// #include "path/to/YYY_message_generator.h"
+// // Generate param traits size methods.
+// #include "ipc/param_traits_size_macros.h"
+// namespace IPC {
+// #include "path/to/YYY_message_generator.h"
+// } // namespace IPC
// // Generate param traits write methods.
// #include "ipc/param_traits_write_macros.h"
// namespace IPC {
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index 6c829c2..639cedd 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -72,6 +72,65 @@ bool ReadValue(const base::Pickle* m,
base::Value** value,
int recursion);
+void GetValueSize(base::PickleSizer* sizer,
+ const base::Value* value,
+ int recursion) {
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in GetValueSize.";
+ return;
+ }
+
+ sizer->AddInt();
+ switch (value->GetType()) {
+ case base::Value::TYPE_NULL:
+ break;
+ case base::Value::TYPE_BOOLEAN:
+ sizer->AddBool();
+ break;
+ case base::Value::TYPE_INTEGER:
+ sizer->AddInt();
+ break;
+ case base::Value::TYPE_DOUBLE:
+ sizer->AddDouble();
+ break;
+ case base::Value::TYPE_STRING: {
+ const base::StringValue* result;
+ value->GetAsString(&result);
+ DCHECK(result);
+ GetParamSize(sizer, result->GetString());
+ break;
+ }
+ case base::Value::TYPE_BINARY: {
+ const base::BinaryValue* binary =
+ static_cast<const base::BinaryValue*>(value);
+ sizer->AddData(static_cast<int>(binary->GetSize()));
+ break;
+ }
+ case base::Value::TYPE_DICTIONARY: {
+ sizer->AddInt();
+ const base::DictionaryValue* dict =
+ static_cast<const base::DictionaryValue*>(value);
+ for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
+ it.Advance()) {
+ GetParamSize(sizer, it.key());
+ GetValueSize(sizer, &it.value(), recursion + 1);
+ }
+ break;
+ }
+ case base::Value::TYPE_LIST: {
+ sizer->AddInt();
+ const base::ListValue* list = static_cast<const base::ListValue*>(value);
+ for (base::ListValue::const_iterator it = list->begin();
+ it != list->end(); ++it) {
+ GetValueSize(sizer, *it, recursion + 1);
+ }
+ break;
+ }
+ default:
+ NOTREACHED() << "Invalid base::Value type.";
+ }
+}
+
void WriteValue(base::Pickle* m, const base::Value* value, int recursion) {
bool result;
if (recursion > kMaxRecursionDepth) {
@@ -278,6 +337,11 @@ void ParamTraits<bool>::Log(const param_type& p, std::string* l) {
l->append(p ? "true" : "false");
}
+void ParamTraits<signed char>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
void ParamTraits<signed char>::Write(base::Pickle* m, const param_type& p) {
m->WriteBytes(&p, sizeof(param_type));
}
@@ -296,6 +360,11 @@ void ParamTraits<signed char>::Log(const param_type& p, std::string* l) {
l->append(base::IntToString(p));
}
+void ParamTraits<unsigned char>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
void ParamTraits<unsigned char>::Write(base::Pickle* m, const param_type& p) {
m->WriteBytes(&p, sizeof(param_type));
}
@@ -314,6 +383,11 @@ void ParamTraits<unsigned char>::Log(const param_type& p, std::string* l) {
l->append(base::UintToString(p));
}
+void ParamTraits<unsigned short>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
void ParamTraits<unsigned short>::Write(base::Pickle* m, const param_type& p) {
m->WriteBytes(&p, sizeof(param_type));
}
@@ -360,6 +434,11 @@ void ParamTraits<float>::Log(const param_type& p, std::string* l) {
l->append(base::StringPrintf("%e", p));
}
+void ParamTraits<double>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddBytes(sizeof(param_type));
+}
+
void ParamTraits<double>::Write(base::Pickle* m, const param_type& p) {
m->WriteBytes(reinterpret_cast<const char*>(&p), sizeof(param_type));
}
@@ -389,6 +468,11 @@ void ParamTraits<base::string16>::Log(const param_type& p, std::string* l) {
l->append(base::UTF16ToUTF8(p));
}
+void ParamTraits<std::vector<char>>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddData(static_cast<int>(p.size()));
+}
+
void ParamTraits<std::vector<char>>::Write(base::Pickle* m,
const param_type& p) {
if (p.empty()) {
@@ -415,6 +499,11 @@ void ParamTraits<std::vector<char> >::Log(const param_type& p, std::string* l) {
LogBytes(p, l);
}
+void ParamTraits<std::vector<unsigned char>>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddData(static_cast<int>(p.size()));
+}
+
void ParamTraits<std::vector<unsigned char>>::Write(base::Pickle* m,
const param_type& p) {
if (p.empty()) {
@@ -443,6 +532,13 @@ void ParamTraits<std::vector<unsigned char> >::Log(const param_type& p,
LogBytes(p, l);
}
+void ParamTraits<std::vector<bool>>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ for (size_t i = 0; i < p.size(); ++i)
+ GetParamSize(sizer, static_cast<bool>(p[i]));
+}
+
void ParamTraits<std::vector<bool>>::Write(base::Pickle* m,
const param_type& p) {
WriteParam(m, static_cast<int>(p.size()));
@@ -500,6 +596,11 @@ void ParamTraits<BrokerableAttachment::AttachmentId>::Log(const param_type& p,
l->append(base::HexEncode(p.nonce, BrokerableAttachment::kNonceSize));
}
+void ParamTraits<base::DictionaryValue>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetValueSize(sizer, &p, 0);
+}
+
void ParamTraits<base::DictionaryValue>::Write(base::Pickle* m,
const param_type& p) {
WriteValue(m, &p, 0);
@@ -712,6 +813,11 @@ void ParamTraits<base::SharedMemoryHandle>::Log(const param_type& p,
}
#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+void ParamTraits<base::FilePath>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ p.GetSizeForPickle(sizer);
+}
+
void ParamTraits<base::FilePath>::Write(base::Pickle* m, const param_type& p) {
p.WriteToPickle(m);
}
@@ -726,6 +832,11 @@ void ParamTraits<base::FilePath>::Log(const param_type& p, std::string* l) {
ParamTraits<base::FilePath::StringType>::Log(p.value(), l);
}
+void ParamTraits<base::ListValue>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetValueSize(sizer, &p, 0);
+}
+
void ParamTraits<base::ListValue>::Write(base::Pickle* m, const param_type& p) {
WriteValue(m, &p, 0);
}
@@ -746,6 +857,12 @@ void ParamTraits<base::ListValue>::Log(const param_type& p, std::string* l) {
l->append(json);
}
+void ParamTraits<base::NullableString16>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.string());
+ GetParamSize(sizer, p.is_null());
+}
+
void ParamTraits<base::NullableString16>::Write(base::Pickle* m,
const param_type& p) {
WriteParam(m, p.string());
@@ -774,6 +891,15 @@ void ParamTraits<base::NullableString16>::Log(const param_type& p,
l->append(")");
}
+void ParamTraits<base::File::Info>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.size);
+ GetParamSize(sizer, p.is_directory);
+ GetParamSize(sizer, p.last_modified.ToDoubleT());
+ GetParamSize(sizer, p.last_accessed.ToDoubleT());
+ GetParamSize(sizer, p.creation_time.ToDoubleT());
+}
+
void ParamTraits<base::File::Info>::Write(base::Pickle* m,
const param_type& p) {
WriteParam(m, p.size);
@@ -814,6 +940,11 @@ void ParamTraits<base::File::Info>::Log(const param_type& p,
l->append(")");
}
+void ParamTraits<base::Time>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt64();
+}
+
void ParamTraits<base::Time>::Write(base::Pickle* m, const param_type& p) {
ParamTraits<int64_t>::Write(m, p.ToInternalValue());
}
@@ -832,6 +963,11 @@ void ParamTraits<base::Time>::Log(const param_type& p, std::string* l) {
ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
}
+void ParamTraits<base::TimeDelta>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt64();
+}
+
void ParamTraits<base::TimeDelta>::Write(base::Pickle* m, const param_type& p) {
ParamTraits<int64_t>::Write(m, p.ToInternalValue());
}
@@ -851,6 +987,11 @@ void ParamTraits<base::TimeDelta>::Log(const param_type& p, std::string* l) {
ParamTraits<int64_t>::Log(p.ToInternalValue(), l);
}
+void ParamTraits<base::TimeTicks>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt64();
+}
+
void ParamTraits<base::TimeTicks>::Write(base::Pickle* m, const param_type& p) {
ParamTraits<int64_t>::Write(m, p.ToInternalValue());
}
@@ -902,6 +1043,19 @@ void ParamTraits<IPC::ChannelHandle>::Log(const param_type& p,
l->append(")");
}
+void ParamTraits<LogData>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ GetParamSize(sizer, p.channel);
+ GetParamSize(sizer, p.routing_id);
+ GetParamSize(sizer, p.type);
+ GetParamSize(sizer, p.flags);
+ GetParamSize(sizer, p.sent);
+ GetParamSize(sizer, p.receive);
+ GetParamSize(sizer, p.dispatch);
+ GetParamSize(sizer, p.message_name);
+ GetParamSize(sizer, p.params);
+}
+
void ParamTraits<LogData>::Write(base::Pickle* m, const param_type& p) {
WriteParam(m, p.channel);
WriteParam(m, p.routing_id);
@@ -979,6 +1133,11 @@ void ParamTraits<Message>::Log(const Message& p, std::string* l) {
}
#if defined(OS_WIN)
+void ParamTraits<HANDLE>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt();
+}
+
// Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
// bit systems. That's why we use the Windows macros to convert to 32 bits.
void ParamTraits<HANDLE>::Write(base::Pickle* m, const param_type& p) {
@@ -999,6 +1158,11 @@ void ParamTraits<HANDLE>::Log(const param_type& p, std::string* l) {
l->append(base::StringPrintf("0x%p", p));
}
+void ParamTraits<LOGFONT>::GetSize(base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddData(sizeof(LOGFONT));
+}
+
void ParamTraits<LOGFONT>::Write(base::Pickle* m, const param_type& p) {
m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT));
}
@@ -1024,6 +1188,10 @@ void ParamTraits<LOGFONT>::Log(const param_type& p, std::string* l) {
l->append(base::StringPrintf("<LOGFONT>"));
}
+void ParamTraits<MSG>::GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddData(sizeof(MSG));
+}
+
void ParamTraits<MSG>::Write(base::Pickle* m, const param_type& p) {
m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG));
}
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index 5654e75..d8b6607 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -100,6 +100,12 @@ struct NoParams {
};
template <class P>
+static inline void GetParamSize(base::PickleSizer* sizer, const P& p) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ ParamTraits<Type>::GetSize(sizer, static_cast<const Type&>(p));
+}
+
+template <class P>
static inline void WriteParam(base::Pickle* m, const P& p) {
typedef typename SimilarTypeTraits<P>::Type Type;
ParamTraits<Type>::Write(m, static_cast<const Type& >(p));
@@ -124,6 +130,9 @@ static inline void LogParam(const P& p, std::string* l) {
template <>
struct ParamTraits<bool> {
typedef bool param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddBool();
+ }
static void Write(base::Pickle* m, const param_type& p) { m->WriteBool(p); }
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -136,6 +145,7 @@ struct ParamTraits<bool> {
template <>
struct IPC_EXPORT ParamTraits<signed char> {
typedef signed char param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -146,6 +156,7 @@ struct IPC_EXPORT ParamTraits<signed char> {
template <>
struct IPC_EXPORT ParamTraits<unsigned char> {
typedef unsigned char param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -156,6 +167,7 @@ struct IPC_EXPORT ParamTraits<unsigned char> {
template <>
struct IPC_EXPORT ParamTraits<unsigned short> {
typedef unsigned short param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -166,6 +178,9 @@ struct IPC_EXPORT ParamTraits<unsigned short> {
template <>
struct ParamTraits<int> {
typedef int param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt();
+ }
static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); }
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -178,6 +193,9 @@ struct ParamTraits<int> {
template <>
struct ParamTraits<unsigned int> {
typedef unsigned int param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt();
+ }
static void Write(base::Pickle* m, const param_type& p) { m->WriteInt(p); }
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -190,6 +208,9 @@ struct ParamTraits<unsigned int> {
template <>
struct ParamTraits<long> {
typedef long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddLongUsingDangerousNonPortableLessPersistableForm();
+ }
static void Write(base::Pickle* m, const param_type& p) {
m->WriteLongUsingDangerousNonPortableLessPersistableForm(p);
}
@@ -204,6 +225,9 @@ struct ParamTraits<long> {
template <>
struct ParamTraits<unsigned long> {
typedef unsigned long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddLongUsingDangerousNonPortableLessPersistableForm();
+ }
static void Write(base::Pickle* m, const param_type& p) {
m->WriteLongUsingDangerousNonPortableLessPersistableForm(p);
}
@@ -218,6 +242,9 @@ struct ParamTraits<unsigned long> {
template <>
struct ParamTraits<long long> {
typedef long long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt64();
+ }
static void Write(base::Pickle* m, const param_type& p) {
m->WriteInt64(static_cast<int64_t>(p));
}
@@ -232,6 +259,9 @@ struct ParamTraits<long long> {
template <>
struct ParamTraits<unsigned long long> {
typedef unsigned long long param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddInt64();
+ }
static void Write(base::Pickle* m, const param_type& p) { m->WriteInt64(p); }
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -247,6 +277,9 @@ struct ParamTraits<unsigned long long> {
template <>
struct IPC_EXPORT ParamTraits<float> {
typedef float param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddFloat();
+ }
static void Write(base::Pickle* m, const param_type& p) { m->WriteFloat(p); }
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -259,6 +292,7 @@ struct IPC_EXPORT ParamTraits<float> {
template <>
struct IPC_EXPORT ParamTraits<double> {
typedef double param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -271,6 +305,9 @@ struct IPC_EXPORT ParamTraits<double> {
template <>
struct ParamTraits<std::string> {
typedef std::string param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddString(p);
+ }
static void Write(base::Pickle* m, const param_type& p) { m->WriteString(p); }
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -283,6 +320,9 @@ struct ParamTraits<std::string> {
template <>
struct ParamTraits<base::string16> {
typedef base::string16 param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ sizer->AddString16(p);
+ }
static void Write(base::Pickle* m, const param_type& p) {
m->WriteString16(p);
}
@@ -297,6 +337,7 @@ struct ParamTraits<base::string16> {
template <>
struct IPC_EXPORT ParamTraits<std::vector<char> > {
typedef std::vector<char> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle*,
base::PickleIterator* iter,
@@ -307,6 +348,7 @@ struct IPC_EXPORT ParamTraits<std::vector<char> > {
template <>
struct IPC_EXPORT ParamTraits<std::vector<unsigned char> > {
typedef std::vector<unsigned char> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -317,6 +359,7 @@ struct IPC_EXPORT ParamTraits<std::vector<unsigned char> > {
template <>
struct IPC_EXPORT ParamTraits<std::vector<bool> > {
typedef std::vector<bool> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -327,6 +370,11 @@ struct IPC_EXPORT ParamTraits<std::vector<bool> > {
template <class P>
struct ParamTraits<std::vector<P> > {
typedef std::vector<P> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ for (size_t i = 0; i < p.size(); i++)
+ GetParamSize(sizer, p[i]);
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, static_cast<int>(p.size()));
for (size_t i = 0; i < p.size(); i++)
@@ -361,6 +409,12 @@ struct ParamTraits<std::vector<P> > {
template <class P>
struct ParamTraits<std::set<P> > {
typedef std::set<P> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter)
+ GetParamSize(sizer, *iter);
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, static_cast<int>(p.size()));
typename param_type::const_iterator iter;
@@ -389,6 +443,14 @@ struct ParamTraits<std::set<P> > {
template <class K, class V, class C, class A>
struct ParamTraits<std::map<K, V, C, A> > {
typedef std::map<K, V, C, A> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ GetParamSize(sizer, iter->first);
+ GetParamSize(sizer, iter->second);
+ }
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, static_cast<int>(p.size()));
typename param_type::const_iterator iter;
@@ -421,6 +483,10 @@ struct ParamTraits<std::map<K, V, C, A> > {
template <class A, class B>
struct ParamTraits<std::pair<A, B> > {
typedef std::pair<A, B> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, p.first);
+ GetParamSize(sizer, p.second);
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, p.first);
WriteParam(m, p.second);
@@ -455,6 +521,7 @@ struct IPC_EXPORT ParamTraits<BrokerableAttachment::AttachmentId> {
template <>
struct IPC_EXPORT ParamTraits<base::DictionaryValue> {
typedef base::DictionaryValue param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -504,6 +571,7 @@ struct IPC_EXPORT ParamTraits<base::SharedMemoryHandle> {
template <>
struct IPC_EXPORT ParamTraits<base::FilePath> {
typedef base::FilePath param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -514,6 +582,7 @@ struct IPC_EXPORT ParamTraits<base::FilePath> {
template <>
struct IPC_EXPORT ParamTraits<base::ListValue> {
typedef base::ListValue param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -524,6 +593,7 @@ struct IPC_EXPORT ParamTraits<base::ListValue> {
template <>
struct IPC_EXPORT ParamTraits<base::NullableString16> {
typedef base::NullableString16 param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -534,6 +604,7 @@ struct IPC_EXPORT ParamTraits<base::NullableString16> {
template <>
struct IPC_EXPORT ParamTraits<base::File::Info> {
typedef base::File::Info param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -556,6 +627,7 @@ struct SimilarTypeTraits<HWND> {
template <>
struct IPC_EXPORT ParamTraits<base::Time> {
typedef base::Time param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -566,6 +638,7 @@ struct IPC_EXPORT ParamTraits<base::Time> {
template <>
struct IPC_EXPORT ParamTraits<base::TimeDelta> {
typedef base::TimeDelta param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -576,6 +649,7 @@ struct IPC_EXPORT ParamTraits<base::TimeDelta> {
template <>
struct IPC_EXPORT ParamTraits<base::TimeTicks> {
typedef base::TimeTicks param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -586,6 +660,7 @@ struct IPC_EXPORT ParamTraits<base::TimeTicks> {
template <>
struct ParamTraits<base::Tuple<>> {
typedef base::Tuple<> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {}
static void Write(base::Pickle* m, const param_type& p) {}
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -599,6 +674,9 @@ struct ParamTraits<base::Tuple<>> {
template <class A>
struct ParamTraits<base::Tuple<A>> {
typedef base::Tuple<A> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, base::get<0>(p));
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, base::get<0>(p));
}
@@ -615,6 +693,10 @@ struct ParamTraits<base::Tuple<A>> {
template <class A, class B>
struct ParamTraits<base::Tuple<A, B>> {
typedef base::Tuple<A, B> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, base::get<0>(p));
+ GetParamSize(sizer, base::get<1>(p));
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, base::get<0>(p));
WriteParam(m, base::get<1>(p));
@@ -635,6 +717,11 @@ struct ParamTraits<base::Tuple<A, B>> {
template <class A, class B, class C>
struct ParamTraits<base::Tuple<A, B, C>> {
typedef base::Tuple<A, B, C> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, base::get<0>(p));
+ GetParamSize(sizer, base::get<1>(p));
+ GetParamSize(sizer, base::get<2>(p));
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, base::get<0>(p));
WriteParam(m, base::get<1>(p));
@@ -659,6 +746,12 @@ struct ParamTraits<base::Tuple<A, B, C>> {
template <class A, class B, class C, class D>
struct ParamTraits<base::Tuple<A, B, C, D>> {
typedef base::Tuple<A, B, C, D> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, base::get<0>(p));
+ GetParamSize(sizer, base::get<1>(p));
+ GetParamSize(sizer, base::get<2>(p));
+ GetParamSize(sizer, base::get<3>(p));
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, base::get<0>(p));
WriteParam(m, base::get<1>(p));
@@ -687,6 +780,13 @@ struct ParamTraits<base::Tuple<A, B, C, D>> {
template <class A, class B, class C, class D, class E>
struct ParamTraits<base::Tuple<A, B, C, D, E>> {
typedef base::Tuple<A, B, C, D, E> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, base::get<0>(p));
+ GetParamSize(sizer, base::get<1>(p));
+ GetParamSize(sizer, base::get<2>(p));
+ GetParamSize(sizer, base::get<3>(p));
+ GetParamSize(sizer, base::get<4>(p));
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, base::get<0>(p));
WriteParam(m, base::get<1>(p));
@@ -752,6 +852,11 @@ struct ParamTraits<ScopedVector<P> > {
template <class P, size_t stack_capacity>
struct ParamTraits<base::StackVector<P, stack_capacity> > {
typedef base::StackVector<P, stack_capacity> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p->size()));
+ for (size_t i = 0; i < p->size(); i++)
+ GetParamSize(sizer, p[i]);
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, static_cast<int>(p->size()));
for (size_t i = 0; i < p->size(); i++)
@@ -792,6 +897,14 @@ struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > {
typedef base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> param_type;
typedef typename param_type::key_type K;
typedef typename param_type::data_type V;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ GetParamSize(sizer, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ GetParamSize(sizer, iter->first);
+ GetParamSize(sizer, iter->second);
+ }
+ }
static void Write(base::Pickle* m, const param_type& p) {
WriteParam(m, static_cast<int>(p.size()));
typename param_type::const_iterator iter;
@@ -824,6 +937,12 @@ struct ParamTraits<base::SmallMap<NormalMap, kArraySize, EqualKey, MapInit> > {
template <class P>
struct ParamTraits<scoped_ptr<P> > {
typedef scoped_ptr<P> param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+ bool valid = !!p;
+ GetParamSize(sizer, valid);
+ if (valid)
+ GetParamSize(sizer, *p);
+ }
static void Write(base::Pickle* m, const param_type& p) {
bool valid = !!p;
WriteParam(m, valid);
@@ -875,6 +994,7 @@ struct IPC_EXPORT ParamTraits<IPC::ChannelHandle> {
template <>
struct IPC_EXPORT ParamTraits<LogData> {
typedef LogData param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -897,6 +1017,7 @@ struct IPC_EXPORT ParamTraits<Message> {
template <>
struct IPC_EXPORT ParamTraits<HANDLE> {
typedef HANDLE param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -907,6 +1028,7 @@ struct IPC_EXPORT ParamTraits<HANDLE> {
template <>
struct IPC_EXPORT ParamTraits<LOGFONT> {
typedef LOGFONT param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
@@ -917,6 +1039,7 @@ struct IPC_EXPORT ParamTraits<LOGFONT> {
template <>
struct IPC_EXPORT ParamTraits<MSG> {
typedef MSG param_type;
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
diff --git a/ipc/ipc_message_utils_unittest.cc b/ipc/ipc_message_utils_unittest.cc
index f3aa31a..0c9a7da 100644
--- a/ipc/ipc_message_utils_unittest.cc
+++ b/ipc/ipc_message_utils_unittest.cc
@@ -90,5 +90,31 @@ TEST(IPCMessageUtilsTest, StackVector) {
EXPECT_EQ(stack_vector[i], output[i]);
}
+// Tests that PickleSizer and Pickle agree on the size of a complex base::Value.
+TEST(IPCMessageUtilsTest, ValueSize) {
+ scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue);
+ value->SetWithoutPathExpansion("foo", new base::FundamentalValue(42));
+ value->SetWithoutPathExpansion("bar", new base::FundamentalValue(3.14));
+ value->SetWithoutPathExpansion("baz", new base::StringValue("hello"));
+ value->SetWithoutPathExpansion("qux", base::Value::CreateNullValue());
+
+ scoped_ptr<base::DictionaryValue> nested_dict(new base::DictionaryValue);
+ nested_dict->SetWithoutPathExpansion("foobar", new base::FundamentalValue(5));
+ value->SetWithoutPathExpansion("nested", std::move(nested_dict));
+
+ scoped_ptr<base::ListValue> list_value(new base::ListValue);
+ list_value->Append(new base::StringValue("im a string"));
+ list_value->Append(new base::StringValue("im another string"));
+ value->SetWithoutPathExpansion("awesome-list", std::move(list_value));
+
+ base::Pickle pickle;
+ IPC::WriteParam(&pickle, *value);
+
+ base::PickleSizer sizer;
+ IPC::GetParamSize(&sizer, *value);
+
+ EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+}
+
} // namespace
} // namespace IPC
diff --git a/ipc/param_traits_macros.h b/ipc/param_traits_macros.h
index 7c4cc692..1003440 100644
--- a/ipc/param_traits_macros.h
+++ b/ipc/param_traits_macros.h
@@ -13,6 +13,8 @@
template <> \
struct IPC_MESSAGE_EXPORT ParamTraits<struct_name> { \
typedef struct_name param_type; \
+ static void GetSize(base::PickleSizer* sizer, \
+ const param_type& p); \
static void Write(base::Pickle* m, const param_type& p); \
static bool Read(const base::Pickle* m, \
base::PickleIterator* iter, \
@@ -53,6 +55,8 @@
template <> \
struct IPC_MESSAGE_EXPORT ParamTraits<enum_name> { \
typedef enum_name param_type; \
+ static void GetSize(base::PickleSizer* sizer, \
+ const param_type& p); \
static void Write(base::Pickle* m, const param_type& p); \
static bool Read(const base::Pickle* m, \
base::PickleIterator* iter, \
diff --git a/ipc/param_traits_size_macros.h b/ipc/param_traits_size_macros.h
new file mode 100644
index 0000000..142b55a
--- /dev/null
+++ b/ipc/param_traits_size_macros.h
@@ -0,0 +1,40 @@
+// Copyright 2016 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 IPC_PARAM_TRAITS_SIZE_MACROS_H_
+#define IPC_PARAM_TRAITS_SIZE_MACROS_H_
+
+// Null out all the macros that need nulling.
+#include "ipc/ipc_message_null_macros.h"
+
+// STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur.
+#undef IPC_STRUCT_BEGIN_WITH_PARENT
+#undef IPC_STRUCT_MEMBER
+#undef IPC_STRUCT_END
+#define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \
+ IPC_STRUCT_TRAITS_BEGIN(struct_name)
+#define IPC_STRUCT_MEMBER(type, name, ...) IPC_STRUCT_TRAITS_MEMBER(name)
+#define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END()
+
+// Set up so next include will generate size methods.
+#undef IPC_STRUCT_TRAITS_BEGIN
+#undef IPC_STRUCT_TRAITS_MEMBER
+#undef IPC_STRUCT_TRAITS_PARENT
+#undef IPC_STRUCT_TRAITS_END
+#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \
+ void ParamTraits<struct_name>::GetSize(base::PickleSizer* sizer, \
+ const param_type& p) {
+#define IPC_STRUCT_TRAITS_MEMBER(name) GetParamSize(sizer, p.name);
+#define IPC_STRUCT_TRAITS_PARENT(type) ParamTraits<type>::GetSize(sizer, p);
+#define IPC_STRUCT_TRAITS_END() }
+
+#undef IPC_ENUM_TRAITS_VALIDATE
+#define IPC_ENUM_TRAITS_VALIDATE(enum_name, validation_expression) \
+ void ParamTraits<enum_name>::GetSize(base::PickleSizer* sizer, \
+ const param_type& value) { \
+ sizer->AddInt(); \
+ }
+
+#endif // IPC_PARAM_TRAITS_SIZE_MACROS_H_
+
diff --git a/mojo/public/cpp/bindings/lib/native_serialization.h b/mojo/public/cpp/bindings/lib/native_serialization.h
index 3c2e54e..d2f9088 100644
--- a/mojo/public/cpp/bindings/lib/native_serialization.h
+++ b/mojo/public/cpp/bindings/lib/native_serialization.h
@@ -29,7 +29,9 @@ struct ShouldUseNativeSerializer { static const bool value = false; };
template <typename T>
size_t GetSerializedSizeNative_(const T& value) {
- return IPC::ParamTraits<T>::GetSize(value);
+ base::PickleSizer sizer;
+ IPC::ParamTraits<T>::GetSize(&sizer, value);
+ return sizer.payload_size() + sizeof(ArrayHeader);
}
template <typename T>
@@ -46,8 +48,24 @@ void SerializeNative_(const T& value,
base::Pickle* pickle = pickler->pickle();
const char* data_start = pickle->end_of_payload();
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+ const char* payload_base = pickle->payload();
+ size_t size_before_write = pickle->payload_size();
+#endif
+
IPC::ParamTraits<T>::Write(pickle, value);
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+ // Ensure the pickle buffer hasn't moved.
+ DCHECK_EQ(payload_base, pickle->payload());
+ // Explicitly validate that the value returned by GetSize() always equals the
+ // number of bytes actually written by Write().
+ DCHECK_GE(pickle->payload_size(), size_before_write);
+ size_t bytes_written = pickle->payload_size() - size_before_write;
+ DCHECK_EQ(bytes_written + sizeof(ArrayHeader),
+ GetSerializedSizeNative_(value));
+#endif
+
// Fix up the ArrayHeader so that num_elements contains the length of the
// pickled data.
size_t pickled_size = pickle->end_of_payload() - data_start;
diff --git a/mojo/public/cpp/bindings/tests/pickled_struct_blink.cc b/mojo/public/cpp/bindings/tests/pickled_struct_blink.cc
index 602f15ae..57a1915 100644
--- a/mojo/public/cpp/bindings/tests/pickled_struct_blink.cc
+++ b/mojo/public/cpp/bindings/tests/pickled_struct_blink.cc
@@ -25,6 +25,13 @@ PickledStructBlink::~PickledStructBlink() {}
namespace IPC {
+void ParamTraits<mojo::test::PickledStructBlink>::GetSize(
+ base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt();
+ sizer->AddInt();
+}
+
void ParamTraits<mojo::test::PickledStructBlink>::Write(base::Pickle* m,
const param_type& p) {
m->WriteInt(p.foo());
diff --git a/mojo/public/cpp/bindings/tests/pickled_struct_blink.h b/mojo/public/cpp/bindings/tests/pickled_struct_blink.h
index c4406b4..ce5b364 100644
--- a/mojo/public/cpp/bindings/tests/pickled_struct_blink.h
+++ b/mojo/public/cpp/bindings/tests/pickled_struct_blink.h
@@ -16,6 +16,7 @@
namespace base {
class Pickle;
class PickleIterator;
+class PickleSizer;
}
namespace mojo {
@@ -61,7 +62,7 @@ template <>
struct ParamTraits<mojo::test::PickledStructBlink> {
using param_type = mojo::test::PickledStructBlink;
- static size_t GetSize(const param_type& p) { return 8; }
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,
diff --git a/mojo/public/cpp/bindings/tests/pickled_struct_chromium.cc b/mojo/public/cpp/bindings/tests/pickled_struct_chromium.cc
index d45a44a5..0dee03f 100644
--- a/mojo/public/cpp/bindings/tests/pickled_struct_chromium.cc
+++ b/mojo/public/cpp/bindings/tests/pickled_struct_chromium.cc
@@ -22,6 +22,13 @@ PickledStructChromium::~PickledStructChromium() {}
namespace IPC {
+void ParamTraits<mojo::test::PickledStructChromium>::GetSize(
+ base::PickleSizer* sizer,
+ const param_type& p) {
+ sizer->AddInt();
+ sizer->AddInt();
+}
+
void ParamTraits<mojo::test::PickledStructChromium>::Write(
base::Pickle* m,
const param_type& p) {
diff --git a/mojo/public/cpp/bindings/tests/pickled_struct_chromium.h b/mojo/public/cpp/bindings/tests/pickled_struct_chromium.h
index b84f7b3..ec34572 100644
--- a/mojo/public/cpp/bindings/tests/pickled_struct_chromium.h
+++ b/mojo/public/cpp/bindings/tests/pickled_struct_chromium.h
@@ -15,6 +15,7 @@
namespace base {
class Pickle;
class PickleIterator;
+class PickleSizer;
}
namespace mojo {
@@ -55,7 +56,7 @@ template <>
struct ParamTraits<mojo::test::PickledStructChromium> {
using param_type = mojo::test::PickledStructChromium;
- static size_t GetSize(const param_type& p) { return 8; }
+ static void GetSize(base::PickleSizer* sizer, const param_type& p);
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
base::PickleIterator* iter,