summaryrefslogtreecommitdiff
path: root/hv.c
diff options
context:
space:
mode:
authorYves Orton <demerphq@gmail.com>2012-11-24 11:16:48 +0100
committerYves Orton <demerphq@gmail.com>2012-11-24 11:18:27 +0100
commit8e3171984bd6a5f4edf04ec5b91032d053bdd8a5 (patch)
tree51eef5a04c3bb4d6f607093326602e23d931d893 /hv.c
parent630b72b081fe290d04732279e069c327eea82b09 (diff)
downloadperl-8e3171984bd6a5f4edf04ec5b91032d053bdd8a5.tar.gz
prevent memory exhaustion from hash attacks
We do not want to resize the hash every time the bucket length is too long. Nor do we want to pay the price of checking how long the bucket length is when there is nothing we can do about it anyway.
Diffstat (limited to 'hv.c')
-rw-r--r--hv.c32
1 files changed, 6 insertions, 26 deletions
diff --git a/hv.c b/hv.c
index c34d4d395d..1511a37e78 100644
--- a/hv.c
+++ b/hv.c
@@ -35,7 +35,7 @@ holds the key and hash value.
#define PERL_HASH_INTERNAL_ACCESS
#include "perl.h"
-#define HV_MAX_LENGTH_BEFORE_SPLIT 14
+#define DO_HSPLIT(xhv) ((xhv)->xhv_keys > (xhv)->xhv_max) /* HvTOTALKEYS(hv) > HvMAX(hv) */
static const char S_strtab_error[]
= "Cannot modify shared string table in hv_%s";
@@ -794,29 +794,9 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
if (masked_flags & HVhek_ENABLEHVKFLAGS)
HvHASKFLAGS_on(hv);
- {
- const HE *counter = HeNEXT(entry);
-
- xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */
- if (!counter) { /* initial entry? */
- } else if (xhv->xhv_keys > xhv->xhv_max) {
- /* Use only the old HvUSEDKEYS(hv) > HvMAX(hv) condition to limit
- bucket splits on a rehashed hash, as we're not going to
- split it again, and if someone is lucky (evil) enough to
- get all the keys in one list they could exhaust our memory
- as we repeatedly double the number of buckets on every
- entry. Linear search feels a less worse thing to do. */
- hsplit(hv);
- } else {
- U32 n_links = 1;
-
- while ((counter = HeNEXT(counter)))
- n_links++;
-
- if (n_links > HV_MAX_LENGTH_BEFORE_SPLIT) {
- hsplit(hv);
- }
- }
+ xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */
+ if ( DO_HSPLIT(xhv) ) {
+ hsplit(hv);
}
if (return_svp) {
@@ -2718,8 +2698,8 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags)
xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */
if (!next) { /* initial entry? */
- } else if (xhv->xhv_keys > xhv->xhv_max /* HvUSEDKEYS(hv) > HvMAX(hv) */) {
- hsplit(PL_strtab);
+ } else if ( DO_HSPLIT(xhv) ) {
+ hsplit(PL_strtab);
}
}