Summary
Wallet_Memory.sync_loop is intended to stop when the wallet closes, but its quit check uses break inside a select — which exits the select, not the enclosing for. The sync loop therefore never terminates.
|
func (w *Wallet_Memory) sync_loop() { |
|
//logger = globals.Logger |
|
for { |
|
select { |
|
case <-w.Quit: |
|
break |
|
default: |
|
} |
|
|
func (w *Wallet_Memory) sync_loop() {
for {
select {
case <-w.Quit:
break // <-- exits the select, NOT the for loop
default:
}
Impact
After Close_Encrypted_Wallet() (which only sleeps 1s "to give goroutines some time to quit", walletapi/wallet_disk.go:149-150), the sync loop keeps running: it continues polling the daemon every timeout seconds and keeps calling save_if_disk() against a wallet the caller believes is closed. Applications that close one wallet and open another accumulate leaked sync loops, duplicate RPC traffic, and concurrent writers against wallet files.
Fix
select {
case <-w.Quit:
return
default:
}
(Any other long-running loops keyed on w.Quit are worth auditing for the same pattern.)
Summary
Wallet_Memory.sync_loopis intended to stop when the wallet closes, but its quit check usesbreakinside aselect— which exits theselect, not the enclosingfor. The sync loop therefore never terminates.derohe/walletapi/daemon_communication.go
Lines 183 to 191 in 6f9bd2c
Impact
After
Close_Encrypted_Wallet()(which only sleeps 1s "to give goroutines some time to quit", walletapi/wallet_disk.go:149-150), the sync loop keeps running: it continues polling the daemon everytimeoutseconds and keeps callingsave_if_disk()against a wallet the caller believes is closed. Applications that close one wallet and open another accumulate leaked sync loops, duplicate RPC traffic, and concurrent writers against wallet files.Fix
(Any other long-running loops keyed on
w.Quitare worth auditing for the same pattern.)