为什么迭代关闭会导致swift中的总线错误?

时间:2015-12-08 02:31:54

标签: swift

我在运行看起来非常安全的快速代码时遇到了一个奇怪的Bus Error。我试图将其减少到最小的测试用例,如下所示:

Apple Swift version 2.2-dev (LLVM 3ebdbb2c7e, Clang f66c5bb67b, Swift 0ddf238ad7)
Target: x86_64-apple-macosx10.9

此代码:

public enum MyError: ErrorType {
  case SomeError(code: Int)
}

public typealias MyType = () throws -> Bool

public class Foo {
  var a:MyType = { () throws -> Bool in
    print("A")
    return true
  }
  var b:MyType = { () throws -> Bool in
    print("B")
    return true
  }
  var c:MyType = { () throws -> Bool in
    print("C")
    throw MyError.SomeError(0)
  }
}

public func handle<T>(test:T) {
  let mirror = Mirror(reflecting: test)
  print(mirror.subjectType)
  for child in mirror.children {
    if let callable = child.value as? MyType {
      do {
        try callable()
      }
      catch MyError.SomeError(let id) {
        print(id)
      }
      catch {
        print("unknown error")
      }
    }
  }
}

let foo = Foo()
handle(foo)

生成此输出:

Foo
A
B
C
Bus error: 10

在调试器中运行它可以正常工作,所以我认为它与运行时的时序问题有关。

我在这段代码中做了非法或不安全的事情吗?

在闭包中异常是不合法的吗?

造成此错误的原因是什么?

编辑:

我已经在此处创建了一个关于swift问题跟踪器的错误:https://bugs.swift.org/browse/SR-324

2 个答案:

答案 0 :(得分:4)

  

造成此错误的原因是什么?

在你到达最后一次关闭之前,错误不会发生:

var c:MyType = { () throws -> Bool in
    print("C")
    throw MyError.SomeError(0)
}

显然,你在这里抛出一个异常,我怀疑这个问题与迭代children的关系不大,更多的是在你执行此操作时抛出异常迭代。我试着在没有迭代的情况下调用c

public func trythis() {
    let foo = Foo()
    do {
        try (foo.c)()
    }
    catch MyError.SomeError(let id) {
        print(id)
    }
    catch { print("unknown") }
}

trythis()

发现它工作正常。我还尝试从throw中删除c

var c:MyType = { () throws -> Bool in
    print("C")
//  throw MyError.SomeError(code: 0)
    return true
}

并发现代码在这种情况下工作正常。因此,在迭代问题列表时抛出组合,这让我怀疑它只是编译器错误或者Mirror类可能有问题

我认为您应该向Apple提交此错误报告。

答案 1 :(得分:2)

我同意Caleb的说法,这一定是个错误。

但是要明确一点,它不是在迭代时抛出的组合。它是反映投掷的组合。

这是handle功能的修改版本:

public func handle<T>(test:T) {
  let mirror = Mirror(reflecting: test)
  print(mirror.subjectType)

  // Extract only the last function, no iteration...
  if let callable = mirror.children[AnyForwardIndex(2)].value as? MyType {
    do {
      try callable()
    }
    catch MyError.SomeError(let id) {
      print(id)
    }
    catch {
      print("unknown error")
    }

  }
}

此功能将导致与您的功能相同的错误。 如果使用反射找到,你根本无法调用抛出的函数。

我会说错误。