swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.46k stars 10.35k forks source link

Windows: the pointer passed to `_swift_willThrow` cannot be weakly referenced #62985

Open grynspan opened 1 year ago

grynspan commented 1 year ago

Description On Windows, the pointer passed to _swift_willThrow does not appear to be a valid heap object, and attempting to weakly reference it causes a crash.

Steps to reproduce Implement a program that sets the _swift_willThrow hook to a function like so:

struct S {
  weak var error: AnyObject
}

func swiftWillThrowHandler(_ errorAddress: UnsafeMutableRawPointer) {
  let errorObject = unsafeBitCast(errorAddress, to: AnyObject.self)
  var s = S()
  s.error = errorObject // crash
}

Expected behavior As on Darwin/Linux, this pointer should be safe to bitcast to an object and then weakly reference.

Environment

grynspan commented 1 year ago

More detailed STR:

  1. Create a Swift package with a C++ target that declares _swift_setWillThrowHandler() appropriately. _swift_willThrow isn't getting exported correctly on Windows right now (#62979), so you can't use it directly.
  2. Create a Swift test target in the package that imports the C++ target and calls _swift_setWillThrowHandler().
  3. In the closure you pass, bitcast (or Unmanaged-cast) the first argument from UnsafeMutableRawPointer to AnyObject.
  4. Assign the pointer to a weak reference somewhere. Crash should then happen.
al45tair commented 1 year ago

Debugging this is proving somewhat tricky; the symbols in libswiftCore seem to be incomplete, or LLDB is buggy on Windows, or maybe both. It looks like it's actually blowing up in the second swift_release() call that gets generated at the end of the catch{} block. (Though the symbols are pointing to something else entirely, but they're clearly wrong.)

grynspan commented 1 year ago

Perhaps this is failing on Darwin/Linux, but since their allocators may allow for more liberal use-after-free, it's less explosive? If so, adding a retain in the handling code manually might solve the problem (i.e. not a Swift bug.)

grynspan commented 1 year ago

Trying at desk, just manually inserting a strong retain doesn't appear to prevent the crash.