Use class templates for Null objects

This allows partial-instantiating custom Null object for template Lookup<T>.
Before, this had to be handcoded per instantiation.  Apparently I missed
adding one for AAT::ankr.lookupTable, so it was getting the wrong (generic)
null for Lookup object, which is wrong and unsafe.

Fixes https://bugs.chromium.org/p/chromium/issues/detail?id=944346
This commit is contained in:
Behdad Esfahbod 2019-03-26 16:18:03 -07:00 committed by Michiharu Ariza
parent 1dfc2dfff5
commit ea281aa8d0
3 changed files with 24 additions and 21 deletions

View File

@ -418,15 +418,11 @@ struct Lookup
} /* Close namespace. */ } /* Close namespace. */
/* Ugly hand-coded null objects for template Lookup<> :(. */ /* Ugly hand-coded null objects for template Lookup<> :(. */
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2]; extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
template <> template <typename T>
/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > () struct Null<AAT::Lookup<T> > {
{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); } static AAT::Lookup<T> const & get_null ()
template <> { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > () };
{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); }
template <>
/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > ()
{ return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); }
namespace AAT { namespace AAT {
enum { DELETED_GLYPH = 0xFFFF }; enum { DELETED_GLYPH = 0xFFFF };

View File

@ -105,15 +105,18 @@ hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_
/* Generic nul-content Null objects. */ /* Generic nul-content Null objects. */
template <typename Type> template <typename Type>
static inline Type const & Null () { struct Null {
static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); static Type const & get_null ()
return *reinterpret_cast<Type const *> (_hb_NullPool); {
} static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
return *reinterpret_cast<Type const *> (_hb_NullPool);
}
};
template <typename QType> template <typename QType>
struct NullHelper struct NullHelper
{ {
typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type; typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
static const Type & get_null () { return Null<Type> (); } static const Type & get_null () { return Null<Type>::get_null (); }
}; };
#define Null(Type) NullHelper<Type>::get_null () #define Null(Type) NullHelper<Type>::get_null ()
@ -122,9 +125,11 @@ struct NullHelper
} /* Close namespace. */ \ } /* Close namespace. */ \
extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \ extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \
template <> \ template <> \
/*static*/ inline const Namespace::Type& Null<Namespace::Type> () { \ struct Null<Namespace::Type> { \
return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \ static Namespace::Type const & get_null () { \
} \ return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
} \
}; \
namespace Namespace { \ namespace Namespace { \
static_assert (true, "Just so we take semicolon after.") static_assert (true, "Just so we take semicolon after.")
#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
@ -134,10 +139,12 @@ struct NullHelper
#define DECLARE_NULL_INSTANCE(Type) \ #define DECLARE_NULL_INSTANCE(Type) \
extern HB_INTERNAL const Type _hb_Null_##Type; \ extern HB_INTERNAL const Type _hb_Null_##Type; \
template <> \ template <> \
/*static*/ inline const Type& Null<Type> () { \ struct Null<Type> { \
return _hb_Null_##Type; \ static Type const & get_null () { \
} \ return _hb_Null_##Type; \
static_assert (true, "Just so we take semicolon after.") } \
}; \
static_assert (true, "Just so we take semicolon after.")
#define DEFINE_NULL_INSTANCE(Type) \ #define DEFINE_NULL_INSTANCE(Type) \
const Type _hb_Null_##Type const Type _hb_Null_##Type