Skip to content

fatal error: concurrent map writes with RegisterFlagCompletionFunc #1320

@MichaelMure

Description

@MichaelMure

Cobra has a global map here to store completion function when those exists.

This global map is not protected in any way, which leads to fatal error: concurrent map writes when handling multiple root command concurrently. Yes, it's a little odd situation but it's a useful one to generate documentation/completion faster (ie, concurrently). Most of those documentation/completion generator will actually mutate things here and there in the commands, which makes them not thread-safe. Now, this global map for completion functions also make things no, thread-safe, even if you duplicated entirely your root command.

I see the following possible solutions:

  • move this completion function (no map anymore) directly into flag.Flag. No more global, no more indirection, but that's another package.
  • move the map into cobra.Command, to at least make be thread-safe when you have a copy of your Command
  • add a mutex or use sync.Map.

Example code to trigger the issue:

package main

import (
	"fmt"
	"sync"

	"github.com/spf13/cobra"
)

func main() {
	cmd := cobra.Command{}

	N := 2
	options := make([]string, N)

	var wg sync.WaitGroup
	for i := 0; i < N; i++ {
		flag := fmt.Sprintf("flag%d", i)
		cmd.Flags().StringVarP(&options[i], flag, "", "value", "usage")
		wg.Add(1)
		go func() {
			defer wg.Done()
			err := cmd.RegisterFlagCompletionFunc(flag, nil)
			if err != nil {
				panic(err)
			}
		}()
	}

	wg.Wait()

}

Originally posted by @krobelus in #1290 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions