ios - Сбой IBOutlet с EXC_BAD_ACCESS, хотя не ноль




swift uiviewcontroller (4)

В UIViewController (rolePageController) я настраиваю другой UIViewController (boxController) и передаю ему 2 UIViews со страницы ролей, которая будет частью конфигурации нейтрального контроллера. Как только ящик контроллера пытается получить доступ к представлениям IBOutlet из rolePageController, он завершается с EXC_BAD_ACCESS (code = EXC_I386_GPFLT).

В 1-ом VC (rolePageController) вот IBOutlets:

@IBOutlet var rolePageDrawerView: UIView!
@IBOutlet var rolePageContentView: UIView!

В rolePageController.viewDidLoad () я делаю вызов к bottomController.configureDrawer (...):

override func viewDidLoad() {
    super.viewDidLoad()

    //other stuff happens here

    let drawerController = UIStoryboard(name: "StoryboardName", bundle: nil).instantiateViewController(withIdentifier: "drawerController") as! DrawerViewController
    drawerController.configureDrawer(drawerContainerView: self.rolePageDrawerView, overlaidView: self.rolePageContentView)

    //other stuff here
}

Протокол DrawerViewController определяется как:

protocol DrawerViewController where Self: UIViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Вот код для функции configureDrawer (...):

private var drawerParentView: UIView!
private var overlaidByDrawerView: UIView!


func configureDrawer(drawerContainerView: UIView, overlaidView: UIView) {
    self.drawerParentView = drawerContainerView
    self.overlaidByDrawerView = overlaidView
}

В отладчике заметил, что вызываемый экземпляр boxController не соответствует собственному экземпляру, который получает вызов. Вот адрес экземпляра, который будет вызываться:

Вот адрес экземпляра, когда я вступаю в вызов:

Когда я перехожу к вызову, адрес перед входящим вызовом не является адресом себя. Этого никогда не должно случиться.

Я создал упрощенный проект, который воспроизводит сбой по адресу https://github.com/ksoftllc/DynamicStackBufferOverflow .

Решение Оказалось, что решение удалить предложение where из протокола DrawerViewController.

protocol DrawerViewController where Self: UIViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Нашел код, вызывающий обиду, но я не знаю, почему это может привести к ошибкам, которые я видел Кассетный ящик соответствует протоколу DrawerViewController, определяемому как:

protocol DrawerViewController where Self: UIViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Когда я удаляю условие «Где», оно больше не падает.

protocol DrawerViewController {
    func configureDrawer(drawerContainerView: UIView, overlaidView: UIView)
}

Предложение where фактически не было необходимо для правильного функционирования программы, поэтому я буду продолжать без него.

ОБНОВЛЕНИЕ Я подал ошибку на swift.org и получил ответ. Добавление предложения where к протоколу не поддерживается в Swift 4.2, но будет поддерживаться в Swift 5.0. Кроме того, @J Doe опубликовал ниже способ достижения этого с обновлением инструментария Xcode.


Переместите этот вызов функции из viewDidLoad в viewWillAppear drawerController.configureDrawer(drawerContainerView: self.rolePageDrawerView, overlaidView: self.rolePageContentView)


Это действительно похоже на ошибку компилятора Swift. Я упростил ваш код для уточнения:

func foo(_ wow: TestProtocol) {
    wow.foo()
}

protocol TestProtocol where Self: NSObject {
    func foo()
}

class TestClass: NSObject, TestProtocol {

    func foo() {
        print("Much wow")
    }

}

foo(TestClass())

Вы можете сообщить об этом как об ошибке. Чтобы решить эту проблему, я предлагаю вам не использовать оператор where или pass с его типом func foo(_ wow: TestClass { .


dynamic-stack-buffer-overflow не имеет ничего общего с рекурсией. Это означает, что буфер alloca был переполнен. Проверьте исходный код времени выполнения asan .

Предположим, что стек спроектирован так, что у вас есть буфер alloca за которым следует указатель объекта - возможно, даже один из указателей объекта, переданных в качестве аргумента.

Предположим, что буфер alloca переполнен. В сборке asan это может вызвать ошибку dynamic-stack-buffer-overflow . Но в сборке, отличной от asan, он просто записывает байты этого указателя объекта. Предположим, он записывает байты, образующие адрес, который не отображается в таблице страниц вашего процесса.

Если программа пытается прочитать этот указатель объекта и сохранить его в другом месте (скажем, в переменной экземпляра), она должна увеличить счетчик ссылок объекта. Но это означает разыменование указателя - и указатель указывает на не отображенный адрес. Возможно, это приводит к общей ошибке защиты, которую Мах вызывает EXC_I386_GPFLT .

Было бы полезно, если бы вы опубликовали трассировку стека asan dynamic-stack-buffer-overflow ошибки dynamic-stack-buffer-overflow и разборки кода, приведшего к ошибке.





swift-protocols