redis-rb / redis-client

Simple low level client for Redis 6+
MIT License
124 stars 60 forks source link

Fix a GC bug in hiredis-client #157

Closed casperisfine closed 9 months ago

casperisfine commented 9 months ago

Since we only mark response values through the stack Array, these values are movable, so we can't trust the reply retuned by redisGetReplyFromReader as it may be outdated if the value was moved.

Instead we can directly take the first element of stack as it should be out response object.

casperisfine commented 9 months ago

Crash when running this test without the fix:

<OBJ_INFO:gc_mark_ptr@gc.c:7058> 0x00000001055bfd28 [0 MP   ] T_NONE 
/Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client/connection_mixin.rb:33: [BUG] try to mark T_NONE object
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]

-- Crash Report log information --------------------------------------------
   See Crash Report log file in one of the following locations:             
     * ~/Library/Logs/DiagnosticReports                                     
     * /Library/Logs/DiagnosticReports                                      
   for more details.                                                        
Don't forget to include the above Crash Report log file in bug reports.     

-- Control frame information -----------------------------------------------
c:0031 p:0037 s:0177 e:000174 METHOD /Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client/connection_mixin.rb:33
c:0030 p:0008 s:0168 e:000167 BLOCK  /Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:257
c:0029 p:0004 s:0165 e:000164 METHOD /Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client/middlewares.rb:16
c:0028 p:0011 s:0159 e:000158 BLOCK  /Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:256
c:0027 p:0072 s:0155 e:000154 METHOD /Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:677
c:0026 p:0015 s:0144 e:000143 METHOD /Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:255
c:0025 p:0014 s:0137 e:000134 BLOCK  test/redis_client_test.rb:181 [FINISH]
c:0024 p:---- s:0132 e:000131 CFUNC  :times
c:0023 p:0063 s:0128 e:000127 METHOD test/redis_client_test.rb:180
c:0022 p:0018 s:0120 e:000119 BLOCK  /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:98
c:0021 p:0002 s:0117 e:000116 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:195
c:0020 p:0004 s:0112 e:000111 BLOCK  /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:95
c:0019 p:0008 s:0109 e:000108 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:281
c:0018 p:0004 s:0104 e:000103 BLOCK  /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:94
c:0017 p:0022 s:0101 E:001c80 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:376
c:0016 p:0027 s:0093 E:001eb8 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:221
c:0015 p:0004 s:0086 E:001760 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:93
c:0014 p:0008 s:0082 e:000081 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:1042
c:0013 p:0019 s:0075 e:000073 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:350
c:0012 p:0009 s:0067 e:000066 BLOCK  /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:337 [FINISH]
c:0011 p:---- s:0063 e:000062 CFUNC  :each
c:0010 p:0005 s:0059 e:000058 BLOCK  /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:336
c:0009 p:0022 s:0056 E:001cc0 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:376
c:0008 p:0019 s:0048 E:001bf8 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:363
c:0007 p:0096 s:0041 E:000838 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:335
c:0006 p:0008 s:0032 e:000031 BLOCK  /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:169 [FINISH]
c:0005 p:---- s:0028 e:000027 CFUNC  :map
c:0004 p:0028 s:0024 e:000023 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:169
c:0003 p:0114 s:0015 e:000014 METHOD /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:146
c:0002 p:0045 s:0008 E:0023b0 BLOCK  /Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:73 [FINISH]
c:0001 p:0000 s:0003 E:000890 DUMMY  [FINISH]

-- Ruby level backtrace information ----------------------------------------
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:73:in `block in autorun'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:146:in `run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:169:in `__run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:169:in `map'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:169:in `block in __run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:335:in `run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:363:in `with_info_handler'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:376:in `on_signal'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:336:in `block in run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:336:in `each'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:337:in `block (2 levels) in run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:350:in `run_one_method'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:1042:in `run_one_method'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:93:in `run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:221:in `with_info_handler'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:376:in `on_signal'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:94:in `block in run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest.rb:281:in `time_it'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:95:in `block (2 levels) in run'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:195:in `capture_exceptions'
/Users/byroot/.gem/ruby/3.2.2/gems/minitest-5.15.0/lib/minitest/test.rb:98:in `block (3 levels) in run'
test/redis_client_test.rb:180:in `test_gc_safety'
test/redis_client_test.rb:180:in `times'
test/redis_client_test.rb:181:in `block in test_gc_safety'
/Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:255:in `call'
/Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:677:in `ensure_connected'
/Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:256:in `block in call'
/Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client/middlewares.rb:16:in `call'
/Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client.rb:257:in `block (2 levels) in call'
/Users/byroot/src/github.com/redis-rb/redis-client/lib/redis_client/connection_mixin.rb:33:in `call'

-- C level backtrace information -------------------------------------------
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_vm_bugreport+0x9a0) [0x105b07f78]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_bug_without_die+0x15c) [0x10592c44c]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_bug+0x1c) [0x105c100c0]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rgengc_check_relation+0x0) [0x10595dc90]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_gc_mark_vm_stack_values+0x48) [0x10594b66c]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_execution_context_mark+0x38) [0x105af3f9c]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(cont_mark+0x2c) [0x10590c8b4]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(gc_mark_stacked_objects_incremental+0x9c) [0x1059569f8]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(gc_marks_rest+0xac) [0x1059568f8]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(gc_rest+0x68) [0x10594a2c8]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(objspace_xmalloc0+0xb0) [0x105950544]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_id_table_create+0x18) [0x105a9ff8c]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_vm_search_method_slowpath+0xf4) [0x105adbf00]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_sendish+0x5fc) [0x105afe5ec]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_exec_core+0x239c) [0x105adfba4]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_vm_exec+0xad4) [0x105af30cc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(invoke_block_from_c_bh+0x398) [0x105b02918]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_yield_1+0x7c) [0x105aeb6e4]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(int_dotimes+0x148) [0x1059cbcf0]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_call_cfunc_with_frame+0xe8) [0x105afc15c]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_sendish+0x4cc) [0x105afe4bc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_exec_core+0x2350) [0x105adfb58]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_vm_exec+0xad4) [0x105af30cc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(invoke_block_from_c_bh+0x398) [0x105b02918]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_yield+0xb4) [0x105aeb7d4]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_ary_each+0x40) [0x10589f3d8]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_call_cfunc_with_frame+0xe8) [0x105afc15c]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_sendish+0x4cc) [0x105afe4bc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_exec_core+0x2350) [0x105adfb58]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_vm_exec+0xad4) [0x105af30cc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(invoke_block_from_c_bh+0x398) [0x105b02918]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_yield+0xb4) [0x105aeb7d4]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_ary_collect+0xd0) [0x1058a57bc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_call_cfunc_with_frame+0xe8) [0x105afc15c]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_sendish+0x4cc) [0x105afe4bc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(vm_exec_core+0x2350) [0x105adfb58]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_vm_exec+0xad4) [0x105af30cc]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_vm_invoke_proc+0x4ac) [0x105af0d40]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_proc_call_kw+0x94) [0x105a05228]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_ec_exec_end_proc+0x1f0) [0x10593b010]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_ec_teardown+0x138) [0x105937634]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(rb_ec_cleanup+0x1d0) [0x105937888]
/opt/rubies/3.2.2/lib/libruby.3.2.dylib(ruby_run_node+0x6c) [0x105937bbc]
/opt/rubies/3.2.2/bin/ruby(main+0x68) [0x104d3bf34]