Skip to content

Rare occurences of panic: send on closed channel in rpc/subscription.go #22322

@samsondav

Description

@samsondav

System information

Geth version: 1.9.25
OS & Version: Linux

Expected behaviour

We are calling rpc.Unsubscribe like so:

	client.SubscribeFilterLogs(ctx, filterQuery, ch)
        # ... some time later ...
	client.Unsubscribe()
	close(ch)

I would expect this to always be safe.

Actual behaviour

In very rare cases this can panic with send on closed channel. It seems that messages can still be sent on the passed in channel even after Unsubscribe returns.

We found this while load testing with fast resubscribes and hundreds of thousands of iterations.

Steps to reproduce the behaviour

Almost impossible to reproduce. Extremely high rates of subscribe/unsubscribe with channel close as detailed above might expose it.

Backtrace

panic: send on closed channel

goroutine 276873727 [running]:
reflect.rselect(0xc03196b860, 0x3, 0x3, 0x188458e, 0xe)
	/usr/local/go/src/runtime/select.go:544 +0x38a
reflect.Select(0xc013d83ee0, 0x3, 0x3, 0xc02e50f6e0, 0x1796e20, 0xc0353b62c0, 0x0, 0x0)
	/usr/local/go/src/reflect/value.go:2229 +0x170
github.com/ethereum/go-ethereum/rpc.(*ClientSubscription).forward(0xc005e0c090, 0xc0324ef100, 0x0, 0x0)
	/root/go/pkg/mod/github.com/ethereum/[email protected]/rpc/subscription.go:299 +0x2db
github.com/ethereum/go-ethereum/rpc.(*ClientSubscription).start(0xc005e0c090)
	/root/go/pkg/mod/github.com/ethereum/[email protected]/rpc/subscription.go:279 +0x2b
created by github.com/ethereum/go-ethereum/rpc.(*handler).handleResponse
	/root/go/pkg/mod/github.com/ethereum/[email protected]/rpc/handler.go:284 +0x23d

Probable cause and suggested fix

It seems that quitWithError (

func (sub *ClientSubscription) quitWithError(unsubscribeServer bool, err error) {
) can race with forward (
func (sub *ClientSubscription) forward() (unsubscribeServer bool, err error) {
) causing messages to be sent even after Unsubscribe returns.

A coordination channel so that quitWithError waits until forward has executed could resolve it.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions