Skip to content

Commit 364da65

Browse files
committed
Do not reuse JS-owned wrapper values.
JavaScript-owned wrapper values cannot be reused because the QML runtime may choose to destroy the value right after it is handed a new reference to the same value. Fixes #68.
1 parent ab659ec commit 364da65

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

bridge.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,11 @@ func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue u
230230

231231
painting := cdata.Ref() == atomic.LoadUintptr(&guiPaintRef)
232232

233+
// Cannot reuse a jsOwner because the QML runtime may choose to destroy
234+
// the value _after_ we hand it a new reference to the same value.
235+
// See issue #68 for details.
233236
prev, ok := engine.values[gvalue]
234-
if ok && (prev.owner == owner || owner != cppOwner || painting) {
237+
if ok && (prev.owner == cppOwner || painting) {
235238
return prev.cvalue
236239
}
237240

@@ -250,11 +253,12 @@ func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue u
250253
}
251254
fold.cvalue = C.newGoValue(unsafe.Pointer(fold), typeInfo(gvalue), parent)
252255
if prev != nil {
253-
prev.next = fold
254-
fold.prev = prev
255-
} else {
256-
engine.values[gvalue] = fold
256+
// Put new fold first so the single cppOwner, if any, is always the first entry.
257+
fold.next = prev
258+
prev.prev = fold
257259
}
260+
engine.values[gvalue] = fold
261+
258262
//fmt.Printf("[DEBUG] value alive (wrapped): cvalue=%x gvalue=%x/%#v\n", fold.cvalue, addrOf(fold.gvalue), fold.gvalue)
259263
stats.valuesAlive(+1)
260264
C.engineSetContextForObject(engine.addr, fold.cvalue)

qml_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,21 @@ var tests = []struct {
12131213
},
12141214
DoneLog: "Signal has run.",
12151215
},
1216+
{
1217+
Summary: "References handed out must not be GCd (issue #68)",
1218+
Init: func(c *TestData) {
1219+
type B struct{ S string }
1220+
type A struct{ B *B }
1221+
c.context.SetVar("a", &A{&B{}})
1222+
},
1223+
QML: `Item { function f() { var x = [[],[],[]]; gc(); if (!a.b) console.log("BUG"); } }`,
1224+
Done: func(c *TestData) {
1225+
for i := 0; i < 100; i++ {
1226+
c.root.Call("f")
1227+
}
1228+
},
1229+
DoneLog: "!BUG",
1230+
},
12161231
}
12171232

12181233
var tablef = flag.String("tablef", "", "if provided, TestTable only runs tests with a summary matching the regexp")

0 commit comments

Comments
 (0)