Add a compile time verification ciphers are sorted for bsearch()

Change-Id: Ibdf5b5194087a44088563141f1de2801cade231b
Reviewed-on: https://boringssl-review.googlesource.com/30144
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc
index 54459a1..5899500 100644
--- a/ssl/ssl_cipher.cc
+++ b/ssl/ssl_cipher.cc
@@ -157,7 +157,7 @@
 namespace bssl {
 
 // kCiphers is an array of all supported ciphers, sorted by id.
-static const SSL_CIPHER kCiphers[] = {
+static constexpr SSL_CIPHER kCiphers[] = {
     // The RSA ciphers
     // Cipher 02
     {
@@ -556,19 +556,6 @@
 
 static const size_t kCipherAliasesLen = OPENSSL_ARRAY_SIZE(kCipherAliases);
 
-static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) {
-  const SSL_CIPHER *a = reinterpret_cast<const SSL_CIPHER *>(in_a);
-  const SSL_CIPHER *b = reinterpret_cast<const SSL_CIPHER *>(in_b);
-
-  if (a->id > b->id) {
-    return 1;
-  } else if (a->id < b->id) {
-    return -1;
-  } else {
-    return 0;
-  }
-}
-
 bool ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
                              size_t *out_mac_secret_len,
                              size_t *out_fixed_iv_len, const SSL_CIPHER *cipher,
@@ -1323,6 +1310,36 @@
 
 using namespace bssl;
 
+static constexpr int ssl_cipher_id_cmp_inner(const SSL_CIPHER *a,
+                                             const SSL_CIPHER *b) {
+  // C++11's constexpr functions must have a body consisting of just a
+  // return-statement.
+  return (a->id > b->id) ? 1 : ((a->id < b->id) ? -1 : 0);
+}
+
+static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) {
+  return ssl_cipher_id_cmp_inner(reinterpret_cast<const SSL_CIPHER *>(in_a),
+                                 reinterpret_cast<const SSL_CIPHER *>(in_b));
+}
+
+template <typename T, size_t N>
+static constexpr size_t countof(T const (&)[N]) {
+  return N;
+}
+
+template <typename T, size_t I>
+static constexpr int check_order(const T (&arr)[I], size_t N) {
+  // C++11's constexpr functions must have a body consisting of just a
+  // return-statement.
+  return N > 1 ? ((ssl_cipher_id_cmp_inner(&arr[N - 2], &arr[N - 1]) < 0)
+                      ? check_order(arr, N - 1)
+                      : 0)
+               : 1;
+}
+
+static_assert(check_order(kCiphers, countof(kCiphers)) == 1,
+              "Ciphers are not sorted, bsearch won't work");
+
 const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) {
   SSL_CIPHER c;