Skip to content

Commit 15ba640

Browse files
committed
Fixed an impedance mismatch between Signal.Core RCU and Bag.
1 parent dadbb19 commit 15ba640

File tree

2 files changed

+13
-8
lines changed

2 files changed

+13
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# master
22
*Please add new entries at the top.*
33

4+
1. Fixed an impedance mismatch in the `Signal` internals that caused heap corruptions. (#449, kudos to @gparker42)
5+
46
1. In Swift 3.2 or later, you may create `BindingTarget` for a key path of a specific object. (#440, kudos to @andersio)
57

68
# 2.0.0-alpha.2

Sources/Signal.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public final class Signal<Value, Error: Swift.Error> {
112112
private var hasDeinitialized: Bool
113113

114114
fileprivate init(_ generator: (Observer) -> Disposable?) {
115-
state = .alive(AliveState())
115+
state = .alive(AliveState(observers: Bag()))
116116

117117
updateLock = Lock.make()
118118
sendLock = Lock.make()
@@ -225,7 +225,9 @@ public final class Signal<Value, Error: Swift.Error> {
225225
updateLock.lock()
226226

227227
if case let .alive(state) = state {
228-
token = state.observers.insert(observer)
228+
var observers = state.observers
229+
token = observers.insert(observer)
230+
self.state = .alive(AliveState(observers: observers))
229231
}
230232

231233
updateLock.unlock()
@@ -250,7 +252,7 @@ public final class Signal<Value, Error: Swift.Error> {
250252
if case let .alive(state) = state {
251253
var observers = state.observers
252254
let observer = observers.remove(using: token)
253-
state.observers = observers
255+
self.state = .alive(AliveState(observers: observers))
254256

255257
var result = OperationResult.none
256258

@@ -450,13 +452,14 @@ public final class Signal<Value, Error: Swift.Error> {
450452
private final class AliveState {
451453
/// The observers of the `Signal`.
452454
///
453-
/// - note: Since `Bag` is a copy-on-write collection, writes can be done safety
454-
/// as long as `updateLock` is acquired.
455-
fileprivate var observers: Bag<Observer>
455+
/// - important: `observer` should not be mutated directly given the layout of
456+
/// `Bag`. Copy the bag, and replace the current `AliveState` with
457+
/// a new one created with the bag instead.
458+
fileprivate let observers: Bag<Observer>
456459

457460
/// Create an alive state.
458-
init() {
459-
self.observers = Bag()
461+
init(observers: Bag<Observer>) {
462+
self.observers = observers
460463
}
461464
}
462465

0 commit comments

Comments
 (0)