> On Jul 21, 2017, at 11:01 AM, Alfred Zien via swift-evolution > <[email protected]> wrote: > > Hi! Recently I discovered a way to make a bad access crash in somewhat > unexpected circumstances. Code to reproduce: > > import Foundation > > class Storage<T> { > var val : T? > } > class A { > let s : Storage<A> > init(s : Storage<A>) { > self.s = s > } > deinit { > s.val = self; > } > } > > var storage : Storage<A> = Storage() > var a : A? = A(s: storage) > > a = nil > > DispatchQueue.main.async { > print(storage.val as Any) > } > > dispatchMain() > > We saving self in storage on deinit. Storage will retain `a`, but after it > `a` will be destroyed. So, `val` will point to object that was deallocated. > When we will try to access it, it will crash. > > Can we do something about it? Of course, this very evil thing to do, but, > unfortunately, swift allows to do that. I have two suggestions: > 1. Completely forbid accessing self in deinit, allowing readonly access only > to properties with default getter method. This is very strict, but will catch > such problems in compile time. > 2. The bigger problem here, not just that it will crash, but it will crash in > very unpredictable place. So, we can make it crash just after deinit method, > if retain count was changed after deinit. > > I'm new to swift evolution, so please forgive me if I'm doing something wrong > :) Thanks!
deinit isn't allowed to "resurrect" the object in this way by escaping new references to the dying object. We could, and probably should, have a runtime check to catch this during object destruction. -Joe
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
