Commit 62f1779ccb for openssl.org

commit 62f1779ccb2bba85a8e3dab50435f1103092d03c
Author: Neil Horman <nhorman@openssl.org>
Date:   Mon Oct 26 16:21:49 2026 -0400

    pre-allocate sub packet strucures for faster parsing

    Reviewed-by: Bob Beck <beck@openssl.org>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Merge-date: Fri Nov  6 13:09:50 2026
    Merged-from: https://github.com/openssl/openssl/pull/33523

diff --git a/crypto/packet.c b/crypto/packet.c
index 56cde3866e..2002f5640b 100644
--- a/crypto/packet.c
+++ b/crypto/packet.c
@@ -8,6 +8,7 @@
  */

 #include "internal/cryptlib.h"
+#include <stdint.h>
 #include "internal/packet.h"
 #if !defined OPENSSL_NO_QUIC && !defined FIPS_MODULE
 #include "internal/packet_quic.h"
@@ -100,14 +101,65 @@ static size_t maxmaxsize(size_t lenbytes)
     return ((size_t)1 << (lenbytes * 8)) - 1 + lenbytes;
 }

+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+static WPACKET_SUB *wpacket_sub_new(WPACKET *pkt)
+{
+    WPACKET_SUB *sub;
+    uint32_t idx;
+
+    if (pkt->nsubs != 0) {
+#if __has_builtin(__builtin_ffs)
+        idx = __builtin_ffs(pkt->nsubs) - 1;
+#else
+        int snsubs = pkt->nsubs;
+        static const int MultiplyDeBruijnBitPosition[32] = {
+            0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+            31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+        };
+
+        /*
+         * (x & -x) isolates the lowest set bit (LSB)
+         * Multiplying hashes that bit uniquely into the upper 5 bits
+         */
+        idx = MultiplyDeBruijnBitPosition[((uint32_t)((snsubs & -snsubs) * 0x077CB531U)) >> 27];
+#endif
+        pkt->nsubs &= (~(1 << idx));
+        sub = &pkt->inline_subs[idx];
+        memset(sub, 0, sizeof(*sub));
+        sub->flags = WPACKET_FLAGS_SUB_INLINE;
+    } else {
+        sub = OPENSSL_zalloc(sizeof(*sub));
+        if (sub == NULL)
+            return NULL;
+    }
+    return sub;
+}
+
+static void wpacket_sub_free(WPACKET *pkt, WPACKET_SUB *sub)
+{
+    if (sub == NULL)
+        return;
+    if (sub->flags & WPACKET_FLAGS_SUB_INLINE) {
+        uintptr_t idx = ((uintptr_t)sub - (uintptr_t)pkt->inline_subs) / sizeof(WPACKET_SUB);
+
+        pkt->nsubs |= (1 << idx);
+        return;
+    }
+    OPENSSL_free(sub);
+}
+
 static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes)
 {
     unsigned char *lenchars;

     pkt->curr = 0;
     pkt->written = 0;
+    pkt->nsubs = (1 << WPACKET_INLINE_SUBS) - 1;

-    if ((pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs))) == NULL)
+    if ((pkt->subs = wpacket_sub_new(pkt)) == NULL)
         return 0;

     if (lenbytes == 0)
@@ -117,7 +169,7 @@ static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes)
     pkt->subs->lenbytes = lenbytes;

     if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) {
-        OPENSSL_free(pkt->subs);
+        wpacket_sub_free(pkt, pkt->subs);
         pkt->subs = NULL;
         return 0;
     }
@@ -202,7 +254,10 @@ int WPACKET_set_flags(WPACKET *pkt, unsigned int flags)
     if (!ossl_assert(pkt->subs != NULL))
         return 0;

-    pkt->subs->flags = flags;
+    /*
+     * Preserve the inline flag to prevent freeing
+     */
+    pkt->subs->flags = (pkt->subs->flags & WPACKET_FLAGS_SUB_INLINE) | flags;

     return 1;
 }
@@ -311,7 +366,7 @@ static int wpacket_intern_close(WPACKET *pkt, WPACKET_SUB *sub, int doclose)

     if (doclose) {
         pkt->subs = sub->parent;
-        OPENSSL_free(sub);
+        wpacket_sub_free(pkt, sub);
     }

     return 1;
@@ -357,7 +412,7 @@ int WPACKET_finish(WPACKET *pkt)

     ret = wpacket_intern_close(pkt, pkt->subs, 1);
     if (ret) {
-        OPENSSL_free(pkt->subs);
+        wpacket_sub_free(pkt, pkt->subs);
         pkt->subs = NULL;
     }

@@ -383,7 +438,7 @@ int WPACKET_start_sub_packet_at_offset_len__(WPACKET *pkt, size_t lenbytes,
     if (lenbytes > 0 && pkt->endfirst)
         return 0;

-    if ((sub = OPENSSL_zalloc(sizeof(*sub))) == NULL)
+    if ((sub = wpacket_sub_new(pkt)) == NULL)
         return 0;

     sub->parent = pkt->subs;
@@ -537,7 +592,7 @@ void WPACKET_cleanup(WPACKET *pkt)

     for (sub = pkt->subs; sub != NULL; sub = parent) {
         parent = sub->parent;
-        OPENSSL_free(sub);
+        wpacket_sub_free(pkt, sub);
     }
     pkt->subs = NULL;
 }
diff --git a/include/internal/packet.h b/include/internal/packet.h
index e15e0db83c..c7628c068f 100644
--- a/include/internal/packet.h
+++ b/include/internal/packet.h
@@ -691,6 +691,7 @@ __owur static ossl_inline int PACKET_get_length_prefixed_3(PACKET *pkt,

 /* Writable packets */

+#define WPACKET_INLINE_SUBS 6
 typedef struct wpacket_sub WPACKET_SUB;
 struct wpacket_sub {
     /* The parent WPACKET_SUB if we have one or NULL otherwise */
@@ -735,6 +736,9 @@ struct wpacket_st {
     /* Our sub-packets (always at least one if not finished) */
     WPACKET_SUB *subs;

+    WPACKET_SUB inline_subs[WPACKET_INLINE_SUBS];
+    unsigned int nsubs;
+
     /* Writing from the end first? */
     unsigned int endfirst : 1;
 };
@@ -756,6 +760,8 @@ struct wpacket_st {
 /* QUIC variable-length integer length prefix */
 #define WPACKET_FLAGS_QUIC_VLINT 4

+#define WPACKET_FLAGS_SUB_INLINE 8
+
 /*
  * Initialise a WPACKET with the buffer in |buf|. The buffer must exist
  * for the whole time that the WPACKET is being used. Additionally |lenbytes| of