> 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

Reply via email to