From c8d6da88dd5e417e57d7125bb805874f78496fcd Mon Sep 17 00:00:00 2001 From: Nao Yonashiro Date: Sun, 3 Jul 2022 06:05:26 +0900 Subject: [PATCH 1/2] fix: confusing nil in direct interface with typed nil fix #376 --- encode_test.go | 18 ++++++++++++++++++ internal/cmd/generator/vm.go.tmpl | 4 +++- internal/encoder/vm/vm.go | 4 +++- internal/encoder/vm_color/vm.go | 4 +++- internal/encoder/vm_color_indent/vm.go | 4 +++- internal/encoder/vm_indent/vm.go | 4 +++- 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/encode_test.go b/encode_test.go index 59bb08ff..1c0de3cc 100644 --- a/encode_test.go +++ b/encode_test.go @@ -2406,3 +2406,21 @@ func TestIssue339(t *testing.T) { t.Errorf("unexpected result: %v != %v", got, expected) } } + +func TestIssue376(t *testing.T) { + type Container struct { + V interface{} `json:"value"` + } + type MapOnly struct { + Map map[string]int64 `json:"map"` + } + b, err := json.Marshal(Container{MapOnly{}}) + if err != nil { + t.Fatal(err) + } + got := string(b) + expected := `{"value":{"map":null}}` + if got != expected { + t.Errorf("unexpected result: %v != %v", got, expected) + } +} diff --git a/internal/cmd/generator/vm.go.tmpl b/internal/cmd/generator/vm.go.tmpl index 91b11e1f..cb4db570 100644 --- a/internal/cmd/generator/vm.go.tmpl +++ b/internal/cmd/generator/vm.go.tmpl @@ -3,6 +3,7 @@ package vm import ( "math" + "reflect" "sort" "unsafe" @@ -193,7 +194,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if ifacePtr == nil && !isDirectedNil { b = appendNullComma(ctx, b) code = code.Next break diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 91b11e1f..cb4db570 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -3,6 +3,7 @@ package vm import ( "math" + "reflect" "sort" "unsafe" @@ -193,7 +194,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if ifacePtr == nil && !isDirectedNil { b = appendNullComma(ctx, b) code = code.Next break diff --git a/internal/encoder/vm_color/vm.go b/internal/encoder/vm_color/vm.go index 5c6c52c3..e8a55974 100644 --- a/internal/encoder/vm_color/vm.go +++ b/internal/encoder/vm_color/vm.go @@ -3,6 +3,7 @@ package vm_color import ( "math" + "reflect" "sort" "unsafe" @@ -193,7 +194,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if ifacePtr == nil && !isDirectedNil { b = appendNullComma(ctx, b) code = code.Next break diff --git a/internal/encoder/vm_color_indent/vm.go b/internal/encoder/vm_color_indent/vm.go index 42dc11ca..79cfdd8d 100644 --- a/internal/encoder/vm_color_indent/vm.go +++ b/internal/encoder/vm_color_indent/vm.go @@ -3,6 +3,7 @@ package vm_color_indent import ( "math" + "reflect" "sort" "unsafe" @@ -193,7 +194,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if ifacePtr == nil && !isDirectedNil { b = appendNullComma(ctx, b) code = code.Next break diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index dfe0cc64..54514846 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -3,6 +3,7 @@ package vm_indent import ( "math" + "reflect" "sort" "unsafe" @@ -193,7 +194,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if ifacePtr == nil && !isDirectedNil { b = appendNullComma(ctx, b) code = code.Next break From 884b8dbf9ac90370b4df41d1b3cba565dc602078 Mon Sep 17 00:00:00 2001 From: Nao Yonashiro Date: Sun, 3 Jul 2022 22:39:31 +0900 Subject: [PATCH 2/2] refactor: to check for IsDirectedNil only if ifacePtr == nil --- internal/cmd/generator/vm.go.tmpl | 12 +++++++----- internal/encoder/vm/vm.go | 12 +++++++----- internal/encoder/vm_color/vm.go | 12 +++++++----- internal/encoder/vm_color_indent/vm.go | 12 +++++++----- internal/encoder/vm_indent/vm.go | 12 +++++++----- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/internal/cmd/generator/vm.go.tmpl b/internal/cmd/generator/vm.go.tmpl index cb4db570..645d20f9 100644 --- a/internal/cmd/generator/vm.go.tmpl +++ b/internal/cmd/generator/vm.go.tmpl @@ -194,11 +194,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) - if ifacePtr == nil && !isDirectedNil { - b = appendNullComma(ctx, b) - code = code.Next - break + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } } ctx.KeepRefs = append(ctx.KeepRefs, up) ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ))) diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index cb4db570..645d20f9 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -194,11 +194,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) - if ifacePtr == nil && !isDirectedNil { - b = appendNullComma(ctx, b) - code = code.Next - break + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } } ctx.KeepRefs = append(ctx.KeepRefs, up) ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ))) diff --git a/internal/encoder/vm_color/vm.go b/internal/encoder/vm_color/vm.go index e8a55974..a63e83e5 100644 --- a/internal/encoder/vm_color/vm.go +++ b/internal/encoder/vm_color/vm.go @@ -194,11 +194,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) - if ifacePtr == nil && !isDirectedNil { - b = appendNullComma(ctx, b) - code = code.Next - break + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } } ctx.KeepRefs = append(ctx.KeepRefs, up) ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ))) diff --git a/internal/encoder/vm_color_indent/vm.go b/internal/encoder/vm_color_indent/vm.go index 79cfdd8d..3b4e22e5 100644 --- a/internal/encoder/vm_color_indent/vm.go +++ b/internal/encoder/vm_color_indent/vm.go @@ -194,11 +194,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) - if ifacePtr == nil && !isDirectedNil { - b = appendNullComma(ctx, b) - code = code.Next - break + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } } ctx.KeepRefs = append(ctx.KeepRefs, up) ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ))) diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index 54514846..836c5c8a 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -194,11 +194,13 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ifacePtr = iface.ptr typ = iface.typ } - isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) - if ifacePtr == nil && !isDirectedNil { - b = appendNullComma(ctx, b) - code = code.Next - break + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } } ctx.KeepRefs = append(ctx.KeepRefs, up) ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))