From 0b522f0cb01a90112f7d0da6e22e4e1e8f1dfa1e Mon Sep 17 00:00:00 2001 From: Prithvi Vishak Date: Tue, 3 May 2022 14:56:15 +0530 Subject: [PATCH 1/3] Convert string to int64 with strconv.ParseInt to prevent overflow on 32-bit systems --- env.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/env.go b/env.go index d5cb875..544f74e 100644 --- a/env.go +++ b/env.go @@ -190,7 +190,13 @@ func set(t reflect.Type, f reflect.Value, value string) error { return err } f.SetFloat(v) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: + v, err := strconv.Atoi(value) + if err != nil { + return err + } + f.SetInt(int64(v)) + case reflect.Int64: if t.PkgPath() == "time" && t.Name() == "Duration" { duration, err := time.ParseDuration(value) if err != nil { @@ -201,11 +207,13 @@ func set(t reflect.Type, f reflect.Value, value string) error { break } - v, err := strconv.Atoi(value) + // Handling this separately because strconv.Atoi returns int, + // which is not guaranteed to be 64-bit on all platforms + v, err := strconv.ParseInt(value, 10, 64) if err != nil { return err } - f.SetInt(int64(v)) + f.SetInt(v) default: return ErrUnsupportedType } From e3bcdfa47e881f9217feacb4c28a2559daaa1c83 Mon Sep 17 00:00:00 2001 From: Prithvi Vishak Date: Wed, 4 May 2022 14:59:56 +0530 Subject: [PATCH 2/3] Add test for int64 unmarshaling --- env_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/env_test.go b/env_test.go index 92fc338..6a78ce3 100644 --- a/env_test.go +++ b/env_test.go @@ -52,6 +52,7 @@ type ValidStruct struct { Int int `env:"INT"` Float32 float32 `env:"FLOAT32"` Float64 float64 `env:"FLOAT64"` + Int64 int64 `env:"INT64"` Bool bool `env:"BOOL"` MultipleTags string `env:"npm_config_cache,NPM_CONFIG_CACHE"` @@ -140,6 +141,7 @@ func TestUnmarshal(t *testing.T) { "INT": "1", "FLOAT32": "2.3", "FLOAT64": "4.5", + "INT64": "4294967296", "BOOL": "true", "npm_config_cache": "first", "NPM_CONFIG_CACHE": "second", @@ -180,6 +182,10 @@ func TestUnmarshal(t *testing.T) { t.Errorf("Expected field value to be '%f' but got '%f'", 4.5, validStruct.Float64) } + if validStruct.Int64 != 4294967296 { + t.Errorf("Expected field value to be '%d' but got '%d'", int64(4294967296), validStruct.Int64) + } + if validStruct.Bool != true { t.Errorf("Expected field value to be '%t' but got '%t'", true, validStruct.Bool) } From 2744555d1347174ccb02c69298dfac3c149447af Mon Sep 17 00:00:00 2001 From: Prithvi Vishak Date: Wed, 4 May 2022 17:35:34 +0530 Subject: [PATCH 3/3] Collapse int-handling cases into one in set() --- env.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/env.go b/env.go index 544f74e..b17202f 100644 --- a/env.go +++ b/env.go @@ -190,13 +190,7 @@ func set(t reflect.Type, f reflect.Value, value string) error { return err } f.SetFloat(v) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: - v, err := strconv.Atoi(value) - if err != nil { - return err - } - f.SetInt(int64(v)) - case reflect.Int64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if t.PkgPath() == "time" && t.Name() == "Duration" { duration, err := time.ParseDuration(value) if err != nil { @@ -207,7 +201,7 @@ func set(t reflect.Type, f reflect.Value, value string) error { break } - // Handling this separately because strconv.Atoi returns int, + // Using ParseInt because strconv.Atoi returns int, // which is not guaranteed to be 64-bit on all platforms v, err := strconv.ParseInt(value, 10, 64) if err != nil {