Skip to content

Conversation

Xazax-hun
Copy link
Contributor

Unowned result conventions do not work well with OSSA. Retain the result right after the call when we come out of OSSA so we can treat the returned value as if it was owned when we do optimizations.

This fix a miscompilation due to the DestroyAddrHoisting pass hoisting destroys above copies with unowned sources. When the destroyed object was the last reference to the pointed memory the copy is happening too late resulting in a use after free.

rdar://160462854

@Xazax-hun Xazax-hun added the c++ interop Feature: Interoperability with C++ label Oct 1, 2025
@Xazax-hun
Copy link
Contributor Author

As per some offline discussions we might want to completely eliminate the unowned result convention from the compiler and use a SILFunctionArgument flag instead that is understood by the eliminator.

@atrick atrick self-requested a review October 1, 2025 16:56
Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

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

Looks great. I'm assuming you still need to update a bunch of lit tests that check for copy_value.

Gabor Horvath added 2 commits October 3, 2025 13:15
…nation

Unowned result conventions do not work well with OSSA. Retain the result
right after the call when we come out of OSSA so we can treat the
returned value as if it was owned when we do optimizations.

This fix a miscompilation due to the DestroyAddrHoisting pass hoisting
destroys above copies with unowned sources. When the destroyed object
was the last reference to the pointed memory the copy is happening too
late resulting in a use after free.

rdar://160462854
Remove SIL tests that are testing result conventions that are never
emitted by the compiler.
@Xazax-hun Xazax-hun force-pushed the fix-overrelease-destroy-hoist branch from eeb3d0c to 5a63808 Compare October 3, 2025 13:59
@Xazax-hun Xazax-hun changed the title [cxx-interop] Delay lowering unowned convention until ownership elimiation [cxx-interop] Delay lowering unowned convention until ownership elimination Oct 6, 2025
Copy link
Contributor

@atrick atrick left a comment

Choose a reason for hiding this comment

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

Re: Remove SIL tests that are testing result conventions that are never
emitted by the compiler.

Some of those tests might cover real corner cases in the optimizer (Namely CSE and OSSA RAUW) that can occur with real source. But they just happen to return an unowned result because it was convenient.

Instead of deleting those tests, can you just convert the return convention to @owned and insert a copy_value after the cast?

I know we talked about not supporting unowned at all in SIL, but I don't know how we would handle these kind of bitcasts yet. Maybe we consider them to have an implicit copy, which could be removed later if we prove the incoming value is trivial. But that's all future work.

return %5 : $ThreeDifferingPayloadEnum
}

sil [ossa] @enum_cases_with_trivial_unowned_cases_arg_into_phi : $@convention(thin) (Builtin.NativeObject) -> ThreeDifferingPayloadEnum {
Copy link
Contributor Author

@Xazax-hun Xazax-hun Oct 7, 2025

Choose a reason for hiding this comment

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

This has a version with owned return type so should be OK to remove.

return %9999 : $()
}

sil [ossa] @unowned_to_ref_is_unowned_instant_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> Builtin.NativeObject {
Copy link
Contributor Author

@Xazax-hun Xazax-hun Oct 7, 2025

Choose a reason for hiding this comment

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

These specifically testing the unowned return type which is not supported. I think these or OK to remove.

// CHECK: ref_to_raw_pointer
// CHECK: raw_pointer_to_ref
// CHECK: } // end sil function 'unchecked_ref_cast_formation_unowned'
sil [ossa] @unchecked_ref_cast_formation_unowned : $@convention(thin) (B) -> F {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the ones in this file are OK to go, specifically testing cases that are never generated.

@Xazax-hun Xazax-hun force-pushed the fix-overrelease-destroy-hoist branch from 518b6b1 to 0e77567 Compare October 7, 2025 11:02
@Xazax-hun Xazax-hun force-pushed the fix-overrelease-destroy-hoist branch from 0e77567 to 8b3b16c Compare October 7, 2025 11:18
@Xazax-hun
Copy link
Contributor Author

Thanks! I updated the tests that had suggestions and ended up converting the ones in OSSA RAUW myself. Let me know if there are some more that should survive.

@Xazax-hun
Copy link
Contributor Author

@swift-ci please test

Copy link
Contributor

@eeckstein eeckstein left a comment

Choose a reason for hiding this comment

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

lgtm!

@Xazax-hun
Copy link
Contributor Author

@swift-ci please test macOS

@Xazax-hun Xazax-hun enabled auto-merge October 8, 2025 16:24
@Xazax-hun Xazax-hun merged commit 0959bce into main Oct 8, 2025
5 checks passed
@Xazax-hun Xazax-hun deleted the fix-overrelease-destroy-hoist branch October 8, 2025 17:42
Xazax-hun added a commit to Xazax-hun/swift that referenced this pull request Oct 8, 2025
…elimination

Explanation: Unowned result conventions do not work well with OSSA. Retain the
result right after the call when we come out of OSSA so we can treat the
returned value as if it was owned when we do optimizations.

This fix a miscompilation due to the DestroyAddrHoisting pass hoisting destroys
above copies with unowned sources. When the destroyed object was the last
reference to the pointed memory the copy is happening too late resulting in
a use after free.

Issues: rdar://160462854
Original PRs: swiftlang#84612
Risk: We change where retaining of the unowned return values
happen in the optimization pipeline. It is hard to anticipate all the
possible effects but it should make the optimizer more correct.
Testing: Added a compiler test.
Reviewers: @eeckstein, @atrick
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ interop Feature: Interoperability with C++

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants