Commit 59d6fed
Fix pm_compile_call for inline_new with keyword args
pm_setup_args mallocs one kw_arg buffer with references = 0. The inline_new branch then feeds that same pointer
to three callinfo constructions:
- 3789 — new_callinfo(... method_id="new" ..., kw_arg, 0) -> the opt_new ci
- 3795 — PUSH_SEND_R(... "initialize", ..., flags | VM_CALL_FCALL, kw_arg)
- 3800 — PUSH_SEND_R(... method_id="new", ..., flags, kw_arg) (fallback)
Tracing the refcount through rb_vm_ci_lookup()
1. It increments kwarg->references and allocates a fresh new_ci before the dedup st_update
2. The dedup (vm_ci_hash_cmp) compares kwarg contents, not the pointer. So if an earlier line already interned a new ci with the
identical keyword set, st_update returns that pre-existing ci (which holds a different buffer) and discards our new_ci.
3. Our kw_arg is now orphaned: references == 1, but the only holder is the discarded new_ci, which is a normal collectable imemo
4. An allocation like PUSH_INSN2 opt_new at or new_callinfo() can trigger a GC. References back to 0, kw_arg buffer freed.
5. new_callinfo() using the freed buffer, does argc += kw_arg->keyword_len (use-after-free)
The fix: Keep the buffer alive across the allocations in inline_new.
Fixes [Bug #22104] (Backport 4.0)1 parent 48ac726 commit 59d6fed
3 files changed
Lines changed: 19 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
577 | 577 | | |
578 | 578 | | |
579 | 579 | | |
580 | | - | |
581 | | - | |
582 | | - | |
583 | | - | |
584 | | - | |
585 | | - | |
| 580 | + | |
586 | 581 | | |
587 | 582 | | |
588 | 583 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3776 | 3776 | | |
3777 | 3777 | | |
3778 | 3778 | | |
| 3779 | + | |
| 3780 | + | |
3779 | 3781 | | |
3780 | 3782 | | |
3781 | 3783 | | |
| |||
3798 | 3800 | | |
3799 | 3801 | | |
3800 | 3802 | | |
| 3803 | + | |
| 3804 | + | |
3801 | 3805 | | |
3802 | 3806 | | |
3803 | 3807 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
64 | 78 | | |
65 | 79 | | |
66 | 80 | | |
| |||
0 commit comments