diff --git a/decode_test.go b/decode_test.go index 577d1d52..1d9f47c5 100644 --- a/decode_test.go +++ b/decode_test.go @@ -3918,3 +3918,16 @@ func TestIssue360(t *testing.T) { t.Errorf("unexpected result: %v", uints) } } + +func TestIssue359(t *testing.T) { + var a interface{} = 1 + var b interface{} = &a + var c interface{} = &b + v, err := json.Marshal(c) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if string(v) != "1" { + t.Errorf("unexpected result: %v", string(v)) + } +} diff --git a/internal/cmd/generator/vm.go.tmpl b/internal/cmd/generator/vm.go.tmpl index 91b11e1f..d4c31eb9 100644 --- a/internal/cmd/generator/vm.go.tmpl +++ b/internal/cmd/generator/vm.go.tmpl @@ -14,6 +14,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b recursiveLevel := 0 ptrOffset := uintptr(0) ctxptr := ctx.Ptr() + codeLength := uintptr(codeSet.CodeLength) var code *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { code = codeSet.EscapeKeyCode @@ -204,8 +205,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b return nil, err } - totalLength := uintptr(code.Length) + 3 - nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + totalLength := codeLength + 4 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 4 var c *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { @@ -219,6 +220,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ptrOffset += totalLength * uintptrSize oldBaseIndent := ctx.BaseIndent ctx.BaseIndent += code.Indent + oldCodeLength := codeLength + codeLength = uintptr(ifaceCodeSet.CodeLength) newLen := offsetNum + totalLength + nextTotalLength if curlen < newLen { @@ -231,6 +234,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + store(ctxptr, end.Offset, oldCodeLength) code = c recursiveLevel++ case encoder.OpInterfaceEnd: @@ -239,6 +243,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b // restore ctxptr offset := load(ctxptr, code.Idx) restoreIndent(ctx, code, ctxptr) + codeLength = load(ctxptr, code.Offset) ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] codePtr := load(ctxptr, code.ElemIdx) diff --git a/internal/encoder/opcode.go b/internal/encoder/opcode.go index b02ae351..d876e66a 100644 --- a/internal/encoder/opcode.go +++ b/internal/encoder/opcode.go @@ -385,6 +385,7 @@ func copyToInterfaceOpcode(code *Opcode) *Opcode { c.Idx += uintptrSize c.ElemIdx = c.Idx + uintptrSize c.Length = c.Idx + 2*uintptrSize + c.Offset = c.Idx + 3*uintptrSize c.Op = OpInterfaceEnd return copied } diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 91b11e1f..d4c31eb9 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -14,6 +14,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b recursiveLevel := 0 ptrOffset := uintptr(0) ctxptr := ctx.Ptr() + codeLength := uintptr(codeSet.CodeLength) var code *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { code = codeSet.EscapeKeyCode @@ -204,8 +205,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b return nil, err } - totalLength := uintptr(code.Length) + 3 - nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + totalLength := codeLength + 4 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 4 var c *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { @@ -219,6 +220,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ptrOffset += totalLength * uintptrSize oldBaseIndent := ctx.BaseIndent ctx.BaseIndent += code.Indent + oldCodeLength := codeLength + codeLength = uintptr(ifaceCodeSet.CodeLength) newLen := offsetNum + totalLength + nextTotalLength if curlen < newLen { @@ -231,6 +234,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + store(ctxptr, end.Offset, oldCodeLength) code = c recursiveLevel++ case encoder.OpInterfaceEnd: @@ -239,6 +243,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b // restore ctxptr offset := load(ctxptr, code.Idx) restoreIndent(ctx, code, ctxptr) + codeLength = load(ctxptr, code.Offset) ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] codePtr := load(ctxptr, code.ElemIdx) diff --git a/internal/encoder/vm_color/vm.go b/internal/encoder/vm_color/vm.go index 5c6c52c3..8790fac3 100644 --- a/internal/encoder/vm_color/vm.go +++ b/internal/encoder/vm_color/vm.go @@ -14,6 +14,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b recursiveLevel := 0 ptrOffset := uintptr(0) ctxptr := ctx.Ptr() + codeLength := uintptr(codeSet.CodeLength) var code *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { code = codeSet.EscapeKeyCode @@ -204,8 +205,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b return nil, err } - totalLength := uintptr(code.Length) + 3 - nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + totalLength := codeLength + 4 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 4 var c *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { @@ -219,6 +220,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ptrOffset += totalLength * uintptrSize oldBaseIndent := ctx.BaseIndent ctx.BaseIndent += code.Indent + oldCodeLength := codeLength + codeLength = uintptr(ifaceCodeSet.CodeLength) newLen := offsetNum + totalLength + nextTotalLength if curlen < newLen { @@ -231,6 +234,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + store(ctxptr, end.Offset, oldCodeLength) code = c recursiveLevel++ case encoder.OpInterfaceEnd: @@ -239,6 +243,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b // restore ctxptr offset := load(ctxptr, code.Idx) restoreIndent(ctx, code, ctxptr) + codeLength = load(ctxptr, code.Offset) ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] codePtr := load(ctxptr, code.ElemIdx) diff --git a/internal/encoder/vm_color_indent/vm.go b/internal/encoder/vm_color_indent/vm.go index 42dc11ca..30f4a437 100644 --- a/internal/encoder/vm_color_indent/vm.go +++ b/internal/encoder/vm_color_indent/vm.go @@ -14,6 +14,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b recursiveLevel := 0 ptrOffset := uintptr(0) ctxptr := ctx.Ptr() + codeLength := uintptr(codeSet.CodeLength) var code *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { code = codeSet.EscapeKeyCode @@ -204,8 +205,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b return nil, err } - totalLength := uintptr(code.Length) + 3 - nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + totalLength := codeLength + 4 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 4 var c *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { @@ -219,6 +220,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ptrOffset += totalLength * uintptrSize oldBaseIndent := ctx.BaseIndent ctx.BaseIndent += code.Indent + oldCodeLength := codeLength + codeLength = uintptr(ifaceCodeSet.CodeLength) newLen := offsetNum + totalLength + nextTotalLength if curlen < newLen { @@ -231,6 +234,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + store(ctxptr, end.Offset, oldCodeLength) code = c recursiveLevel++ case encoder.OpInterfaceEnd: @@ -239,6 +243,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b // restore ctxptr offset := load(ctxptr, code.Idx) restoreIndent(ctx, code, ctxptr) + codeLength = load(ctxptr, code.Offset) ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] codePtr := load(ctxptr, code.ElemIdx) diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index dfe0cc64..e2021e0c 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -14,6 +14,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b recursiveLevel := 0 ptrOffset := uintptr(0) ctxptr := ctx.Ptr() + codeLength := uintptr(codeSet.CodeLength) var code *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { code = codeSet.EscapeKeyCode @@ -204,8 +205,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b return nil, err } - totalLength := uintptr(code.Length) + 3 - nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + totalLength := codeLength + 4 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 4 var c *encoder.Opcode if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { @@ -219,6 +220,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b ptrOffset += totalLength * uintptrSize oldBaseIndent := ctx.BaseIndent ctx.BaseIndent += code.Indent + oldCodeLength := codeLength + codeLength = uintptr(ifaceCodeSet.CodeLength) newLen := offsetNum + totalLength + nextTotalLength if curlen < newLen { @@ -231,6 +234,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b store(ctxptr, end.Idx, oldOffset) store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + store(ctxptr, end.Offset, oldCodeLength) code = c recursiveLevel++ case encoder.OpInterfaceEnd: @@ -239,6 +243,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b // restore ctxptr offset := load(ctxptr, code.Idx) restoreIndent(ctx, code, ctxptr) + codeLength = load(ctxptr, code.Offset) ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] codePtr := load(ctxptr, code.ElemIdx)