Repository: goccy/go-json (go)

Issue:
Marshal panic
Hi, every one!
   The go-json is a great project but just unstable and painc in some cases.

This problem can be reproduced with the following code:

```go
package main

import (
    "fmt"

    "github.com/goccy/go-json"
)

type UserTypeReq struct {
    UserType string `json:"user_type,omitempty"`
}

type Path struct {
    OrgID       *int `json:"org_id,omitempty"`  //
    UserTypeReq                                 // HERE IF CHAGE FIELD POSITION, MARSHAL IS WORKING OK.
    UserID      int  `json:"user_id,omitempty"` //
}

func main() {
    var route = Path{}

    var bytesJson, err = json.Marshal(route)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(bytesJson))
}
```

Panic information:
```text
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0xc0e19c]

goroutine 1 [running]:
github.com/goccy/go-json/internal/encoder/vm.Run(0xc000094340, {0xc0000f6000?, 0x0?, 0x0?}, 0x0?)
        D:/Work/GOPATH/pkg/mod/github.com/goccy/go-json@v0.10.1/internal/encoder/vm/vm.go:26 +0x7c
github.com/goccy/go-json.encodeRunCode(0xc0000c9e38?, {0xc0000f6000?, 0xdc2160?, 0xc0000f8000?}, 0xc0000f6400?)
        D:/Work/GOPATH/pkg/mod/github.com/goccy/go-json@v0.10.1/encode.go:310 +0x68
github.com/goccy/go-json.encode(0xc000094340, {0xc51840, 0xc0000a03e0})
        D:/Work/GOPATH/pkg/mod/github.com/goccy/go-json@v0.10.1/encode.go:235 +0x21f
github.com/goccy/go-json.marshal({0xc51840, 0xc0000a03e0}, {0x0, 0x0, 0xc0000c9f50?})
        D:/Work/GOPATH/pkg/mod/github.com/goccy/go-json@v0.10.1/encode.go:150 +0xb9
github.com/goccy/go-json.MarshalWithOption(...)
        D:/Work/GOPATH/pkg/mod/github.com/goccy/go-json@v0.10.1/json.go:186     
github.com/goccy/go-json.Marshal({0xc51840?, 0xc0000a03e0?})
        D:/Work/GOPATH/pkg/mod/github.com/goccy/go-json@v0.10.1/json.go:171 +0x2a
main.main()
        D:/Temp/go-json-err/main.go:22 +0x45
```




Pull request:
fix: fixed a problem with NextField being wrong when combining structure embedding and omitempty
fix #441

before:
![before](https://user-images.githubusercontent.com/1029249/225595133-debd79e5-bee7-42bf-b995-83a8ef7f252c.png)

after:
![after](https://user-images.githubusercontent.com/1029249/225595154-2f5f6bbb-129d-4271-99cf-59e850c2f33c.png)



Patch:
diff --git a/internal/encoder/code.go b/internal/encoder/code.go
index 66425a8..5b08fae 100644
--- a/internal/encoder/code.go
+++ b/internal/encoder/code.go
@@ -397,7 +397,7 @@ func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *
 func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode {
 	// firstField is special StructHead operation for anonymous structure.
 	// So, StructHead's next operation is truly struct head operation.
-	for firstField.Op == OpStructHead {
+	for firstField.Op == OpStructHead || firstField.Op == OpStructField {
 		firstField = firstField.Next
 	}
 	lastField := firstField
diff --git a/internal/encoder/opcode.go b/internal/encoder/opcode.go
index 05fc3ce..df22f55 100644
--- a/internal/encoder/opcode.go
+++ b/internal/encoder/opcode.go
@@ -1,7 +1,9 @@
 package encoder
 
 import (
+	"bytes"
 	"fmt"
+	"sort"
 	"strings"
 	"unsafe"
 
@@ -555,6 +557,87 @@ func (c *Opcode) Dump() string {
 	return strings.Join(codes, "\n")
 }
 
+func (c *Opcode) DumpDOT() string {
+	type edge struct {
+		from, to *Opcode
+		label    string
+		weight   int
+	}
+	var edges []edge
+
+	b := &bytes.Buffer{}
+	fmt.Fprintf(b, "digraph \"%p\" {\n", c.Type)
+	fmt.Fprintln(b, "mclimit=1.5;\nrankdir=TD;\nordering=out;\nnode[shape=box];")
+	for code := c; !code.IsEnd(); {
+		label := code.Op.String()
+		fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, label)
+		if p := code.Next; p != nil {
+			edges = append(edges, edge{
+				from:   code,
+				to:     p,
+				label:  "Next",
+				weight: 10,
+			})
+		}
+		if p := code.NextField; p != nil {
+			edges = append(edges, edge{
+				from:   code,
+				to:     p,
+				label:  "NextField",
+				weight: 2,
+			})
+		}
+		if p := code.End; p != nil {
+			edges = append(edges, edge{
+				from:   code,
+				to:     p,
+				label:  "End",
+				weight: 1,
+			})
+		}
+		if p := code.Jmp; p != nil {
+			edges = append(edges, edge{
+				from:   code,
+				to:     p.Code,
+				label:  "Jmp",
+				weight: 1,
+			})
+		}
+
+		switch code.Op.CodeType() {
+		case CodeSliceHead:
+			code = code.Next
+		case CodeMapHead:
+			code = code.Next
+		case CodeArrayElem, CodeSliceElem:
+			code = code.End
+		case CodeMapKey:
+			code = code.End
+		case CodeMapValue:
+			code = code.Next
+		case CodeMapEnd:
+			code = code.Next
+		case CodeStructField:
+			code = code.Next
+		case CodeStructEnd:
+			code = code.Next
+		default:
+			code = code.Next
+		}
+		if code.IsEnd() {
+			fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, code.Op.String())
+		}
+	}
+	sort.Slice(edges, func(i, j int) bool {
+		return edges[i].to.DisplayIdx < edges[j].to.DisplayIdx
+	})
+	for _, e := range edges {
+		fmt.Fprintf(b, "\"%p\" -> \"%p\" [label=%q][weight=%d];\n", e.from, e.to, e.label, e.weight)
+	}
+	fmt.Fprint(b, "}")
+	return b.String()
+}
+
 func newSliceHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode {
 	idx := opcodeOffset(ctx.ptrIndex)
 	ctx.incPtrIndex()
diff --git a/internal/encoder/option.go b/internal/encoder/option.go
index 82d5ce3..12c58e4 100644
--- a/internal/encoder/option.go
+++ b/internal/encoder/option.go
@@ -23,6 +23,7 @@ type Option struct {
 	ColorScheme *ColorScheme
 	Context     context.Context
 	DebugOut    io.Writer
+	DebugDOTOut io.WriteCloser
 }
 
 type EncodeFormat struct {
diff --git a/internal/encoder/vm/debug_vm.go b/internal/encoder/vm/debug_vm.go
index fbbc0de..82b6dd4 100644
--- a/internal/encoder/vm/debug_vm.go
+++ b/internal/encoder/vm/debug_vm.go
@@ -2,6 +2,7 @@ package vm
 
 import (
 	"fmt"
+	"io"
 
 	"github.com/goccy/go-json/internal/encoder"
 )
@@ -14,6 +15,11 @@ func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet)
 		} else {
 			code = codeSet.NoescapeKeyCode
 		}
+		if wc := ctx.Option.DebugDOTOut; wc != nil {
+			_, _ = io.WriteString(wc, code.DumpDOT())
+			wc.Close()
+			ctx.Option.DebugDOTOut = nil
+		}
 
 		if err := recover(); err != nil {
 			w := ctx.Option.DebugOut
diff --git a/option.go b/option.go
index af400a4..378031a 100644
--- a/option.go
+++ b/option.go
@@ -48,6 +48,13 @@ func DebugWith(w io.Writer) EncodeOptionFunc {
 	}
 }
 
+// DebugDOT sets the destination to write opcodes graph.
+func DebugDOT(w io.WriteCloser) EncodeOptionFunc {
+	return func(opt *EncodeOption) {
+		opt.DebugDOTOut = w
+	}
+}
+
 // Colorize add an identifier for coloring to the string of the encoded result.
 func Colorize(scheme *ColorScheme) EncodeOptionFunc {
 	return func(opt *EncodeOption) {


Test patch:
diff --git a/encode_test.go b/encode_test.go
index d328c02..1165f6a 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -2694,3 +2694,19 @@ func TestIssue426(t *testing.T) {
 	b, _ := json.Marshal(s)
 	assertEq(t, "unexpected result", `{"I":null,"Val":"456"}`, string(b))
 }
+
+func TestIssue441(t *testing.T) {
+	type A struct {
+		Y string `json:"y,omitempty"`
+	}
+
+	type B struct {
+		X *int `json:"x,omitempty"`
+		A
+		Z int `json:"z,omitempty"`
+	}
+
+	b, err := json.Marshal(B{})
+	assertErr(t, err)
+	assertEq(t, "unexpected result", "{}", string(b))
+}