mirror of
https://github.com/amnezia-vpn/amneziawg-go.git
synced 2026-10-13 21:34:25 +00:00
[PR #205] fix: clear the timer duration under modifyingLock #203
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
amnezia-vpn/amneziawg-go#203
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/amnezia-vpn/amneziawg-go/pull/205
Author: @StarProxima
Created: 10/9/2026
Status: 🔄 Open
Base:
master← Head:fix/timer-duration-race📝 Commits (1)
0421ab3fix: clear the timer duration under modifyingLock📊 Changes
2 files changed (+32 additions, -1 deletions)
View changed files
📝
device/timers.go(+1 -1)➕
device/timers_test.go(+31 -0)📄 Description
Fixes #204.
What changes
In the expiry function of
Timer,timer.duration = 0moves beforemodifyingLock.Unlock()(device/timers.go#L39-L41):It also adds
TestTimerExpiryRaceindevice/timers_test.go, which fails under the race detector without the change.Why this way
Mod,DelandIsPendingaccessdurationundermodifyingLock; the expiry wrote it after unlocking. Besides the race report, aModthat ran between the unlock and the write lost its duration: the timer stayed armed withduration == 0, so its next expiry returned without calling the handler. Clearing the field under the lock is the order wireguard-go keeps forisPendingand the order this code had before 3.0.The change keeps
durationas both the pending flag and the value passed to the handler, so it touches one line.Relation to #194
The last commit of #194 fixes the same race differently: it restores a separate
isPendingflag. That also changes one more case: withdurationas the flag,Mod(0)leaves the timer not pending and its expiry does nothing, andMod(0)is reachable when a range such askeepalive_timeout = 0-10picks 0. This PR does not change that case. If #194 is merged first, the test from this PR still applies to it: it passes on the head of #194 (0 failures in 100 runs).How it was tested
macOS 26 arm64, Go 1.26.4.
master(b5928ef) with the test onlyTestTimerExpiryRaceunder-race, 100 separate processesDATA RACEbetweentimers.go:41(write) andtimers.go:73(IsPending)TestTimerExpiryRaceunder-race,-count=1000in one processTestTimerExpiryRacewithout-race,-count=1000Separate processes, because the race detector reports a given race only once per process.
The rest of the suite on this branch:
gofmt -l .is clean,go build ./...passes.go vet ./...reports only the copylocks warning atdevice/pools_test.go:67, as onmaster(#157, #192).go test ./... -count=1andgo test -race ./... -count=1pass exceptTestAWGDevicePing, which fails onmasteras well because of #168 (20 of 20 runs on this machine). With a fix for #168 on top,go test -race ./... -count=1passes in full, andTestAWGDevicePingpasses 10 of 10 under-race.CGO_ENABLED=0for linux/amd64, arm64, 386, arm; windows/amd64, arm64, 386; darwin/amd64, arm64; freebsd/amd64; openbsd/amd64; and the library packages for android/arm64, arm, amd64 and ios/arm64.outline/is left out of these builds becausegolang.getoutline.org/sdk/x/smartneeds cgo on unix targets, which is the same onmaster.-racewith this change and a fix for #168.Not tested
Moddescribed above was found by reading the code; I have no test that hits the window between the unlock and the write.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.