https://swift.org/blog/swift-5-exclusivity/
https://developer.apple.com/documentation/xcode_release_notes/xcode_10_2_beta_2_release_notes
https://download.developer.apple.com/Developer_Tools/Xcode_10.2_Beta_2/Xcode_10.2_Beta_2.xip
The Swift 5 release enables runtime checking of “Exclusive Access to Memory” by default in Release builds, further enhancing Swift’s capabilities as a safe language. In Swift 4, these runtime checks were only enabled in Debug builds. In this post, I’ll first explain what this change means for Swift developers before delving into why it is essential to Swift’s strategy for safety and performance.
Swift5版本允许在发布版本中默认检查“对内存的独占访问”,进一步增强了Swift作为安全语言的能力。在Swift4中,这些运行时检查仅在调试版本中启用。在本文中,我将首先解释这一变化对Swift开发人员意味着什么,然后再探究为什么它对Swift的安全和性能战略至关重要。
To achieve memory safety, Swift requires exclusive access to a variable in order to modify that variable. In essence, a variable cannot be accessed via a different name for the duration in which the same variable is being modified as an inout argument or as self within a mutating method.
In the following example, count is accessed for modification by passing it as an inout argument. The exclusivity violation occurs because the modifier closure both reads the captured count variable and is called within the scope of the same variable’s modification. Inside the modifyTwice function, the count variable may only be safely accessed via the value inout argument, and within the modified closure it may only safely be accessed as $0.
为了实现内存安全,swift需要对变量进行独占访问,以便修改该变量。本质上,在同一个变量被修改为inout参数或可变方法中的self的持续时间内,不能通过其他名称访问变量。
在下面的示例中,通过将count作为inout参数传递,可以访问它进行修改。发生独占性冲突的原因是修饰符闭包同时读取捕获的count变量,并在同一变量的修改范围内调用。在modifytwice函数内部,只能通过value inout参数安全地访问count变量,并且在修改后的闭包内,只能安全地访问它$0。
func modifyTwice(_ value: inout Int, by modifier: (inout Int) -> ()) {
modifier(&value)
modifier(&value)
}
func testCount() {
var count = 1
modifyTwice(&count) { $0 += count }
print(count)
}
As is often the case with exclusivity violations, the programmer’s intention is somewhat ambiguous. Do they expect count to be printed as “3” or “4”? Either way, the compiler does not guarantee the behavior. Worse yet, compiler optimizations can produce subtly unpredictable behavior in the presence of such errors. To protect against exclusivity violations and to allow the introduction of language features that depend on safety guarantees, exclusivity enforcement was first introduced in Swift 4.0: SE-0176: Enforce Exclusive Access to Memory.
Compile-time (static) diagnostics catch many common exclusivity violations, but run-time (dynamic) diagnostics are also required to catch violations involving escaping closures, properties of class types, static properties, and global variables. Swift 4.0 provided both compile-time and run-time enforcement, but run-time enforcement was only enabled in Debug builds.
In Swift 4.1 and 4.2, compiler diagnostics were gradually strengthened to catch more and more of the cases in which programmers could skirt exclusivity rules–most notably by capturing variables in nonescaping closures or by converting nonescaping closures to escaping closures. The Swift 4.2 announcement, Upgrading exclusive access warning to be an error in Swift 4.2, explains some of the common cases affected by the newly enforced exclusivity diagnostics.
Swift 5 fixes the remaining holes in the language model and fully enforces that model1. Since run-time exclusivity enforcement is now enabled by default in Release builds, some Swift programs that previously appeared well-behaved, but weren’t fully tested in Debug mode, could be affected.
与经常发生的侵犯排他性的情况一样,程序员的意图有些模棱两可。他们是否希望计数打印为“3”或“4”?不管怎样,编译器都不能保证该行为。更糟的是,编译器优化可能会在出现此类错误时产生不可预测的微妙行为。为了防止侵犯排他性并允许引入依赖于安全保证的语言功能,在Swift 4.0:SE-0176:Enforce exclusive access to memory中首次引入了排他性强制。
编译时(静态)诊断捕获许多常见的独占性冲突,但运行时(动态)诊断也需要捕获涉及转义闭包、类类型的属性、静态属性和全局变量的冲突。Swift4.0提供了编译时和运行时强制,但仅在调试版本中启用了运行时强制。
在Swift 4.1和4.2中,编译器诊断逐渐得到加强,以捕获越来越多的程序员可以绕过排他性规则的情况,尤其是通过捕获非捕获闭包中的变量或将非捕获闭包转换为转义闭包。Swift4.2公告将独占访问警告升级为Swift4.2中的错误,解释了一些受新强制的独占性诊断影响的常见情况。
Swift5修复了语言模型中的其余漏洞,并完全强制该模型1。由于运行时独占性强制现在在发布版本中默认启用,一些以前表现良好但未在调试模式下完全测试的swift程序可能会受到影响。