BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Swift 5 Will Enforce Exclusive Access to Memory

Swift 5 Will Enforce Exclusive Access to Memory

This item in japanese

Bookmarks

Swift 5 will improve memory safety of Swift programs by ensuring variables cannot be accessed using a different name while they are being modified by another portion of the program. This change has important implications both on existing apps behaviour and on the Swift compiler itself.

The issue of exclusive access to memory arises in many different contexts. The compiler can catch many of them statically, but other cases can only be dealt with at runtime. Those includes exclusivity violations with escaping closures, class type properties, static properties, and global variables.

To illustrate the issue, let's consider a rather generic case: a variable that is being modified as an inout argument to a function that also executes a closure argument that accesses that same variable using two different names in the same scope:

func modifyTwice(_ value: inout Int, by modifier: (inout Int) -> ()) {
  modifier(&value)
  modifier(&value)
}

func testCount() {
  var count = 1
  modifyTwice(&count) { $0 += count }
  print(count)
}

In this example, the issue arises due to the use of count as an inout argument to modifyTwice and in modifier at the same time. As an effect of this, it is not clear what the print statement should print out. The first time count is incremented, its value is incremented to 2. But, when the second addition is executed, what is the value of count to be added to the $0 value? This may depend on a number of factors since memory operations are not necessarily instantaneous. Even worse, the compiler may introduce optimizations that further complicate the analysis of such a scenario.

The problem is not only related to the unpredictability of simultaneous changes to memory through different variable names, as described above, but also to the complexities that this forces down to the compiler.

This can lead to unexpected and confusing results. It also forces a great deal of conservatism onto the implementation of the compiler and the standard libraries, which must generally ensure the basic soundness of the program (no crashes or undefined behavior) even in unusual circumstances.

All of this means that an applications compiled using the Swift 5 compiler will crash at runtime if an exclusive access violation is found. This behaviour was previously available in debug mode with the Swift 4 compiler, so programs that were only tested in Runtime mode are at risk of crashing when compiled with Swift 5.

The general approach to fixing access exclusivity violations is making a copy of the data. In our example, this would come down to:

func modifyTwice(_ value: inout Int, by modifier: (inout Int) -> ()) {
  modifier(&value)
  modifier(&value)
}

func testCount() {
  var count = 1
  let increment = count
  modifyTwice(&count) { $0 += increment }
  print(count)
}

As it happens, access exclusivity violation checks may be disabled, but this practice is highly discouraged:

While disabling run-time checks may work around a performance regression, it does not mean that exclusivity violations are safe. Without enforcement enabled, the programmer must take responsibility for obeying exclusivity rules.

Do not miss the original post for more detail and additional examples.

Rate this Article

Adoption
Style

BT