Register stack deleters automatically.
Rather than manually register the stack deleters separately, instantiate
them automatically from DEFINE_STACK_OF and BORINGSSL_MAKE_DELETER. The
StackTraits bridge in DEFINE_STACK_OF will additionally be used for
other C++ STACK_OF conveniences.
Bug: 132
Change-Id: I95d6c15b2219b34c7a8ce06dd8012d073dc19c27
Reviewed-on: https://boringssl-review.googlesource.com/18465
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/stack.h b/include/openssl/stack.h
index 5c4b506..8f15ea2 100644
--- a/include/openssl/stack.h
+++ b/include/openssl/stack.h
@@ -212,11 +212,38 @@
* This set of macros is used to emit the typed functions that act on a
* |STACK_OF(T)|. */
+#if !defined(BORINGSSL_NO_CXX)
+extern "C++" {
+namespace bssl {
+namespace internal {
+template <typename T>
+struct StackTraits {};
+}
+}
+}
+
+#define BORINGSSL_DEFINE_STACK_TRAITS(name, is_const) \
+ extern "C++" { \
+ namespace bssl { \
+ namespace internal { \
+ template <> \
+ struct StackTraits<STACK_OF(name)> { \
+ using Type = name; \
+ static constexpr bool kIsConst = is_const; \
+ }; \
+ } \
+ } \
+ }
+
+#else
+#define BORINGSSL_DEFINE_STACK_TRAITS(name, is_const)
+#endif
+
/* Stack functions must be tagged unused to support file-local stack types.
* Clang's -Wunused-function only allows unused static inline functions if they
* are defined in a header. */
-#define DEFINE_STACK_OF_IMPL(name, ptrtype, constptrtype) \
+#define BORINGSSL_DEFINE_STACK_OF_IMPL(name, ptrtype, constptrtype) \
DECLARE_STACK_OF(name); \
\
typedef int (*stack_##name##_cmp_func)(constptrtype *a, constptrtype *b); \
@@ -323,19 +350,22 @@
/* DEFINE_STACK_OF defines |STACK_OF(type)| to be a stack whose elements are
* |type| *. */
-#define DEFINE_STACK_OF(type) DEFINE_STACK_OF_IMPL(type, type *, const type *)
+#define DEFINE_STACK_OF(type) \
+ BORINGSSL_DEFINE_STACK_OF_IMPL(type, type *, const type *) \
+ BORINGSSL_DEFINE_STACK_TRAITS(type, false)
/* DEFINE_CONST_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
* are const |type| *. */
#define DEFINE_CONST_STACK_OF(type) \
- DEFINE_STACK_OF_IMPL(type, const type *, const type *)
+ BORINGSSL_DEFINE_STACK_OF_IMPL(type, const type *, const type *) \
+ BORINGSSL_DEFINE_STACK_TRAITS(type, true)
/* DEFINE_SPECIAL_STACK_OF defines |STACK_OF(type)| to be a stack whose elements
* are |type|, where |type| must be a typedef for a pointer. */
#define DEFINE_SPECIAL_STACK_OF(type) \
OPENSSL_COMPILE_ASSERT(sizeof(type) == sizeof(void *), \
special_stack_of_non_pointer_##type); \
- DEFINE_STACK_OF_IMPL(type, type, const type)
+ BORINGSSL_DEFINE_STACK_OF_IMPL(type, type, const type)
typedef char *OPENSSL_STRING;
@@ -348,4 +378,40 @@
} /* extern C */
#endif
+#if !defined(BORINGSSL_NO_CXX)
+extern "C++" {
+
+#include <type_traits>
+
+namespace bssl {
+
+namespace internal {
+
+// Stacks defined with |DEFINE_CONST_STACK_OF| are freed with |sk_free|.
+template <typename Stack>
+struct DeleterImpl<
+ Stack, typename std::enable_if<StackTraits<Stack>::kIsConst>::type> {
+ static void Free(Stack *sk) { sk_free(reinterpret_cast<_STACK *>(sk)); }
+};
+
+// Stacks defined with |DEFINE_STACK_OF| are freed with |sk_pop_free| and the
+// corresponding type's deleter.
+template <typename Stack>
+struct DeleterImpl<
+ Stack, typename std::enable_if<!StackTraits<Stack>::kIsConst>::type> {
+ static void Free(Stack *sk) {
+ sk_pop_free(
+ reinterpret_cast<_STACK *>(sk),
+ reinterpret_cast<void (*)(void *)>(
+ DeleterImpl<typename StackTraits<Stack>::Type>::Free));
+ }
+};
+
+} // namespace internal
+
+} // namespace bssl
+
+} // extern C++
+#endif
+
#endif /* OPENSSL_HEADER_STACK_H */