Search code examples
gostack-overflow

Appending a ChildNode using Goldmark In golang is causing a stack over flow


I've been playing around with Goldmark in Go, I'm new to go so I'm not sure if i'm doing this correctly. I've been reading the documentation but, I feel a little confused as to why this is happening.

I've parsed a markdown file and used the ast.Walk to walk the ast.

My goal is to inject a sub list under a list item.

ast.Walk(doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
    if entering {
        if n.Kind() == ast.KindListItem {
            subList := ast.NewList(0)
            subListItem := ast.NewListItem(0)
            subList.AppendChild(subList, subListItem)

            leaf := ast.NewString([]byte("Hello"))
            subListItem.AppendChild(subListItem, leaf)
            n.AppendChild(n, subList)
        }
    }

    return ast.WalkContinue, nil
})

However when ever I run this I get

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc04f9803c8 stack=[0xc04f980000, 0xc06f980000]
fatal error: stack overflow

I think this is being caused by adding a new node and visiting that node on the next iteration. However I'm not fully sure how to skip over the new node.


Solution

  • You are correct that the stack overflow error is caused by the visiting of the new nodes.

    To address the issue, you can record the added nodes and skip them in the walk func.

    // for recording the added nodes
    added := make(map[*ast.List]bool)
    
    ast.Walk(doc, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
        if entering {
            if n.Kind() == ast.KindList {
                if _, ok := added[n.(*ast.List)]; ok {
                    // skip the added node
                    return ast.WalkSkipChildren, nil
                }
            }
            if n.Kind() == ast.KindListItem {
                subList := ast.NewList(0)
                subListItem := ast.NewListItem(0)
                subList.AppendChild(subList, subListItem)
    
                leaf := ast.NewString([]byte("Hello"))
                subListItem.AppendChild(subListItem, leaf)
                n.AppendChild(n, subList)
    
                // record the added node
                added[subList] = true
            }
        }
    
        return ast.WalkContinue, nil
    })