Skip to content

Guard the lifetime of StringObject.nativeStorage in mutating methods. #42623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from

Conversation

atrick
Copy link
Contributor

@atrick atrick commented Apr 25, 2022

This is a placeholder to demonstrate a fix for reference. The two fixes are

  1. avoid using unsafeBitcast to a reference
  2. add lexical variable scopes for objects in fields need to be alive while the parent struct is reassigned

The other commits are for temporary testing purposes.

atrick added 5 commits April 22, 2022 21:46
Plug a hole in the semantics of deinitialization barriers.

Adds strong_copy_(unowned|unmanaged)_value to mayLoadWeakOrUnowned.
Deinitialization barriers includes loads from weak references.
Converting an unowned or unmanaged reference to a strong reference
is the moral equivalent.
Use an Unmanaged reference when reinterpreting a strong reference to
any unmanaged (trivial) representation.

Mutating StringGuts methods, such as appendInPlace, are currently
miscompiled just by reordering the optimization pipeline. The fact
that 'self' is guaranteed within a method scope only applies to
nonmutating methods. In mutating methods, the contents of 'self' are
conceptually destroyed at the beginning of the method. Futhermore, the
compiler cannot provide any lifetime guarantees in the presence of a
bitcasting from an integer to a strong reference.

As a basic rule, Swift code should never directly bitcast an integer
to a reference. There's no reasonable way for the compiler to support
this. Generating a strong reference out of thin air requires an
explicit conversion from an unmanaged reference.

This rule will need to be clearly documented. To start with, it
will be explained in an upcoming proposal for object lifetimes.
StringGuts has mutating methods that access StringObject.nativeStorage
while modifying self as such:

  self = _StringGuts(self._object.nativeStorage)

`self._object` can be destroyed immediately after its last use. We
can't rely on `self` having a lexical lifetime within a mutating
method. This follows from the fact that `self` is effectively `inout`
within this scope, and thus conceptually destroyed on function entry.

Since the nativeStorage property generates a new reference out of thin
air (from an integer bitcast), `object` may be destroyed before the new
reference is retained.

Fix this by creating a separate copy of object with its own lexical
scope that covers the use of `nativeStorage`:

  var object = self._object
  self = _StringGuts(object.nativeStorage)
@atrick atrick requested a review from nate-chandler April 25, 2022 01:22
@atrick
Copy link
Contributor Author

atrick commented Mar 24, 2023

Fixed in
Extend deinit barriers to handle conversion to strong reference. #42624
and [stdlib] Rework String breadcrumbs initialization/loading #63592

@atrick atrick closed this Mar 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant