-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Avoid losing the high bits of bridged constant tagged pointers #31110
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
Conversation
This is not the right approach actually |
@swift-ci please test |
Build failed |
Build failed |
@swift-ci please test |
Build failed |
Build failed |
9032822
to
c6100f8
Compare
@swift-ci please test |
Build failed |
Build failed |
c6100f8
to
bf4fd69
Compare
@swift-ci please test |
Build failed |
Build failed |
providesFastUTF8: false, //TODO: if contentsPtr is UTF8 compatible, use it | ||
isASCII: taggedContents.asciiContentsPointer != nil, | ||
isASCII: true, | ||
length: taggedContents.utf16Length |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this what we want, or do we want to bring it in as an immortal string? Have you tested that ref counting and message sending Swift-side works on that untagged object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want to, but I'm trying to be conservative about the changes initially both to unblock people and to reduce risk. This limits the changes to just the bridging paths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(and yes, that's been tested, it's an ordinary NSCFConstantString)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They'd also have be null-terminated.
@@ -590,7 +619,8 @@ extension String { | |||
|
|||
_internalInvariant(_guts._object.hasObjCBridgeableObject, | |||
"Unknown non-bridgeable object case") | |||
return _guts._object.objCBridgeableObject | |||
let result = _guts._object.objCBridgeableObject | |||
return formConstantTaggedCocoaString(untaggedCocoa: result) ?? result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we'd be checking a spare perf flag on the second word instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I think that's ultimately where we want to end up.
…eObject doesn't stomp the high bits
@swift-ci please test |
bf4fd69
to
220f0cc
Compare
…git failed to push, so that previous test run was useless |
@swift-ci please test |
Build failed |
Build failed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely get someone to look at that potential lifetime management issue
let retaggedPointer = UInt(bitPattern: constantPtr) | expectedConstantTagValue | ||
|
||
return unsafeBitCast(retaggedPointer, to: AnyObject.self) | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still seems a little sketchy without at least a defer { _fixLifetime(untaggedCocoa) }
. Make sure to check with @atrick or @eeckstein.
In practice, would ref counting always be disabled here? How are the retain/release counts balanced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These objects are in immutable memory, so can't be refcounted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
let payload = taggedValue & payloadMask | ||
let ivarPointer = UnsafePointer<_swift_shims_builtin_CFString>( | ||
bitPattern: payload | ||
)! | ||
|
||
guard _swift_stdlib_dyld_is_objc_constant_string( | ||
unsafeBitCast(ivarPointer, to: UnsafeRawPointer.self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if going through ObjectIdentifier
is more sanctioned. @lorentey , thoughts?
let length = ivarPointer.pointee.length | ||
let isUTF16Mask:UInt = 0x0000_0000_0000_0004 //CFStringFlags bit 4: isUnicode | ||
let isASCII = ivarPointer.pointee.flags & isUTF16Mask == 0 | ||
precondition(isASCII) // we don't currently support non-ASCII here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should be the behavior if this check fails? Should we trap in the stdlib?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so. It's pretty much "assert the world is as we expected"
Fixes rdar://problem/61273899