d35ea2
From c5eed6e541fe27d9e9dfd31f42c43f4dfa1f486b Mon Sep 17 00:00:00 2001
d35ea2
From: Yves Orton <demerphq@gmail.com>
d35ea2
Date: Sat, 11 Jul 2020 09:26:21 +0200
d35ea2
Subject: [PATCH] hv.c: add a guard clause to prevent the number of buckets in
d35ea2
 a hash from getting too large
d35ea2
MIME-Version: 1.0
d35ea2
Content-Type: text/plain; charset=UTF-8
d35ea2
Content-Transfer-Encoding: 8bit
d35ea2
d35ea2
This caps it at 1<<28 buckets, eg, ~268M. In theory without a guard clause like
d35ea2
this we could grow to the point of possibly wrapping around in terms of size,
d35ea2
not to mention being ridiculously wasteful of memory at larger sizes.
d35ea2
Even this cap is probably too high. It should probably be something like 1<<24.
d35ea2
d35ea2
Petr Písař: Ported to 5.32.1 from
d35ea2
aae087f7cec022be14a17deb95cb2208e16b7891.
d35ea2
d35ea2
Signed-off-by: Petr Písař <ppisar@redhat.com>
d35ea2
---
d35ea2
 hv.c | 10 +++++++++-
d35ea2
 1 file changed, 9 insertions(+), 1 deletion(-)
d35ea2
d35ea2
diff --git a/hv.c b/hv.c
d35ea2
index eccae62..32dbd19 100644
d35ea2
--- a/hv.c
d35ea2
+++ b/hv.c
d35ea2
@@ -38,7 +38,13 @@ holds the key and hash value.
d35ea2
  * NOTE if you change this formula so we split earlier than previously
d35ea2
  * you MUST change the logic in hv_ksplit()
d35ea2
  */
d35ea2
-#define DO_HSPLIT(xhv) ( ((xhv)->xhv_keys + ((xhv)->xhv_keys >> 1))  > (xhv)->xhv_max )
d35ea2
+
d35ea2
+/*  MAX_BUCKET_MAX is the maximum max bucket index, at which point we stop growing the
d35ea2
+ *  number of buckets,
d35ea2
+ */
d35ea2
+#define MAX_BUCKET_MAX ((1<<26)-1)
d35ea2
+#define DO_HSPLIT(xhv) ( ( ((xhv)->xhv_keys + ((xhv)->xhv_keys >> 1)) > (xhv)->xhv_max ) && \
d35ea2
+                           ((xhv)->xhv_max < MAX_BUCKET_MAX) )
d35ea2
 #define HV_FILL_THRESHOLD 31
d35ea2
 
d35ea2
 static const char S_strtab_error[]
d35ea2
@@ -1426,6 +1432,8 @@ S_hsplit(pTHX_ HV *hv, STRLEN const oldsize, STRLEN newsize)
d35ea2
     );
d35ea2
 
d35ea2
     PERL_ARGS_ASSERT_HSPLIT;
d35ea2
+    if (newsize > MAX_BUCKET_MAX+1)
d35ea2
+            return;
d35ea2
 
d35ea2
     PL_nomemok = TRUE;
d35ea2
     Renew(a, PERL_HV_ARRAY_ALLOC_BYTES(newsize)
d35ea2
-- 
d35ea2
2.26.2
d35ea2