Skip to content

Commit 28e4bc6

Browse files
committed
Use decoder.UseNumber() to avoid unmarshalling to floats
Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
1 parent 3ea5614 commit 28e4bc6

File tree

2 files changed

+19
-30
lines changed

2 files changed

+19
-30
lines changed

pkg/fftypes/jsonany.go

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2023 Kaleido, Inc.
1+
// Copyright © 2024 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -21,7 +21,7 @@ import (
2121
"crypto/sha256"
2222
"database/sql/driver"
2323
"encoding/json"
24-
"math/big"
24+
"strings"
2525

2626
"github.com/hyperledger/firefly-common/pkg/i18n"
2727
"github.com/hyperledger/firefly-common/pkg/log"
@@ -78,37 +78,13 @@ func (h *JSONAny) Unmarshal(ctx context.Context, v interface{}) error {
7878
return i18n.NewError(ctx, i18n.MsgNilOrNullObject)
7979
}
8080

81-
err := json.Unmarshal([]byte(*h), v)
82-
if err != nil {
81+
d := json.NewDecoder(strings.NewReader(h.String()))
82+
d.UseNumber()
83+
if err := d.Decode(v); err != nil {
8384
return err
8485
}
8586

86-
// To support large numbers, check if Go unmarshalled the data to a float64 and then
87-
// unmarshal it to a string instead
88-
if vt, ok := v.(*interface{}); ok {
89-
if _, ok := (*vt).(float64); ok {
90-
// If the value has unmarshalled to a float64 we can't be sure the number
91-
// didn't overflow 2^64-1 so we'll use parseFloat on the original value
92-
// and return the string representation of the number.
93-
i := new(big.Int)
94-
f, _, err := big.ParseFloat(h.String(), 10, 256, big.ToNearestEven)
95-
if err != nil {
96-
return err
97-
}
98-
i, accuracy := f.Int(i)
99-
if accuracy != big.Exact {
100-
// If we weren't able to decode without losing precision, return an error
101-
return i18n.NewError(ctx, i18n.MsgBigIntParseFailed)
102-
}
103-
104-
err = json.Unmarshal([]byte("\""+i.String()+"\""), v)
105-
if err != nil {
106-
return err
107-
}
108-
}
109-
}
110-
111-
return err
87+
return nil
11288
}
11389

11490
func (h *JSONAny) Hash() *Bytes32 {

pkg/fftypes/jsonany_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,19 @@ func TestUnmarshal(t *testing.T) {
181181
assert.Equal(t, "value1", myObj.Key1)
182182
}
183183

184+
func TestUnmarshalHugeNumber(t *testing.T) {
185+
186+
var h *JSONAny
187+
var myObj struct {
188+
Key1 interface{} `json:"key1"`
189+
}
190+
191+
h = JSONAnyPtr(`{"key1":123456789123456789123456789}`)
192+
err := h.Unmarshal(context.Background(), &myObj)
193+
assert.NoError(t, err)
194+
assert.Equal(t, json.Number("123456789123456789123456789"), myObj.Key1)
195+
}
196+
184197
func TestNilHash(t *testing.T) {
185198
assert.Nil(t, (*JSONAny)(nil).Hash())
186199
}

0 commit comments

Comments
 (0)