From e50ce7bbfbcad5009a0e2942780de54c4c6e86b4 Mon Sep 17 00:00:00 2001 From: Patrick Taibel Date: Wed, 4 Sep 2024 12:33:07 +0200 Subject: [PATCH] PROTON-2843: [Go] Fix segfault on settling a message on closed receivers Deliveries can not be settled after the receiver has been freed. Therefore, this adds a check to ensure that the receiver was not closed (which ensures that `Free` has not been called on the link yet) --- go/pkg/electron/electron_test.go | 15 +++++++++++++++ go/pkg/electron/receiver.go | 16 ++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/go/pkg/electron/electron_test.go b/go/pkg/electron/electron_test.go index d76e10ad32..ddbce35ec1 100644 --- a/go/pkg/electron/electron_test.go +++ b/go/pkg/electron/electron_test.go @@ -331,3 +331,18 @@ func TestHeartbeat(t *testing.T) { t.Error("expected server side time-out or connection abort error") } } + +func TestReceiverCloseBeforeAcknowledge(t *testing.T) { + p := newPipe(t, nil, nil) + defer func() { p.close() }() + r, s := p.receiver(Source("foo")) + go func() { + out := s.SendSync(amqp.NewMessageWith(0)) + _ = test.ErrorIf(t, test.Differ(Closed, out.Error)) + }() + rm, err := r.Receive() + test.FatalIf(t, err) + r.Close(nil) + <-r.Done() + _ = test.ErrorIf(t, test.Differ(Closed, rm.Accept())) +} diff --git a/go/pkg/electron/receiver.go b/go/pkg/electron/receiver.go index d412ac1eca..af49c5351d 100644 --- a/go/pkg/electron/receiver.go +++ b/go/pkg/electron/receiver.go @@ -28,7 +28,6 @@ import ( ) // Receiver is a Link that receives messages. -// type Receiver interface { Endpoint LinkSettings @@ -201,10 +200,19 @@ type ReceivedMessage struct { // Acknowledge a ReceivedMessage with the given delivery status. func (rm *ReceivedMessage) acknowledge(status uint64) error { - return rm.receiver.(*receiver).engine().Inject(func() { - // Deliveries are valid as long as the connection is, unless settled. - rm.pDelivery.SettleAs(uint64(status)) + receiverError := make(chan error) + err := rm.receiver.(*receiver).engine().Inject(func() { + // Deliveries are valid as long as the receiver is, unless settled. + err := rm.receiver.Error() + receiverError <- err + if err == nil { + rm.pDelivery.SettleAs(status) + } }) + if err != nil { + return err + } + return <-receiverError } // Accept tells the sender that we take responsibility for processing the message.