diff --git a/go.mod b/go.mod index 267c757..18604df 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/jonboulle/clockwork v0.4.0 github.com/letsencrypt/pebble/v2 v2.4.0 github.com/rekby/fastuuid v0.9.0 - github.com/rekby/safemutex v0.1.0 + github.com/rekby/safemutex v0.2.0 golang.org/x/time v0.3.0 ) diff --git a/go.sum b/go.sum index 415c081..1451d75 100644 --- a/go.sum +++ b/go.sum @@ -218,8 +218,8 @@ github.com/rekby/fastuuid v0.9.0 h1:iQk8V/AyqSrgQAtKRdqx/CVep+CaKwaSWeerw1yEP3Q= github.com/rekby/fastuuid v0.9.0/go.mod h1:qP8Lh0BH2+4rNGVRDHmDpkvE/ZuLUhjmKpRWjx+WesY= github.com/rekby/fixenv v0.3.1 h1:zOPocbQmcsxSIjiVu5U+9JAfeu6WeLN7a9ryZkGTGJY= github.com/rekby/fixenv v0.3.1/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c= -github.com/rekby/safemutex v0.1.0 h1:DAj4PeL17C/4sfOmDaW+gGwL/dXzJmNducd3VZF9NUc= -github.com/rekby/safemutex v0.1.0/go.mod h1:6I/yJdmctX0RmxEp00RzYBJJXl3ona8PsBiIDqg0v+U= +github.com/rekby/safemutex v0.2.0 h1:iEfcPqsR3EApwWHwdHvp+srN9Wfna+IG8bSpN467Jmk= +github.com/rekby/safemutex v0.2.0/go.mod h1:6I/yJdmctX0RmxEp00RzYBJJXl3ona8PsBiIDqg0v+U= github.com/rekby/zapcontext v0.0.4 h1:85600nHTteGCLcuOhGp/SzXHymm9QcCA5sn+MPKCodY= github.com/rekby/zapcontext v0.0.4/go.mod h1:lTIxvHAwWXBZBPPfEvmAEXPbVEcTwd52VaASZWZWcxI= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/internal/acme_client_manager/client_manager.go b/internal/acme_client_manager/client_manager.go index 85da0fc..b8e1f54 100644 --- a/internal/acme_client_manager/client_manager.go +++ b/internal/acme_client_manager/client_manager.go @@ -45,7 +45,7 @@ type AcmeManager struct { httpClient *http.Client background sync.WaitGroup - mu safemutex.Mutex[acmeManagerSynced] + mu safemutex.MutexWithPointers[acmeManagerSynced] } type acmeManagerSynced struct { @@ -71,7 +71,7 @@ func New(ctx context.Context, cache cache.Bytes) *AcmeManager { AgreeFunction: acme.AcceptTOS, RenewAccountInterval: renewAccountInterval, httpClient: http.DefaultClient, - mu: safemutex.NewWithOptions(acmeManagerSynced{lastAccountIndex: -1}, safemutex.MutexOptions{AllowPointers: true}), + mu: safemutex.NewWithPointers(acmeManagerSynced{lastAccountIndex: -1}), } } diff --git a/internal/acme_client_manager/client_manager_test.go b/internal/acme_client_manager/client_manager_test.go index 4ec7c14..170bae3 100644 --- a/internal/acme_client_manager/client_manager_test.go +++ b/internal/acme_client_manager/client_manager_test.go @@ -5,7 +5,6 @@ import ( "context" "crypto/rsa" "encoding/json" - "github.com/rekby/safemutex" "math/big" "testing" @@ -199,9 +198,7 @@ func TestClientManager_nextEnabledClientIndex(t *testing.T) { e, _, flush := th.NewEnv(t) defer flush() - m := AcmeManager{ - mu: safemutex.NewWithOptions(acmeManagerSynced{}, safemutex.MutexOptions{AllowPointers: true}), - } + m := AcmeManager{} m.mu.Lock(func(synced acmeManagerSynced) acmeManagerSynced { synced.lastAccountIndex = test.lastAccountIndex diff --git a/internal/cert_manager/manager.go b/internal/cert_manager/manager.go index 4c08cdc..1fa49e1 100644 --- a/internal/cert_manager/manager.go +++ b/internal/cert_manager/manager.go @@ -114,7 +114,7 @@ type Manager struct { certForDomainAuthorize cache.Value - certStateMu safemutex.Mutex[cache.Value] + certStateMu safemutex.MutexWithPointers[cache.Value] httpTokens cache.Bytes @@ -127,7 +127,7 @@ func New(acmeClientManager AcmeClientManager, c cache.Bytes, r prometheus.Regist res := Manager{} res.acmeClientManager = acmeClientManager res.certForDomainAuthorize = cache.NewMemoryValueLRU("authcert") - res.certStateMu = safemutex.NewWithOptions[cache.Value](cache.NewMemoryValueLRU("certstate"), safemutex.MutexOptions{AllowPointers: true}) + res.certStateMu = safemutex.NewWithPointers[cache.Value](cache.NewMemoryValueLRU("certstate")) res.CertificateIssueTimeout = time.Minute res.httpTokens = cache.NewMemoryCache("Http validation tokens") res.Cache = c diff --git a/internal/cert_manager/manager_test.go b/internal/cert_manager/manager_test.go index 1c68a06..a73ad2f 100644 --- a/internal/cert_manager/manager_test.go +++ b/internal/cert_manager/manager_test.go @@ -278,7 +278,7 @@ func createManager(t *testing.T) (res testManagerContext, cancel func()) { AllowRSACert: true, AllowECDSACert: true, certForDomainAuthorize: res.certForDomainAuthorize, - certStateMu: safemutex.NewWithOptions[cache.Value](res.certState, safemutex.MutexOptions{AllowPointers: true}), + certStateMu: safemutex.NewWithPointers[cache.Value](res.certState), httpTokens: res.httpTokens, } res.manager.initMetrics(nil) diff --git a/internal/th/fixenv.go b/internal/th/fixenv.go index 439c947..74b006b 100644 --- a/internal/th/fixenv.go +++ b/internal/th/fixenv.go @@ -21,7 +21,6 @@ func NewEnv(t *testing.T) (env *Env, ctx context.Context, cancel func()) { ctx, ctxCancel := TestContext(td) tWrap := &testWrapper{ T: td, - m: safemutex.NewWithOptions(testWrapperSynced{}, safemutex.MutexOptions{AllowPointers: true}), } env = &Env{ EnvT: fixenv.NewEnv(tWrap), @@ -44,7 +43,7 @@ type TD struct { type testWrapper struct { *testdeep.T - m safemutex.Mutex[testWrapperSynced] + m safemutex.MutexWithPointers[testWrapperSynced] } type testWrapperSynced struct { diff --git a/internal/th/fixtures.go b/internal/th/fixtures.go index 63c2948..777a4a5 100644 --- a/internal/th/fixtures.go +++ b/internal/th/fixtures.go @@ -15,7 +15,7 @@ import ( ) var ( - freeListenAddressMutex = safemutex.NewWithOptions(map[string]bool{}, safemutex.MutexOptions{AllowPointers: true}) + freeListenAddressMutex = safemutex.NewWithPointers(map[string]bool{}) ) func MockController(e fixenv.Env) minimock.MockController { diff --git a/vendor/github.com/egorgasay/cidranger/.gitignore b/vendor/github.com/egorgasay/cidranger/.gitignore new file mode 100644 index 0000000..cb756e9 --- /dev/null +++ b/vendor/github.com/egorgasay/cidranger/.gitignore @@ -0,0 +1,2 @@ +vendor +.idea \ No newline at end of file diff --git a/vendor/github.com/egorgasay/cidranger/.travis.yml b/vendor/github.com/egorgasay/cidranger/.travis.yml new file mode 100644 index 0000000..ecc3fb1 --- /dev/null +++ b/vendor/github.com/egorgasay/cidranger/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: + - 1.13.x + - 1.14.x + - tip +before_install: + - travis_retry go get github.com/mattn/goveralls +script: + - go test -v -covermode=count -coverprofile=coverage.out ./... + - travis_retry $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci diff --git a/vendor/github.com/rekby/safemutex/README.md b/vendor/github.com/rekby/safemutex/README.md index cd9b0d3..edf6ac0 100644 --- a/vendor/github.com/rekby/safemutex/README.md +++ b/vendor/github.com/rekby/safemutex/README.md @@ -28,16 +28,16 @@ type GuardedStruct struct { } func main() { - simleIntMutex := safe_mutex.New(1) - simleIntMutex.Lock(func(value int) (newValue int) { - fmt.Println(value) - return value + simleIntMutex := safemutex.New(1) + simleIntMutex.Lock(func(synced int) int { + fmt.Println(synced) + return synced }) - mutexWithStruct := safe_mutex.New(GuardedStruct{Name: "test", Val: 1}) - mutexWithStruct.Lock(func(value GuardedStruct) (newValue GuardedStruct) { - fmt.Println(value) - return value + mutexWithStruct := safemutex.New(GuardedStruct{Name: "test", Val: 1}) + mutexWithStruct.Lock(func(synced GuardedStruct) GuardedStruct { + fmt.Println(synced) + return synced }) } ``` diff --git a/vendor/github.com/rekby/safemutex/callback.go b/vendor/github.com/rekby/safemutex/callback.go index ffd6a14..1490488 100644 --- a/vendor/github.com/rekby/safemutex/callback.go +++ b/vendor/github.com/rekby/safemutex/callback.go @@ -1,3 +1,4 @@ package safemutex -type ReadWriteCallback[T any] func(value T) (newValue T) +// ReadWriteCallback receive current value, saved in mutex and return new value +type ReadWriteCallback[T any] func(synced T) T diff --git a/vendor/github.com/rekby/safemutex/errors.go b/vendor/github.com/rekby/safemutex/errors.go index ab377ff..e70f058 100644 --- a/vendor/github.com/rekby/safemutex/errors.go +++ b/vendor/github.com/rekby/safemutex/errors.go @@ -2,7 +2,7 @@ package safemutex import "errors" -var errContainPointers = errors.New("safe mutex: value type possible to contain pointers, use NewWithOptions for allow pointers into guarded value") +var errContainPointers = errors.New("safe mutex: value type possible to contain pointers, use MutexWithPointers for allow pointers into guarded value") var ErrPoisoned = errors.New("safe mutex: mutex poisoned (exit from callback with panic), use NewWithOptions for allow use poisoned value") diff --git a/vendor/github.com/rekby/safemutex/mutex.go b/vendor/github.com/rekby/safemutex/mutex.go index df2dd97..bbee804 100644 --- a/vendor/github.com/rekby/safemutex/mutex.go +++ b/vendor/github.com/rekby/safemutex/mutex.go @@ -2,33 +2,25 @@ package safemutex import ( "reflect" - "sync" ) // Mutex contains guarded value inside, access to value allowed inside callbacks only // it allow to guarantee not access to the value without lock the mutex // zero value is usable as mutex with default options and zero value of guarded type +// Mutex deny to save value with any type of pointers, which allow accidentally change internal state. +// it will panic if T contains any pointer. type Mutex[T any] struct { - m sync.Mutex - value T - options MutexOptions + mutexBase[T] initialized bool - errWrap errWrap } // New create Mutex with initial value and default options. // New call internal checks for T and panic if checks failed, see MutexOptions for details func New[T any](value T) Mutex[T] { - return NewWithOptions(value, MutexOptions{}) -} - -// NewWithOptions create Mutex with initial value and custom options. -// MutexOptions allow to reduce default security when it needs. -// NewWithOptions call internal checks for T and panic if checks failed, see MutexOptions for details -func NewWithOptions[T any](value T, options MutexOptions) Mutex[T] { res := Mutex[T]{ - value: value, - options: options, + mutexBase: mutexBase[T]{ + value: value, + }, } res.validateLocked() @@ -46,46 +38,23 @@ func (m *Mutex[T]) Lock(f ReadWriteCallback[T]) { m.m.Lock() defer m.m.Unlock() - m.callLocked(f) -} - -func (m *Mutex[T]) callLocked(f ReadWriteCallback[T]) { m.validateLocked() - - hasPanic := true - - defer func() { - if hasPanic && !m.options.AllowPoisoned { - m.errWrap = errWrap{ErrPoisoned} - } - }() - - m.value = f(m.value) - hasPanic = false - + m.callLocked(f) } func (m *Mutex[T]) validateLocked() { - if m.errWrap.err != nil { - panic(m.errWrap) - } + m.baseValidateLocked() if m.initialized { return } - m.initialized = true - - if !m.options.AllowPointers { - if checkTypeCanContainPointers(reflect.TypeOf(m.value)) { - panic(errContainPointers) - } + // check pointers + if checkTypeCanContainPointers(reflect.TypeOf(m.value)) { + panic(errContainPointers) } -} -type MutexOptions struct { - AllowPointers bool - AllowPoisoned bool + m.initialized = true } // checkTypeCanContainPointers check the value for potential contain pointers diff --git a/vendor/github.com/rekby/safemutex/mutex_allow_pointers.go b/vendor/github.com/rekby/safemutex/mutex_allow_pointers.go new file mode 100644 index 0000000..e841ddb --- /dev/null +++ b/vendor/github.com/rekby/safemutex/mutex_allow_pointers.go @@ -0,0 +1,33 @@ +package safemutex + +// MutexWithPointers contains guarded value inside, access to value allowed inside callbacks only +// it allow to guarantee not access to the value without lock the mutex +// zero value is usable as mutex with default options and zero value of guarded type +type MutexWithPointers[T any] struct { + mutexBase[T] +} + +// NewWithPointers create Mutex with initial value and default options. +// NewWithPointers call internal checks for T and panic if checks failed, see MutexOptions for details +func NewWithPointers[T any](value T) MutexWithPointers[T] { + res := MutexWithPointers[T]{ + mutexBase: mutexBase[T]{ + value: value, + }, + } + + //nolint:govet + //goland:noinspection GoVetCopyLock + return res +} + +// Lock - call f within locked mutex. +// it will panic with ErrPoisoned if previous call exited without return value: +// with panic or runtime.Goexit() +func (m *MutexWithPointers[T]) Lock(f ReadWriteCallback[T]) { + m.m.Lock() + defer m.m.Unlock() + + m.baseValidateLocked() + m.callLocked(f) +} diff --git a/vendor/github.com/rekby/safemutex/mutex_base.go b/vendor/github.com/rekby/safemutex/mutex_base.go new file mode 100644 index 0000000..3be55f6 --- /dev/null +++ b/vendor/github.com/rekby/safemutex/mutex_base.go @@ -0,0 +1,21 @@ +package safemutex + +import "sync" + +type mutexBase[T any] struct { + m sync.Mutex + value T + errWrap errWrap +} + +func (m *mutexBase[T]) baseValidateLocked() { + if m.errWrap.err != nil { + panic(m.errWrap) + } +} + +func (m *mutexBase[T]) callLocked(f ReadWriteCallback[T]) { + m.errWrap.err = ErrPoisoned + m.value = f(m.value) + m.errWrap.err = nil +} diff --git a/vendor/github.com/rekby/safemutex/mutex_try_lock.go b/vendor/github.com/rekby/safemutex/mutex_try_lock.go index 5f15e03..be8fccf 100644 --- a/vendor/github.com/rekby/safemutex/mutex_try_lock.go +++ b/vendor/github.com/rekby/safemutex/mutex_try_lock.go @@ -18,6 +18,26 @@ func (m *Mutex[T]) TryLock(f ReadWriteCallback[T]) bool { } defer m.m.Unlock() + m.validateLocked() + m.callLocked(f) + return true +} + +// TryLock - call f within locked mutex if locked successfully. +// returned true if locked successfully +// return true if mutex already locked +// it will panic with ErrPoisoned if locked successfully and previous call exited without return value: +// with panic or runtime.Goexit() +// +// Available since go 1.19 only +func (m *MutexWithPointers[T]) TryLock(f ReadWriteCallback[T]) bool { + locked := m.m.TryLock() + if !locked { + return false + } + defer m.m.Unlock() + + m.baseValidateLocked() m.callLocked(f) return true } diff --git a/vendor/modules.txt b/vendor/modules.txt index a0036df..47c59ff 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -139,7 +139,7 @@ github.com/rekby/fastuuid/internal/ibytes # github.com/rekby/fixenv v0.3.1 ## explicit; go 1.18 github.com/rekby/fixenv -# github.com/rekby/safemutex v0.1.0 +# github.com/rekby/safemutex v0.2.0 ## explicit; go 1.18 github.com/rekby/safemutex # github.com/rekby/zapcontext v0.0.4