Skip to content

SILGen: Fix potential use-after-free in @_backDeploy coroutines #60021

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

Merged

Conversation

tshortli
Copy link
Contributor

The SIL verifier has identified an issue with the SIL generated for property accessors structured like this:

public struct S {
  @available(macOS, introduced: 12.0)
  @_backDeploy(before: macOS 13.0)
  public var x: String {
    _read {
      yield "x"
    }
  }
}

The emitted SIL is invalid because the value %9 is used after end_apply may have ended the lifetime of the value:

bb1:
  %8 = function_ref @$s4test1SV1xSSvrTwB : $@yield_once @convention(method) (S) -> @yields @guaranteed String9
  (%9, %10) = begin_apply %8(%0) : $@yield_once @convention(method) (S) -> @yields @guaranteed String
  end_apply %10
  yield %9 : $String, resume bb3, unwind bb2

The fix is to move the end_apply to the resume and unwind blocks, after the value has been yielded to the caller.

Resolves rdar://96879247

The SIL verifier has identified an issue with the SIL generated for property accessors structured like this:

```
public struct S {
  @available(macOS, introduced: 12.0)
  @_backDeploy(before: macOS 13.0)
  public var x: String {
    _read {
      yield "x"
    }
  }
}
```

The emitted SIL is invalid because the value `%9` is used after `end_apply` may have ended the lifetime of the value:

```
bb1:
  %8 = function_ref @$s4test1SV1xSSvrTwB : $@yield_once @convention(method) (S) -> @yields @guaranteed String9
  (%9, %10) = begin_apply %8(%0) : $@yield_once @convention(method) (S) -> @yields @guaranteed String
  end_apply %10
  yield %9 : $String, resume bb3, unwind bb2
```

The fix is to move the `end_apply` to the resume and unwind blocks, after the value has been yielded to the caller.

Resolves rdar://96879247
@tshortli tshortli requested a review from eeckstein July 12, 2022 18:50
@tshortli
Copy link
Contributor Author

@swift-ci please smoke test

@gottesmm
Copy link
Contributor

I am not reviewing this... but unless the test that you modified has this specific test there, you aren't actually testing the broken test case? If my guess is right, can you dd that test case explicitly and check the SILGen?

@tshortli
Copy link
Contributor Author

tshortli commented Jul 12, 2022

I am not reviewing this... but unless the test that you modified has this specific test there, you aren't actually testing the broken test case? If my guess is right, can you dd that test case explicitly and check the SILGen?

The changed location of end_apply in the test is the main thing I'm trying verify.

I am not sure whether the fact that the verifier didn't catch this on this existing test case is a bug in the verifier or not. It seems like the lifetime of %9 in the example I gave in the description is not validated by the verifier when %9 holds an Int, but it would if I changed the return type of the function from Int to String. I could duplicate this test case and modify it to use a return type that does cause the current implementation of the verifier to trip, though.

Copy link
Contributor

@rjmccall rjmccall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems correct to me.

@tshortli tshortli merged commit 3e75bb9 into swiftlang:main Jul 13, 2022
@tshortli tshortli deleted the back-deploy-coroutine-use-after-free branch July 13, 2022 02:30
@eeckstein
Copy link
Contributor

I could duplicate this test case and modify it to use a return type that does cause the current implementation of the verifier to trip, though.

Yes, I think that's a good idea. You can do that in a follow-up PR.

These kind of lifetime/ownership verifications are only done for non-trivial types. So if you use e.g. a class in your test, it should work.

tshortli added a commit to tshortli/swift that referenced this pull request Jul 13, 2022
…lds a non-trivial value.

This is a follow up to swiftlang#60021 to ensure that a test exists that would cause lifetime verification to fail if the fix regressed.
@tshortli
Copy link
Contributor Author

I've expanded the runtime tests for @_backDeploy to include code that causes lifetime verification to fail without this fix: #60037

hborla pushed a commit to hborla/swift that referenced this pull request Jul 21, 2022
…lds a non-trivial value.

This is a follow up to swiftlang#60021 to ensure that a test exists that would cause lifetime verification to fail if the fix regressed.
Catfish-Man pushed a commit to Catfish-Man/swift that referenced this pull request Jul 28, 2022
…lds a non-trivial value.

This is a follow up to swiftlang#60021 to ensure that a test exists that would cause lifetime verification to fail if the fix regressed.
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.

4 participants