зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1475409 - Part 3: Make the different categories of types in xptinfo more explicit, r=mccr8
Summary: This should make it more clear which types have which behaviours, and should make it easier to add new types without forgetting to handle a special case somewhere. Depends On D2114 Reviewers: mccr8! Tags: #secure-revision Bug #: 1475409 Differential Revision: https://phabricator.services.mozilla.com/D2115
This commit is contained in:
Родитель
b24e4f4b40
Коммит
4e4ab925ca
|
@ -1637,9 +1637,9 @@ xpc::InnerCleanupValue(const nsXPTType& aType, void* aValue, uint32_t aArrayLen)
|
||||||
MOZ_CRASH("Unknown Type!");
|
MOZ_CRASH("Unknown Type!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Null out the pointer if we have it.
|
// Clear any non-complex values to the valid '0' state.
|
||||||
if (aType.HasPointerRepr()) {
|
if (!aType.IsComplex()) {
|
||||||
*(void**)aValue = nullptr;
|
aType.ZeroValue(aValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1672,7 +1672,7 @@ xpc::InitializeValue(const nsXPTType& aType, void* aValue)
|
||||||
|
|
||||||
// The remaining types all have valid states where all bytes are '0'.
|
// The remaining types all have valid states where all bytes are '0'.
|
||||||
default:
|
default:
|
||||||
memset(aValue, 0, aType.Stride());
|
aType.ZeroValue(aValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,7 +530,10 @@ xpc::CleanupValue(const nsXPTType& aType,
|
||||||
// Check if we can do a cheap early return, and only perform the inner call
|
// Check if we can do a cheap early return, and only perform the inner call
|
||||||
// if we can't. We never have to clean up null pointer types or arithmetic
|
// if we can't. We never have to clean up null pointer types or arithmetic
|
||||||
// types.
|
// types.
|
||||||
if (aType.IsArithmetic() || (aType.HasPointerRepr() && !*(void**)aValue)) {
|
//
|
||||||
|
// NOTE: We can skip zeroing arithmetic types in CleanupValue, as they are
|
||||||
|
// already in a valid state.
|
||||||
|
if (aType.IsArithmetic() || (aType.IsPointer() && !*(void**)aValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
xpc::InnerCleanupValue(aType, aValue, aArrayLen);
|
xpc::InnerCleanupValue(aType, aValue, aArrayLen);
|
||||||
|
|
|
@ -745,25 +745,27 @@ nsXPCWrappedJSClass::CleanupOutparams(const nsXPTMethodInfo* info,
|
||||||
if (!param.IsOut())
|
if (!param.IsOut())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Extract the array length so we can use it in CleanupValue.
|
MOZ_ASSERT(param.IsIndirect(), "Outparams are always indirect");
|
||||||
|
|
||||||
|
// Call 'CleanupValue' on parameters which we know to be initialized:
|
||||||
|
// 1. Complex parameters (initialized by caller)
|
||||||
|
// 2. 'inout' parameters (initialized by caller)
|
||||||
|
// 3. 'out' parameters when 'inOutOnly' is 'false' (initialized by us)
|
||||||
|
//
|
||||||
|
// We skip non-complex 'out' parameters before the call, as they may
|
||||||
|
// contain random junk.
|
||||||
|
if (param.Type().IsComplex() || param.IsIn() || !inOutOnly) {
|
||||||
uint32_t arrayLen = 0;
|
uint32_t arrayLen = 0;
|
||||||
if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
|
if (!GetArraySizeFromParam(info, param.Type(), nativeParams, &arrayLen))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MOZ_ASSERT(param.IsIndirect(), "Outparams are always indirect");
|
|
||||||
|
|
||||||
// The inOutOnly flag is necessary because full outparams may contain
|
|
||||||
// uninitialized junk before the call is made, and we don't want to try
|
|
||||||
// to clean up uninitialized junk.
|
|
||||||
if (!inOutOnly || param.IsIn()) {
|
|
||||||
xpc::CleanupValue(param.Type(), nativeParams[i].val.p, arrayLen);
|
xpc::CleanupValue(param.Type(), nativeParams[i].val.p, arrayLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if we didn't call CleanupValue, null out any pointers. This is
|
// Ensure our parameters are in a clean state. Complex values are always
|
||||||
// just to protect C++ callers which may read garbage if they forget to
|
// handled by CleanupValue, and others have a valid null representation.
|
||||||
// check the error value.
|
if (!param.Type().IsComplex()) {
|
||||||
if (param.Type().HasPointerRepr()) {
|
param.Type().ZeroValue(nativeParams[i].val.p);
|
||||||
*(void**)nativeParams[i].val.p = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,13 @@ static_assert(sizeof(nsXPTInterfaceInfo) == 28, "wrong size?");
|
||||||
enum nsXPTTypeTag : uint8_t
|
enum nsXPTTypeTag : uint8_t
|
||||||
{
|
{
|
||||||
// Arithmetic (POD) Types
|
// Arithmetic (POD) Types
|
||||||
|
// - Do not require cleanup,
|
||||||
|
// - All bit patterns are valid,
|
||||||
|
// - Outparams may be uninitialized by caller,
|
||||||
|
// - Directly supported in xptcall.
|
||||||
|
//
|
||||||
|
// NOTE: The name 'Arithmetic' comes from Harbison/Steele. Despite being a tad
|
||||||
|
// unclear, it is used frequently in xptcall, so is unlikely to be changed.
|
||||||
TD_INT8 = 0,
|
TD_INT8 = 0,
|
||||||
TD_INT16 = 1,
|
TD_INT16 = 1,
|
||||||
TD_INT32 = 2,
|
TD_INT32 = 2,
|
||||||
|
@ -167,27 +174,42 @@ enum nsXPTTypeTag : uint8_t
|
||||||
TD_BOOL = 10,
|
TD_BOOL = 10,
|
||||||
TD_CHAR = 11,
|
TD_CHAR = 11,
|
||||||
TD_WCHAR = 12,
|
TD_WCHAR = 12,
|
||||||
|
_TD_LAST_ARITHMETIC = TD_WCHAR,
|
||||||
|
|
||||||
// Non-Arithmetic Types
|
// Pointer Types
|
||||||
|
// - Require cleanup unless NULL,
|
||||||
|
// - All-zeros (NULL) bit pattern is valid,
|
||||||
|
// - Outparams may be uninitialized by caller,
|
||||||
|
// - Supported in xptcall as raw pointer.
|
||||||
TD_VOID = 13,
|
TD_VOID = 13,
|
||||||
TD_PNSIID = 14,
|
TD_PNSIID = 14,
|
||||||
TD_DOMSTRING = 15,
|
TD_PSTRING = 15,
|
||||||
TD_PSTRING = 16,
|
TD_PWSTRING = 16,
|
||||||
TD_PWSTRING = 17,
|
TD_INTERFACE_TYPE = 17,
|
||||||
TD_INTERFACE_TYPE = 18,
|
TD_INTERFACE_IS_TYPE = 18,
|
||||||
TD_INTERFACE_IS_TYPE = 19,
|
TD_ARRAY = 19,
|
||||||
TD_ARRAY = 20,
|
TD_PSTRING_SIZE_IS = 20,
|
||||||
TD_PSTRING_SIZE_IS = 21,
|
TD_PWSTRING_SIZE_IS = 21,
|
||||||
TD_PWSTRING_SIZE_IS = 22,
|
TD_DOMOBJECT = 22,
|
||||||
TD_UTF8STRING = 23,
|
TD_PROMISE = 23,
|
||||||
TD_CSTRING = 24,
|
_TD_LAST_POINTER = TD_PROMISE,
|
||||||
TD_ASTRING = 25,
|
|
||||||
TD_JSVAL = 26,
|
// Complex Types
|
||||||
TD_DOMOBJECT = 27,
|
// - Require cleanup,
|
||||||
TD_PROMISE = 28,
|
// - Always passed indirectly,
|
||||||
TD_SEQUENCE = 29
|
// - Outparams must be initialized by caller,
|
||||||
|
// - Supported in xptcall due to indirection.
|
||||||
|
TD_DOMSTRING = 24,
|
||||||
|
TD_UTF8STRING = 25,
|
||||||
|
TD_CSTRING = 26,
|
||||||
|
TD_ASTRING = 27,
|
||||||
|
TD_JSVAL = 28,
|
||||||
|
TD_SEQUENCE = 29,
|
||||||
|
_TD_LAST_COMPLEX = TD_SEQUENCE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static_assert(_TD_LAST_COMPLEX < 32, "nsXPTTypeTag must fit in 5 bits");
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A nsXPTType is a union used to identify the type of a method argument or
|
* A nsXPTType is a union used to identify the type of a method argument or
|
||||||
|
@ -239,33 +261,22 @@ public:
|
||||||
return xpt::detail::GetDOMObjectInfo(Data16());
|
return xpt::detail::GetDOMObjectInfo(Data16());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'Arithmetic' here roughly means that the value is self-contained and
|
// See the comments in nsXPTTypeTag for an explanation as to what each of
|
||||||
// doesn't depend on anything else in memory (ie: not a pointer, not an
|
// these categories mean.
|
||||||
// XPCOM object, not a jsval, etc).
|
bool IsArithmetic() const { return Tag() <= _TD_LAST_ARITHMETIC; }
|
||||||
//
|
bool IsPointer() const { return !IsArithmetic() && Tag() <= _TD_LAST_POINTER; }
|
||||||
// Supposedly this terminology comes from Harbison/Steele, but it's still
|
bool IsComplex() const { return Tag() > _TD_LAST_POINTER; }
|
||||||
// a rather crappy name. We'd change it if it wasn't used all over the
|
|
||||||
// place in xptcall. :-(
|
|
||||||
bool IsArithmetic() const { return Tag() <= TD_WCHAR; }
|
|
||||||
|
|
||||||
bool IsInterfacePointer() const {
|
bool IsInterfacePointer() const {
|
||||||
return Tag() == TD_INTERFACE_TYPE || Tag() == TD_INTERFACE_IS_TYPE;
|
return Tag() == TD_INTERFACE_TYPE || Tag() == TD_INTERFACE_IS_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsArray() const { return Tag() == TD_ARRAY; }
|
|
||||||
|
|
||||||
bool IsDependent() const {
|
bool IsDependent() const {
|
||||||
return (Tag() == TD_SEQUENCE && InnermostType().IsDependent()) ||
|
return (Tag() == TD_SEQUENCE && InnermostType().IsDependent()) ||
|
||||||
Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_ARRAY ||
|
Tag() == TD_INTERFACE_IS_TYPE || Tag() == TD_ARRAY ||
|
||||||
Tag() == TD_PSTRING_SIZE_IS || Tag() == TD_PWSTRING_SIZE_IS;
|
Tag() == TD_PSTRING_SIZE_IS || Tag() == TD_PWSTRING_SIZE_IS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsAlwaysIndirect() const {
|
|
||||||
return Tag() == TD_ASTRING || Tag() == TD_DOMSTRING ||
|
|
||||||
Tag() == TD_CSTRING || Tag() == TD_UTF8STRING ||
|
|
||||||
Tag() == TD_JSVAL || Tag() == TD_SEQUENCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap a nested type to its innermost value (e.g. through arrays).
|
// Unwrap a nested type to its innermost value (e.g. through arrays).
|
||||||
const nsXPTType& InnermostType() const {
|
const nsXPTType& InnermostType() const {
|
||||||
if (Tag() == TD_ARRAY || Tag() == TD_SEQUENCE) {
|
if (Tag() == TD_ARRAY || Tag() == TD_SEQUENCE) {
|
||||||
|
@ -274,15 +285,20 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper methods for working with the type's native representation.
|
// In-memory size of native type in bytes.
|
||||||
inline size_t Stride() const;
|
inline size_t Stride() const;
|
||||||
inline bool HasPointerRepr() const;
|
|
||||||
|
|
||||||
// Offset the given base pointer to reference the element at the given index.
|
// Offset the given base pointer to reference the element at the given index.
|
||||||
void* ElementPtr(const void* aBase, uint32_t aIndex) const {
|
void* ElementPtr(const void* aBase, uint32_t aIndex) const {
|
||||||
return (char*)aBase + (aIndex * Stride());
|
return (char*)aBase + (aIndex * Stride());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Zero out a native value of the given type. The type must not be 'complex'.
|
||||||
|
void ZeroValue(void* aValue) const {
|
||||||
|
MOZ_RELEASE_ASSERT(!IsComplex(), "Cannot zero a complex value");
|
||||||
|
memset(aValue, 0, Stride());
|
||||||
|
}
|
||||||
|
|
||||||
// Indexes into the extra types array of a small set of known types.
|
// Indexes into the extra types array of a small set of known types.
|
||||||
enum class Idx : uint8_t
|
enum class Idx : uint8_t
|
||||||
{
|
{
|
||||||
|
@ -394,10 +410,10 @@ struct nsXPTParamInfo
|
||||||
const nsXPTType& GetType() const { return Type(); } // XXX remove (backcompat)
|
const nsXPTType& GetType() const { return Type(); } // XXX remove (backcompat)
|
||||||
|
|
||||||
// Whether this parameter is passed indirectly on the stack. All out/inout
|
// Whether this parameter is passed indirectly on the stack. All out/inout
|
||||||
// params are passed indirectly, although some types are passed indirectly
|
// params are passed indirectly, and complex types are always passed
|
||||||
// unconditionally.
|
// indirectly.
|
||||||
bool IsIndirect() const {
|
bool IsIndirect() const {
|
||||||
return IsOut() || Type().IsAlwaysIndirect();
|
return IsOut() || Type().IsComplex();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
@ -634,29 +650,6 @@ GetString(uint32_t aIndex)
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace xpt
|
} // namespace xpt
|
||||||
|
|
||||||
inline bool
|
|
||||||
nsXPTType::HasPointerRepr() const
|
|
||||||
{
|
|
||||||
// This method should return `true` if the given type would be represented as
|
|
||||||
// a pointer when not passed indirectly.
|
|
||||||
switch (Tag()) {
|
|
||||||
case TD_VOID:
|
|
||||||
case TD_PNSIID:
|
|
||||||
case TD_PSTRING:
|
|
||||||
case TD_PWSTRING:
|
|
||||||
case TD_INTERFACE_TYPE:
|
|
||||||
case TD_INTERFACE_IS_TYPE:
|
|
||||||
case TD_ARRAY:
|
|
||||||
case TD_PSTRING_SIZE_IS:
|
|
||||||
case TD_PWSTRING_SIZE_IS:
|
|
||||||
case TD_DOMOBJECT:
|
|
||||||
case TD_PROMISE:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
nsXPTType::Stride() const
|
nsXPTType::Stride() const
|
||||||
{
|
{
|
||||||
|
@ -675,6 +668,7 @@ nsXPTType::Stride() const
|
||||||
case TD_BOOL: return sizeof(bool);
|
case TD_BOOL: return sizeof(bool);
|
||||||
case TD_CHAR: return sizeof(char);
|
case TD_CHAR: return sizeof(char);
|
||||||
case TD_WCHAR: return sizeof(char16_t);
|
case TD_WCHAR: return sizeof(char16_t);
|
||||||
|
|
||||||
case TD_VOID: return sizeof(void*);
|
case TD_VOID: return sizeof(void*);
|
||||||
case TD_PNSIID: return sizeof(nsIID*);
|
case TD_PNSIID: return sizeof(nsIID*);
|
||||||
case TD_DOMSTRING: return sizeof(nsString);
|
case TD_DOMSTRING: return sizeof(nsString);
|
||||||
|
@ -685,12 +679,13 @@ nsXPTType::Stride() const
|
||||||
case TD_ARRAY: return sizeof(void*);
|
case TD_ARRAY: return sizeof(void*);
|
||||||
case TD_PSTRING_SIZE_IS: return sizeof(char*);
|
case TD_PSTRING_SIZE_IS: return sizeof(char*);
|
||||||
case TD_PWSTRING_SIZE_IS: return sizeof(char16_t*);
|
case TD_PWSTRING_SIZE_IS: return sizeof(char16_t*);
|
||||||
|
case TD_DOMOBJECT: return sizeof(void*);
|
||||||
|
case TD_PROMISE: return sizeof(void*);
|
||||||
|
|
||||||
case TD_UTF8STRING: return sizeof(nsCString);
|
case TD_UTF8STRING: return sizeof(nsCString);
|
||||||
case TD_CSTRING: return sizeof(nsCString);
|
case TD_CSTRING: return sizeof(nsCString);
|
||||||
case TD_ASTRING: return sizeof(nsString);
|
case TD_ASTRING: return sizeof(nsString);
|
||||||
case TD_JSVAL: return sizeof(JS::Value);
|
case TD_JSVAL: return sizeof(JS::Value);
|
||||||
case TD_DOMOBJECT: return sizeof(void*);
|
|
||||||
case TD_PROMISE: return sizeof(void*);
|
|
||||||
case TD_SEQUENCE: return sizeof(xpt::detail::UntypedSequence);
|
case TD_SEQUENCE: return sizeof(xpt::detail::UntypedSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче