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