Skip to content

encoding/json: Unmarshal leaves ±Inf in the destination on float overflow in Go 1.27 #81062

Description

@IBlackVoid

Go version

go1.27.0

What did you do

Unmarshal a number that overflows the destination float, then inspect the destination.

package main

import (
	"encoding/json"
	"fmt"
	"math"
)

func main() {
	var f float64
	err := json.Unmarshal([]byte("1e1000"), &f)
	fmt.Printf("err=%v value=%v isInf=%v\n", err != nil, f, math.IsInf(f, 0))

	var v any
	json.Unmarshal([]byte(`{"x":1e1000}`), &v)
	out, err := json.Marshal(v)
	fmt.Printf("re-marshal: %q err=%v\n", out, err)
}

What did you see happen

go1.27.0:

err=true value=+Inf isInf=true
re-marshal: "" err=json: unsupported value: +Inf

go1.27.0 with GOEXPERIMENT=nojsonv2:

err=true value=0 isInf=false
re-marshal: "{\"x\":null}" err=<nil>

Both report the overflow. They differ in what they leave behind: the new implementation stores the clamped ±Inf that strconv.ParseFloat returns alongside ErrRange, the previous one left the destination alone.

What did you expect to see

0, as before, and a value that encoding/json can still marshal.

Unmarshal documents that it decodes as much as it can when it encounters an error, so the residue is observable rather than undefined, and encoding/json/v2 documents this specific value as unreachable (arshal.go):

It fails if it overflows the representation of the Go float type. Since JSON lacks a native representation for a NaN or ±Inf, such values cannot be the result of decoding.

The practical consequence is the second half of the reproducer: Marshal rejects ±Inf, so decoding, logging the error, and re-encoding the partially populated value used to succeed and now fails.

Worth noting before this is treated as a plain oversight: v2/arshal_test.go asserts the current behaviour on purpose (Floats/Float32/Overflow and Floats/Float64/Overflow expect math.Inf(-1)). So the code, its test, and the package documentation do not agree, and I am not sure which of the three is meant to give.


Found while comparing pre-1.27 and 1.27 encoding/json behaviour with a differential harness (https://github.com/IBlackVoid/jsonparity).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    FixPendingIssues that have a fix which has not yet been reviewed or submitted.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions