[swift-evolution] Retain self in deinit.

Alfred Zien zienag at yandex-team.ru
Fri Jul 21 12:54:37 CDT 2017


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!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170721/d62e64ad/attachment.html>


More information about the swift-evolution mailing list