NethermindEth / NethermindEth/juno
db: `View`/`Update`/`Write` race with `Close()` — no lock or closed-check
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 444
- Forks
- 244
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 78
Description
Summary
The View, Update and Write helpers on the pebble, pebblev2 and memory backends don't guard against a concurrent Close(), unlike the other public DB methods (Get, Has, NewIterator, ...).
Surfaced by Copilot review on #3846 — the problem predates that PR (it only added snapshot cleanup), so it's tracked here separately.
Details
pebble / pebblev2 (db/pebble/db.go, db/pebblev2/db.go):
Viewneither takescloseLocknor checksd.closed, so calling it concurrently withClose()makespebble.DB.NewSnapshot()panic on a closed DB instead of returningpebble.ErrClosed.Update/Writedo checkd.closed, but without holdingcloseLock, so the check itself is racy and the batch can still be created/committed whileClose()runs.
memory (db/memory/db.go):
Viewreadsd.dbandNewSnapshotpanics ond.db == nilwithout holdingd.lock, whileClose()writesd.db = nilunder the lock — a data race the race detector can flag.Update/Writehave the same unguarded check.
Suggested fix
Mirror the Get/Has pattern: take closeLock.RLock() (resp. d.lock.RLock() in memory), check the closed flag, and hold the lock for the duration of the callback so Close() blocks until in-flight transactions finish.
One pitfall in the memory backend: NewSnapshot() → Copy() takes d.lock.RLock() itself, so naively grabbing RLock in View before calling it is a recursive read-lock — a documented deadlock when a writer is waiting in between. The copy needs to happen under a single lock acquisition (e.g. an unexported unlocked copy helper).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Get/Has and Close implementations in db/pebble/db.go, db/pebblev2/db.go, and db/memory/db.go, then trace View, Update, and Write. Use the race detector while exercising concurrent operations and closing. Done means these helpers no longer panic or race with Close, and in-flight callbacks finish safely before closing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100