From 52c82d2c35929ed7a1d7f3bde47bd7a931b1a456 Mon Sep 17 00:00:00 2001 From: sueun-dev Date: Mon, 29 Jun 2026 20:26:11 +0900 Subject: [PATCH] json: report integer duration overflow against time.Duration decodeDuration parses integer durations with parseInt(b, durationType), but on error it returned inputError(b, int32Type) and then checked v < math.MinInt64 || v > math.MaxInt64. v is an int64, so that branch is unreachable (staticcheck SA4003, the lint in #150), and both error paths reported int32 instead of time.Duration. time.Duration is backed by int64, so propagate the parseInt error the same way decodeInt64 does. Add a regression test. Fixes #150 --- json/decode.go | 6 +----- json/json_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/json/decode.go b/json/decode.go index 36720337..dd6a11b5 100644 --- a/json/decode.go +++ b/json/decode.go @@ -447,11 +447,7 @@ func (d decoder) decodeDuration(b []byte, p unsafe.Pointer) ([]byte, error) { if len(b) > 0 && b[0] != '"' { v, r, err := d.parseInt(b, durationType) if err != nil { - return d.inputError(b, int32Type) - } - - if v < math.MinInt64 || v > math.MaxInt64 { - return r, unmarshalOverflow(b[:len(b)-len(r)], int32Type) + return r, err } *(*time.Duration)(p) = time.Duration(v) diff --git a/json/json_test.go b/json/json_test.go index 8256be2a..b3658f47 100644 --- a/json/json_test.go +++ b/json/json_test.go @@ -495,6 +495,32 @@ func TestCodecDuration(t *testing.T) { } } +// TestDecodeDurationOverflow checks that decoding an integer that overflows +// int64 into a time.Duration reports the error against time.Duration, the same +// way the int64 decoder does. Previously the duration decoder reported these +// errors against int32, which is neither the field's type nor consistent with +// the rest of the package. +func TestDecodeDurationOverflow(t *testing.T) { + const overflow = `100000000000000000000000` + + var d time.Duration + durErr := Unmarshal([]byte(`{"D":`+overflow+`}`), &struct{ D *time.Duration }{D: &d}) + if durErr == nil { + t.Fatal("expected an error decoding an overflowing duration, got nil") + } + + ute, ok := durErr.(*UnmarshalTypeError) + if !ok { + t.Fatalf("expected *UnmarshalTypeError, got %T: %v", durErr, durErr) + } + if want := reflect.TypeOf(time.Duration(0)); ute.Type != want { + t.Errorf("UnmarshalTypeError.Type = %v, want %v", ute.Type, want) + } + if strings.Contains(durErr.Error(), "int32") { + t.Errorf("error should not mention int32: %v", durErr) + } +} + var numericParseTests = [...]struct { name string input string