[swift-evolution] Retain self in deinit.
Joe Groff
jgroff at apple.com
Fri Jul 21 13:48:34 CDT 2017
> On Jul 21, 2017, at 11:01 AM, Alfred Zien via swift-evolution <swift-evolution at swift.org> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170721/57384688/attachment.html>
More information about the swift-evolution
mailing list