Bug 1596562: Add ParamTraits specializations for mozilla::Vector and std::vector; r=froydnj,bwc

While the need for adding `mozilla::Vector` is self-evident, we also need
`std::vector` so that we can send some pre-existing telemetry data structures
that use it.

The new implementations are basically modified from the `nsTArray`
specializations. Note that the `mozilla::Vector` specialization does support
any type of allocator, so we still check for OOM failures in that case.

This patch also removes the specialization for `std::vector` that lives in
WebRTC in favour of the centralized implementation.

Differential Revision: https://phabricator.services.mozilla.com/D53085

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Aaron Klotz 2019-11-18 19:45:41 +00:00
parent 976b5d7d73
commit abf8d763be
2 changed files with 159 additions and 30 deletions

View File

@ -20,36 +20,6 @@ typedef std::vector<std::string> StringVector;
namespace IPC {
template <typename T>
struct ParamTraits<std::vector<T>> {
typedef std::vector<T> paramType;
static void Write(Message* aMsg, const paramType& aParam) {
aMsg->WriteUInt32(aParam.size());
for (const T& elem : aParam) {
WriteParam(aMsg, elem);
}
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
uint32_t size;
if (!aMsg->ReadUInt32(aIter, &size)) {
return false;
}
while (size--) {
// Only works when T is movable. Meh.
T elem;
if (!ReadParam(aMsg, aIter, &elem)) {
return false;
}
aResult->emplace_back(std::move(elem));
}
return true;
}
};
template <>
struct ParamTraits<mozilla::dom::OwningStringOrStringSequence> {
typedef mozilla::dom::OwningStringOrStringSequence paramType;

View File

@ -24,11 +24,14 @@
#endif
#include "mozilla/TypeTraits.h"
#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/Vector.h"
#include <limits>
#include <stdint.h>
#include <type_traits>
#include <vector>
#include "nsDebug.h"
#include "nsExceptionHandler.h"
#include "nsHashKeys.h"
#include "nsID.h"
@ -638,6 +641,162 @@ struct ParamTraits<AutoTArray<E, N>> : ParamTraits<nsTArray<E>> {
typedef AutoTArray<E, N> paramType;
};
template <typename E, size_t N, typename AP>
struct ParamTraits<mozilla::Vector<E, N, AP>> {
typedef mozilla::Vector<E, N, AP> paramType;
// We write arrays of integer or floating-point data using a single pickling
// call, rather than writing each element individually. We deliberately do
// not use mozilla::IsPod here because it is perfectly reasonable to have
// a data structure T for which IsPod<T>::value is true, yet also have a
// ParamTraits<T> specialization.
static const bool sUseWriteBytes =
(mozilla::IsIntegral<E>::value || mozilla::IsFloatingPoint<E>::value);
static void Write(Message* aMsg, const paramType& aParam) {
uint32_t length = aParam.length();
WriteParam(aMsg, length);
if (sUseWriteBytes) {
int pickledLength = 0;
MOZ_RELEASE_ASSERT(ByteLengthIsValid(length, sizeof(E), &pickledLength));
aMsg->WriteBytes(aParam.begin(), pickledLength);
return;
}
for (const E& elem : aParam) {
WriteParam(aMsg, elem);
}
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
uint32_t length;
if (!ReadParam(aMsg, aIter, &length)) {
return false;
}
if (sUseWriteBytes) {
int pickledLength = 0;
if (!ByteLengthIsValid(length, sizeof(E), &pickledLength)) {
return false;
}
if (!aResult->resizeUninitialized(length)) {
// So that OOM failure shows up as OOM crash instead of IPC FatalError.
NS_ABORT_OOM(length * sizeof(E));
}
E* elements = aResult->begin();
return aMsg->ReadBytesInto(aIter, elements, pickledLength);
}
// Each ReadParam<E> may read more than 1 byte each; this is an attempt
// to minimally validate that the length isn't much larger than what's
// actually available in aMsg.
if (!aMsg->HasBytesAvailable(aIter, length)) {
return false;
}
if (!aResult->resize(length)) {
// So that OOM failure shows up as OOM crash instead of IPC FatalError.
NS_ABORT_OOM(length * sizeof(E));
}
for (uint32_t index = 0; index < length; ++index) {
if (!ReadParam(aMsg, aIter, &((*aResult)[index]))) {
return false;
}
}
return true;
}
static void Log(const paramType& aParam, std::wstring* aLog) {
for (uint32_t index = 0, len = aParam.length(); index < len; ++index) {
if (index) {
aLog->append(L" ");
}
LogParam(aParam[index], aLog);
}
}
};
template <typename E>
struct ParamTraits<std::vector<E>> {
typedef std::vector<E> paramType;
// We write arrays of integer or floating-point data using a single pickling
// call, rather than writing each element individually. We deliberately do
// not use mozilla::IsPod here because it is perfectly reasonable to have
// a data structure T for which IsPod<T>::value is true, yet also have a
// ParamTraits<T> specialization.
static const bool sUseWriteBytes =
(mozilla::IsIntegral<E>::value || mozilla::IsFloatingPoint<E>::value);
static void Write(Message* aMsg, const paramType& aParam) {
uint32_t length = aParam.size();
WriteParam(aMsg, length);
if (sUseWriteBytes) {
int pickledLength = 0;
MOZ_RELEASE_ASSERT(ByteLengthIsValid(length, sizeof(E), &pickledLength));
aMsg->WriteBytes(aParam.data(), pickledLength);
return;
}
for (const E& elem : aParam) {
WriteParam(aMsg, elem);
}
}
static bool Read(const Message* aMsg, PickleIterator* aIter,
paramType* aResult) {
uint32_t length;
if (!ReadParam(aMsg, aIter, &length)) {
return false;
}
if (sUseWriteBytes) {
int pickledLength = 0;
if (!ByteLengthIsValid(length, sizeof(E), &pickledLength)) {
return false;
}
aResult->resize(length);
E* elements = aResult->data();
return aMsg->ReadBytesInto(aIter, elements, pickledLength);
}
// Each ReadParam<E> may read more than 1 byte each; this is an attempt
// to minimally validate that the length isn't much larger than what's
// actually available in aMsg.
if (!aMsg->HasBytesAvailable(aIter, length)) {
return false;
}
aResult->resize(length);
for (uint32_t index = 0; index < length; ++index) {
if (!ReadParam(aMsg, aIter, &((*aResult)[index]))) {
return false;
}
}
return true;
}
static void Log(const paramType& aParam, std::wstring* aLog) {
for (uint32_t index = 0, len = aParam.size(); index < len; ++index) {
if (index) {
aLog->append(L" ");
}
LogParam(aParam[index], aLog);
}
}
};
template <>
struct ParamTraits<float> {
typedef float paramType;