fyne
fyne copied to clipboard
Binding Two Labels to One BoundString Creates a Race Condition
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
- Create a bound string: binding.NewString()
- Create two labels with the same bound string: widget.NewLabelWithData(boundString)
- Set the value of the bound string: boundString.Set(boundValue)
- 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()
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()
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()
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()
================== 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