goadesign / goa

🌟 Goa: Elevate Go API development! 🚀 Streamlined design, automatic code generation, and seamless HTTP/gRPC support. ✨
https://goa.design
MIT License
5.69k stars 560 forks source link

Recursive media type reference using media type identifier stuck in infinite loop #613

Closed illyabusigin closed 8 years ago

illyabusigin commented 8 years ago

When trying to recursively reference a media type using the media type identifier goagen gets stuck in an infinite loop.

  1. You can reproduce this issue with the following design:
package design

import (
    . "github.com/goadesign/goa/design"
    . "github.com/goadesign/goa/design/apidsl"
)

// This is the api definition used by goa to generate the api
var _ = API("core", func() {
    Scheme("https")
    Host("test.api")

    Title("Test API")
    Description("TBD")

    Host("test.api")
    Scheme("https")
    BasePath("/v1")

    ResponseTemplate(Created, func(pattern string) {
        Description("Resource created")
        Status(201)
        Headers(func() {
            Header("Location", String, "href to created resource", func() {
                Pattern(pattern)
            })
        })
    })
})

// Menu is a hierarchical construct within an application.
var Menu = MediaType("application/vnd.menu+json", func() {
    Attributes(func() {
        Attribute("name", String, "The name of an application")
        Attribute("children", CollectionOf("application/vnd.menu"))
    })

    View("default", func() {
        Attribute("name")
    })
})
  1. Run goagen:
goagen app -d path/to/design
  1. Observe infinite loop results.

I'll try and dig into this a bit more today and tomorrow to see if I can find the root cause.

illyabusigin commented 8 years ago

Attaching stack output, it looks like the issue is within finalizeExample:

exit status 2
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x5ae870, 0xe)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/panic.go:547 +0x90
runtime.newstack()
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/stack.go:940 +0xb11
runtime.morestack()
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/asm_amd64.s:359 +0x7f

goroutine 1 [stack growth]:
runtime.heapBitsSetType(0xc8217d46a0, 0x20, 0x20, 0x410e40)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/mbitmap.go:679 fp=0xc8402002f0 sp=0xc8402002e8
runtime.mallocgc(0x20, 0x410e40, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/malloc.go:682 +0x6c0 fp=0xc8402003c8 sp=0xc8402002f0
runtime.newarray(0x410e40, 0x2, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/malloc.go:798 +0xc9 fp=0xc840200408 sp=0xc8402003c8
runtime.makeslice(0x3fdf80, 0x0, 0x2, 0x0, 0x0, 0x0)
    /usr/local/Cellar/go/1.6.2/libexec/src/runtime/slice.go:32 +0x165 fp=0xc840200458 sp=0xc840200408
ingaged/vendor/github.com/goadesign/goa/design.(*AttributeDefinition).finalizeExample(0xc820084b40, 0xc82316a000, 0x6bca0, 0x71800, 0x0, 0x0, 0x0)
    /Users/illyabusigin/Documents/code/go/src/ingaged/vendor/github.com/goadesign/goa/design/definitions.go:1009 +0x69e fp=0xc8402006b8 sp=0xc840200458
ingaged/vendor/github.com/goadesign/goa/design.(*AttributeDefinition).finalizeExample(0xc820084900, 0xc82316a000, 0x6bc9f, 0x71800, 0x0, 0x0, 0x0)
    /Users/illyabusigin/Documents/code/go/src/ingaged/vendor/github.com/goadesign/goa/design/definitions.go:996 +0x10a fp=0xc840200918 sp=0xc8402006b8
ingaged/vendor/github.com/goadesign/goa/design.(*AttributeDefinition).finalizeExample(0xc820084b40, 0xc82316a000, 0x6bc9f, 0x71800, 0x0, 0x0, 0x0)
    /Users/illyabusigin/Documents/code/go/src/ingaged/vendor/github.com/goadesign/goa/design/definitions.go:1041 +0xaec fp=0xc840200b78 sp=0xc840200918
ingaged/vendor/github.com/goadesign/goa/design.(*AttributeDefinition).finalizeExample(0xc820084900, 0xc82316a000, 0x6bc9e, 0x71800, 0x0, 0x0, 0x0)
    /Users/illyabusigin/Documents/code/go/src/ingaged/vendor/github.com/goadesign/goa/design/definitions.go:996 +0x10a fp=0xc840200dd8 sp=0xc840200b78
illyabusigin commented 8 years ago

I found a workaround for this issue. If you use NoExample(), finalize example is never called. Example updated media type:

var Menu = MediaType("application/vnd.menu+json", func() {
    Attributes(func() {
        Attribute("name", String, "The name of an application")
        Attribute("children", CollectionOf("application/vnd.menu"), func() {
            NoExample()
        })
    })

    View("default", func() {
        Attribute("name")
        Attribute("children")
    })
})
raphael commented 8 years ago

Thank you for the detailed report! I'll take a look.

raphael commented 8 years ago

The PR above should fix it, can you confirm? Thanks!

illyabusigin commented 8 years ago

Confirmed, thank you!