Query() đọc d.rkhông giữ lock, trong khi Reload() ghi d.r và đóng reader cũ dưới write-lock. Mỗi ngày (@daily) service tải DB mới → gọi Reload(). Nếu có request đang query cùng lúc → data race + reader bị close khi đang dùng.
Bằng chứng (đã xác nhận bằng -race)
WARNING: DATA RACE
Write at ...(*IpDb).Reload() // ghi d.r (ipdb.go:92) + tmpR.Close() (line 95)
... maxminddb-golang.(*Reader).LookupNetwork() // đọc reader đang bị Close (query.go:15)
Có thể panic hoặc trả kết quả sai khi refresh DB dưới tải. sync.RWMutex (d.mu) đã có sẵn nhưng chưa được dùng ở phía đọc.
Fix đề xuất
func(d*IpDb)Query(ipArgstring)(...){ip:=net.ParseIP(ipArg)ifip==nil{returnnil,nil,fmt.Errorf("invalid IP: %s",ipArg)}d.mu.RLock()deferd.mu.RUnlock()ifd.r==nil{returnnil,nil,fmt.Errorf("db not loaded")}...d.r.LookupNetwork(ip,&anyData)}
Làm tương tự cho IsLoaded(). Thêm test -race regression.
## Vấn đề
`Query()` đọc `d.r` **không giữ lock**, trong khi `Reload()` ghi `d.r` và **đóng reader cũ** dưới write-lock. Mỗi ngày (`@daily`) service tải DB mới → gọi `Reload()`. Nếu có request đang query cùng lúc → data race + reader bị close khi đang dùng.
## Bằng chứng (đã xác nhận bằng `-race`)
```
WARNING: DATA RACE
Write at ...(*IpDb).Reload() // ghi d.r (ipdb.go:92) + tmpR.Close() (line 95)
... maxminddb-golang.(*Reader).LookupNetwork() // đọc reader đang bị Close (query.go:15)
```
Tệp: `internal/data/query.go:15`, `internal/data/ipdb.go:71-104`
## Hậu quả
Có thể panic hoặc trả kết quả sai khi refresh DB dưới tải. `sync.RWMutex` (`d.mu`) đã có sẵn nhưng chưa được dùng ở phía đọc.
## Fix đề xuất
```go
func (d *IpDb) Query(ipArg string) (...) {
ip := net.ParseIP(ipArg)
if ip == nil { return nil, nil, fmt.Errorf("invalid IP: %s", ipArg) }
d.mu.RLock()
defer d.mu.RUnlock()
if d.r == nil { return nil, nil, fmt.Errorf("db not loaded") }
...d.r.LookupNetwork(ip, &anyData)
}
```
Làm tương tự cho `IsLoaded()`. Thêm test `-race` regression.
claudecode
added the bug label 2026-07-22 11:20:59 +07:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Vấn đề
Query()đọcd.rkhông giữ lock, trong khiReload()ghid.rvà đóng reader cũ dưới write-lock. Mỗi ngày (@daily) service tải DB mới → gọiReload(). Nếu có request đang query cùng lúc → data race + reader bị close khi đang dùng.Bằng chứng (đã xác nhận bằng
-race)Tệp:
internal/data/query.go:15,internal/data/ipdb.go:71-104Hậu quả
Có thể panic hoặc trả kết quả sai khi refresh DB dưới tải.
sync.RWMutex(d.mu) đã có sẵn nhưng chưa được dùng ở phía đọc.Fix đề xuất
Làm tương tự cho
IsLoaded(). Thêm test-raceregression.