Use traits structs for StackAllocated and StackAllocatedMovable

This CL refactors StackAllocated{,Movable} to take the init/cleanup/move
function pointers wrapped in a Traits struct (as a typename template
argument) rather than directly as non-type template arguments, to work
around a build issue(*), and it makes the code perhaps marginally
cleaner.

(*) When function pointers are passed directly as non-type template
arguments to StackAllocated / StackAllocatedMovable, clang under
-gsimple-template-names generates DW_TAG_template_value_parameter
relocations in .debug_info pointing directly to those functions. If the
type instantiated by the template has internal init/cleanup functions,
and is used across a shared library boundary, this can cause undefined
symbol linker failures because those functions are not exported, even if
the type is never constructed or destroyed. This occurs in some
configurations for Chromium's component build.

Bug: 549361069
Cq-Include-Trybots: luci.boringssl.try:linux_clang_shared_compile,linux_clang_shared_rel_compile
Change-Id: I0cf796458f50509e99158d2625a7d3e26a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/101527
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Auto-Submit: Lily Chen <chlily@google.com>
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h
index 6ba5ecc..f5a76da 100644
--- a/crypto/x509/internal.h
+++ b/crypto/x509/internal.h
@@ -40,9 +40,8 @@
 // A ScopedX509Algor is a stack-allocatable `X509_ALGOR` with managed lifetime.
 // This cannot use `DECLARE_OPAQUE_STRUCT` because `X509_ALGOR` is a public
 // struct.
-using ScopedX509Algor =
-    internal::StackAllocated<X509_ALGOR, void, x509_algor_init,
-                             x509_algor_cleanup>;
+BORINGSSL_MAKE_STACK_TRAITS(X509_ALGOR, x509_algor_init, x509_algor_cleanup)
+using ScopedX509Algor = internal::StackAllocated<X509_ALGOR>;
 
 // x509_parse_algorithm parses a DER-encoded, AlgorithmIdentifier from `cbs` and
 // writes the result to `*out`. It returns one on success and zero on error.
diff --git a/include/openssl/aead.h b/include/openssl/aead.h
index af90b26..339e34a 100644
--- a/include/openssl/aead.h
+++ b/include/openssl/aead.h
@@ -634,9 +634,9 @@
 
 BSSL_NAMESPACE_BEGIN
 
-using ScopedEVP_AEAD_CTX =
-    internal::StackAllocated<EVP_AEAD_CTX, void, EVP_AEAD_CTX_zero,
-                             EVP_AEAD_CTX_cleanup>;
+BORINGSSL_MAKE_STACK_TRAITS(EVP_AEAD_CTX, EVP_AEAD_CTX_zero,
+                            EVP_AEAD_CTX_cleanup)
+using ScopedEVP_AEAD_CTX = internal::StackAllocated<EVP_AEAD_CTX>;
 
 BORINGSSL_MAKE_DELETER(EVP_AEAD_CTX, EVP_AEAD_CTX_free)
 
diff --git a/include/openssl/base.h b/include/openssl/base.h
index fec3237..83cc91b 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -395,6 +395,9 @@
 
 #define BORINGSSL_MAKE_DELETER(type, deleter)
 #define BORINGSSL_MAKE_UP_REF(type, up_ref_func)
+#define BORINGSSL_MAKE_STACK_TRAITS(type, init_func, cleanup_func)
+#define BORINGSSL_MAKE_STACK_TRAITS_MOVABLE(type, init_func, cleanup_func, \
+                                            move_func)
 
 #else
 
@@ -427,12 +430,14 @@
   }
 };
 
-template <typename T, typename CleanupRet, void (*init)(T *),
-          CleanupRet (*cleanup)(T *)>
+template <typename T>
+struct StackAllocatedTraits {};
+
+template <typename T, typename Traits = StackAllocatedTraits<T> >
 class StackAllocated {
  public:
-  StackAllocated() { init(&ctx_); }
-  ~StackAllocated() { cleanup(&ctx_); }
+  StackAllocated() { Traits::Init(&ctx_); }
+  ~StackAllocated() { Traits::Cleanup(&ctx_); }
 
   StackAllocated(const StackAllocated &) = delete;
   StackAllocated &operator=(const StackAllocated &) = delete;
@@ -444,27 +449,29 @@
   const T *operator->() const { return &ctx_; }
 
   void Reset() {
-    cleanup(&ctx_);
-    init(&ctx_);
+    Traits::Cleanup(&ctx_);
+    Traits::Init(&ctx_);
   }
 
  private:
   T ctx_;
 };
 
-template <typename T, typename CleanupRet, void (*init)(T *),
-          CleanupRet (*cleanup)(T *), void (*move)(T *, T *)>
+template <typename T>
+struct StackAllocatedMovableTraits {};
+
+template <typename T, typename Traits = StackAllocatedMovableTraits<T> >
 class StackAllocatedMovable {
  public:
-  StackAllocatedMovable() { init(&ctx_); }
-  ~StackAllocatedMovable() { cleanup(&ctx_); }
+  StackAllocatedMovable() { Traits::Init(&ctx_); }
+  ~StackAllocatedMovable() { Traits::Cleanup(&ctx_); }
 
   StackAllocatedMovable(StackAllocatedMovable &&other) {
-    init(&ctx_);
-    move(&ctx_, &other.ctx_);
+    Traits::Init(&ctx_);
+    Traits::Move(&ctx_, &other.ctx_);
   }
   StackAllocatedMovable &operator=(StackAllocatedMovable &&other) {
-    move(&ctx_, &other.ctx_);
+    Traits::Move(&ctx_, &other.ctx_);
     return *this;
   }
 
@@ -475,8 +482,8 @@
   const T *operator->() const { return &ctx_; }
 
   void Reset() {
-    cleanup(&ctx_);
-    init(&ctx_);
+    Traits::Cleanup(&ctx_);
+    Traits::Init(&ctx_);
   }
 
  private:
@@ -493,6 +500,26 @@
   };                                              \
   }
 
+#define BORINGSSL_MAKE_STACK_TRAITS(type, init_func, cleanup_func) \
+  namespace internal {                                             \
+  template <>                                                      \
+  struct StackAllocatedTraits<type> {                              \
+    static void Init(type *ptr) { init_func(ptr); }                \
+    static void Cleanup(type *ptr) { cleanup_func(ptr); }          \
+  };                                                               \
+  }
+
+#define BORINGSSL_MAKE_STACK_TRAITS_MOVABLE(type, init_func, cleanup_func, \
+                                            move_func)                     \
+  namespace internal {                                                     \
+  template <>                                                              \
+  struct StackAllocatedMovableTraits<type> {                               \
+    static void Init(type *ptr) { init_func(ptr); }                        \
+    static void Cleanup(type *ptr) { cleanup_func(ptr); }                  \
+    static void Move(type *out, type *in) { move_func(out, in); }          \
+  };                                                                       \
+  }
+
 // Holds ownership of heap-allocated BoringSSL structures. Sample usage:
 //   bssl::UniquePtr<RSA> rsa(RSA_new());
 //   bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index e1b7089..d1d607c 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -785,7 +785,8 @@
 
 BSSL_NAMESPACE_BEGIN
 
-using ScopedCBB = internal::StackAllocated<CBB, void, CBB_zero, CBB_cleanup>;
+BORINGSSL_MAKE_STACK_TRAITS(CBB, CBB_zero, CBB_cleanup)
+using ScopedCBB = internal::StackAllocated<CBB>;
 
 BSSL_NAMESPACE_END
 
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
index 1410f33..9ca8d27 100644
--- a/include/openssl/cipher.h
+++ b/include/openssl/cipher.h
@@ -778,9 +778,9 @@
 
 BORINGSSL_MAKE_DELETER(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
 
-using ScopedEVP_CIPHER_CTX =
-    internal::StackAllocated<EVP_CIPHER_CTX, int, EVP_CIPHER_CTX_init,
-                             EVP_CIPHER_CTX_cleanup>;
+BORINGSSL_MAKE_STACK_TRAITS(EVP_CIPHER_CTX, EVP_CIPHER_CTX_init,
+                            EVP_CIPHER_CTX_cleanup)
+using ScopedEVP_CIPHER_CTX = internal::StackAllocated<EVP_CIPHER_CTX>;
 
 BSSL_NAMESPACE_END
 
diff --git a/include/openssl/digest.h b/include/openssl/digest.h
index d9f46d6..8a81bc1 100644
--- a/include/openssl/digest.h
+++ b/include/openssl/digest.h
@@ -381,9 +381,9 @@
 
 BORINGSSL_MAKE_DELETER(EVP_MD_CTX, EVP_MD_CTX_free)
 
-using ScopedEVP_MD_CTX =
-    internal::StackAllocatedMovable<EVP_MD_CTX, int, EVP_MD_CTX_init,
-                                    EVP_MD_CTX_cleanup, EVP_MD_CTX_move>;
+BORINGSSL_MAKE_STACK_TRAITS_MOVABLE(EVP_MD_CTX, EVP_MD_CTX_init,
+                                    EVP_MD_CTX_cleanup, EVP_MD_CTX_move)
+using ScopedEVP_MD_CTX = internal::StackAllocatedMovable<EVP_MD_CTX>;
 
 BSSL_NAMESPACE_END
 
diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h
index 18e9c02..4fbc764 100644
--- a/include/openssl/hmac.h
+++ b/include/openssl/hmac.h
@@ -138,8 +138,8 @@
 
 BORINGSSL_MAKE_DELETER(HMAC_CTX, HMAC_CTX_free)
 
-using ScopedHMAC_CTX =
-    internal::StackAllocated<HMAC_CTX, void, HMAC_CTX_init, HMAC_CTX_cleanup>;
+BORINGSSL_MAKE_STACK_TRAITS(HMAC_CTX, HMAC_CTX_init, HMAC_CTX_cleanup)
+using ScopedHMAC_CTX = internal::StackAllocated<HMAC_CTX>;
 
 BSSL_NAMESPACE_END
 
diff --git a/include/openssl/hpke.h b/include/openssl/hpke.h
index ae2d619..c743e0f 100644
--- a/include/openssl/hpke.h
+++ b/include/openssl/hpke.h
@@ -407,12 +407,13 @@
 
 BSSL_NAMESPACE_BEGIN
 
-using ScopedEVP_HPKE_CTX =
-    internal::StackAllocated<EVP_HPKE_CTX, void, EVP_HPKE_CTX_zero,
-                             EVP_HPKE_CTX_cleanup>;
-using ScopedEVP_HPKE_KEY =
-    internal::StackAllocatedMovable<EVP_HPKE_KEY, void, EVP_HPKE_KEY_zero,
-                                    EVP_HPKE_KEY_cleanup, EVP_HPKE_KEY_move>;
+BORINGSSL_MAKE_STACK_TRAITS(EVP_HPKE_CTX, EVP_HPKE_CTX_zero,
+                            EVP_HPKE_CTX_cleanup)
+using ScopedEVP_HPKE_CTX = internal::StackAllocated<EVP_HPKE_CTX>;
+
+BORINGSSL_MAKE_STACK_TRAITS_MOVABLE(EVP_HPKE_KEY, EVP_HPKE_KEY_zero,
+                                    EVP_HPKE_KEY_cleanup, EVP_HPKE_KEY_move)
+using ScopedEVP_HPKE_KEY = internal::StackAllocatedMovable<EVP_HPKE_KEY>;
 
 BORINGSSL_MAKE_DELETER(EVP_HPKE_CTX, EVP_HPKE_CTX_free)
 BORINGSSL_MAKE_DELETER(EVP_HPKE_KEY, EVP_HPKE_KEY_free)