Give ssl_cipher_preference_list_st a destructor.

Change-Id: I578a284c6a8cae773a97d3d30ad8a5cd13f56164
Reviewed-on: https://boringssl-review.googlesource.com/27491
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc
index 32e6c2c..f02fa8a 100644
--- a/ssl/ssl_cipher.cc
+++ b/ssl/ssl_cipher.cc
@@ -811,9 +811,14 @@
   *head = curr;
 }
 
-static void ssl_cipher_collect_ciphers(CIPHER_ORDER *co_list,
-                                       CIPHER_ORDER **head_p,
-                                       CIPHER_ORDER **tail_p) {
+static bool ssl_cipher_collect_ciphers(Array<CIPHER_ORDER> *out_co_list,
+                                       CIPHER_ORDER **out_head,
+                                       CIPHER_ORDER **out_tail) {
+  Array<CIPHER_ORDER> co_list;
+  if (!co_list.Init(kCiphersLen)) {
+    return false;
+  }
+
   size_t co_list_num = 0;
   for (const SSL_CIPHER &cipher : kCiphers) {
     // TLS 1.3 ciphers do not participate in this mechanism.
@@ -844,9 +849,35 @@
 
     co_list[co_list_num - 1].next = NULL;
 
-    *head_p = &co_list[0];
-    *tail_p = &co_list[co_list_num - 1];
+    *out_head = &co_list[0];
+    *out_tail = &co_list[co_list_num - 1];
+  } else {
+    *out_head = nullptr;
+    *out_tail = nullptr;
   }
+  *out_co_list = std::move(co_list);
+  return true;
+}
+
+SSLCipherPreferenceList::~SSLCipherPreferenceList() {
+  OPENSSL_free(in_group_flags);
+}
+
+bool SSLCipherPreferenceList::Init(UniquePtr<STACK_OF(SSL_CIPHER)> ciphers_arg,
+                                   Span<const bool> in_group_flags_arg) {
+  if (sk_SSL_CIPHER_num(ciphers_arg.get()) != in_group_flags_arg.size()) {
+    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+    return false;
+  }
+
+  Array<bool> copy;
+  if (!copy.CopyFrom(in_group_flags_arg)) {
+    return false;
+  }
+  ciphers = std::move(ciphers_arg);
+  size_t unused_len;
+  copy.Release(&in_group_flags, &unused_len);
+  return true;
 }
 
 // ssl_cipher_apply_rule applies the rule type |rule| to ciphers matching its
@@ -1201,15 +1232,8 @@
   return true;
 }
 
-bool ssl_create_cipher_list(
-    struct ssl_cipher_preference_list_st **out_cipher_list,
-    const char *rule_str, bool strict) {
-  STACK_OF(SSL_CIPHER) *cipherstack = NULL;
-  CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
-  uint8_t *in_group_flags = NULL;
-  unsigned int num_in_group_flags = 0;
-  struct ssl_cipher_preference_list_st *pref_list = NULL;
-
+bool ssl_create_cipher_list(SSLCipherPreferenceList **out_cipher_list,
+                            const char *rule_str, bool strict) {
   // Return with error if nothing to do.
   if (rule_str == NULL || out_cipher_list == NULL) {
     return false;
@@ -1218,14 +1242,12 @@
   // Now we have to collect the available ciphers from the compiled in ciphers.
   // We cannot get more than the number compiled in, so it is used for
   // allocation.
-  co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen);
-  if (co_list == NULL) {
-    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+  Array<CIPHER_ORDER> co_list;
+  CIPHER_ORDER *head = nullptr, *tail = nullptr;
+  if (!ssl_cipher_collect_ciphers(&co_list, &head, &tail)) {
     return false;
   }
 
-  ssl_cipher_collect_ciphers(co_list, &head, &tail);
-
   // Now arrange all ciphers by preference:
   // TODO(davidben): Compute this order once and copy it.
 
@@ -1285,7 +1307,7 @@
   if (strncmp(rule_str, "DEFAULT", 7) == 0) {
     if (!ssl_cipher_process_rulestr(SSL_DEFAULT_CIPHER_LIST, &head, &tail,
                                     strict)) {
-      goto err;
+      return false;
     }
     rule_p += 7;
     if (*rule_p == ':') {
@@ -1295,75 +1317,52 @@
 
   if (*rule_p != '\0' &&
       !ssl_cipher_process_rulestr(rule_p, &head, &tail, strict)) {
-    goto err;
+    return false;
   }
 
   // Allocate new "cipherstack" for the result, return with error
   // if we cannot get one.
-  cipherstack = sk_SSL_CIPHER_new_null();
-  if (cipherstack == NULL) {
-    goto err;
-  }
-
-  in_group_flags = (uint8_t *)OPENSSL_malloc(kCiphersLen);
-  if (!in_group_flags) {
-    goto err;
+  UniquePtr<STACK_OF(SSL_CIPHER)> cipherstack(sk_SSL_CIPHER_new_null());
+  Array<bool> in_group_flags;
+  if (cipherstack == nullptr ||
+      !in_group_flags.Init(kCiphersLen)) {
+    return false;
   }
 
   // The cipher selection for the list is done. The ciphers are added
   // to the resulting precedence to the STACK_OF(SSL_CIPHER).
-  for (curr = head; curr != NULL; curr = curr->next) {
+  size_t num_in_group_flags = 0;
+  for (CIPHER_ORDER *curr = head; curr != NULL; curr = curr->next) {
     if (curr->active) {
-      if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) {
-        goto err;
+      if (!sk_SSL_CIPHER_push(cipherstack.get(), curr->cipher)) {
+        return false;
       }
       in_group_flags[num_in_group_flags++] = curr->in_group;
     }
   }
-  OPENSSL_free(co_list);  // Not needed any longer
-  co_list = NULL;
 
-  pref_list = (ssl_cipher_preference_list_st *)OPENSSL_malloc(
-      sizeof(struct ssl_cipher_preference_list_st));
-  if (!pref_list) {
-    goto err;
+  UniquePtr<SSLCipherPreferenceList> pref_list =
+      MakeUnique<SSLCipherPreferenceList>();
+  if (!pref_list ||
+      !pref_list->Init(
+          std::move(cipherstack),
+          MakeConstSpan(in_group_flags).subspan(0, num_in_group_flags))) {
+    return false;
   }
-  pref_list->ciphers = cipherstack;
-  pref_list->in_group_flags = NULL;
-  if (num_in_group_flags) {
-    pref_list->in_group_flags = (uint8_t *)OPENSSL_malloc(num_in_group_flags);
-    if (!pref_list->in_group_flags) {
-      goto err;
-    }
-    OPENSSL_memcpy(pref_list->in_group_flags, in_group_flags,
-                   num_in_group_flags);
+
+  if (*out_cipher_list) {
+    Delete(*out_cipher_list);
   }
-  OPENSSL_free(in_group_flags);
-  in_group_flags = NULL;
-  if (*out_cipher_list != NULL) {
-    ssl_cipher_preference_list_free(*out_cipher_list);
-  }
-  *out_cipher_list = pref_list;
-  pref_list = NULL;
+  *out_cipher_list = pref_list.release();
 
   // Configuring an empty cipher list is an error but still updates the
   // output.
-  if (sk_SSL_CIPHER_num((*out_cipher_list)->ciphers) == 0) {
+  if (sk_SSL_CIPHER_num((*out_cipher_list)->ciphers.get()) == 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
     return false;
   }
 
   return true;
-
-err:
-  OPENSSL_free(co_list);
-  OPENSSL_free(in_group_flags);
-  sk_SSL_CIPHER_free(cipherstack);
-  if (pref_list) {
-    OPENSSL_free(pref_list->in_group_flags);
-  }
-  OPENSSL_free(pref_list);
-  return false;
 }
 
 uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) {