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 59bb08f..1c0de3c 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 91b11e1..cb4db57 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 91b11e1..cb4db57 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 5c6c52c..e8a5597 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 42dc11c..79cfdd8 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 dfe0cc6..5451484 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 cb4db57..645d20f 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 cb4db57..645d20f 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 e8a5597..a63e83e 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 79cfdd8..3b4e22e 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 5451484..836c5c8 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)))