From 9a226c28bca688d7a636e3d4e0e55e2afd327cb9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 8 Mar 2025 16:14:26 +0900 Subject: [PATCH] hash.c: add arity check for Hash#default_proc (and Hash.new); fix #6484 --- src/hash.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/hash.c b/src/hash.c index f270134c9..bafeff4a7 100644 --- a/src/hash.c +++ b/src/hash.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -1273,6 +1274,21 @@ mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val) mrb_field_write_barrier_value(mrb, mrb_basic_ptr(hash), key); mrb_field_write_barrier_value(mrb, mrb_basic_ptr(hash), val); } +static void +hash_set_default_proc(mrb_state *mrb, mrb_value hash, mrb_value proc) +{ + struct RProc *p = mrb_proc_ptr(proc); + if (MRB_PROC_STRICT_P(p)) { + int n = mrb_proc_arity(p); + if (n != 2 && (n >= 0 || n < -3)) { + if (n < 0) n = -n-1; + mrb_raisef(mrb, E_TYPE_ERROR, "default_proc takes two arguments (2 for %d)", n); + } + } + mrb_iv_set(mrb, hash, MRB_SYM(ifnone), proc); + RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; + RHASH(hash)->flags |= MRB_HASH_DEFAULT; +} /* 15.2.13.4.16 */ /* @@ -1323,10 +1339,10 @@ mrb_hash_init(mrb_state *mrb, mrb_value hash) if (ifnone_p) { mrb_argnum_error(mrb, 1, 0, 0); } - RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; - ifnone = block; + hash_set_default_proc(mrb, hash, block); + return hash; } - if (!mrb_nil_p(ifnone)) { + if (ifnone_p && !mrb_nil_p(ifnone)) { RHASH(hash)->flags |= MRB_HASH_DEFAULT; mrb_iv_set(mrb, hash, MRB_SYM(ifnone), ifnone); } @@ -1482,14 +1498,12 @@ mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash) } mrb_iv_set(mrb, hash, MRB_SYM(ifnone), ifnone); if (!mrb_nil_p(ifnone)) { - RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT; - RHASH(hash)->flags |= MRB_HASH_DEFAULT; + hash_set_default_proc(mrb, hash, ifnone); } else { RHASH(hash)->flags &= ~MRB_HASH_DEFAULT; RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT; } - return ifnone; }