diff --git a/ads/go.mod b/ads/go.mod index 6cf8439c2..a68912640 100644 --- a/ads/go.mod +++ b/ads/go.mod @@ -3,6 +3,7 @@ module github.com/iotaledger/hive.go/ads go 1.22 require ( + fortio.org/safecast v1.0.0 github.com/iotaledger/hive.go/ds v0.0.0-20240517131232-748f1ce3a2d2 github.com/iotaledger/hive.go/ierrors v0.0.0-20240517131232-748f1ce3a2d2 github.com/iotaledger/hive.go/kvstore v0.0.0-20240517131232-748f1ce3a2d2 diff --git a/ads/go.sum b/ads/go.sum index 2bda3a9fc..8a06509df 100644 --- a/ads/go.sum +++ b/ads/go.sum @@ -1,3 +1,5 @@ +fortio.org/safecast v1.0.0 h1:dr3131WPX8iS1pTf76+39WeXbTrerDYLvi9s7Oi3wiY= +fortio.org/safecast v1.0.0/go.mod h1:xZmcPk3vi4kuUFf+tq4SvnlVdwViqf6ZSZl91Jr9Jdg= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/ads/map_impl.go b/ads/map_impl.go index 7a191d557..2c689b726 100644 --- a/ads/map_impl.go +++ b/ads/map_impl.go @@ -4,6 +4,8 @@ import ( "crypto/sha256" "sync" + "fortio.org/safecast" + "github.com/pokt-network/smt" "github.com/iotaledger/hive.go/ds/types" @@ -124,7 +126,12 @@ func (m *authenticatedMap[IdentifierType, K, V]) Size() int { return 0 } - return int(size) + v, err := safecast.Convert[int](size) + if err != nil { + return 0 + } + + return v } // Commit persists the current state of the map to the storage. @@ -277,7 +284,19 @@ func (m *authenticatedMap[IdentifierType, K, V]) addSize(delta int) error { return ierrors.Wrap(err, "failed to get size") } - if err := m.size.Set(uint64(int(size) + delta)); err != nil { + sizeInt, err := safecast.Convert[int](size) + if err != nil { + return ierrors.Wrap(err, "failed to convert size to int") + } + + newSize := sizeInt + delta + + updatedSize, err := safecast.Convert[uint64](newSize) + if err != nil { + return ierrors.Wrap(err, "failed to convert new size to uint64") + } + + if err := m.size.Set(updatedSize); err != nil { return ierrors.Wrap(err, "failed to set size") } diff --git a/app/config.go b/app/config.go index 1b70442a5..4b85a2005 100644 --- a/app/config.go +++ b/app/config.go @@ -136,7 +136,9 @@ func loadConfigurations(configFilesFlagSet *flag.FlagSet, configurationSets []*C for _, config := range configurationSets { // propagate values in the config back to bound parameters - config.config.UpdateBoundParameters() + if err := config.config.UpdateBoundParameters(); err != nil { + return err + } } return nil diff --git a/app/configuration/configuration.go b/app/configuration/configuration.go index 54e0edd2a..26eba3dca 100644 --- a/app/configuration/configuration.go +++ b/app/configuration/configuration.go @@ -10,6 +10,8 @@ import ( "strings" "time" + "fortio.org/safecast" + "github.com/knadh/koanf" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/file" @@ -616,7 +618,7 @@ func (c *Configuration) BindParameters(flagset *flag.FlagSet, namespace string, // UpdateBoundParameters updates parameters that were bound using the BindParameters method with the current values in // the configuration. -func (c *Configuration) UpdateBoundParameters() { +func (c *Configuration) UpdateBoundParameters() error { for _, boundParameter := range c.boundParameters { parameterName := boundParameter.Name @@ -633,25 +635,57 @@ func (c *Configuration) UpdateBoundParameters() { case reflectutils.IntType: *(boundParameter.BoundPointer.(*int)) = c.Int(parameterName) case reflectutils.Int8Type: - *(boundParameter.BoundPointer.(*int8)) = int8(c.Int(parameterName)) + v, err := safecast.Convert[int8](c.Int(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*int8)) = v case reflectutils.Int16Type: - *(boundParameter.BoundPointer.(*int16)) = int16(c.Int(parameterName)) + v, err := safecast.Convert[int16](c.Int(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*int16)) = v case reflectutils.Int32Type: - *(boundParameter.BoundPointer.(*int32)) = int32(c.Int(parameterName)) + v, err := safecast.Convert[int32](c.Int(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*int32)) = v case reflectutils.Int64Type: *(boundParameter.BoundPointer.(*int64)) = c.Int64(parameterName) case reflectutils.StringType: *(boundParameter.BoundPointer.(*string)) = c.String(parameterName) case reflectutils.UintType: - *(boundParameter.BoundPointer.(*uint)) = uint(c.Int(parameterName)) + v, err := safecast.Convert[uint](c.Int(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*uint)) = v case reflectutils.Uint8Type: - *(boundParameter.BoundPointer.(*uint8)) = uint8(c.Int(parameterName)) + v, err := safecast.Convert[uint8](c.Int(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*uint8)) = v case reflectutils.Uint16Type: - *(boundParameter.BoundPointer.(*uint16)) = uint16(c.Int(parameterName)) + v, err := safecast.Convert[uint16](c.Int(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*uint16)) = v case reflectutils.Uint32Type: - *(boundParameter.BoundPointer.(*uint32)) = uint32(c.Int(parameterName)) + v, err := safecast.Convert[uint32](c.Int(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*uint32)) = v case reflectutils.Uint64Type: - *(boundParameter.BoundPointer.(*uint64)) = uint64(c.Int64(parameterName)) + v, err := safecast.Convert[uint64](c.Int64(parameterName)) + if err != nil { + return err + } + *(boundParameter.BoundPointer.(*uint64)) = v case reflectutils.StringSliceType: *(boundParameter.BoundPointer.(*[]string)) = c.Strings(parameterName) case reflectutils.StringMapType: @@ -672,6 +706,8 @@ func (c *Configuration) UpdateBoundParameters() { reflect.ValueOf(boundParameter.BoundPointer).Elem().Set(newBoundParameterPointer.Elem()) } } + + return nil } // GetParameterPath returns the path to the parameter with the given name. diff --git a/app/configuration/configuration_test.go b/app/configuration/configuration_test.go index 76087611b..218c83d82 100644 --- a/app/configuration/configuration_test.go +++ b/app/configuration/configuration_test.go @@ -272,7 +272,8 @@ func TestBindAndUpdateParameters(t *testing.T) { err = config.LoadFlagSet(flagset) assert.NoError(t, err) - config.UpdateBoundParameters() + err = config.UpdateBoundParameters() + assert.NoError(t, err) assertFlag(t, flagset, config, ¶meters.TestField, "configuration.testField", diff --git a/app/go.mod b/app/go.mod index c61e05292..55aa5b2b3 100644 --- a/app/go.mod +++ b/app/go.mod @@ -3,6 +3,7 @@ module github.com/iotaledger/hive.go/app go 1.22 require ( + fortio.org/safecast v1.0.0 github.com/felixge/fgprof v0.9.4 github.com/hashicorp/go-version v1.6.0 github.com/iotaledger/hive.go/ierrors v0.0.0-20240517131232-748f1ce3a2d2 diff --git a/app/go.sum b/app/go.sum index bacd42475..7bf0d7440 100644 --- a/app/go.sum +++ b/app/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +fortio.org/safecast v1.0.0 h1:dr3131WPX8iS1pTf76+39WeXbTrerDYLvi9s7Oi3wiY= +fortio.org/safecast v1.0.0/go.mod h1:xZmcPk3vi4kuUFf+tq4SvnlVdwViqf6ZSZl91Jr9Jdg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= diff --git a/app/shutdown/shutdown.go b/app/shutdown/shutdown.go index 07b34db22..f7662d890 100644 --- a/app/shutdown/shutdown.go +++ b/app/shutdown/shutdown.go @@ -122,7 +122,7 @@ func (gs *ShutdownHandler) writeSelfShutdownLogFile(msg string, critical bool) { message += " (CRITICAL)" } - if _, err := f.WriteString(fmt.Sprintf("%s: %s\n", time.Now().Format(time.RFC3339), message)); err != nil { + if _, err := fmt.Fprintf(f, "%s: %s\n", time.Now().Format(time.RFC3339), message); err != nil { gs.LogWarnf("self-shutdown log can't be written, error: %s", err.Error()) } } diff --git a/core/safemath/safe_math.go b/core/safemath/safe_math.go index 25d2f6fc3..c4265b580 100644 --- a/core/safemath/safe_math.go +++ b/core/safemath/safe_math.go @@ -83,6 +83,8 @@ func SafeMulUint64(x, y uint64) (uint64, error) { // Returns x * y or an error if that computation would under- or overflow. // // According to benchmarks, this function is about 27% faster than SafeMul. +// +//nolint:gosec // disable G115 - integer overlfows are checked manually func SafeMulInt64(x, y int64) (int64, error) { // This function stores the sign of the resulting int64 multiplication // and then executes the multiplication with two uint64s, in 128-bit space. diff --git a/crypto/randomness.go b/crypto/randomness.go index e18df1c3a..f19121373 100644 --- a/crypto/randomness.go +++ b/crypto/randomness.go @@ -14,7 +14,7 @@ func (s RandomnessSource) Seed(int64) {} // Int63 returns a non-negative random 63-bit integer as an int64. func (s RandomnessSource) Int63() int64 { - return int64(s.Uint64() & ^uint64(1<<63)) + return int64(s.Uint64() & ^uint64(1<<63)) //nolint:gosec // ignore integer overflow error } // Uint64 returns a random 64-bit value as a uint64. diff --git a/ds/go.mod b/ds/go.mod index 873355029..a070f2a63 100644 --- a/ds/go.mod +++ b/ds/go.mod @@ -3,6 +3,7 @@ module github.com/iotaledger/hive.go/ds go 1.22 require ( + fortio.org/safecast v1.0.0 github.com/iotaledger/hive.go/constraints v0.0.0-20240517131232-748f1ce3a2d2 github.com/iotaledger/hive.go/ierrors v0.0.0-20240517131232-748f1ce3a2d2 github.com/iotaledger/hive.go/lo v0.0.0-20240517131232-748f1ce3a2d2 diff --git a/ds/go.sum b/ds/go.sum index 012009e12..985b6547b 100644 --- a/ds/go.sum +++ b/ds/go.sum @@ -1,3 +1,5 @@ +fortio.org/safecast v1.0.0 h1:dr3131WPX8iS1pTf76+39WeXbTrerDYLvi9s7Oi3wiY= +fortio.org/safecast v1.0.0/go.mod h1:xZmcPk3vi4kuUFf+tq4SvnlVdwViqf6ZSZl91Jr9Jdg= github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/ds/reactive/clock_impl.go b/ds/reactive/clock_impl.go index 0a0c32637..e953048b1 100644 --- a/ds/reactive/clock_impl.go +++ b/ds/reactive/clock_impl.go @@ -21,7 +21,7 @@ func newClock(granularity time.Duration) *clock { } // set the initial value. - c.variable.Set(time.Now()) + c.Set(time.Now()) go func() { // align the ticker to the given granularity. @@ -29,14 +29,14 @@ func newClock(granularity time.Duration) *clock { ticker := time.NewTicker(granularity) // first tick after the initial value. - c.variable.Set(time.Now().Truncate(granularity)) + c.Set(time.Now().Truncate(granularity)) for { select { case <-c.shutdown: return case t := <-ticker.C: - c.variable.Set(t.Truncate(granularity)) + c.Set(t.Truncate(granularity)) } } }() diff --git a/ds/reactive/wait_group_impl.go b/ds/reactive/wait_group_impl.go index 1a8384045..fa19bd339 100644 --- a/ds/reactive/wait_group_impl.go +++ b/ds/reactive/wait_group_impl.go @@ -6,6 +6,8 @@ import ( "sync" "sync/atomic" + "fortio.org/safecast" + "github.com/iotaledger/hive.go/ds" "github.com/iotaledger/hive.go/lo" ) @@ -37,7 +39,8 @@ func newWaitGroup[T comparable](elements ...T) *waitGroup[T] { // Add adds the given elements to the wait group. func (w *waitGroup[T]) Add(elements ...T) { // first increase the counter so that the trigger is not executed before all elements are added - w.pendingElementsCounter.Add(int32(len(elements))) + v := safecast.MustConvert[int32](len(elements)) + w.pendingElementsCounter.Add(v) // then add the elements (and correct the counter if the elements are already present) for _, element := range elements { diff --git a/ds/serializableorderedmap/serializable_orderedmap.go b/ds/serializableorderedmap/serializable_orderedmap.go index b200b81ff..8155a94ad 100644 --- a/ds/serializableorderedmap/serializable_orderedmap.go +++ b/ds/serializableorderedmap/serializable_orderedmap.go @@ -3,6 +3,8 @@ package serializableorderedmap import ( "context" + "fortio.org/safecast" + "github.com/iotaledger/hive.go/ds/orderedmap" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/serializer/v2" @@ -23,9 +25,14 @@ func New[K comparable, V any]() *SerializableOrderedMap[K, V] { // Encode returns a serialized byte slice of the object. func (o *SerializableOrderedMap[K, V]) Encode(api *serix.API) ([]byte, error) { + v, err := safecast.Convert[uint32](o.Size()) + if err != nil { + return nil, err + } + seri := serializer.NewSerializer() - seri.WriteNum(uint32(o.Size()), func(err error) error { + seri.WriteNum(v, func(err error) error { return ierrors.Wrap(err, "failed to write SerializableOrderedMap size to serializer") }) diff --git a/ds/set_impl.go b/ds/set_impl.go index f83e25055..26f69942a 100644 --- a/ds/set_impl.go +++ b/ds/set_impl.go @@ -155,7 +155,7 @@ func newReadableSet[T comparable](elements ...T) *readableSet[T] { } for _, element := range elements { - r.OrderedMap.Set(element, types.Void) + r.Set(element, types.Void) } return r diff --git a/ierrors/ierrors.go b/ierrors/ierrors.go index 81a1795ac..a72e9dc43 100644 --- a/ierrors/ierrors.go +++ b/ierrors/ierrors.go @@ -2,7 +2,7 @@ // It enhances error handling by adding additional error creation and manipulation functions. // This package also supports stacktraces when the "stacktrace" build tag is added. // -//nolint:goerr113 +//nolint:err113 package ierrors import ( diff --git a/ierrors/ierrors_no_stacktrace.go b/ierrors/ierrors_no_stacktrace.go index 4f68f012e..815ccb9b7 100644 --- a/ierrors/ierrors_no_stacktrace.go +++ b/ierrors/ierrors_no_stacktrace.go @@ -1,6 +1,6 @@ //go:build !stacktrace -//nolint:goerr113 +//nolint:err113 package ierrors import ( diff --git a/kvstore/go.mod b/kvstore/go.mod index 239ce73e5..bd9577e36 100644 --- a/kvstore/go.mod +++ b/kvstore/go.mod @@ -3,6 +3,7 @@ module github.com/iotaledger/hive.go/kvstore go 1.22 require ( + fortio.org/safecast v1.0.0 github.com/iotaledger/grocksdb v1.7.5-0.20230220105546-5162e18885c7 github.com/iotaledger/hive.go/ds v0.0.0-20240517131232-748f1ce3a2d2 github.com/iotaledger/hive.go/ierrors v0.0.0-20240517131232-748f1ce3a2d2 diff --git a/kvstore/go.sum b/kvstore/go.sum index 04443f5a1..dede64510 100644 --- a/kvstore/go.sum +++ b/kvstore/go.sum @@ -1,3 +1,5 @@ +fortio.org/safecast v1.0.0 h1:dr3131WPX8iS1pTf76+39WeXbTrerDYLvi9s7Oi3wiY= +fortio.org/safecast v1.0.0/go.mod h1:xZmcPk3vi4kuUFf+tq4SvnlVdwViqf6ZSZl91Jr9Jdg= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/kvstore/mapdb/mapdb.go b/kvstore/mapdb/mapdb.go index 6156a52e6..9b54b92da 100644 --- a/kvstore/mapdb/mapdb.go +++ b/kvstore/mapdb/mapdb.go @@ -112,6 +112,7 @@ func (s *mapDB) Set(key kvstore.Key, value kvstore.Value) error { return s.set(key, value) } +//nolint:unparam // error is always nil func (s *mapDB) set(key kvstore.Key, value kvstore.Value) error { s.m.set(byteutils.ConcatBytes(s.realm, key), value) @@ -142,6 +143,7 @@ func (s *mapDB) Delete(key kvstore.Key) error { return s.delete(key) } +//nolint:unparam // error is always nil func (s *mapDB) delete(key kvstore.Key) error { s.m.delete(byteutils.ConcatBytes(s.realm, key)) diff --git a/kvstore/testutil/util.go b/kvstore/testutil/util.go index da98041f4..34e23327d 100644 --- a/kvstore/testutil/util.go +++ b/kvstore/testutil/util.go @@ -74,28 +74,28 @@ func RandString(length int) string { } // RandUint8 returns a random uint8. -func RandUint8(max uint8) uint8 { - return uint8(RandomInt31n(int32(max))) +func RandUint8(maximum uint8) uint8 { + return uint8(RandomInt31n(int32(maximum))) //nolint:gosec } // RandUint16 returns a random uint16. -func RandUint16(max uint16) uint16 { - return uint16(RandomInt31n(int32(max))) +func RandUint16(maximum uint16) uint16 { + return uint16(RandomInt31n(int32(maximum))) //nolint:gosec } // RandUint32 returns a random uint32. -func RandUint32(max uint32) uint32 { - return uint32(RandomInt63n(int64(max))) +func RandUint32(maximum uint32) uint32 { + return uint32(RandomInt63n(int64(maximum))) //nolint:gosec } // RandUint64 returns a random uint64. -func RandUint64(max uint64) uint64 { - return uint64(RandomInt63n(int64(uint32(max)))) +func RandUint64(maximum uint64) uint64 { + return uint64(RandomInt63n(int64(uint32(maximum)))) //nolint:gosec } // RandFloat64 returns a random float64. -func RandFloat64(max float64) float64 { - return RandomFloat64() * max +func RandFloat64(maximum float64) float64 { + return RandomFloat64() * maximum } // Rand32ByteArray returns an array with 32 random bytes. diff --git a/lo/lo.go b/lo/lo.go index 2bb167d10..bb6c14c80 100644 --- a/lo/lo.go +++ b/lo/lo.go @@ -222,12 +222,12 @@ func Max[T constraints.Ordered](collection ...T) T { maxElem = collection[0] - return Reduce(collection, func(max, value T) T { - if Comparator(value, max) > 0 { + return Reduce(collection, func(accum, value T) T { + if Comparator(value, accum) > 0 { return value } - return max + return accum }, maxElem) } @@ -240,12 +240,12 @@ func Min[T constraints.Ordered](collection ...T) T { minElem = collection[0] - return Reduce(collection, func(min, value T) T { - if Comparator(value, min) < 0 { + return Reduce(collection, func(accum, value T) T { + if Comparator(value, accum) < 0 { return value } - return min + return accum }, minElem) } diff --git a/runtime/backoff/options.go b/runtime/backoff/options.go index 349f99437..7982098f9 100644 --- a/runtime/backoff/options.go +++ b/runtime/backoff/options.go @@ -29,11 +29,11 @@ func (f statelessOptionFunc) apply(p Policy) Policy { } // MaxRetries configures a backoff policy to return Stop if NextBackOff() has been called too many times. -func MaxRetries(max int) Option { +func MaxRetries(maximum int) Option { return optionFunc(func(p Policy) Policy { return &maxRetriesOption{ delegate: p, - maxTries: max, + maxTries: maximum, numTries: 0, } }) diff --git a/runtime/contextutils/merged_context.go b/runtime/contextutils/merged_context.go index fe5d4c0d0..79a613d60 100644 --- a/runtime/contextutils/merged_context.go +++ b/runtime/contextutils/merged_context.go @@ -87,20 +87,20 @@ func MergeContexts(ctxPrimary context.Context, ctxSecondary context.Context) (co // Deadline returns ok==false when no deadline is set. // Successive calls to Deadline return the same results. func (mc *mergedContext) Deadline() (time.Time, bool) { - min := time.Time{} + minimum := time.Time{} if dl, ok := mc.ctxPrimary.Deadline(); ok { - min = dl + minimum = dl } if dl, ok := mc.ctxSecondary.Deadline(); ok { // if deadline not set yet or secondary deadline is before current deadline - if min.IsZero() || dl.Before(min) { - min = dl + if minimum.IsZero() || dl.Before(minimum) { + minimum = dl } } - return min, !min.IsZero() + return minimum, !minimum.IsZero() } // Done returns a channel that's closed when work done on behalf of the diff --git a/runtime/event/options.go b/runtime/event/options.go index 35890ba8c..53c9c0fb1 100644 --- a/runtime/event/options.go +++ b/runtime/event/options.go @@ -3,6 +3,8 @@ package event import ( "sync/atomic" + "fortio.org/safecast" + "github.com/iotaledger/hive.go/lo" "github.com/iotaledger/hive.go/runtime/options" "github.com/iotaledger/hive.go/runtime/workerpool" @@ -50,12 +52,15 @@ func (t *triggerSettings) WasTriggered() bool { // TriggerCount returns the number of times Trigger was called. func (t *triggerSettings) TriggerCount() int { - return int(t.triggerCount.Load()) + v := safecast.MustConvert[int](t.triggerCount.Load()) + return v } // MaxTriggerCount returns the maximum number of times Trigger can be called. func (t *triggerSettings) MaxTriggerCount() int { - return int(t.maxTriggerCount) + v := safecast.MustConvert[int](t.maxTriggerCount) + + return v } // MaxTriggerCountReached returns true if the maximum number of times Trigger can be called was reached. diff --git a/runtime/go.mod b/runtime/go.mod index 4052953e4..369a35c49 100644 --- a/runtime/go.mod +++ b/runtime/go.mod @@ -3,6 +3,7 @@ module github.com/iotaledger/hive.go/runtime go 1.22 require ( + fortio.org/safecast v1.0.0 github.com/fjl/memsize v0.0.2 github.com/iotaledger/hive.go/constraints v0.0.0-20240517131232-748f1ce3a2d2 github.com/iotaledger/hive.go/ds v0.0.0-20240517131232-748f1ce3a2d2 diff --git a/runtime/go.sum b/runtime/go.sum index e4b6fd567..a9e478d00 100644 --- a/runtime/go.sum +++ b/runtime/go.sum @@ -1,3 +1,5 @@ +fortio.org/safecast v1.0.0 h1:dr3131WPX8iS1pTf76+39WeXbTrerDYLvi9s7Oi3wiY= +fortio.org/safecast v1.0.0/go.mod h1:xZmcPk3vi4kuUFf+tq4SvnlVdwViqf6ZSZl91Jr9Jdg= github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/serializer/error.go b/serializer/error.go index 5d45df95b..8426d3255 100644 --- a/serializer/error.go +++ b/serializer/error.go @@ -89,9 +89,9 @@ func CheckExactByteLength(exact int, length int) error { } // CheckMinByteLength checks that length is at least min. -func CheckMinByteLength(min int, length int) error { - if length < min { - return ierrors.Wrapf(ErrDeserializationNotEnoughData, "data must be at least %d bytes long but is %d", min, length) +func CheckMinByteLength(minimum int, length int) error { + if length < minimum { + return ierrors.Wrapf(ErrDeserializationNotEnoughData, "data must be at least %d bytes long but is %d", minimum, length) } return nil diff --git a/serializer/go.mod b/serializer/go.mod index cb3eaea70..bfcf05c2d 100644 --- a/serializer/go.mod +++ b/serializer/go.mod @@ -3,6 +3,7 @@ module github.com/iotaledger/hive.go/serializer/v2 go 1.22 require ( + fortio.org/safecast v1.0.0 github.com/ethereum/go-ethereum v1.14.3 github.com/iancoleman/orderedmap v0.3.0 github.com/iotaledger/hive.go/ds v0.0.0-20240517131232-748f1ce3a2d2 diff --git a/serializer/go.sum b/serializer/go.sum index 996eefbb4..9fae98813 100644 --- a/serializer/go.sum +++ b/serializer/go.sum @@ -1,3 +1,5 @@ +fortio.org/safecast v1.0.0 h1:dr3131WPX8iS1pTf76+39WeXbTrerDYLvi9s7Oi3wiY= +fortio.org/safecast v1.0.0/go.mod h1:xZmcPk3vi4kuUFf+tq4SvnlVdwViqf6ZSZl91Jr9Jdg= github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= diff --git a/serializer/serializer.go b/serializer/serializer.go index 3354cb8c0..1d9ce64c4 100644 --- a/serializer/serializer.go +++ b/serializer/serializer.go @@ -10,6 +10,8 @@ import ( "sort" "time" + "fortio.org/safecast" + "github.com/iotaledger/hive.go/ierrors" ) @@ -231,7 +233,7 @@ func (s *Serializer) writeSliceLength(l int, lenType SeriLengthPrefixType, errPr return } - if err := binary.Write(&s.buf, binary.LittleEndian, uint16(l)); err != nil { + if err := binary.Write(&s.buf, binary.LittleEndian, uint16(l)); err != nil { //nolint:gosec // overflow checked above s.err = errProducer(err) return @@ -242,7 +244,7 @@ func (s *Serializer) writeSliceLength(l int, lenType SeriLengthPrefixType, errPr return } - if err := binary.Write(&s.buf, binary.LittleEndian, uint32(l)); err != nil { + if err := binary.Write(&s.buf, binary.LittleEndian, uint32(l)); err != nil { //nolint:gosec // overflow checked above s.err = errProducer(err) return @@ -432,12 +434,17 @@ func TimeToUint64(value time.Time) uint64 { unixNano = 0 } - return uint64(unixNano) + return uint64(unixNano) //nolint:gosec // overflow checked above } // Uint64ToTime converts a uint64 unix timestamp with nanosecond-precision to a time.Time. -func Uint64ToTime(value uint64) time.Time { - return time.Unix(0, int64(value)).UTC() +func Uint64ToTime(value uint64) (time.Time, error) { + v, err := safecast.Convert[int64](value) + if err != nil { + return time.Unix(0, 0), err + } + + return time.Unix(0, v).UTC(), nil } // WritePayload writes the given payload Serializable into the Serializer. @@ -493,7 +500,11 @@ func (s *Serializer) WritePayloadLength(length int, errProducer ErrProducer) *Se } func (s *Serializer) writePayloadLength(length int) error { - if err := binary.Write(&s.buf, binary.LittleEndian, uint32(length)); err != nil { + v, err := safecast.Convert[uint32](length) + if err != nil { + return ierrors.Wrap(err, "unable to serialize payload length") + } + if err := binary.Write(&s.buf, binary.LittleEndian, v); err != nil { return ierrors.Wrap(err, "unable to serialize payload length") } @@ -687,19 +698,19 @@ func (d *Deserializer) ReadNum(dest any, errProducer ErrProducer) *Deserializer *x = data[0] case *int16: - *x = int16(binary.LittleEndian.Uint16(data)) + *x = safecast.MustConvert[int16](binary.LittleEndian.Uint16(data)) case *uint16: *x = binary.LittleEndian.Uint16(data) case *int32: - *x = int32(binary.LittleEndian.Uint32(data)) + *x = safecast.MustConvert[int32](binary.LittleEndian.Uint32(data)) case *uint32: *x = binary.LittleEndian.Uint32(data) case *int64: - *x = int64(binary.LittleEndian.Uint64(data)) + *x = safecast.MustConvert[int64](binary.LittleEndian.Uint64(data)) case *uint64: *x = binary.LittleEndian.Uint64(data) @@ -984,7 +995,13 @@ func (d *Deserializer) ReadSequenceOfObjects( var arrayElementValidator ElementValidationFunc if deSeriMode.HasMode(DeSeriModePerformValidation) { - if err := arrayRules.CheckBounds(uint(sliceLength)); err != nil { + v, err := safecast.Convert[uint](sliceLength) + if err != nil { + d.err = errProducer(err) + + return d + } + if err := arrayRules.CheckBounds(v); err != nil { d.err = errProducer(err) return d @@ -1053,7 +1070,7 @@ func (d *Deserializer) ReadTime(dest *time.Time, errProducer ErrProducer) *Deser nanoseconds = math.MaxInt64 } - *dest = time.Unix(0, int64(nanoseconds)).UTC() + *dest = time.Unix(0, int64(nanoseconds)).UTC() //nolint:gosec // overflow checked above d.offset += UInt64ByteSize diff --git a/serializer/serix/map_decode.go b/serializer/serix/map_decode.go index a2dc52d52..aba929fd5 100644 --- a/serializer/serix/map_decode.go +++ b/serializer/serix/map_decode.go @@ -145,7 +145,11 @@ func (api *API) mapDecodeBasedOnType(ctx context.Context, mapVal any, value refl sliceValue := sliceFromArray(value) sliceValueType := sliceValue.Type() if sliceValueType.AssignableTo(bytesType) { - byteSlice, err := DecodeHex(mapVal.(string)) + str, ok := mapVal.(string) + if !ok { + return ierrors.New("non string value for string field") + } + byteSlice, err := DecodeHex(str) if err != nil { return ierrors.Wrap(err, "failed to read byte slice from map") } @@ -262,8 +266,11 @@ func (api *API) mapDecodeFloat(value reflect.Value, valueType reflect.Type, mapV addrValue := value.Addr() bitSize, _, addrTypeToConvert := getNumberTypeToConvert(valueType.Kind()) addrValue = addrValue.Convert(addrTypeToConvert) - - f, err := strconv.ParseFloat(mapVal.(string), bitSize) + str, ok := mapVal.(string) + if !ok { + return ierrors.New("non string value for string field") + } + f, err := strconv.ParseFloat(str, bitSize) if err != nil { return err } @@ -315,8 +322,11 @@ func (api *API) mapDecodeStruct(ctx context.Context, mapVal any, value reflect.V if err != nil { return ierrors.Wrapf(err, "unable to parse time %s map value", strVal) } - - value.Set(reflect.ValueOf(serializer.Uint64ToTime(nanoTime))) + t, err := serializer.Uint64ToTime(nanoTime) + if err != nil { + return ierrors.Wrapf(err, "unable to parse time %s map value", strVal) + } + value.Set(reflect.ValueOf(t)) return nil } diff --git a/serializer/serix/map_encode_test.go b/serializer/serix/map_encode_test.go index 47e5445eb..9077c0cfb 100644 --- a/serializer/serix/map_encode_test.go +++ b/serializer/serix/map_encode_test.go @@ -377,7 +377,8 @@ func TestMapEncodeDecode(t *testing.T) { uint64Time, err := serix.DecodeUint64("1660301478120072000") require.NoError(t, err) - exampleTime := serializer.Uint64ToTime(uint64Time) + exampleTime, err := serializer.Uint64ToTime(uint64Time) + require.NoError(t, err) return paras{ api: api, diff --git a/serializer/serix/type_settings.go b/serializer/serix/type_settings.go index 8161eabd1..5d83cbbe0 100644 --- a/serializer/serix/type_settings.go +++ b/serializer/serix/type_settings.go @@ -4,6 +4,8 @@ import ( "reflect" "sync" + "fortio.org/safecast" + hiveorderedmap "github.com/iotaledger/hive.go/ds/orderedmap" "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/serializer/v2" @@ -212,15 +214,23 @@ func (ts TypeSettings) MaxLen() (uint, bool) { // MinMaxLen returns min/max lengths for the object. // Returns 0 for either value if they are not set. func (ts TypeSettings) MinMaxLen() (int, int) { - var min, max int + var minimum, maximum int if ts.arrayRules != nil { - min = int(ts.arrayRules.Min) + v, err := safecast.Convert[int](ts.arrayRules.Min) + if err != nil { + panic("array rule min conversion failed") + } + minimum = v } if ts.arrayRules != nil { - max = int(ts.arrayRules.Max) + v, err := safecast.Convert[int](ts.arrayRules.Max) + if err != nil { + panic("array rule max conversion failed") + } + maximum = v } - return min, max + return minimum, maximum } func (ts TypeSettings) ensureOrdering() TypeSettings { @@ -267,13 +277,20 @@ func (ts TypeSettings) toMode(opts *options) serializer.DeSerializationMode { // checkMinMaxBoundsLength checks whether the given length is within its defined bounds. func (ts TypeSettings) checkMinMaxBoundsLength(length int) error { + v, err := safecast.Convert[uint](length) if minLen, ok := ts.MinLen(); ok { - if uint(length) < minLen { + if err != nil { + return ierrors.Wrap(err, "invalid length specified") + } + if v < minLen { return ierrors.Wrapf(serializer.ErrArrayValidationMinElementsNotReached, "min length %d not reached (len %d)", minLen, length) } } if maxLen, ok := ts.MaxLen(); ok { - if uint(length) > maxLen { + if err != nil { + return ierrors.Wrap(err, "invalid length specified") + } + if v > maxLen { return ierrors.Wrapf(serializer.ErrArrayValidationMaxElementsExceeded, "max length %d exceeded (len %d)", maxLen, length) } } diff --git a/serializer/stream/read.go b/serializer/stream/read.go index 1b10440df..f1e3f74fa 100644 --- a/serializer/stream/read.go +++ b/serializer/stream/read.go @@ -5,6 +5,8 @@ import ( "fmt" "io" + "fortio.org/safecast" + "github.com/iotaledger/hive.go/ierrors" "github.com/iotaledger/hive.go/serializer/v2" ) @@ -127,29 +129,48 @@ func readFixedSize(reader io.Reader, lenType serializer.SeriLengthPrefixType) (i if err != nil { return 0, ierrors.Wrap(err, "failed to read length prefix") } + v, err := safecast.Convert[int](result) + if err != nil { + return 0, ierrors.Wrap(err, "failed to convert length prefix") + } - return int(result), nil + return v, nil case serializer.SeriLengthPrefixTypeAsUint16: result, err := Read[uint16](reader) if err != nil { return 0, ierrors.Wrap(err, "failed to read length prefix") } - return int(result), nil + v, err := safecast.Convert[int](result) + if err != nil { + return 0, ierrors.Wrap(err, "failed to convert length prefix") + } + + return v, nil case serializer.SeriLengthPrefixTypeAsUint32: result, err := Read[uint32](reader) if err != nil { return 0, ierrors.Wrap(err, "failed to read length prefix") } - return int(result), nil + v, err := safecast.Convert[int](result) + if err != nil { + return 0, ierrors.Wrap(err, "failed to convert length prefix") + } + + return v, nil case serializer.SeriLengthPrefixTypeAsUint64: result, err := Read[uint64](reader) if err != nil { return 0, ierrors.Wrap(err, "failed to read length prefix") } - return int(result), nil + v, err := safecast.Convert[int](result) + if err != nil { + return 0, ierrors.Wrap(err, "failed to convert length prefix") + } + + return v, nil default: panic(fmt.Sprintf("unknown slice length type %v", lenType)) } diff --git a/serializer/stream/write.go b/serializer/stream/write.go index 05d25a1c6..12a7ba636 100644 --- a/serializer/stream/write.go +++ b/serializer/stream/write.go @@ -131,6 +131,9 @@ func writeFixedSize(writer io.Writer, l int, lenType serializer.SeriLengthPrefix return nil case serializer.SeriLengthPrefixTypeAsUint64: + if l < 0 { + return ierrors.Errorf("unable to serialize collection length: length %d must be non-negative", l) + } if err := Write(writer, uint64(l)); err != nil { return ierrors.Wrap(err, "unable to write length") } diff --git a/web/websockethub/hub.go b/web/websockethub/hub.go index 2aa7bfe8f..140d100ec 100644 --- a/web/websockethub/hub.go +++ b/web/websockethub/hub.go @@ -186,7 +186,7 @@ drainLoop: } // cleanup the logger - client.Logger.Shutdown() + client.Shutdown() h.events.ClientDisconnected.Trigger(&ClientConnectionEvent{ID: client.id})