Shopify / liquid-c

Liquid performance extension in C.
MIT License
119 stars 24 forks source link

Fix crash in the VM from garbage collected object #190

Closed peterzhu2118 closed 1 year ago

peterzhu2118 commented 1 year ago

vm_stack_pop_n_use_in_place removes objects from the VM stack. If these objects do not have any other references, then they can be garbage collected, leading to T_NONE objects being passed into vm_invoke_filter.

This commit fixes this issue in OP_HASH_NEW and OP_FILTER by first peeking from the VM stack and only pop after it is safe to do so.

Here's a stack trace of a crash:

(gdb) bt 20
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007f0efd742859 in __GI_abort () at abort.c:79
#2  0x000055cf5fdc5d4f in die () at error.c:817
#3  rb_bug_for_fatal_signal (default_sighandler=0x0, sig=sig@entry=11, ctx=ctx@entry=0x7f0efc743900, fmt=fmt@entry=0x55cf601e37aa "Segmentation fault at %p") at error.c:817
#4  0x000055cf5ff2872d in sigsegv (sig=11, info=0x7f0efc743a30, ctx=0x7f0efc743900) at signal.c:964
#5  0x00007f0efd941420 in <signal handler called> () at /lib/x86_64-linux-gnu/libpthread.so.0
#6  0x000055cf5ff65895 in hash_table_index (tbl=0x7f0efd47d9d0, tbl=0x7f0efd47d9d0, key=208) at id_table.c:136
#7  rb_id_table_lookup (tbl=tbl@entry=0x7f0efd47d9d0, id=id@entry=3329, valp=valp@entry=0x7ffe292bef28) at id_table.c:230
#8  0x000055cf5ffb154f in vm_search_cc (ci=0xd0100100001, klass=139702356286280) at vm_insnhelper.c:1980
#9  rb_vm_search_method_slowpath (ci=0xd0100100001, klass=139702356286280) at vm_insnhelper.c:2077
#10 0x000055cf5ffb1917 in vm_search_method_slowpath0 (cd_owner=139702216605640, klass=<optimized out>, cd=<optimized out>, cd=<optimized out>) at vm_insnhelper.c:2099
#11 0x000055cf5ffccc9e in vm_search_method_fastpath (klass=<optimized out>, cd=<optimized out>, cd_owner=<optimized out>) at vm_insnhelper.c:2165
#12 vm_sendish (block_handler=<optimized out>, method_explorer=<optimized out>, cd=<optimized out>, reg_cfp=<optimized out>, ec=<optimized out>) at vm_insnhelper.c:5079
#13 vm_exec_core (ec=0x7f0efd07f050, initial=3329) at insns.def:820
#14 0x000055cf5ffba61b in rb_vm_exec (ec=0x7f0efd07f050, jit_enable_p=true) at vm.c:2374
#15 0x000055cf5ffc2963 in vm_call0_body (ec=0x7f0efd07f050, calling=0x7ffe292bf300, argv=0x7f0df298d4b0) at vm_eval.c:206
#16 0x000055cf5ffc6a40 in vm_call0_cc (kw_splat=0, cc=<optimized out>, argv=0x7f0df298d4b0, argc=1, id=7105, recv=139697051590800, ec=0x7f0efd07f050) at vm_eval.c:87
#17 rb_funcallv_scope (recv=139697051590800, mid=7105, argc=1, argv=0x7f0df298d4b0, scope=CALL_FCALL) at vm_eval.c:1051
#18 0x00007f0ee7a78af8 in vm_invoke_filter (args=0x7f0df298d4b0, num_args=1, filter_name=<optimized out>, vm=0x7f0d5abbd280) at vm.c:179
#19 vm_render_until_error (uncast_args=uncast_args@entry=140729589167664) at vm.c:340

We can see that the object is a T_NONE:

(gdb) f 18
#18 0x00007f0ee7a78af8 in vm_invoke_filter (args=0x7f0df298d4b0, num_args=1, filter_name=<optimized out>, vm=0x7f0d5abbd280) at vm.c:179
(gdb) p *(struct RBasic *)args[0]
$82 = {flags = 0, klass = 139702356286280}