Fix data race / nil-pointer panic between serve goroutine and Close - #13
Merged
Merged
Conversation
serve() read the m.l listener field on every Accept() loop iteration, while Close() -> server.close() concurrently set that field to nil. When Close() ran before the freshly spawned serve goroutine first read m.l (common on short-lived servers), Accept() was invoked on a nil listener, panicking in a goroutine no caller can recover. Capture the listener synchronously in newServer() - which runs during Run(), happens-before any Close() - and pass it into serve(), so the goroutine never touches the shared field. Close() still closes the same listener, unblocking the parked Accept() cleanly. Adds TestRunClose, which reproduces both the data race and the panic under -race on the old code.
MeteorSis
self-requested a review
June 2, 2026 11:35
MeteorSis
approved these changes
Jun 2, 2026
MeteorSis
left a comment
Contributor
There was a problem hiding this comment.
Thank you for your contribution.
reinkrul
added a commit
to nuts-foundation/nuts-node
that referenced
this pull request
Jun 4, 2026
v1.2.1 includes the upstream fix (daangn/minimemcached#13) for the nil-pointer panic between the serve goroutine and Close, so the probe loop that waited for the accept loop to park is no longer needed. Assisted by AI
reinkrul
added a commit
to nuts-foundation/nuts-node
that referenced
this pull request
Jun 4, 2026
…#4326) * chore(deps): bump github.com/daangn/minimemcached from 1.2.0 to 1.2.1 Bumps [github.com/daangn/minimemcached](https://github.com/daangn/minimemcached) from 1.2.0 to 1.2.1. - [Release notes](https://github.com/daangn/minimemcached/releases) - [Commits](daangn/minimemcached@v1.2.0...v1.2.1) --- updated-dependencies: - dependency-name: github.com/daangn/minimemcached dependency-version: 1.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * test(storage): remove minimemcached startup-race workaround v1.2.1 includes the upstream fix (daangn/minimemcached#13) for the nil-pointer panic between the serve goroutine and Close, so the probe loop that waited for the accept loop to park is no longer needed. Assisted by AI --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Rein Krul <info@reinkrul.nl>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Closing a server shortly after
Run()can panic in a goroutine that no caller can recover, crashing the test binary:Root cause
Run()→start()setsm.server = sand spawnsgo m.serve(). The goroutine loops onm.l.Accept(), reading the embedded listener field on every iteration:Close()→server.close()concurrently nils that same field:Two defects:
serve()readsm.lwith no lock whileClose()writes it underm.mu.Close()runs before the freshly spawnedservegoroutine first readsm.l(common for short-lived servers in unit tests),Accept()is called on a nil listener and panics — in a goroutine the caller cannot recover.Fix
Capture the listener synchronously in
newServer(), which executes duringRun()and therefore happens-before anyClose()(a caller can onlyClose()afterRun()returns). Pass it intoserve()so the goroutine never touches the shared field.Close()still closes the same listener, so the parkedAccept()unblocks with an error andserve()returns cleanly.Test
Adds
TestRunClose, which loopsRun()/Close(). Undergo test -raceit reliably reproduces both the data race and the nil-pointer panic on the current code, and passes with the fix.