diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-03-31 13:02:01 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-03-31 13:02:01 +0900 |
| commit | 39ca4ef3bcdfec6047647e697f94cb84f2251175 (patch) | |
| tree | 8802ace4a1bf60991e53bd7f7cb59de4fbeb82fe | |
| parent | 952207d2433d2de1443c791ec1932c05dbd53be8 (diff) | |
| download | mruby-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.
| -rw-r--r-- | src/hash.c | 12 |
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; |
