Fix unaligned panic on windows

This commit is contained in:
世界 2024-02-10 21:16:33 +08:00
parent 38c945fec5
commit 9b7c2a0a3c
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -9,7 +9,6 @@ import (
"net/netip" "net/netip"
"os" "os"
"sync" "sync"
"sync/atomic"
"time" "time"
"unsafe" "unsafe"
@ -17,6 +16,7 @@ import (
"github.com/sagernet/sing-tun/internal/winsys" "github.com/sagernet/sing-tun/internal/winsys"
"github.com/sagernet/sing-tun/internal/wintun" "github.com/sagernet/sing-tun/internal/wintun"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/windnsapi" "github.com/sagernet/sing/common/windnsapi"
@ -34,7 +34,7 @@ type NativeTun struct {
rate rateJuggler rate rateJuggler
running sync.WaitGroup running sync.WaitGroup
closeOnce sync.Once closeOnce sync.Once
close int32 close atomic.Int32
fwpmSession uintptr fwpmSession uintptr
} }
@ -334,13 +334,13 @@ func (t *NativeTun) ReadPacket() ([]byte, func(), error) {
t.running.Add(1) t.running.Add(1)
defer t.running.Done() defer t.running.Done()
retry: retry:
if atomic.LoadInt32(&t.close) == 1 { if t.close.Load() == 1 {
return nil, nil, os.ErrClosed return nil, nil, os.ErrClosed
} }
start := nanotime() start := nanotime()
shouldSpin := atomic.LoadUint64(&t.rate.current) >= spinloopRateThreshold && uint64(start-atomic.LoadInt64(&t.rate.nextStartTime)) <= rateMeasurementGranularity*2 shouldSpin := t.rate.current.Load() >= spinloopRateThreshold && uint64(start-t.rate.nextStartTime.Load()) <= rateMeasurementGranularity*2
for { for {
if atomic.LoadInt32(&t.close) == 1 { if t.close.Load() == 1 {
return nil, nil, os.ErrClosed return nil, nil, os.ErrClosed
} }
packet, err := t.session.ReceivePacket() packet, err := t.session.ReceivePacket()
@ -369,13 +369,13 @@ func (t *NativeTun) ReadFunc(block func(b []byte)) error {
t.running.Add(1) t.running.Add(1)
defer t.running.Done() defer t.running.Done()
retry: retry:
if atomic.LoadInt32(&t.close) == 1 { if t.close.Load() == 1 {
return os.ErrClosed return os.ErrClosed
} }
start := nanotime() start := nanotime()
shouldSpin := atomic.LoadUint64(&t.rate.current) >= spinloopRateThreshold && uint64(start-atomic.LoadInt64(&t.rate.nextStartTime)) <= rateMeasurementGranularity*2 shouldSpin := t.rate.current.Load() >= spinloopRateThreshold && uint64(start-t.rate.nextStartTime.Load()) <= rateMeasurementGranularity*2
for { for {
if atomic.LoadInt32(&t.close) == 1 { if t.close.Load() == 1 {
return os.ErrClosed return os.ErrClosed
} }
packet, err := t.session.ReceivePacket() packet, err := t.session.ReceivePacket()
@ -405,7 +405,7 @@ retry:
func (t *NativeTun) Write(p []byte) (n int, err error) { func (t *NativeTun) Write(p []byte) (n int, err error) {
t.running.Add(1) t.running.Add(1)
defer t.running.Done() defer t.running.Done()
if atomic.LoadInt32(&t.close) == 1 { if t.close.Load() == 1 {
return 0, os.ErrClosed return 0, os.ErrClosed
} }
t.rate.update(uint64(len(p))) t.rate.update(uint64(len(p)))
@ -427,7 +427,7 @@ func (t *NativeTun) Write(p []byte) (n int, err error) {
func (t *NativeTun) write(packetElementList [][]byte) (n int, err error) { func (t *NativeTun) write(packetElementList [][]byte) (n int, err error) {
t.running.Add(1) t.running.Add(1)
defer t.running.Done() defer t.running.Done()
if atomic.LoadInt32(&t.close) == 1 { if t.close.Load() == 1 {
return 0, os.ErrClosed return 0, os.ErrClosed
} }
var packetSize int var packetSize int
@ -461,7 +461,7 @@ func (t *NativeTun) WriteVectorised(buffers []*buf.Buffer) error {
func (t *NativeTun) Close() error { func (t *NativeTun) Close() error {
var err error var err error
t.closeOnce.Do(func() { t.closeOnce.Do(func() {
atomic.StoreInt32(&t.close, 1) t.close.Store(1)
windows.SetEvent(t.readWait) windows.SetEvent(t.readWait)
t.running.Wait() t.running.Wait()
t.session.End() t.session.End()
@ -491,24 +491,24 @@ func procyield(cycles uint32)
func nanotime() int64 func nanotime() int64
type rateJuggler struct { type rateJuggler struct {
current uint64 current atomic.Uint64
nextByteCount uint64 nextByteCount atomic.Uint64
nextStartTime int64 nextStartTime atomic.Int64
changing int32 changing atomic.Int32
} }
func (rate *rateJuggler) update(packetLen uint64) { func (rate *rateJuggler) update(packetLen uint64) {
now := nanotime() now := nanotime()
total := atomic.AddUint64(&rate.nextByteCount, packetLen) total := rate.nextByteCount.Add(packetLen)
period := uint64(now - atomic.LoadInt64(&rate.nextStartTime)) period := uint64(now - rate.nextStartTime.Load())
if period >= rateMeasurementGranularity { if period >= rateMeasurementGranularity {
if !atomic.CompareAndSwapInt32(&rate.changing, 0, 1) { if !rate.changing.CompareAndSwap(0, 1) {
return return
} }
atomic.StoreInt64(&rate.nextStartTime, now) rate.nextStartTime.Store(now)
atomic.StoreUint64(&rate.current, total*uint64(time.Second/time.Nanosecond)/period) rate.current.Store(total * uint64(time.Second/time.Nanosecond) / period)
atomic.StoreUint64(&rate.nextByteCount, 0) rate.nextByteCount.Store(0)
atomic.StoreInt32(&rate.changing, 0) rate.changing.Store(0)
} }
} }