cue icon indicating copy to clipboard operation
cue copied to clipboard

cue/load: load.Instances and resulting build.Instance are not safe for concurrent use

Open myitcv opened this issue 3 years ago • 11 comments

What version of CUE are you using (cue version)?

$ cue version
v0.4.3

Does this issue reproduce with the latest release?

Yes

What did you do?

go mod tidy
go run -race .
cmp stdout stdout.golden

-- go.mod --
module github.com/myitcv/playground

go 1.18

require cuelang.org/go v0.4.3

-- main.go --
package main

import (
	"fmt"
	"sync"

	"cuelang.org/go/cue/cuecontext"
	"cuelang.org/go/cue/load"
)

const goroutineCount = 5

func main() {
	Test1()
	Test2()
}

// Separate load.Instances call per goroutine
func Test1() {
	var wg sync.WaitGroup
	for i := 0; i < goroutineCount; i++ {
		wg.Add(1)
		go func() {
			bps := load.Instances([]string{"."}, nil)
			ctx := cuecontext.New()
			v := ctx.BuildInstance(bps[0])
			fmt.Printf("%v\n", v)
			wg.Done()
		}()
	}
	wg.Wait()
}

// Single load.Instances shared by multiple goroutines
func Test2() {
	var wg sync.WaitGroup
	bps := load.Instances([]string{"."}, nil)
	for i := 0; i < goroutineCount; i++ {
		wg.Add(1)
		go func() {
			ctx := cuecontext.New()
			v := ctx.BuildInstance(bps[0])
			fmt.Printf("%v\n", v)
			wg.Done()
		}()
	}
	wg.Wait()
}
-- main.cue --
package main

"hello world"
-- stdout.golden --
"hello world"
"hello world"
"hello world"
"hello world"
"hello world"
"hello world"
"hello world"
"hello world"
"hello world"
"hello world"

What did you expect to see?

A passing test.

What did you see instead?

Errors because of data races in both "tests":

WARNING: DATA RACE
Read at 0x00c000308cb0 by goroutine 13:
  cuelang.org/go/internal/core/adt.(*nodeContext).done()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1087 +0x50
  cuelang.org/go/internal/core/adt.(*nodeContext).expandOne()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1907 +0x80
  cuelang.org/go/internal/core/adt.(*OpContext).Unify()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:254 +0xa64
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:454 +0xdc
  cuelang.org/go/cue.(*Instance).Value()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/instance.go:212 +0x5c
  cuelang.org/go/internal/filetypes.parseType()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/filetypes/filetypes.go:286 +0x50
  cuelang.org/go/internal/filetypes.ParseFile()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/filetypes/filetypes.go:242 +0x4b4
  cuelang.org/go/cue/load.(*loader).importPkg()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/import.go:185 +0x1724
  cuelang.org/go/cue/load.(*loader).importPathsQuiet()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/search.go:373 +0x7fc
  cuelang.org/go/cue/load.(*loader).importPaths()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/search.go:328 +0x44
  cuelang.org/go/cue/load.Instances()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/loader.go:67 +0x250
  main.Test1.func1()
      $WORK/main.go:24 +0x58

Previous write at 0x00c000308cb0 by goroutine 12:
  cuelang.org/go/internal/core/adt.(*OpContext).newNodeContext()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:923 +0x44c
  cuelang.org/go/internal/core/adt.(*Vertex).getNodeContext()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:935 +0x6c
  cuelang.org/go/internal/core/adt.(*OpContext).Unify()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:180 +0xf4
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:454 +0xdc
  cuelang.org/go/cue.(*Instance).Value()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/instance.go:212 +0x5c
  cuelang.org/go/internal/filetypes.parseType()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/filetypes/filetypes.go:286 +0x50
  cuelang.org/go/internal/filetypes.ParseFile()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/filetypes/filetypes.go:242 +0x4b4
  cuelang.org/go/cue/load.(*loader).importPkg()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/import.go:185 +0x1724
  cuelang.org/go/cue/load.(*loader).importPathsQuiet()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/search.go:373 +0x7fc
  cuelang.org/go/cue/load.(*loader).importPaths()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/search.go:328 +0x44
  cuelang.org/go/cue/load.Instances()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/loader.go:67 +0x250
  main.Test1.func1()
      $WORK/main.go:24 +0x58
WARNING: DATA RACE
Read at 0x00c00061bc00 by goroutine 27:
  cuelang.org/go/internal/core/runtime.resolveFile()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/resolve.go:63 +0x8c
  cuelang.org/go/internal/core/runtime.(*Runtime).ResolveFiles()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/resolve.go:50 +0x36c
  cuelang.org/go/internal/core/runtime.(*Runtime).Build()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/build.go:66 +0x1a0
  cuelang.org/go/cue.(*Context).BuildInstance()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/context.go:122 +0x140
  main.Test2.func1()
      $WORK/main.go:42 +0x394

Previous write at 0x00c00061bc00 by goroutine 25:
  cuelang.org/go/internal/core/runtime.resolveFile()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/resolve.go:158 +0x11bc
  cuelang.org/go/internal/core/runtime.(*Runtime).ResolveFiles()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/resolve.go:50 +0x36c
  cuelang.org/go/internal/core/runtime.(*Runtime).Build()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/build.go:66 +0x1a0
  cuelang.org/go/cue.(*Context).BuildInstance()
      /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/context.go:122 +0x140
  main.Test2.func1()
      $WORK/main.go:42 +0x394

Including, on occasion, the following panic:

panic: runtime error: index out of range [0] with length 0

goroutine 38 [running]:
cuelang.org/go/internal/core/adt.(*nodeContext).insertConjuncts(0xc0000b8000)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:382 +0x2a0
cuelang.org/go/internal/core/adt.(*OpContext).Unify(0xc0004320d0, 0xc000247050, 0x5)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:191 +0x254
cuelang.org/go/internal/core/adt.(*Vertex).Finalize(...)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:454
cuelang.org/go/cue.(*Instance).Value(0xc0002ee460)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/instance.go:212 +0xe0
cuelang.org/go/internal/filetypes.parseType({0x0, 0x0}, 0x0)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/filetypes/filetypes.go:286 +0x54
cuelang.org/go/internal/filetypes.ParseFile({0xc00042a42c, 0x6}, 0x2b?)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/internal/filetypes/filetypes.go:242 +0x4b8
cuelang.org/go/cue/load.(*loader).importPkg(0xc00042c280, {0x0?, 0x7ab9d0?}, 0xc000430000)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/import.go:185 +0x1728
cuelang.org/go/cue/load.(*loader).importPathsQuiet(0xc00042c280, {0xc00041bfa0, 0x1, 0x1})
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/search.go:373 +0x800
cuelang.org/go/cue/load.(*loader).importPaths(0x7ab753?, {0xc00041bfa0, 0x1, 0x1})
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/search.go:328 +0x48
cuelang.org/go/cue/load.Instances({0xc000399fa0, 0x1, 0x1}, 0x0)
        /home/myitcv/gostuff/pkg/mod/cuelang.org/[email protected]/cue/load/loader.go:67 +0x254
main.Test1.func1()
        $WORK/main.go:24 +0x5c
created by main.Test1
        $WORK/main.go:23 +0x54
exit status 2

myitcv avatar Jun 02 '22 13:06 myitcv

Here's a simpler reproducer. There's a race inside load.Instances itself (there might be more at a later stage too).

go mod tidy
go run -race .
cmp stdout stdout.golden

-- go.mod --
module github.com/myitcv/playground

go 1.20

require cuelang.org/go v0.5.0

-- main.go --
package main

import (
	"sync"

	"cuelang.org/go/cue/load"
)

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 2; i++ {
		wg.Add(1)
		go func() {
			load.Instances([]string{"."}, nil)
			wg.Done()
		}()
	}
	wg.Wait()
}

-- main.cue --
"hello world"
-- stdout.golden --

rogpeppe avatar Jul 11 '23 10:07 rogpeppe

Roger's solved the race in Test1, which was also reported in https://github.com/cue-lang/cue/issues/460.

The race in Test2 is still present as of afe322d6497e6727c2bd6f5f423f966b30f03f8d; this is because Runtime.Build calls Runtime.ResolveFiles, which modifies the ast.File.Unresolved slice in-place.

I guess my question in terms of API design would be - why would any end user be trying to build/compile the same build.Instance multiple times concurrently? It seems to me like one may want to build multiple instances concurrently, but each only once, not multiple times. But I'm not sure there is a value in adding any sort of mutexes or atomics to protect against "double builds" of a single instance, because I'm not sure when that would ever be useful.

mvdan avatar May 14 '24 21:05 mvdan

With version 0.9.2, I've just observed a race detection when two Go tests were run in parallel, each performing load.Instances, then cuecontext.New().BuildInstance() (so like in Test1). Here's an extract from the logs:

==================
WARNING: DATA RACE
Write at 0x0000016402b0 by goroutine 25:
  cuelang.org/go/internal/pkg.(*Package).MustCompile()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:73 +0x33a
  cuelang.org/go/internal/pkg.Register.func1()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/register.go:28 +0xab
  cuelang.org/go/internal/core/runtime.(*Runtime).LoadImport()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/imports.go:145 +0x22f
  cuelang.org/go/internal/core/adt.(*ImportReference).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:846 +0xa6
  cuelang.org/go/internal/core/adt.(*OpContext).unifyNode()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:838 +0x3b5
  cuelang.org/go/internal/core/adt.(*OpContext).node()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:1061 +0x88
  cuelang.org/go/internal/core/adt.(*SelectorExpr).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1007 +0xbc
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:706 +0x3e5
  cuelang.org/go/internal/core/adt.(*OpContext).value()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:653 +0x44
  cuelang.org/go/internal/core/adt.(*CallExpr).evaluate()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1487 +0x89
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:702 +0xf48
  cuelang.org/go/internal/core/adt.(*OpContext).evaluateRec()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:635 +0x164
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1682 +0x23d
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1621 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).insertConjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:413 +0x326
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:247 +0x19fc
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:816 +0xa4
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1668 +0x9b6
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1621 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).insertConjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:413 +0x326
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:247 +0x19fc
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:816 +0xa4
  cuelang.org/go/cue.newVertexRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:602 +0x3e
  cuelang.org/go/cue.newValueRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:611 +0x77
  cuelang.org/go/cue.(*Context).make()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:257 +0xcc
  cuelang.org/go/cue.(*Context).BuildInstance()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:130 +0x224
  ...

Previous read at 0x0000016402b0 by goroutine 8:
  cuelang.org/go/internal/pkg.ToBuiltin()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:124 +0x63d
  cuelang.org/go/internal/pkg.(*Package).MustCompile()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:81 +0x4d9
  cuelang.org/go/internal/pkg.Register.func1()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/register.go:28 +0xab
  cuelang.org/go/internal/core/runtime.(*Runtime).LoadImport()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/imports.go:145 +0x22f
  cuelang.org/go/internal/core/adt.(*ImportReference).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:846 +0xa6
  cuelang.org/go/internal/core/adt.(*OpContext).unifyNode()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:838 +0x3b5
  cuelang.org/go/internal/core/adt.(*OpContext).node()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:1061 +0x88
  cuelang.org/go/internal/core/adt.(*SelectorExpr).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1007 +0xbc
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:706 +0x3e5
  cuelang.org/go/internal/core/adt.(*OpContext).value()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:653 +0x44
  cuelang.org/go/internal/core/adt.(*CallExpr).evaluate()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1487 +0x89
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:702 +0xf48
  cuelang.org/go/internal/core/adt.(*OpContext).evaluateRec()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:635 +0x164
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1682 +0x23d
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1621 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).insertConjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:413 +0x326
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:247 +0x19fc
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:816 +0xa4
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1668 +0x9b6
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1621 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).insertConjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:413 +0x326
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:247 +0x19fc
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:816 +0xa4
  cuelang.org/go/cue.newVertexRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:602 +0x3e
  cuelang.org/go/cue.newValueRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:611 +0x77
  cuelang.org/go/cue.(*Context).make()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:257 +0xcc
  cuelang.org/go/cue.(*Context).BuildInstance()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:130 +0x224
  ...
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1689 +0x21e
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1742 +0x44
Goroutine 25 (running) created at:
  some/package.TestNewResolver.func1()
      /some/file_test.go:50 +0x57
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1689 +0x21e
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1742 +0x44
Goroutine 8 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1742 +0x825
  testing.runTests.func1()
      /usr/local/go/src/testing/testing.go:2161 +0x85
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1689 +0x21e
  testing.runTests()
      /usr/local/go/src/testing/testing.go:2159 +0x8be
  testing.(*M).Run()
      /usr/local/go/src/testing/testing.go:2027 +0xf17
  main.main()
      _testmain.go:83 +0x2e4
==================
==================
WARNING: DATA RACE
Write at 0x00000163f110 by goroutine 8:
  cuelang.org/go/internal/pkg.(*Package).MustCompile()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:73 +0x33a
  cuelang.org/go/internal/pkg.Register.func1()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/register.go:28 +0xab
  cuelang.org/go/internal/core/runtime.(*Runtime).LoadImport()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/imports.go:145 +0x22f
  cuelang.org/go/internal/core/adt.(*ImportReference).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:846 +0xa6
  cuelang.org/go/internal/core/adt.(*OpContext).unifyNode()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:838 +0x3b5
  cuelang.org/go/internal/core/adt.(*OpContext).node()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:1061 +0x88
  cuelang.org/go/internal/core/adt.(*SelectorExpr).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1007 +0xbc
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:706 +0x3e5
  cuelang.org/go/internal/core/adt.(*OpContext).value()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:653 +0x44
  cuelang.org/go/internal/core/adt.(*CallExpr).evaluate()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1487 +0x89
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:702 +0xf48
  cuelang.org/go/internal/core/adt.(*OpContext).evaluateRec()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:635 +0x164
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1682 +0x23d
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1621 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).insertConjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:413 +0x326
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:247 +0x19fc
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:816 +0xa4
  cuelang.org/go/cue.newVertexRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:602 +0x3e
  cuelang.org/go/cue.newValueRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:611 +0x77
  cuelang.org/go/cue.(*Context).make()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:257 +0xcc
  cuelang.org/go/cue.(*Context).BuildInstance()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:130 +0x224
  ...
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1689 +0x21e
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1742 +0x44
Previous read at 0x00000163f110 by goroutine 25:
  cuelang.org/go/internal/pkg.ToBuiltin()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:124 +0x63d
  cuelang.org/go/internal/pkg.(*Package).MustCompile()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:81 +0x4d9
  cuelang.org/go/internal/pkg.Register.func1()
      /go/pkg/mod/cuelang.org/[email protected]/internal/pkg/register.go:28 +0xab
  cuelang.org/go/internal/core/runtime.(*Runtime).LoadImport()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/imports.go:145 +0x22f
  cuelang.org/go/internal/core/adt.(*ImportReference).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:846 +0xa6
  cuelang.org/go/internal/core/adt.(*OpContext).unifyNode()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:838 +0x3b5
  cuelang.org/go/internal/core/adt.(*OpContext).node()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:1061 +0x88
  cuelang.org/go/internal/core/adt.(*SelectorExpr).resolve()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1007 +0xbc
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:706 +0x3e5
  cuelang.org/go/internal/core/adt.(*OpContext).value()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:653 +0x44
  cuelang.org/go/internal/core/adt.(*CallExpr).evaluate()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1487 +0x89
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:702 +0xf48
  cuelang.org/go/internal/core/adt.(*OpContext).evaluateRec()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:635 +0x164
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1682 +0x23d
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1621 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).insertConjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:413 +0x326
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:247 +0x19fc
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:176 +0x70a
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:816 +0xa4
  cuelang.org/go/cue.newVertexRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:602 +0x3e
  cuelang.org/go/cue.newValueRoot()
      /go/pkg/mod/cuelang.org/[email protected]/cue/types.go:611 +0x77
  cuelang.org/go/cue.(*Context).make()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:257 +0xcc
  cuelang.org/go/cue.(*Context).BuildInstance()
      /go/pkg/mod/cuelang.org/[email protected]/cue/context.go:130 +0x224
  ...
Goroutine 8 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1742 +0x825
  testing.runTests.func1()
      /usr/local/go/src/testing/testing.go:2161 +0x85
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1689 +0x21e
  testing.runTests()
      /usr/local/go/src/testing/testing.go:2159 +0x8be
  testing.(*M).Run()
      /usr/local/go/src/testing/testing.go:2027 +0xf17
  main.main()
      _testmain.go:83 +0x2e4
Goroutine 25 (running) created at:
  some/package.TestNewResolver.func1()
      /some/file_test.go:50 +0x57
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1689 +0x21e
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1742 +0x44
==================

roman-mazur avatar Jul 20 '24 21:07 roman-mazur

With version 0.9.2, I've just observed a race detection when two Go tests were run in parallel, each performing load.Instances, then cuecontext.New().BuildInstance() (so like in Test1). Here's an extract from the logs:

Would you be able to share some code to reproduce this race, by any chance?

rogpeppe avatar Aug 01 '24 17:08 rogpeppe

It will be difficult. Are you interested more in the CUE or Go part?

roman-mazur avatar Aug 06 '24 11:08 roman-mazur

@roman-mazur more the Go part. I assume you have concurrent Go tests which compile/load CUE code, and this CUE code imports CUE standard library packages?

mvdan avatar Aug 06 '24 11:08 mvdan

The function that uses the load package looks the following way:

func load(someCueString1, someCueString1 string) cue.Value {
	cfg := &load.Config{
		Package: "config",
		Dir:     tmpDir,
		Overlay: make(map[string]load.Source),
	}
	cfg.Overlay[filepath.Join(tmpDir, "file1.cue")] = load.FromString(someCueString1)
	cfg.Overlay[filepath.Join(tmpDir, "file2.cue")] = load.FromString(someCueString2)

	instances := load.Instances([]string{"file1.cue", "file2.cue"}, cfg)
	return cuecontext.New().BuildInstance(instances[0])
}

roman-mazur avatar Aug 06 '24 12:08 roman-mazur

I'm also experiencing this issue with tests and was able to reproduce it for tests but not with go run. Here’s a minimal example:

// main.go
package main

import (
	"cuelang.org/go/cue"
	"cuelang.org/go/cue/cuecontext"
	"cuelang.org/go/cue/load"
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			val, err := GetCueVal()
			if err != nil {
				panic(err)
			}
			fmt.Println(val)
		}()
		wg.Wait()
	}
}

func GetCueVal() (cue.Value, error) {
	ctx := cuecontext.New()
	insts := load.Instances([]string{"."}, nil)
	val := ctx.BuildInstance(insts[0])
	if val.Err() != nil {
		return cue.Value{}, val.Err()
	}
	return val, nil
}
// main_test.go
package main

import (
	"cuelang.org/go/cue/cuecontext"
	"cuelang.org/go/cue/load"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestCueLoad(t *testing.T) {
	t.Parallel()

	for i := 0; i < 10; i++ {
		t.Run("test number "+string(rune(i)), func(t *testing.T) {
			t.Parallel()
			ctx := cuecontext.New()
			insts := load.Instances([]string{"."}, nil)
			v := ctx.BuildInstance(insts[0])
			assert.NotEmpty(t, v)
		})
	}
}
// file.cue
package example

import "list"

l: [1, 2, 3]

#b: [1,2,3]

for num in l {
	#b: list.Contains(num)
}

Running go run -race . works fine, but running go test -race . outputs:

==================
WARNING: DATA RACE
Write at 0x000001699b50 by goroutine 9:
  cuelang.org/go/internal/pkg.(*Package).MustCompile()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:73 +0x33a
  cuelang.org/go/internal/pkg.Register.func1()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/pkg/register.go:28 +0xab
  cuelang.org/go/internal/core/runtime.(*Runtime).LoadImport()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/imports.go:145 +0x22f
  cuelang.org/go/internal/core/adt.(*ImportReference).resolve()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:846 +0xa6
  cuelang.org/go/internal/core/adt.(*OpContext).unifyNode()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:838 +0x3b5
  cuelang.org/go/internal/core/adt.(*OpContext).node()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:1061 +0x88
  cuelang.org/go/internal/core/adt.(*SelectorExpr).resolve()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1007 +0xbc
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:706 +0x3e5
  cuelang.org/go/internal/core/adt.(*OpContext).value()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:653 +0x44
  cuelang.org/go/internal/core/adt.(*CallExpr).evaluate()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1487 +0x89
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:702 +0xf48
  cuelang.org/go/internal/core/adt.(*OpContext).evaluateRec()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:635 +0x164
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1684 +0x23d
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1623 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).processComprehensionInner()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/comprehension.go:517 +0xcf0
  cuelang.org/go/internal/core/adt.(*nodeContext).processComprehension()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/comprehension.go:407 +0x39
  cuelang.org/go/internal/core/adt.(*nodeContext).injectComprehensions()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/comprehension.go:352 +0x1bc
  cuelang.org/go/internal/core/adt.(*nodeContext).expandOne()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:2204 +0x17c
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:275 +0xbeb
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:178 +0x6ea
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:822 +0xa4
  cuelang.org/go/cue.newVertexRoot()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/types.go:602 +0x3e
  cuelang.org/go/cue.newValueRoot()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/types.go:611 +0x77
  cuelang.org/go/cue.(*Context).make()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/context.go:252 +0xcc
  cuelang.org/go/cue.(*Context).BuildInstance()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/context.go:128 +0x224
  cue_test_race.TestCueLoad.func1()
      /home/userName/repos/testings/cue_test_race/main_test.go:18 +0xa7
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1690 +0x226
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1743 +0x44

Previous write at 0x000001699b50 by goroutine 18:
  cuelang.org/go/internal/pkg.(*Package).MustCompile()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/pkg/builtin.go:73 +0x33a
  cuelang.org/go/internal/pkg.Register.func1()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/pkg/register.go:28 +0xab
  cuelang.org/go/internal/core/runtime.(*Runtime).LoadImport()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/runtime/imports.go:145 +0x22f
  cuelang.org/go/internal/core/adt.(*ImportReference).resolve()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:846 +0xa6
  cuelang.org/go/internal/core/adt.(*OpContext).unifyNode()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:838 +0x3b5
  cuelang.org/go/internal/core/adt.(*OpContext).node()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:1061 +0x88
  cuelang.org/go/internal/core/adt.(*SelectorExpr).resolve()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1007 +0xbc
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:706 +0x3e5
  cuelang.org/go/internal/core/adt.(*OpContext).value()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:653 +0x44
  cuelang.org/go/internal/core/adt.(*CallExpr).evaluate()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/expr.go:1487 +0x89
  cuelang.org/go/internal/core/adt.(*OpContext).evalState()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:702 +0xf48
  cuelang.org/go/internal/core/adt.(*OpContext).evaluateRec()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/context.go:635 +0x164
  cuelang.org/go/internal/core/adt.(*nodeContext).evalExpr()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1684 +0x23d
  cuelang.org/go/internal/core/adt.(*nodeContext).addExprConjunct()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:1623 +0x74e
  cuelang.org/go/internal/core/adt.(*nodeContext).processComprehensionInner()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/comprehension.go:517 +0xcf0
  cuelang.org/go/internal/core/adt.(*nodeContext).processComprehension()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/comprehension.go:407 +0x39
  cuelang.org/go/internal/core/adt.(*nodeContext).injectComprehensions()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/comprehension.go:352 +0x1bc
  cuelang.org/go/internal/core/adt.(*nodeContext).expandOne()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:2204 +0x17c
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:275 +0xbeb
  cuelang.org/go/internal/core/adt.(*nodeContext).completeArcs()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:811 +0x446
  cuelang.org/go/internal/core/adt.(*nodeContext).postDisjunct()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:595 +0x486
  cuelang.org/go/internal/core/adt.(*nodeContext).expandDisjuncts()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/disjunct.go:178 +0x6ea
  cuelang.org/go/internal/core/adt.(*OpContext).unify()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/eval.go:302 +0xcea
  cuelang.org/go/internal/core/adt.(*Vertex).Finalize()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/internal/core/adt/composite.go:822 +0xa4
  cuelang.org/go/cue.newVertexRoot()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/types.go:602 +0x3e
  cuelang.org/go/cue.newValueRoot()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/types.go:611 +0x77
  cuelang.org/go/cue.(*Context).make()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/context.go:252 +0xcc
  cuelang.org/go/cue.(*Context).BuildInstance()
      /home/userName/go/pkg/mod/cuelang.org/[email protected]/cue/context.go:128 +0x224
  cue_test_race.TestCueLoad.func1()
      /home/userName/repos/testings/cue_test_race/main_test.go:18 +0xa7
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1690 +0x226
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1743 +0x44

Goroutine 9 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1743 +0x825
  cue_test_race.TestCueLoad()
      /home/userName/repos/testings/cue_test_race/main_test.go:14 +0x74
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1690 +0x226
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1743 +0x44

Goroutine 18 (running) created at:
  testing.(*T).Run()
      /usr/local/go/src/testing/testing.go:1743 +0x825
  cue_test_race.TestCueLoad()
      /home/userName/repos/testings/cue_test_race/main_test.go:14 +0x74
  testing.tRunner()
      /usr/local/go/src/testing/testing.go:1690 +0x226
  testing.(*T).Run.gowrap1()
      /usr/local/go/src/testing/testing.go:1743 +0x44
==================

==================
--- FAIL: TestCueLoad (0.00s)
    --- FAIL: TestCueLoad/test_number_\x01 (0.05s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number__ (0.07s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\x04 (0.08s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\x06 (0.08s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\b (0.08s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\x00 (0.08s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\a (0.08s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\x03 (0.08s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\x05 (0.08s)
        testing.go:1399: race detected during execution of test
    --- FAIL: TestCueLoad/test_number_\x02 (0.08s)
        testing.go:1399: race detected during execution of test
FAIL
FAIL    cue_test_race   0.102s
FAIL
...

ilayalog avatar Sep 03 '24 21:09 ilayalog

~Haven't been able to reproduce it with 0.10.0 so far.~

UPD: never mind, reproduced with 0.10.0, same as reported in https://github.com/cue-lang/cue/issues/1746#issuecomment-2327483444

roman-mazur avatar Sep 28 '24 21:09 roman-mazur

@mvdan

I guess my question in terms of API design would be - why would any end user be trying to build/compile the same build.Instance multiple times concurrently? It seems to me like one may want to build multiple instances concurrently, but each only once, not multiple times. But I'm not sure there is a value in adding any sort of mutexes or atomics to protect against "double builds" of a single instance, because I'm not sure when that would ever be useful.

Having just run across this once more, here's one answer: given that cue.Context is not safe for concurrent use, if one does wish to run CUE evaluations concurrently on a package, it makes sense to load the instance for that package once, then use that instance multiple times as an argument to cue.Context.BuildInstance, once for each concurrent Context.

In terms of API, it would be good if whatever future API was used would return something "resolved enough" from the loader API such that the future equivalent of cue.Context.BuildInstance would not need to mutate the underlying instance. That would probably involve a little extra work to look up symbols when creating the cue.Value from the *ast.File but that probably wouldn't have significant impact on overall runtime.

rogpeppe avatar Mar 13 '25 12:03 rogpeppe