Commit d340a89d authored by Russ Cox's avatar Russ Cox

encoding/json: roll back Unmarshal optimization + test

The second attempt at the Unmarshal optimization allowed
panics to get out of the json package. Add test for that bug
and remove the optimization.

Let's stop trying to optimize Unmarshal.

Fixes #4784.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7300108
parent da6207f7
......@@ -56,8 +56,7 @@ import (
// an UnmarshalTypeError describing the earliest such error.
//
func Unmarshal(data []byte, v interface{}) error {
// Quick check for well-formedness.
// Check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
var d decodeState
......@@ -66,23 +65,6 @@ func Unmarshal(data []byte, v interface{}) error {
return err
}
// skip heavy processing for primitive values
var first byte
var i int
for i, first = range data {
if first > ' ' || !isSpace(rune(first)) {
break
}
}
if first != '{' && first != '[' {
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return &InvalidUnmarshalError{reflect.TypeOf(v)}
}
d.literalStore(data[i:], rv.Elem(), false)
return d.savedError
}
d.init(data)
return d.unmarshal(v)
}
......
......@@ -11,6 +11,7 @@ import (
"reflect"
"strings"
"testing"
"time"
)
type T struct {
......@@ -1113,3 +1114,30 @@ func TestUnmarshalUnexported(t *testing.T) {
t.Errorf("got %q, want %q", out, want)
}
}
// Time3339 is a time.Time which encodes to and from JSON
// as an RFC 3339 time in UTC.
type Time3339 time.Time
func (t *Time3339) UnmarshalJSON(b []byte) error {
if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time")
}
tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1]))
if err != nil {
return err
}
*t = Time3339(tm)
return nil
}
func TestUnmarshalJSONLiteralError(t *testing.T) {
var t3 Time3339
err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3)
if err == nil {
t.Fatalf("expected error; got time %v", time.Time(t3))
}
if !strings.Contains(err.Error(), "range") {
t.Errorf("got err = %v; want out of range error", err)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment