summaryrefslogtreecommitdiffhomepage
path: root/src/hash.c
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-03-31 13:02:01 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-03-31 13:02:01 +0900
commit39ca4ef3bcdfec6047647e697f94cb84f2251175 (patch)
tree8802ace4a1bf60991e53bd7f7cb59de4fbeb82fe /src/hash.c
parent952207d2433d2de1443c791ec1932c05dbd53be8 (diff)
downloadmruby-39ca4ef3bcdfec6047647e697f94cb84f2251175.tar.gz
mruby-39ca4ef3bcdfec6047647e697f94cb84f2251175.zip
Avoid crash if hv.n is greater than kh_size(h); fix #3565
The resulting behavior is different from CRuby, but modifying hash key afterwards is undefined behavior in ISO spec.
Diffstat (limited to 'src/hash.c')
-rw-r--r--src/hash.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/src/hash.c b/src/hash.c
index 3a7aea245..f55f85d69 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -750,20 +750,26 @@ MRB_API mrb_value
mrb_hash_keys(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
- khiter_t k;
+ khiter_t k, end;
mrb_value ary;
mrb_value *p;
if (!h || kh_size(h) == 0) return mrb_ary_new(mrb);
ary = mrb_ary_new_capa(mrb, kh_size(h));
- mrb_ary_set(mrb, ary, kh_size(h)-1, mrb_nil_value());
+ end = kh_size(h)-1;
+ mrb_ary_set(mrb, ary, end, mrb_nil_value());
p = mrb_ary_ptr(ary)->ptr;
for (k = kh_begin(h); k != kh_end(h); k++) {
if (kh_exist(h, k)) {
mrb_value kv = kh_key(h, k);
mrb_hash_value hv = kh_value(h, k);
- p[hv.n] = kv;
+ if (hv.n <= end) {
+ p[hv.n] = kv;
+ }
+ else {
+ p[end] = kv;
+ }
}
}
return ary;