redis-rb/redis-client

Thread safety issue with PubSub and hiredis

rianmcguire opened this issue · 2 comments

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 redis/redis-rb#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 `<main>'
repro.rb:15:in `loop'
repro.rb:16:in `block in <main>'
/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  (<unknown module>)
    #5 0xffff959e9b34 in vm_call_cfunc_with_frame_ /usr/src/ruby/./vm_insnhelper.c:3594:11
    #6 0x30ffff959ab1fc  (<unknown module>)
    #7 0x71ffff9599f900  (<unknown module>)
    #8 0x3ffff95651d5c  (<unknown module>)
    #9 0x79ffff95651b94  (<unknown module>)
    #10 0x39aaaacf1dbf1c  (<unknown module>)
    #11 0x10ffff94f8777c  (<unknown module>)
    #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  (<unknown module>)
    #9 0x71ffff9599f900  (<unknown module>)
    #10 0x3ffff95651d5c  (<unknown module>)
    #11 0x79ffff95651b94  (<unknown module>)
    #12 0x39aaaacf1dbf1c  (<unknown module>)
    #13 0x10ffff94f8777c  (<unknown module>)
    #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  (<unknown module>)
    #6 0x4cffff959f8e70  (<unknown module>)
    #7 0x21ffff959fc1b0  (<unknown module>)
    #8 0xaffff9593c28c  (<unknown module>)
    #9 0x42ffff959e9b34  (<unknown module>)
    #10 0x6effff959d8510  (<unknown module>)
    #11 0x3fffff959d7f54  (<unknown module>)
    #12 0x28ffff959a3a80  (<unknown module>)
    #13 0x71ffff9599f900  (<unknown module>)
    #14 0x3ffff95651d5c  (<unknown module>)
    #15 0x79ffff95651b94  (<unknown module>)
    #16 0x39aaaacf1dbf1c  (<unknown module>)
    #17 0x10ffff94f8777c  (<unknown module>)
    #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

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

def write(command)
_write(command)
flush
rescue SystemCallError, IOError => error
raise ConnectionError.with_config(error.message, config)
rescue Error => error
error._set_config(config)
raise error
end
def write_multi(commands)
commands.each do |command|
_write(command)
end
flush
rescue SystemCallError, IOError => error
raise ConnectionError.with_config(error.message, config)
rescue Error => error
error._set_config(config)
raise error
end

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.

Nice catch.