You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
close() can free the native client handle while another thread is mid-dispatch in Bindings.command / Bindings.batch / Bindings.invoke_script. Those FFI calls are blocking: true (they release the GVL and run in native code), so a concurrent close calling Bindings.close_client tears down the connection under a live dispatch → intermittent malloc(): unaligned tcache chunk detected SIGABRT.
This is distinct from the close-vs-close double-free already fixed in #224. That fix serializes close against close; it does not serialize close against an in-flight command.
Repro
require"valkey-glide"client=Valkey.newworkers=20.times.mapdoThread.new{loop{client.get("k")rescuebreak}}endsleep0.05# let GETs start dispatching into native codeclient.close# frees the handle while commands are still in-flightworkers.each(&:join)# Intermittent: `malloc(): unaligned tcache chunk detected`, SIGABRT.# Run in a loop to reproduce reliably:# while ruby repro.rb; do :; done
invoke_script reproduces the same way (swap client.get("k") for an EVAL).
Expected
close() should either wait for in-flight commands to finish or make them fail fast — it must never free the handle while a native dispatch is live. After close, further commands should raise ConnectionError("the client is closed"), not crash.
Summary
close()can free the native client handle while another thread is mid-dispatch inBindings.command/Bindings.batch/Bindings.invoke_script. Those FFI calls areblocking: true(they release the GVL and run in native code), so a concurrentclosecallingBindings.close_clienttears down the connection under a live dispatch → intermittentmalloc(): unaligned tcache chunk detectedSIGABRT.This is distinct from the close-vs-close double-free already fixed in #224. That fix serializes
closeagainstclose; it does not serializecloseagainst an in-flight command.Repro
invoke_scriptreproduces the same way (swapclient.get("k")for anEVAL).Expected
close()should either wait for in-flight commands to finish or make them fail fast — it must never free the handle while a native dispatch is live. After close, further commands should raiseConnectionError("the client is closed"), not crash.Notes
@close_lockbefore freeing;try_lockphase keepsSignal.trapshutdown working).close_client-drains-in-flight guarantee inlibglide_ffiwould be the complete cross-client fix.