From 23a28f5ad059a45ff861a06a63d8537dab7f81b7 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 16 Apr 2021 13:22:05 -0600 Subject: [PATCH] Avoid undefined-behavior If a struct had (because it's a union) sizeof that is larger than the null_size, we were providing only null_size bytes for its Null object. We know we'd never access beyond that, but is undefined-behavior nonetheless according to the standard. The alternative fix would have required use of flexible-arrays, which are not standard and have their own issues in various compiler. We've discussed that extensively in the follow Mozilla issue (currently locked; I've asked that it be opened): https://bugzilla.mozilla.org/show_bug.cgi?id=1577584 Part of https://github.com/harfbuzz/harfbuzz/pull/2067 --- src/hb-null.hh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hb-null.hh b/src/hb-null.hh index 38ddd5785..db38a4dfd 100644 --- a/src/hb-null.hh +++ b/src/hb-null.hh @@ -39,8 +39,11 @@ #define HB_NULL_POOL_SIZE 384 -/* Use SFINAE to sniff whether T has min_size; in which case return T::null_size, - * otherwise return sizeof(T). */ +/* Use SFINAE to sniff whether T has min_size; in which case return the larger + * of sizeof(T) and T::null_size, otherwise return sizeof(T). + * + * The main purpose of this is to let structs communicate that they are not nullable, + * by defining min_size but *not* null_size. */ /* The hard way... * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol @@ -49,7 +52,9 @@ template struct _hb_null_size : hb_integral_constant {}; template -struct _hb_null_size> : hb_integral_constant {}; +struct _hb_null_size> + : hb_integral_constant T::null_size ? sizeof (T) : T::null_size)> {}; template using hb_null_size = _hb_null_size; #define hb_null_size(T) hb_null_size::value