Skip to content

vector: rade condition when rendering vectors on sub-images #3333

@hajimehoshi

Description

@hajimehoshi

Ebitengine Version

v2.9.2

Operating System

  • Windows
  • macOS
  • Linux
  • FreeBSD
  • OpenBSD
  • Android
  • iOS
  • Nintendo Switch
  • PlayStation 5
  • Xbox
  • Web Browsers

Go Version (go version)

go version go1.25.1 darwin/arm64

What steps will reproduce the problem?

Run this test:

func TestRaceConditionWithSubImage(t *testing.T) {
	const w, h = 16, 16
	src := ebiten.NewImage(w, h)

	var wg sync.WaitGroup
	for i := range h {
		for j := range w {
			wg.Add(1)
			go func() {
				subImg := src.SubImage(image.Rect(i, j, i+1, j+1)).(*ebiten.Image)
				var p vector.Path
				p.MoveTo(0, 0)
				p.LineTo(w, 0)
				p.LineTo(w, h)
				p.LineTo(0, h)
				p.Close()
				op := &vector.DrawPathOptions{}
				op.ColorScale.ScaleWithColor(color.White)
				op.AntiAlias = true
				vector.FillPath(subImg, &p, nil, op)
				dst := ebiten.NewImage(w, h)
				dst.DrawImage(subImg, nil)
				wg.Done()
			}()
		}
	}
	wg.Wait()
}

What is the expected result?

The test passes

What happens instead?

The test crashes:

=== RUN   TestRaceConditionWithSubImage
fatal error: concurrent map writes

goroutine 13 [running]:
internal/runtime/maps.fatal({0x104ceeffc?, 0x104dd16a0?})
        /usr/local/go/src/runtime/panic.go:1046 +0x20
internal/runtime/maps.(*Map).Delete(0x1400023e1b0, 0x104dd16a0, 0x140003298c8)
        /usr/local/go/src/internal/runtime/maps/map.go:678 +0x11c
github.com/hajimehoshi/ebiten/v2/vector.FillPath.func1()
        /Users/hajimehoshi/ebiten/vector/util.go:379 +0x6c
github.com/hajimehoshi/ebiten/v2.(*Image).invokeUsageCallbacks(0x14000645b38?)
        /Users/hajimehoshi/ebiten/image.go:1645 +0xb8
github.com/hajimehoshi/ebiten/v2.(*Image).invokeUsageCallbacks(0x140004d8008?)
        /Users/hajimehoshi/ebiten/image.go:1631 +0x9c
github.com/hajimehoshi/ebiten/v2.(*Image).DrawImage(0x14000161340, 0x1400045abb0, 0x0)
        /Users/hajimehoshi/ebiten/image.go:273 +0x58
github.com/hajimehoshi/ebiten/v2/vector_test.TestRaceConditionWithSubImage.func1()
        /Users/hajimehoshi/ebiten/vector/util_test.go:166 +0x118
created by github.com/hajimehoshi/ebiten/v2/vector_test.TestRaceConditionWithSubImage in goroutine 9
        /Users/hajimehoshi/ebiten/vector/util_test.go:153 +0x94
...

Anything else you feel useful to add?

There seems another crash:

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

goroutine 26 [running]:
github.com/hajimehoshi/ebiten/v2/vector.(*atlas).pathRenderingPositionAt(...)
        /Users/hajimehoshi/ebiten/vector/atlas.go:195
github.com/hajimehoshi/ebiten/v2/vector.(*fillPathsState).fillPaths(0x140001e4c40, 0x14000157340)
        /Users/hajimehoshi/ebiten/vector/fill.go:250 +0x16d8
github.com/hajimehoshi/ebiten/v2/vector.FillPath.func1()
        /Users/hajimehoshi/ebiten/vector/util.go:382 +0x9c
github.com/hajimehoshi/ebiten/v2.(*Image).invokeUsageCallbacks(0x140004efb38?)
        /Users/hajimehoshi/ebiten/image.go:1645 +0xb8
github.com/hajimehoshi/ebiten/v2.(*Image).invokeUsageCallbacks(0x14000185808?)
        /Users/hajimehoshi/ebiten/image.go:1631 +0x9c
github.com/hajimehoshi/ebiten/v2.(*Image).DrawImage(0x1400059bb80, 0x14000157340, 0x0)
        /Users/hajimehoshi/ebiten/image.go:273 +0x58
github.com/hajimehoshi/ebiten/v2/vector_test.TestRaceConditionWithSubImage.func1()
        /Users/hajimehoshi/ebiten/vector/util_test.go:166 +0x118
created by github.com/hajimehoshi/ebiten/v2/vector_test.TestRaceConditionWithSubImage in goroutine 24
        /Users/hajimehoshi/ebiten/vector/util_test.go:153 +0x94
FAIL    github.com/hajimehoshi/ebiten/v2/vector 0.407s
FAIL

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions