redis-rb / redis-client

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

Thread safety issue with PubSub and hiredis #208

Closed rianmcguire closed 2 months ago

rianmcguire commented 2 months ago

I've been digging into some Ruby crashes we've been seeing with ActionCable in our test suite, and I think I've uncovered a thread safety issue when HiredisConnection is used with #pubsub.

Minimal reproduction:

require 'redis-client'
require 'hiredis-client'

redis_config = RedisClient.config
redis = redis_config.new_client
pubsub = redis.pubsub

reader = Thread.new do
    while event = pubsub.next_event
    end
end

loop do
    pubsub.call_v(["subscribe", "channel"])
    pubsub.call_v(["unsubscribe", "channel"])
end

I understand using multiple threads here is supposed to be safe, as PubSub #call_v only writes to the socket, and #next_event only reads from the socket (see also https://github.com/redis/redis-rb/pull/1131).

Without hiredis-client, this runs indefinitely without errors.

With hiredis-client, it either fails with a weird connection error:

/var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:113:in `rescue in write': Connection reset by peer (redis://localhost:6379) (RedisClient::ConnectionError)
    from /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:109:in `write'
    from /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client.rb:498:in `call_v'
    from repro.rb:17:in `block in <main>'
    from repro.rb:15:in `loop'
    from repro.rb:15:in `<main>'
/var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:111:in `flush': Connection reset by peer (Errno::ECONNRESET)
    from /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:111:in `write'
    from /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client.rb:498:in `call_v'
    from repro.rb:17:in `block in <main>'
    from repro.rb:15:in `loop'
    from repro.rb:15:in `<main>'

Or crashes Ruby with a seg fault:

Ruby crash dump

``` /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:111: [BUG] Segmentation fault at 0x0000000000000008 ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [aarch64-linux-gnu] -- Control frame information ----------------------------------------------- c:0007 p:---- s:0032 e:000031 CFUNC :flush c:0006 p:0009 s:0028 e:000027 METHOD /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:111 c:0005 p:0012 s:0022 e:000021 METHOD /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client.rb:498 c:0004 p:0010 s:0017 e:000016 BLOCK repro.rb:16 [FINISH] c:0003 p:---- s:0014 e:000013 CFUNC :loop c:0002 p:0055 s:0010 E:001610 EVAL repro.rb:15 [FINISH] c:0001 p:0000 s:0003 E:000030 (none) [FINISH] -- Ruby level backtrace information ---------------------------------------- repro.rb:15:in `

' repro.rb:15:in `loop' repro.rb:16:in `block in
' /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client.rb:498:in `call_v' /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:111:in `write' /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb:111:in `flush' -- Machine register context ------------------------------------------------ x0: 0x0000000000000000 x1: 0x0000fffff9875bcc x2: 0x0000000000000000 x3: 0x0000000000000001 x4: 0x0000000000000000 x5: 0x0000aaaaffac0170 x6: 0x0000000000000000 x7: 0x000000000040b79e x18: 0x0000ffffb2b55670 x19: 0x0000fffff9875bd0 x20: 0x0000000000000000 x21: 0x0000000000000001 x22: 0x0000ffffaec13054 x23: 0x0000fffff9875bd0 x24: 0x0000aaaaffabfd80 x25: 0x0000aaaaffabc0f0 x26: 0x0000aaaaffabd310 x27: 0x0000000000000000 x28: 0x0000000000000000 x29: 0x0000fffff9875ab0 sp: 0x0000fffff9875ab0 fau: 0x0000000000000008 -- C level backtrace information ------------------------------------------- /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(0xffffb3011ecc) [0xffffb3011ecc] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(0xffffb2e6c854) [0xffffb2e6c854] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(0xffffb2f88eb8) [0xffffb2f88eb8] linux-vdso.so.1(__kernel_rt_sigreturn+0x0) [0xffffb319e7bc] [0xffffaec1924c] [0xffffaec1306c] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(rb_nogvl+0xc0) [0xffffb2fc2a74] [0xffffaec152cc] [0xffffb2ff67a4] [0xffffb2ff8bc0] [0xffffb2ffb74c] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(rb_vm_exec+0xd4) [0xffffb2ffffd4] [0xffffb300314c] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(rb_vrescue2+0xec) [0xffffb2e73a3c] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(rb_rescue2+0x78) [0xffffb2e73c6c] [0xffffb2ff67a4] [0xffffb2ff8bc0] [0xffffb2ffb7ac] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(rb_vm_exec+0xd4) [0xffffb2ffffd4] [0xffffb2e72694] /lib/aarch64-linux-gnu/libruby-3.1.so.3.1(ruby_run_node+0x68) [0xffffb2e75fc8] [0xaaaae4410b1c] [0xffffb2a67780] [0xffffb2a67858] /usr/bin/ruby3.1(_start+0x30) [0xaaaae4410bb0] -- Other runtime information ----------------------------------------------- * Loaded script: repro.rb * Loaded features: 0 enumerator.so 1 thread.rb 2 fiber.so 3 rational.so 4 complex.so 5 ruby2_keywords.rb 6 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/encdb.so 7 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/trans/transdb.so 8 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/rbconfig.rb 9 /usr/lib/ruby/vendor_ruby/rubygems/compatibility.rb 10 /usr/lib/ruby/vendor_ruby/rubygems/defaults.rb 11 /usr/lib/ruby/vendor_ruby/rubygems/deprecate.rb 12 /usr/lib/ruby/vendor_ruby/rubygems/errors.rb 13 /usr/lib/ruby/vendor_ruby/rubygems/unknown_command_spell_checker.rb 14 /usr/lib/ruby/vendor_ruby/rubygems/exceptions.rb 15 /usr/lib/ruby/vendor_ruby/rubygems/basic_specification.rb 16 /usr/lib/ruby/vendor_ruby/rubygems/stub_specification.rb 17 /usr/lib/ruby/vendor_ruby/rubygems/platform.rb 18 /usr/lib/ruby/vendor_ruby/rubygems/version.rb 19 /usr/lib/ruby/vendor_ruby/rubygems/requirement.rb 20 /usr/lib/ruby/vendor_ruby/rubygems/util/list.rb 21 /usr/lib/ruby/vendor_ruby/rubygems/specification.rb 22 /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb 23 /usr/lib/ruby/vendor_ruby/rubygems/util.rb 24 /usr/lib/ruby/vendor_ruby/rubygems/dependency.rb 25 /usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_gem.rb 26 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/monitor.so 27 /usr/lib/ruby/3.1.0/monitor.rb 28 /usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb 29 /usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_warn.rb 30 /usr/lib/ruby/vendor_ruby/rubygems.rb 31 /usr/lib/ruby/vendor_ruby/rubygems/path_support.rb 32 /usr/lib/ruby/3.1.0/error_highlight/version.rb 33 /usr/lib/ruby/3.1.0/error_highlight/base.rb 34 /usr/lib/ruby/3.1.0/error_highlight/formatter.rb 35 /usr/lib/ruby/3.1.0/error_highlight/core_ext.rb 36 /usr/lib/ruby/3.1.0/error_highlight.rb 37 /usr/lib/ruby/3.1.0/did_you_mean/version.rb 38 /usr/lib/ruby/3.1.0/did_you_mean/core_ext/name_error.rb 39 /usr/lib/ruby/3.1.0/did_you_mean/levenshtein.rb 40 /usr/lib/ruby/3.1.0/did_you_mean/jaro_winkler.rb 41 /usr/lib/ruby/3.1.0/did_you_mean/spell_checker.rb 42 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb 43 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb 44 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/name_error_checkers.rb 45 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/method_name_checker.rb 46 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/key_error_checker.rb 47 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/null_checker.rb 48 /usr/lib/ruby/3.1.0/did_you_mean/tree_spell_checker.rb 49 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/require_path_checker.rb 50 /usr/lib/ruby/3.1.0/did_you_mean/spell_checkers/pattern_key_name_checker.rb 51 /usr/lib/ruby/3.1.0/did_you_mean/formatter.rb 52 /usr/lib/ruby/3.1.0/did_you_mean.rb 53 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/version.rb 54 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/command_builder.rb 55 /usr/lib/ruby/3.1.0/uri/version.rb 56 /usr/lib/ruby/3.1.0/uri/rfc2396_parser.rb 57 /usr/lib/ruby/3.1.0/uri/rfc3986_parser.rb 58 /usr/lib/ruby/3.1.0/uri/common.rb 59 /usr/lib/ruby/3.1.0/uri/generic.rb 60 /usr/lib/ruby/3.1.0/uri/file.rb 61 /usr/lib/ruby/3.1.0/uri/ftp.rb 62 /usr/lib/ruby/3.1.0/uri/http.rb 63 /usr/lib/ruby/3.1.0/uri/https.rb 64 /usr/lib/ruby/3.1.0/uri/ldap.rb 65 /usr/lib/ruby/3.1.0/uri/ldaps.rb 66 /usr/lib/ruby/3.1.0/uri/mailto.rb 67 /usr/lib/ruby/3.1.0/uri/ws.rb 68 /usr/lib/ruby/3.1.0/uri.rb 69 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/url_config.rb 70 /usr/lib/ruby/3.1.0/digest/version.rb 71 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/digest.so 72 /usr/lib/ruby/3.1.0/digest/loader.rb 73 /usr/lib/ruby/3.1.0/digest.rb 74 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/openssl.so 75 /usr/lib/ruby/3.1.0/openssl/bn.rb 76 /usr/lib/ruby/3.1.0/openssl/marshal.rb 77 /usr/lib/ruby/3.1.0/openssl/pkey.rb 78 /usr/lib/ruby/3.1.0/openssl/cipher.rb 79 /usr/lib/ruby/3.1.0/openssl/digest.rb 80 /usr/lib/ruby/3.1.0/openssl/hmac.rb 81 /usr/lib/ruby/3.1.0/openssl/x509.rb 82 /usr/lib/ruby/3.1.0/openssl/buffering.rb 83 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/nonblock.so 84 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/socket.so 85 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/wait.so 86 /usr/lib/ruby/3.1.0/socket.rb 87 /usr/lib/ruby/3.1.0/ipaddr.rb 88 /usr/lib/ruby/3.1.0/openssl/ssl.rb 89 /usr/lib/ruby/3.1.0/openssl/pkcs5.rb 90 /usr/lib/ruby/3.1.0/openssl/version.rb 91 /usr/lib/ruby/3.1.0/openssl.rb 92 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/config.rb 93 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/pid_cache.rb 94 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/sentinel_config.rb 95 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/middlewares.rb 96 /usr/lib/ruby/3.1.0/timeout.rb 97 /var/lib/gems/3.1.0/gems/connection_pool-2.4.1/lib/connection_pool/version.rb 98 /var/lib/gems/3.1.0/gems/connection_pool-2.4.1/lib/connection_pool/timed_stack.rb 99 /var/lib/gems/3.1.0/gems/connection_pool-2.4.1/lib/connection_pool/wrapper.rb 100 /var/lib/gems/3.1.0/gems/connection_pool-2.4.1/lib/connection_pool.rb 101 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/pooled.rb 102 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/circuit_breaker.rb 103 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/connection_mixin.rb 104 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/ruby_connection/buffered_io.rb 105 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/ruby_connection/resp3.rb 106 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client/ruby_connection.rb 107 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis_client.rb 108 /var/lib/gems/3.1.0/gems/redis-client-0.22.2/lib/redis-client.rb 109 /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.so 110 /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.rb 111 /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/hiredis-client.rb * Process memory map: aaaae4410000-aaaae4411000 r-xp 00000000 fe:01 4798 /usr/bin/ruby3.1 aaaae442f000-aaaae4430000 r--p 0000f000 fe:01 4798 /usr/bin/ruby3.1 aaaae4430000-aaaae4431000 rw-p 00010000 fe:01 4798 /usr/bin/ruby3.1 aaaaffabb000-aaab00081000 rw-p 00000000 00:00 0 [heap] ffffa8000000-ffffa8021000 rw-p 00000000 00:00 0 ffffa8021000-ffffac000000 ---p 00000000 00:00 0 ffffae400000-ffffae782000 r--s 00000000 fe:01 7924 /usr/lib/aarch64-linux-gnu/libruby-3.1.so.3.1.2 ffffae980000-ffffae994000 r-xp 00000000 fe:01 1599 /usr/lib/aarch64-linux-gnu/libgcc_s.so.1 ffffae994000-ffffae9af000 ---p 00014000 fe:01 1599 /usr/lib/aarch64-linux-gnu/libgcc_s.so.1 ffffae9af000-ffffae9b0000 r--p 0001f000 fe:01 1599 /usr/lib/aarch64-linux-gnu/libgcc_s.so.1 ffffae9b0000-ffffae9b1000 rw-p 00020000 fe:01 1599 /usr/lib/aarch64-linux-gnu/libgcc_s.so.1 ffffae9b7000-ffffae9c8000 r--s 00000000 fe:01 4798 /usr/bin/ruby3.1 ffffae9c8000-ffffaea00000 rw-p 00000000 00:00 0 ffffaea00000-ffffaea10000 ---p 00000000 00:00 0 ffffaea10000-ffffaec10000 rw-p 00000000 00:00 0 ffffaec10000-ffffaec27000 r-xp 00000000 fe:01 824845 /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.so ffffaec27000-ffffaec3f000 ---p 00017000 fe:01 824845 /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.so ffffaec3f000-ffffaec40000 r--p 0001f000 fe:01 824845 /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.so ffffaec40000-ffffaec41000 rw-p 00020000 fe:01 824845 /var/lib/gems/3.1.0/gems/hiredis-client-0.22.2/lib/redis_client/hiredis_connection.so ffffaec48000-ffffaec50000 rw-p 00000000 00:00 0 ffffaec50000-ffffaec52000 r-xp 00000000 fe:01 397265 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/wait.so ffffaec52000-ffffaec6f000 ---p 00002000 fe:01 397265 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/wait.so ffffaec6f000-ffffaec70000 r--p 0000f000 fe:01 397265 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/wait.so ffffaec70000-ffffaec71000 rw-p 00010000 fe:01 397265 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/wait.so ffffaec78000-ffffaec80000 rw-p 00000000 00:00 0 ffffaec80000-ffffaecae000 r-xp 00000000 fe:01 397284 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/socket.so ffffaecae000-ffffaecbf000 ---p 0002e000 fe:01 397284 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/socket.so ffffaecbf000-ffffaecc0000 r--p 0002f000 fe:01 397284 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/socket.so ffffaecc0000-ffffaecc1000 rw-p 00030000 fe:01 397284 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/socket.so ffffaecc8000-ffffaecd0000 rw-p 00000000 00:00 0 ffffaecd0000-ffffaecd1000 r-xp 00000000 fe:01 397264 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/nonblock.so ffffaecd1000-ffffaecef000 ---p 00001000 fe:01 397264 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/nonblock.so ffffaecef000-ffffaecf0000 r--p 0000f000 fe:01 397264 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/nonblock.so ffffaecf0000-ffffaecf1000 rw-p 00010000 fe:01 397264 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/io/nonblock.so ffffaecf8000-ffffaed00000 rw-p 00000000 00:00 0 ffffaed00000-ffffaed04000 r-xp 00000000 fe:01 397195 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/digest.so ffffaed04000-ffffaed1f000 ---p 00004000 fe:01 397195 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/digest.so ffffaed1f000-ffffaed20000 r--p 0000f000 fe:01 397195 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/digest.so ffffaed20000-ffffaed21000 rw-p 00010000 fe:01 397195 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/digest.so ffffaed28000-ffffaed30000 rw-p 00000000 00:00 0 ffffaed30000-ffffaf113000 r-xp 00000000 fe:01 2195 /usr/lib/aarch64-linux-gnu/libcrypto.so.3 ffffaf113000-ffffaf125000 ---p 003e3000 fe:01 2195 /usr/lib/aarch64-linux-gnu/libcrypto.so.3 ffffaf125000-ffffaf180000 r--p 003e5000 fe:01 2195 /usr/lib/aarch64-linux-gnu/libcrypto.so.3 ffffaf180000-ffffaf183000 rw-p 00440000 fe:01 2195 /usr/lib/aarch64-linux-gnu/libcrypto.so.3 ffffaf183000-ffffaf186000 rw-p 00000000 00:00 0 ffffaf18c000-ffffaf190000 rw-p 00000000 00:00 0 ffffaf190000-ffffaf22b000 r-xp 00000000 fe:01 2196 /usr/lib/aarch64-linux-gnu/libssl.so.3 ffffaf22b000-ffffaf236000 ---p 0009b000 fe:01 2196 /usr/lib/aarch64-linux-gnu/libssl.so.3 ffffaf236000-ffffaf240000 r--p 000a6000 fe:01 2196 /usr/lib/aarch64-linux-gnu/libssl.so.3 ffffaf240000-ffffaf244000 rw-p 000b0000 fe:01 2196 /usr/lib/aarch64-linux-gnu/libssl.so.3 ffffaf248000-ffffaf250000 rw-p 00000000 00:00 0 ffffaf250000-ffffaf2aa000 r-xp 00000000 fe:01 397273 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/openssl.so ffffaf2aa000-ffffaf2bc000 ---p 0005a000 fe:01 397273 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/openssl.so ffffaf2bc000-ffffaf2c0000 r--p 0005c000 fe:01 397273 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/openssl.so ffffaf2c0000-ffffaf2c1000 rw-p 00060000 fe:01 397273 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/openssl.so ffffaf2c8000-ffffaf320000 rw-p 00000000 00:00 0 ffffaf320000-ffffaf322000 r-xp 00000000 fe:01 397270 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/monitor.so ffffaf322000-ffffaf33f000 ---p 00002000 fe:01 397270 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/monitor.so ffffaf33f000-ffffaf340000 r--p 0000f000 fe:01 397270 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/monitor.so ffffaf340000-ffffaf341000 rw-p 00010000 fe:01 397270 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/monitor.so ffffaf344000-ffffaf3a0000 rw-p 00000000 00:00 0 ffffaf3a0000-ffffaf3a2000 r-xp 00000000 fe:01 397245 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/trans/transdb.so ffffaf3a2000-ffffaf3bf000 ---p 00002000 fe:01 397245 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/trans/transdb.so ffffaf3bf000-ffffaf3c0000 r--p 0000f000 fe:01 397245 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/trans/transdb.so ffffaf3c0000-ffffaf3c1000 rw-p 00010000 fe:01 397245 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/trans/transdb.so ffffaf3c8000-ffffaf3d0000 rw-p 00000000 00:00 0 ffffaf3d0000-ffffaf3d2000 r-xp 00000000 fe:01 397201 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/encdb.so ffffaf3d2000-ffffaf3ef000 ---p 00002000 fe:01 397201 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/encdb.so ffffaf3ef000-ffffaf3f0000 r--p 0000f000 fe:01 397201 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/encdb.so ffffaf3f0000-ffffaf3f1000 rw-p 00010000 fe:01 397201 /usr/lib/aarch64-linux-gnu/ruby/3.1.0/enc/encdb.so ffffaf3f8000-ffffaf400000 rw-p 00000000 00:00 0 ffffaf400000-ffffaf401000 ---p 00000000 00:00 0 ffffaf401000-ffffaf4a2000 rw-p 00000000 00:00 0 ffffaf4a2000-ffffaf4a3000 ---p 00000000 00:00 0 ffffaf4a3000-ffffaf544000 rw-p 00000000 00:00 0 ffffaf544000-ffffaf545000 ---p 00000000 00:00 0 ffffaf545000-ffffaf5e6000 rw-p 00000000 00:00 0 ffffaf5e6000-ffffaf5e7000 ---p 00000000 00:00 0 ffffaf5e7000-ffffaf688000 rw-p 00000000 00:00 0 ffffaf688000-ffffaf689000 ---p 00000000 00:00 0 ffffaf689000-ffffaf72a000 rw-p 00000000 00:00 0 ffffaf72a000-ffffaf72b000 ---p 00000000 00:00 0 ffffaf72b000-ffffaf7cc000 rw-p 00000000 00:00 0 ffffaf7cc000-ffffaf7cd000 ---p 00000000 00:00 0 ffffaf7cd000-ffffaf86e000 rw-p 00000000 00:00 0 ffffaf86e000-ffffaf86f000 ---p 00000000 00:00 0 ffffaf86f000-ffffaf910000 rw-p 00000000 00:00 0 ffffaf910000-ffffaf911000 ---p 00000000 00:00 0 ffffaf911000-ffffaf9b2000 rw-p 00000000 00:00 0 ffffaf9b2000-ffffaf9b3000 ---p 00000000 00:00 0 ffffaf9b3000-ffffafa54000 rw-p 00000000 00:00 0 ffffafa54000-ffffafa55000 ---p 00000000 00:00 0 ffffafa55000-ffffafaf6000 rw-p 00000000 00:00 0 ffffafaf6000-ffffafaf7000 ---p 00000000 00:00 0 ffffafaf7000-ffffafb98000 rw-p 00000000 00:00 0 ffffafb98000-ffffafb99000 ---p 00000000 00:00 0 ffffafb99000-ffffafc3a000 rw-p 00000000 00:00 0 ffffafc3a000-ffffafc3b000 ---p 00000000 00:00 0 ffffafc3b000-ffffafcdc000 rw-p 00000000 00:00 0 ffffafcdc000-ffffafcdd000 ---p 00000000 00:00 0 ffffafcdd000-ffffafd7e000 rw-p 00000000 00:00 0 ffffafd7e000-ffffafd7f000 ---p 00000000 00:00 0 ffffafd7f000-ffffafe20000 rw-p 00000000 00:00 0 ffffafe20000-ffffafe21000 ---p 00000000 00:00 0 ffffafe21000-ffffafec2000 rw-p 00000000 00:00 0 ffffafec2000-ffffafec3000 ---p 00000000 00:00 0 ffffafec3000-ffffaff64000 rw-p 00000000 00:00 0 ffffaff64000-ffffaff65000 ---p 00000000 00:00 0 ffffaff65000-ffffb0006000 rw-p 00000000 00:00 0 ffffb0006000-ffffb0007000 ---p 00000000 00:00 0 ffffb0007000-ffffb00a8000 rw-p 00000000 00:00 0 ffffb00a8000-ffffb00a9000 ---p 00000000 00:00 0 ffffb00a9000-ffffb014a000 rw-p 00000000 00:00 0 ffffb014a000-ffffb014b000 ---p 00000000 00:00 0 ffffb014b000-ffffb01ec000 rw-p 00000000 00:00 0 ffffb01ec000-ffffb01ed000 ---p 00000000 00:00 0 ffffb01ed000-ffffb028e000 rw-p 00000000 00:00 0 ffffb028e000-ffffb028f000 ---p 00000000 00:00 0 ffffb028f000-ffffb0330000 rw-p 00000000 00:00 0 ffffb0330000-ffffb0331000 ---p 00000000 00:00 0 ffffb0331000-ffffb03d2000 rw-p 00000000 00:00 0 ffffb03d2000-ffffb03d3000 ---p 00000000 00:00 0 ffffb03d3000-ffffb0474000 rw-p 00000000 00:00 0 ffffb0474000-ffffb0475000 ---p 00000000 00:00 0 ffffb0475000-ffffb0516000 rw-p 00000000 00:00 0 ffffb0516000-ffffb0517000 ---p 00000000 00:00 0 ffffb0517000-ffffb05b8000 rw-p 00000000 00:00 0 ffffb05b8000-ffffb05b9000 ---p 00000000 00:00 0 ffffb05b9000-ffffb065a000 rw-p 00000000 00:00 0 ffffb065a000-ffffb065b000 ---p 00000000 00:00 0 ffffb065b000-ffffb06fc000 rw-p 00000000 00:00 0 ffffb06fc000-ffffb06fd000 ---p 00000000 00:00 0 ffffb06fd000-ffffb079e000 rw-p 00000000 00:00 0 ffffb079e000-ffffb079f000 ---p 00000000 00:00 0 ffffb079f000-ffffb2840000 rw-p 00000000 00:00 0 ffffb2847000-ffffb29e9000 rw-p 00000000 00:00 0 ffffb29e9000-ffffb2a40000 r--p 00000000 fe:01 4298 /usr/lib/locale/C.utf8/LC_CTYPE ffffb2a40000-ffffb2bc7000 r-xp 00000000 fe:01 25337 /usr/lib/aarch64-linux-gnu/libc.so.6 ffffb2bc7000-ffffb2bdc000 ---p 00187000 fe:01 25337 /usr/lib/aarch64-linux-gnu/libc.so.6 ffffb2bdc000-ffffb2be0000 r--p 0018c000 fe:01 25337 /usr/lib/aarch64-linux-gnu/libc.so.6 ffffb2be0000-ffffb2be2000 rw-p 00190000 fe:01 25337 /usr/lib/aarch64-linux-gnu/libc.so.6 ffffb2be2000-ffffb2bef000 rw-p 00000000 00:00 0 ffffb2bf0000-ffffb2c70000 r-xp 00000000 fe:01 25340 /usr/lib/aarch64-linux-gnu/libm.so.6 ffffb2c70000-ffffb2c7f000 ---p 00080000 fe:01 25340 /usr/lib/aarch64-linux-gnu/libm.so.6 ffffb2c7f000-ffffb2c80000 r--p 0008f000 fe:01 25340 /usr/lib/aarch64-linux-gnu/libm.so.6 ffffb2c80000-ffffb2c81000 rw-p 00090000 fe:01 25340 /usr/lib/aarch64-linux-gnu/libm.so.6 ffffb2c88000-ffffb2c90000 rw-p 00000000 00:00 0 ffffb2c90000-ffffb2cbe000 r-xp 00000000 fe:01 1530 /usr/lib/aarch64-linux-gnu/libcrypt.so.1.1.0 ffffb2cbe000-ffffb2ccf000 ---p 0002e000 fe:01 1530 /usr/lib/aarch64-linux-gnu/libcrypt.so.1.1.0 ffffb2ccf000-ffffb2cd0000 r--p 0002f000 fe:01 1530 /usr/lib/aarch64-linux-gnu/libcrypt.so.1.1.0 ffffb2cd0000-ffffb2cd1000 rw-p 00030000 fe:01 1530 /usr/lib/aarch64-linux-gnu/libcrypt.so.1.1.0 ffffb2cd1000-ffffb2cd9000 rw-p 00000000 00:00 0 ffffb2ce0000-ffffb2d55000 r-xp 00000000 fe:01 1629 /usr/lib/aarch64-linux-gnu/libgmp.so.10.4.1 ffffb2d55000-ffffb2d6f000 ---p 00075000 fe:01 1629 /usr/lib/aarch64-linux-gnu/libgmp.so.10.4.1 ffffb2d6f000-ffffb2d70000 r--p 0007f000 fe:01 1629 /usr/lib/aarch64-linux-gnu/libgmp.so.10.4.1 ffffb2d70000-ffffb2d71000 rw-p 00080000 fe:01 1629 /usr/lib/aarch64-linux-gnu/libgmp.so.10.4.1 ffffb2d78000-ffffb2d80000 rw-p 00000000 00:00 0 ffffb2d80000-ffffb2d9a000 r-xp 00000000 fe:01 4913 /usr/lib/aarch64-linux-gnu/libz.so.1.2.13 ffffb2d9a000-ffffb2daf000 ---p 0001a000 fe:01 4913 /usr/lib/aarch64-linux-gnu/libz.so.1.2.13 ffffb2daf000-ffffb2db0000 r--p 0001f000 fe:01 4913 /usr/lib/aarch64-linux-gnu/libz.so.1.2.13 ffffb2db0000-ffffb2db1000 rw-p 00020000 fe:01 4913 /usr/lib/aarch64-linux-gnu/libz.so.1.2.13 ffffb2db8000-ffffb2dc0000 rw-p 00000000 00:00 0 ffffb2dc0000-ffffb312a000 r-xp 00000000 fe:01 7924 /usr/lib/aarch64-linux-gnu/libruby-3.1.so.3.1.2 ffffb312a000-ffffb3136000 ---p 0036a000 fe:01 7924 /usr/lib/aarch64-linux-gnu/libruby-3.1.so.3.1.2 ffffb3136000-ffffb3140000 r--p 00376000 fe:01 7924 /usr/lib/aarch64-linux-gnu/libruby-3.1.so.3.1.2 ffffb3140000-ffffb3141000 rw-p 00380000 fe:01 7924 /usr/lib/aarch64-linux-gnu/libruby-3.1.so.3.1.2 ffffb3141000-ffffb3152000 rw-p 00000000 00:00 0 ffffb3158000-ffffb3160000 rw-p 00000000 00:00 0 ffffb3161000-ffffb3187000 r-xp 00000000 fe:01 25329 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1 ffffb318c000-ffffb3190000 rw-p 00000000 00:00 0 ffffb3193000-ffffb319a000 r--s 00000000 fe:01 25601 /usr/lib/aarch64-linux-gnu/gconv/gconv-modules.cache ffffb319a000-ffffb319c000 rw-p 00000000 00:00 0 ffffb319c000-ffffb319e000 r--p 00000000 00:00 0 [vvar] ffffb319e000-ffffb319f000 r-xp 00000000 00:00 0 [vdso] ffffb319f000-ffffb31a1000 r--p 0002e000 fe:01 25329 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1 ffffb31a1000-ffffb31a3000 rw-p 00030000 fe:01 25329 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1 fffff9079000-fffff9878000 rw-p 00000000 00:00 0 [stack] Aborted (core dumped) ```

With Ruby 3.4.0-preview1 compiled with ASAN, ASAN detects a heap-use-after-free.

Full ASAN report

``` ================================================================= ==99==ERROR: AddressSanitizer: heap-use-after-free on address 0x5070000da3d3 at pc 0xaaaacf167d90 bp 0xffff70e2b5c0 sp 0xffff70e2adb0 READ of size 32 at 0x5070000da3d3 thread T2 #0 0xaaaacf167d8c in send (/usr/local/bin/ruby+0x97d8c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) #1 0xffff70f52024 in redisNetWrite /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/net.c:83:24 #2 0xffff70f58c88 in redisBufferWrite /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/hiredis.c:971:28 #3 0xffff70f517b8 in hiredis_buffer_write_safe /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:272:26 #4 0xffff95930b84 in rb_nogvl /usr/src/ruby/thread.c:1543:5 #5 0xffff70f4f264 in hiredis_buffer_write_nogvl /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:280:5 #6 0xffff70f4f264 in hiredis_read_internal /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:745:17 #7 0xffff70f4f264 in hiredis_read /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:808:13 #8 0xffff959e9b34 in vm_call_cfunc_with_frame_ /usr/src/ruby/./vm_insnhelper.c:3594:11 #9 0xffff959ab1fc in vm_sendish /usr/src/ruby/./vm_insnhelper.c:5723:15 #10 0xffff959ab1fc in vm_exec_core /usr/src/ruby/insns.def:891:11 #11 0xffff9599f660 in rb_vm_exec /usr/src/ruby/vm.c:2559:22 #12 0xffff959cd4b8 in invoke_block /usr/src/ruby/vm.c:1517:12 #13 0xffff959cd4b8 in invoke_iseq_block_from_c /usr/src/ruby/vm.c:1587:16 #14 0xffff959cd4b8 in invoke_block_from_c_proc /usr/src/ruby/vm.c:1685:16 #15 0xffff959cd4b8 in vm_invoke_proc /usr/src/ruby/vm.c:1715:12 #16 0xffff9594685c in thread_do_start_proc /usr/src/ruby/thread.c:594:16 #17 0xffff959451b8 in thread_do_start /usr/src/ruby/thread.c:611:18 #18 0xffff959451b8 in thread_start_func_2 /usr/src/ruby/thread.c:666:18 #19 0xffff959445f4 in call_thread_start_func_2 /usr/src/ruby/./thread_pthread.c:2235:5 #20 0xffff959445f4 in nt_start /usr/src/ruby/./thread_pthread.c:2280:13 #21 0xaaaacf19e124 in asan_thread_start(void*) asan_interceptors.cpp.o #22 0xffff94fdee54 in start_thread nptl/pthread_create.c:442:8 #23 0xffff95047f98 in thread_start misc/../sysdeps/unix/sysv/linux/aarch64/clone.S:79 0x5070000da3d3 is located 3 bytes inside of 68-byte region [0x5070000da3d0,0x5070000da414) freed by thread T0 here: #0 0xaaaacf1a057c in free (/usr/local/bin/ruby+0xd057c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) #1 0xffff70f58d9c in redisBufferWrite /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/hiredis.c:976:17 #2 0xffff70f517b8 in hiredis_buffer_write_safe /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:272:26 #3 0xffff95930b84 in rb_nogvl /usr/src/ruby/thread.c:1543:5 #4 0x36ffff70f4f6f8 () #5 0xffff959e9b34 in vm_call_cfunc_with_frame_ /usr/src/ruby/./vm_insnhelper.c:3594:11 #6 0x30ffff959ab1fc () #7 0x71ffff9599f900 () #8 0x3ffff95651d5c () #9 0x79ffff95651b94 () #10 0x39aaaacf1dbf1c () #11 0x10ffff94f8777c () #12 0xffff94f87854 in __libc_start_main csu/../csu/libc-start.c:360:3 #13 0xaaaacf10436c in _start (/usr/local/bin/ruby+0x3436c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) previously allocated by thread T0 here: #0 0xaaaacf1a0bbc in realloc (/usr/local/bin/ruby+0xd0bbc) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) #1 0xffff70f5c7e4 in hi_realloc /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/./alloc.h:66:12 #2 0xffff70f5c7e4 in sdsMakeRoomFor /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/sds.c:223:17 #3 0xffff70f5e338 in sdscatlen /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/sds.c:381:9 #4 0xffff70f5a27c in __redisAppendCommand /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/hiredis.c:1065:14 #5 0xffff70f5a27c in redisAppendCommandArgv /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/hiredis.c:1126:9 #6 0xffff70f4ece8 in hiredis_write /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:684:5 #7 0xffff959e9b34 in vm_call_cfunc_with_frame_ /usr/src/ruby/./vm_insnhelper.c:3594:11 #8 0x30ffff959ab1fc () #9 0x71ffff9599f900 () #10 0x3ffff95651d5c () #11 0x79ffff95651b94 () #12 0x39aaaacf1dbf1c () #13 0x10ffff94f8777c () #14 0xffff94f87854 in __libc_start_main csu/../csu/libc-start.c:360:3 #15 0xaaaacf10436c in _start (/usr/local/bin/ruby+0x3436c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) Thread T2 created by T0 here: #0 0xaaaacf186538 in pthread_create (/usr/local/bin/ruby+0xb6538) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) #1 0xffff9592e504 in native_thread_create0 /usr/src/ruby/./thread_pthread.c:2152:11 #2 0xffff9592e504 in native_thread_create_dedicated /usr/src/ruby/./thread_pthread.c:2219:12 #3 0xffff9592e504 in native_thread_create /usr/src/ruby/./thread_pthread.c:2398:16 #4 0xffff9592e504 in thread_create_core /usr/src/ruby/thread.c:859:11 #5 0x31ffff9593d77c () #6 0x4cffff959f8e70 () #7 0x21ffff959fc1b0 () #8 0xaffff9593c28c () #9 0x42ffff959e9b34 () #10 0x6effff959d8510 () #11 0x3fffff959d7f54 () #12 0x28ffff959a3a80 () #13 0x71ffff9599f900 () #14 0x3ffff95651d5c () #15 0x79ffff95651b94 () #16 0x39aaaacf1dbf1c () #17 0x10ffff94f8777c () #18 0xffff94f87854 in __libc_start_main csu/../csu/libc-start.c:360:3 #19 0xaaaacf10436c in _start (/usr/local/bin/ruby+0x3436c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) SUMMARY: AddressSanitizer: heap-use-after-free (/usr/local/bin/ruby+0x97d8c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835) in send Shadow bytes around the buggy address: 0x5070000da100: fd fd fa fa fa fa fd fd fd fd fd fd fd fd fd fd 0x5070000da180: fa fa fa fa fd fd fd fd fd fd fd fd fd fa fa fa 0x5070000da200: fa fa fd fd fd fd fd fd fd fd fd fa fa fa fa fa 0x5070000da280: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fd fd 0x5070000da300: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd =>0x5070000da380: fd fd fd fd fd fa fa fa fa fa[fd]fd fd fd fd fd 0x5070000da400: fd fd fd fa fa fa fa fa fd fd fd fd fd fd fd fd 0x5070000da480: fd fd fa fa fa fa fd fd fd fd fd fd fd fd fd fd 0x5070000da500: fa fa fa fa fd fd fd fd fd fd fd fd fd fa fa fa 0x5070000da580: fa fa fd fd fd fd fd fd fd fd fd fa fa fa fa fa 0x5070000da600: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==99==ABORTING ```

==99==ERROR: AddressSanitizer: heap-use-after-free on address 0x5070000da3d3 at pc 0xaaaacf167d90 bp 0xffff70e2b5c0 sp 0xffff70e2adb0

T2 in the ASAN report is the reader Ruby thread that's calling #next_event:

READ of size 32 at 0x5070000da3d3 thread T2
    #0 0xaaaacf167d8c in send (/usr/local/bin/ruby+0x97d8c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835)
    #1 0xffff70f52024 in redisNetWrite /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/net.c:83:24
    #2 0xffff70f58c88 in redisBufferWrite /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/hiredis.c:971:28
    #3 0xffff70f517b8 in hiredis_buffer_write_safe /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:272:26
    #4 0xffff95930b84 in rb_nogvl /usr/src/ruby/thread.c:1543:5
    #5 0xffff70f4f264 in hiredis_buffer_write_nogvl /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:280:5
    #6 0xffff70f4f264 in hiredis_read_internal /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:745:17
    #7 0xffff70f4f264 in hiredis_read /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:808:13

This thread should just be reading, but it ends up accessing the write buffer, as hiredis_read_internal also drains the write buffer.

The write buffer had already been freed by the main Ruby thread that's writing subscribe and unsubscribe commands:

0x5070000da3d3 is located 3 bytes inside of 68-byte region [0x5070000da3d0,0x5070000da414)
freed by thread T0 here:
    #0 0xaaaacf1a057c in free (/usr/local/bin/ruby+0xd057c) (BuildId: 432048382036ad8473f2cd7178b25f9bda061835)
    #1 0xffff70f58d9c in redisBufferWrite /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/vendor/hiredis.c:976:17
    #2 0xffff70f517b8 in hiredis_buffer_write_safe /usr/local/bundle/gems/hiredis-client-0.22.2/ext/redis_client/hiredis/hiredis_connection.c:272:26
    #3 0xffff95930b84 in rb_nogvl /usr/src/ruby/thread.c:1543:5
rianmcguire commented 2 months ago

From my naive understanding, it seems flushing the write buffer inside hiredis_read_internal is unnecessary, as HiredisConnection already calls flush after writes?

https://github.com/redis-rb/redis-client/blob/e8aff08b9ef179e44deda2227b3e8328c2f0172c/hiredis-client/lib/redis_client/hiredis_connection.rb#L109-L129

Removing the write buffer flush from hiredis_read_internal fixes the crashes/ASAN errors in my reproduction above. I've made a PR with the change.

byroot commented 2 months ago

Nice catch.