Avoid excessive OSSL_DECODER_do_all_provided calls
authorMatt Caswell <matt@openssl.org>
Fri, 11 Jun 2021 11:43:00 +0000 (12:43 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 14 Jun 2021 09:05:50 +0000 (10:05 +0100)
OSSL_DECODER_CTX_add_extra was calling OSSL_DECODER_do_all_provided in a
loop which was resulting in a large number of calls. Since
OSSL_DECODER_do_all_provided is quite "heavy" this was causing performance
issues.

Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15716)

crypto/encode_decode/decoder_lib.c

index eb90a9eaf537b8d45ee64aec85a9ff012605a668..4053eac62e810aea8874014c70a175048b1231ab 100644 (file)
@@ -343,6 +343,16 @@ struct collect_extra_decoder_data_st {
     size_t w_new_start, w_new_end;   /* "new" decoders */
 };
 
+DEFINE_STACK_OF(OSSL_DECODER)
+
+static void collect_all_decoders(OSSL_DECODER *decoder, void *arg)
+{
+    STACK_OF(OSSL_DECODER) *skdecoders = arg;
+
+    if (OSSL_DECODER_up_ref(decoder))
+        sk_OSSL_DECODER_push(skdecoders, decoder);
+}
+
 static void collect_extra_decoder(OSSL_DECODER *decoder, void *arg)
 {
     struct collect_extra_decoder_data_st *data = arg;
@@ -459,6 +469,8 @@ int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx,
     struct collect_extra_decoder_data_st data;
     size_t depth = 0; /* Counts the number of iterations */
     size_t count; /* Calculates how many were added in each iteration */
+    size_t numdecoders;
+    STACK_OF(OSSL_DECODER) *skdecoders;
 
     if (!ossl_assert(ctx != NULL)) {
         ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
@@ -477,12 +489,21 @@ int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx,
                    (void *)ctx);
     } OSSL_TRACE_END(DECODER);
 
+
+    skdecoders = sk_OSSL_DECODER_new_null();
+    if (skdecoders == NULL) {
+        ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    OSSL_DECODER_do_all_provided(libctx, collect_all_decoders, skdecoders);
+    numdecoders = sk_OSSL_DECODER_num(skdecoders);
+
     memset(&data, 0, sizeof(data));
     data.ctx = ctx;
     data.w_prev_start = 0;
     data.w_prev_end = sk_OSSL_DECODER_INSTANCE_num(ctx->decoder_insts);
     do {
-        size_t i;
+        size_t i, j;
 
         data.w_new_start = data.w_new_end = data.w_prev_end;
 
@@ -504,8 +525,9 @@ int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx,
                     = OSSL_DECODER_INSTANCE_get_input_type(decoder_inst);
 
 
-                OSSL_DECODER_do_all_provided(libctx,
-                                             collect_extra_decoder, &data);
+                for (j = 0; j < numdecoders; j++)
+                    collect_extra_decoder(sk_OSSL_DECODER_value(skdecoders, j),
+                                          &data);
             }
         }
         /* How many were added in this iteration */
@@ -518,6 +540,7 @@ int OSSL_DECODER_CTX_add_extra(OSSL_DECODER_CTX *ctx,
         depth++;
     } while (count != 0 && depth <= 10);
 
+    sk_OSSL_DECODER_pop_free(skdecoders, OSSL_DECODER_free);
     return 1;
 }