fyne icon indicating copy to clipboard operation
fyne copied to clipboard

Binding Two Labels to One BoundString Creates a Race Condition

Open pbrown12303 opened this issue 1 year ago • 0 comments

Checklist

  • [X] I have searched the issue tracker for open issues that relate to the same problem, before opening a new one.
  • [X] This issue only relates to a single bug. I will open new issues for any other problems.

Describe the bug

Create a bound string. Create two labels with the same boundString binding. Set the value of the binding. One of the two labels will end up with the wrong text string

Running the tests with the -race flag shows the race conditions

If you insert a time.Sleep(100*time.Millisecond) call after the Set() call, the widgets end up with the correct value, but the race condition is still there.

How to reproduce

  1. Create a bound string: binding.NewString()
  2. Create two labels with the same bound string: widget.NewLabelWithData(boundString)
  3. Set the value of the bound string: boundString.Set(boundValue)
  4. Only one of the labels will have the boundValue as its text. The other will have the empty string.

Screenshots

Running tool: C:\Program Files\Go\bin\go.exe test -timeout 600s -run ^TestRaceCondition$ github.com/pbrown12303/fynebindingtest -race

=== RUN TestRaceCondition

WARNING: DATA RACE Write at 0x00c000096c70 by goroutine 9: fyne.io/fyne/v2/widget.(*Label).SetText() C:/GoWorkspace/src/github.com/fyne/widget/label.go:117 +0x84 fyne.io/fyne/v2/widget.(*Label).updateFromData() C:/GoWorkspace/src/github.com/fyne/widget/label.go:172 +0x7a fyne.io/fyne/v2/widget.(*Label).updateFromData-fm() :1 +0x47 fyne.io/fyne/v2/widget.(*basicBinder).Bind.func1() C:/GoWorkspace/src/github.com/fyne/widget/bind_helper.go:24 +0x68 fyne.io/fyne/v2/data/binding.(*listener).DataChanged() C:/GoWorkspace/src/github.com/fyne/data/binding/binding.go:56 +0x35 fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm() :1 +0x42 fyne.io/fyne/v2/data/binding.queueItem.func1.1() C:/GoWorkspace/src/github.com/fyne/data/binding/queue.go:19 +0x70

Previous read at 0x00c000096c70 by goroutine 7: github.com/pbrown12303/fynebindingtest.TestRaceCondition() c:/GoWorkspace/src/github.com/pbrown12303/fynebindingraceconditiontest/bindingracecondition_test.go:24 +0x144 testing.tRunner() C:/Program Files/Go/src/testing/testing.go:1595 +0x238 testing.(*T).Run.func1() C:/Program Files/Go/src/testing/testing.go:1648 +0x44

Goroutine 9 (running) created at: fyne.io/fyne/v2/data/binding.queueItem.func1() C:/GoWorkspace/src/github.com/fyne/data/binding/queue.go:17 +0x6a sync.(*Once).doSlow() C:/Program Files/Go/src/sync/once.go:74 +0xf0 sync.(*Once).Do() C:/Program Files/Go/src/sync/once.go:65 +0x44 fyne.io/fyne/v2/data/binding.queueItem() C:/GoWorkspace/src/github.com/fyne/data/binding/queue.go:15 +0x2f fyne.io/fyne/v2/data/binding.(*base).AddListener() C:/GoWorkspace/src/github.com/fyne/data/binding/binding.go:68 +0xea fyne.io/fyne/v2/data/binding.(*boundString).AddListener() :1 +0x45 fyne.io/fyne/v2/widget.(*basicBinder).Bind() C:/GoWorkspace/src/github.com/fyne/widget/bind_helper.go:27 +0x139 fyne.io/fyne/v2/widget.(*Label).Bind() C:/GoWorkspace/src/github.com/fyne/widget/label.go:57 +0xde fyne.io/fyne/v2/widget.NewLabelWithData() C:/GoWorkspace/src/github.com/fyne/widget/label.go:34 +0x44 github.com/pbrown12303/fynebindingtest.TestRaceCondition() c:/GoWorkspace/src/github.com/pbrown12303/fynebindingraceconditiontest/bindingracecondition_test.go:19 +0xfb testing.tRunner() C:/Program Files/Go/src/testing/testing.go:1595 +0x238 testing.(*T).Run.func1() C:/Program Files/Go/src/testing/testing.go:1648 +0x44

Goroutine 7 (running) created at: testing.(*T).Run() C:/Program Files/Go/src/testing/testing.go:1648 +0x82a testing.runTests.func1() C:/Program Files/Go/src/testing/testing.go:2054 +0x84 testing.tRunner() C:/Program Files/Go/src/testing/testing.go:1595 +0x238 testing.runTests() C:/Program Files/Go/src/testing/testing.go:2052 +0x896 testing.(*M).Run() C:/Program Files/Go/src/testing/testing.go:1925 +0xb57 main.main() _testmain.go:47 +0x2bd

================== c:\GoWorkspace\src\github.com\pbrown12303\fynebindingraceconditiontest\bindingracecondition_test.go:25: Initial binding of label1 failed: label has text: []

WARNING: DATA RACE Read at 0x00c000096e10 by goroutine 7: github.com/pbrown12303/fynebindingtest.TestRaceCondition() c:/GoWorkspace/src/github.com/pbrown12303/fynebindingraceconditiontest/bindingracecondition_test.go:28 +0x1dc testing.tRunner() C:/Program Files/Go/src/testing/testing.go:1595 +0x238 testing.(*T).Run.func1() C:/Program Files/Go/src/testing/testing.go:1648 +0x44

Previous write at 0x00c000096e10 by goroutine 9: fyne.io/fyne/v2/widget.(*Label).SetText() C:/GoWorkspace/src/github.com/fyne/widget/label.go:117 +0x84 fyne.io/fyne/v2/widget.(*Label).updateFromData() C:/GoWorkspace/src/github.com/fyne/widget/label.go:172 +0x7a fyne.io/fyne/v2/widget.(*Label).updateFromData-fm() :1 +0x47 fyne.io/fyne/v2/widget.(*basicBinder).Bind.func1() C:/GoWorkspace/src/github.com/fyne/widget/bind_helper.go:24 +0x68 fyne.io/fyne/v2/data/binding.(*listener).DataChanged() C:/GoWorkspace/src/github.com/fyne/data/binding/binding.go:56 +0x35 fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm() :1 +0x42 fyne.io/fyne/v2/data/binding.queueItem.func1.1() C:/GoWorkspace/src/github.com/fyne/data/binding/queue.go:19 +0x70

Goroutine 7 (running) created at: testing.(*T).Run() C:/Program Files/Go/src/testing/testing.go:1648 +0x82a testing.runTests.func1() C:/Program Files/Go/src/testing/testing.go:2054 +0x84 testing.tRunner() C:/Program Files/Go/src/testing/testing.go:1595 +0x238 testing.runTests() C:/Program Files/Go/src/testing/testing.go:2052 +0x896 testing.(*M).Run() C:/Program Files/Go/src/testing/testing.go:1925 +0xb57 main.main() _testmain.go:47 +0x2bd

Goroutine 9 (running) created at: fyne.io/fyne/v2/data/binding.queueItem.func1() C:/GoWorkspace/src/github.com/fyne/data/binding/queue.go:17 +0x6a sync.(*Once).doSlow() C:/Program Files/Go/src/sync/once.go:74 +0xf0 sync.(*Once).Do() C:/Program Files/Go/src/sync/once.go:65 +0x44 fyne.io/fyne/v2/data/binding.queueItem() C:/GoWorkspace/src/github.com/fyne/data/binding/queue.go:15 +0x2f fyne.io/fyne/v2/data/binding.(*base).AddListener() C:/GoWorkspace/src/github.com/fyne/data/binding/binding.go:68 +0xea fyne.io/fyne/v2/data/binding.(*boundString).AddListener() :1 +0x45 fyne.io/fyne/v2/widget.(*basicBinder).Bind() C:/GoWorkspace/src/github.com/fyne/widget/bind_helper.go:27 +0x139 fyne.io/fyne/v2/widget.(*Label).Bind() C:/GoWorkspace/src/github.com/fyne/widget/label.go:57 +0xde fyne.io/fyne/v2/widget.NewLabelWithData() C:/GoWorkspace/src/github.com/fyne/widget/label.go:34 +0x44 github.com/pbrown12303/fynebindingtest.TestRaceCondition() c:/GoWorkspace/src/github.com/pbrown12303/fynebindingraceconditiontest/bindingracecondition_test.go:19 +0xfb testing.tRunner() C:/Program Files/Go/src/testing/testing.go:1595 +0x238 testing.(*T).Run.func1() C:/Program Files/Go/src/testing/testing.go:1648 +0x44

================== c:\GoWorkspace\src\github.com\pbrown12303\fynebindingraceconditiontest\testing.go:1465: race detected during execution of test --- FAIL: TestRaceCondition (0.01s) c:\GoWorkspace\src\github.com\pbrown12303\fynebindingraceconditiontest\testing.go:1465: race detected during execution of test FAIL FAIL github.com/pbrown12303/fynebindingtest 2.029s

Example code

package bindingraceconditiontest

import (
	"testing"

	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/widget"
)

var entryWidget *widget.Entry

// TestRaceCondition tries to re-create the race condition.
func TestRaceCondition(t *testing.T) {

	boundValue := "initial string"

	boundString := binding.NewString()

	label1 := widget.NewLabelWithData(boundString)
	label2 := widget.NewLabelWithData(boundString)

	boundString.Set(boundValue)

	// time.Sleep(100 * time.Millisecond)

	if label1.Text != boundValue {
		t.Errorf("Initial binding of label1 failed: label has text: [%s]", label1.Text)
	}

	if label2.Text != boundValue {
		t.Errorf("Initial binding of label2 failed: label has text: [%s]", label2.Text)
	}

}

Fyne version

2.4.1 develop

Go compiler version

1.212.3

Operating system and version

Windows 10

Additional Information

No response

pbrown12303 avatar Nov 09 '23 19:11 pbrown12303