Skip to content

Commit a4d3261

Browse files
authored
Merge pull request #31110 from Catfish-Man/tagged-too-two
Avoid losing the high bits of bridged constant tagged pointers
2 parents 8bf3691 + 220f0cc commit a4d3261

File tree

2 files changed

+50
-17
lines changed

2 files changed

+50
-17
lines changed

stdlib/public/core/StringBridge.swift

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,42 @@ private func _getCocoaStringPointer(
413413
return .none
414414
}
415415

416+
#if arch(arm64)
417+
//11000000..payload..111
418+
private var constantTagMask:UInt {
419+
0b1111_1111_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0111
420+
}
421+
private var expectedConstantTagValue:UInt {
422+
0b1100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0111
423+
}
424+
#endif
425+
426+
@inline(__always)
427+
private func formConstantTaggedCocoaString(
428+
untaggedCocoa: _CocoaString
429+
) -> AnyObject? {
430+
#if !arch(arm64)
431+
return nil
432+
#else
433+
434+
let constantPtr:UnsafeRawPointer = Builtin.reinterpretCast(untaggedCocoa)
435+
436+
// Check if what we're pointing to is actually a valid tagged constant
437+
guard _swift_stdlib_dyld_is_objc_constant_string(constantPtr) == 1 else {
438+
return nil
439+
}
440+
441+
let retaggedPointer = UInt(bitPattern: constantPtr) | expectedConstantTagValue
442+
443+
return unsafeBitCast(retaggedPointer, to: AnyObject.self)
444+
#endif
445+
}
416446

417447
@inline(__always)
418448
private func getConstantTaggedCocoaContents(_ cocoaString: _CocoaString) ->
419-
(utf16Length: Int, asciiContentsPointer: UnsafePointer<UInt8>?)? {
449+
(utf16Length: Int,
450+
asciiContentsPointer: UnsafePointer<UInt8>,
451+
untaggedCocoa: _CocoaString)? {
420452
#if !arch(arm64)
421453
return nil
422454
#else
@@ -427,34 +459,33 @@ private func getConstantTaggedCocoaContents(_ cocoaString: _CocoaString) ->
427459

428460
let taggedValue = unsafeBitCast(cocoaString, to: UInt.self)
429461

430-
//11000000..payload..111
431-
let tagMask:UInt =
432-
0b1111_1111_1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0111
433-
let expectedValue:UInt =
434-
0b1100_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0111
435462

436-
guard taggedValue & tagMask == expectedValue else {
437-
return nil
438-
}
439463

440-
guard _swift_stdlib_dyld_is_objc_constant_string(
441-
cocoaString as! UnsafeRawPointer
442-
) == 1 else {
464+
guard taggedValue & constantTagMask == expectedConstantTagValue else {
443465
return nil
444466
}
445467

446-
let payloadMask = ~tagMask
468+
let payloadMask = ~constantTagMask
447469
let payload = taggedValue & payloadMask
448470
let ivarPointer = UnsafePointer<_swift_shims_builtin_CFString>(
449471
bitPattern: payload
450472
)!
473+
474+
guard _swift_stdlib_dyld_is_objc_constant_string(
475+
unsafeBitCast(ivarPointer, to: UnsafeRawPointer.self)
476+
) == 1 else {
477+
return nil
478+
}
479+
451480
let length = ivarPointer.pointee.length
452481
let isUTF16Mask:UInt = 0x0000_0000_0000_0004 //CFStringFlags bit 4: isUnicode
453482
let isASCII = ivarPointer.pointee.flags & isUTF16Mask == 0
483+
precondition(isASCII) // we don't currently support non-ASCII here
454484
let contentsPtr = ivarPointer.pointee.str
455485
return (
456486
utf16Length: Int(length),
457-
asciiContentsPointer: isASCII ? contentsPtr : nil
487+
asciiContentsPointer: contentsPtr,
488+
untaggedCocoa: Builtin.reinterpretCast(ivarPointer)
458489
)
459490
#endif
460491
}
@@ -476,9 +507,9 @@ internal func _bridgeCocoaString(_ cocoaString: _CocoaString) -> _StringGuts {
476507
case .constantTagged:
477508
let taggedContents = getConstantTaggedCocoaContents(cocoaString)!
478509
return _StringGuts(
479-
cocoa: cocoaString,
510+
cocoa: taggedContents.untaggedCocoa,
480511
providesFastUTF8: false, //TODO: if contentsPtr is UTF8 compatible, use it
481-
isASCII: taggedContents.asciiContentsPointer != nil,
512+
isASCII: true,
482513
length: taggedContents.utf16Length
483514
)
484515
#endif
@@ -590,7 +621,8 @@ extension String {
590621

591622
_internalInvariant(_guts._object.hasObjCBridgeableObject,
592623
"Unknown non-bridgeable object case")
593-
return _guts._object.objCBridgeableObject
624+
let result = _guts._object.objCBridgeableObject
625+
return formConstantTaggedCocoaString(untaggedCocoa: result) ?? result
594626
}
595627
}
596628

stdlib/public/stubs/FoundationHelpers.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ typedef __swift_uint8_t (*getCStringImplPtr)(id,
112112

113113
__swift_uint8_t
114114
swift::_swift_stdlib_dyld_is_objc_constant_string(const void *addr) {
115+
initializeBridgingFunctions();
115116
if (!dyld_is_objc_constant) return false;
116117
return dyld_is_objc_constant(dyld_objc_string_kind, addr) ? 1 : 0;
117118
}

0 commit comments

Comments
 (0)