Skip to content

[overlays] Clean up some sources of undefined behaviour #18799

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
merged 2 commits into from
Sep 28, 2018

Conversation

hamishknight
Copy link
Contributor

@hamishknight hamishknight commented Aug 17, 2018

While experimenting with forbidding temporary argument conversions for UnsafePointer initialiser parameters (amongst others), I found a few cases where we're currently making such unsound calls in the SDK overlays (unsound because such temporary argument conversions produce pointers valid only for the duration of the call).

This PR removes such usages by performing the temporary argument conversions directly without going through any UnsafePointer initialiser calls first.

In the case of MTLCopyAllDevicesWithObserver, such usage led to us over-releasing the observer, as the call to AutoreleasingUnsafeMutablePointer's initialiser:

AutoreleasingUnsafeMutablePointer<NSObjectProtocol?>(&resultTuple.observer)

treats the +1 memory as having +0 semantics, leading to an unbalanced autorelease (this didn't appear to cause issues for users though as Metal itself keeps the observer retained).

While experimenting with forbidding temporary argument conversions for `UnsafePointer` initialiser parameters (amongst others), I found a few cases where we're currently making such unsound calls in the SDK overlays.

This commit removes such usages by performing the temporary argument conversions directly without going through any `UnsafePointer` initialiser calls first.

In the case of `MTLCopyAllDevicesWithObserver`, we were even over-releasing the observer through the usage of:

```swift
AutoreleasingUnsafeMutablePointer<NSObjectProtocol?>(&resultTuple.observer)
```

As we're treating +1 memory as having +0 semantics (this didn't appear to cause issues for users though as Metal itself appears to keep the observer retained).
let devices = __MTLCopyAllDevicesWithObserver(&observer, handler)
// FIX-ME: The force cast here isn't great – ideally we would return the
// observer as an NSObjectProtocol.
return (devices, observer as! NSObject)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As said in the comment, the force cast here isn't ideal, but it's better than what the code was previously doing – which was type punning an NSObject pointer to a NSObjectProtocol? pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, can I confirm that __MTLCopyAllDevicesWithObserver is guaranteed to set observer? The previous code was initially assigning NSObject(), but I'm not sure whether that was specifically because it could actually return that as the observer.

Copy link
Contributor

Choose a reason for hiding this comment

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

Pinged Metal team about that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Here is the reply:

MTLCopyAllDevicesWithObserver(id <NSObject>* observer, MTLDeviceNotificationHandler handler) allocates a framework object to return via the observer pointer (specifically a _MTLDeviceNotifier object), so the pointer passed in can be set to nullptr.

@jrose-apple jrose-apple requested review from lancep and moiseev August 17, 2018 21:22
@airspeedswift airspeedswift changed the title [stdlib] Clean up some sources of undefined behaviour [overlays] Clean up some sources of undefined behaviour Aug 18, 2018
@hamishknight
Copy link
Contributor Author

Review ping @lancep @moiseev

@moiseev
Copy link
Contributor

moiseev commented Sep 27, 2018

Ouch.. This is the first time I see this PR. Taking a look now.

return resultTuple
var observer: NSObjectProtocol?
let devices = __MTLCopyAllDevicesWithObserver(&observer, handler)
// FIX-ME: The force cast here isn't great – ideally we would return the
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: the - in fixme makes it undiscoverable. All other FIXME's in the codebase don't have it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good spot, thanks!

@moiseev
Copy link
Contributor

moiseev commented Sep 27, 2018

@swift-ci Please test macOS platform

@moiseev
Copy link
Contributor

moiseev commented Sep 27, 2018

@swift-ci Please smoke test Linux platform

@moiseev
Copy link
Contributor

moiseev commented Sep 27, 2018

@swift-ci Please test macOS platform

@moiseev
Copy link
Contributor

moiseev commented Sep 27, 2018

@swift-ci Please smoke test Linux platform

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - d07ff79

@moiseev moiseev merged commit b8c9d8f into swiftlang:master Sep 28, 2018
@hamishknight hamishknight deleted the ub-good-now branch September 28, 2018 20:39
@hamishknight
Copy link
Contributor Author

Thanks Max! I have filed a bug over the observer being returned as an NSObject: SR-8882

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.

3 participants