From d324b2ac86d5ed6ba1c9bf8432e07e5981344c2d Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Thu, 9 Jan 2025 19:33:04 +0100 Subject: [PATCH] fix(db): correct unsafe RLock order (fixes #9906) (#9910) Marshal() was called with the read lock held, and in turn called Created() which also takes the read lock. This is fine by itself, but there is a risk of deadlock if another call to lock the mutex happens concurrently, as the lock call will block the inner rlock and the outer rlock can never become unlocked. It's an easy fix as marshalling is guaranteed to be called with a read lock and does not need to call any methods that read lock themselves. --- lib/db/meta.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/db/meta.go b/lib/db/meta.go index ece2b07ad..fd7ec1fce 100644 --- a/lib/db/meta.go +++ b/lib/db/meta.go @@ -76,11 +76,12 @@ func (m *metadataTracker) Unmarshal(bs []byte) error { return nil } -// Marshal returns the protobuf representation of the metadataTracker -func (m *metadataTracker) Marshal() ([]byte, error) { +// protoMarshal returns the protobuf representation of the metadataTracker. +// Must be called with the read lock held. +func (m *metadataTracker) protoMarshal() ([]byte, error) { dbc := &dbproto.CountsSet{ Counts: make([]*dbproto.Counts, len(m.counts.Counts)), - Created: m.Created().UnixNano(), + Created: m.counts.Created, } for i, c := range m.counts.Counts { dbc.Counts[i] = c.toWire() @@ -109,7 +110,7 @@ func (m *metadataTracker) toDB(t backend.WriteTransaction, folder []byte) error return nil } - bs, err := m.Marshal() + bs, err := m.protoMarshal() if err != nil { return err }