420f236d31
There are concurrent threads that are accessing and modifying IMAPWorker.seqMap (the mapping of sequence numbers to message UIDs). This can lead to crashes when trying to add and remove a message ID. panic: runtime error: index out of range [391] with length 390 goroutine 1834 [running]: git.sr.ht/~rjarry/aerc/logging.PanicHandler() logging/panic-logger.go:47 +0x6de panic({0xa41760, 0xc0019b3290}) /usr/lib/golang/src/runtime/panic.go:838 +0x207 git.sr.ht/~rjarry/aerc/worker/imap.(*IMAPWorker).handleFetchMessages.func1() worker/imap/fetch.go:214 +0x185 created by git.sr.ht/~rjarry/aerc/worker/imap.(*IMAPWorker).handleFetchMessages worker/imap/fetch.go:209 +0x12b Use a map which makes more sense than a simple array for random access operations. Also, it allows better typing for the key values. Protect the map with a mutex. Add internal API to access the map. Add basic unit tests to ensure that concurrent access works. Fixes: https://todo.sr.ht/~rjarry/aerc/49 Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Moritz Poldrack <moritz@poldrack.dev>
48 lines
782 B
Go
48 lines
782 B
Go
package imap
|
|
|
|
import "sync"
|
|
|
|
type SeqMap struct {
|
|
lock sync.Mutex
|
|
// map of IMAP sequence numbers to message UIDs
|
|
m map[uint32]uint32
|
|
}
|
|
|
|
func (s *SeqMap) Size() int {
|
|
s.lock.Lock()
|
|
size := len(s.m)
|
|
s.lock.Unlock()
|
|
return size
|
|
}
|
|
|
|
func (s *SeqMap) Get(seqnum uint32) (uint32, bool) {
|
|
s.lock.Lock()
|
|
uid, found := s.m[seqnum]
|
|
s.lock.Unlock()
|
|
return uid, found
|
|
}
|
|
|
|
func (s *SeqMap) Put(seqnum, uid uint32) {
|
|
s.lock.Lock()
|
|
if s.m == nil {
|
|
s.m = make(map[uint32]uint32)
|
|
}
|
|
s.m[seqnum] = uid
|
|
s.lock.Unlock()
|
|
}
|
|
|
|
func (s *SeqMap) Pop(seqnum uint32) (uint32, bool) {
|
|
s.lock.Lock()
|
|
uid, found := s.m[seqnum]
|
|
if found {
|
|
delete(s.m, seqnum)
|
|
}
|
|
s.lock.Unlock()
|
|
return uid, found
|
|
}
|
|
|
|
func (s *SeqMap) Clear() {
|
|
s.lock.Lock()
|
|
s.m = make(map[uint32]uint32)
|
|
s.lock.Unlock()
|
|
}
|