@@ -110,6 +110,17 @@ extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(Sh);
110110// / Nominal type descriptor for Swift.String.
111111extern " C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM (SS);
112112
113+ // If this returns `true`, then we will call `fatalError` when we encounter a
114+ // null reference in a storage locaation whose type does not allow null.
115+ static bool unexpectedNullIsFatal () {
116+ return true ; // Placeholder for an upcoming check.
117+ }
118+
119+ // / This issues a fatal error or warning if the srcValue contains a null object
120+ // / reference. It is used when the srcType is a non-nullable reference type, in
121+ // / which case it is dangerous to continue with a null reference. The null
122+ // / reference is returned if we're operating in backwards-compatibility mode, so
123+ // / callers still have to check for null.
113124static HeapObject * getNonNullSrcObject (OpaqueValue *srcValue,
114125 const Metadata *srcType,
115126 const Metadata *destType) {
@@ -120,12 +131,27 @@ static HeapObject * getNonNullSrcObject(OpaqueValue *srcValue,
120131
121132 std::string srcTypeName = nameForMetadata (srcType);
122133 std::string destTypeName = nameForMetadata (destType);
123- swift::fatalError (/* flags = */ 0 ,
124- " Found unexpected null pointer value"
134+ const char *msg = " Found unexpected null pointer value"
125135 " while trying to cast value of type '%s' (%p)"
126- " to '%s' (%p)\n " ,
127- srcTypeName.c_str (), srcType,
128- destTypeName.c_str (), destType);
136+ " to '%s' (%p)%s\n " ;
137+ if (unexpectedNullIsFatal ()) {
138+ // By default, Swift 5.4 and later issue a fatal error.
139+ swift::fatalError (/* flags = */ 0 , msg,
140+ srcTypeName.c_str (), srcType,
141+ destTypeName.c_str (), destType,
142+ " " );
143+ } else {
144+ // In backwards compatibility mode, this code will warn and return the null
145+ // reference anyway: If you examine the calls to the function, you'll see
146+ // that most callers fail the cast in that case, but a few casts (e.g., with
147+ // Obj-C or CF destination type) sill succeed in that case. This is
148+ // dangerous, but necessary for compatibility.
149+ swift::warning (/* flags = */ 0 , msg,
150+ srcTypeName.c_str (), srcType,
151+ destTypeName.c_str (), destType,
152+ " : Continuing with null object, but expect problems later." );
153+ }
154+ return object;
129155}
130156
131157/* *****************************************************************************/
@@ -310,7 +336,9 @@ tryCastFromClassToObjCBridgeable(
310336 _getBridgedObjectiveCType (MetadataState::Complete, destType,
311337 destBridgeWitness).Value ;
312338 void *srcObject = getNonNullSrcObject (srcValue, srcType, destType);
313- if (nullptr == swift_dynamicCastUnknownClass (srcObject, targetBridgedClass)) {
339+ // Note: srcObject can be null here in compatibility mode
340+ if (nullptr == srcObject
341+ || nullptr == swift_dynamicCastUnknownClass (srcObject, targetBridgedClass)) {
314342 destFailureType = targetBridgedClass;
315343 return DynamicCastResult::Failure;
316344 }
@@ -422,8 +450,12 @@ tryCastToSwiftClass(
422450 switch (srcType->getKind ()) {
423451 case MetadataKind::Class: // Swift class => Swift class
424452 case MetadataKind::ObjCClassWrapper: { // Obj-C class => Swift class
425- void *object = getNonNullSrcObject (srcValue, srcType, destType);
426- if (auto t = swift_dynamicCastClass (object, destClassType)) {
453+ void *srcObject = getNonNullSrcObject (srcValue, srcType, destType);
454+ // Note: srcObject can be null in compatibility mode.
455+ if (srcObject == nullptr ) {
456+ return DynamicCastResult::Failure;
457+ }
458+ if (auto t = swift_dynamicCastClass (srcObject, destClassType)) {
427459 auto castObject = const_cast <void *>(t);
428460 *(reinterpret_cast <void **>(destLocation)) = castObject;
429461 if (takeOnSuccess) {
@@ -465,6 +497,17 @@ tryCastToObjectiveCClass(
465497 case MetadataKind::ObjCClassWrapper: // Obj-C class => Obj-C class
466498 case MetadataKind::ForeignClass: { // CF class => Obj-C class
467499 auto srcObject = getNonNullSrcObject (srcValue, srcType, destType);
500+ // If object is null, then we're in the compatibility mode.
501+ // Earlier cast logic always succeeded `as!` casts of nil
502+ // class references but failed `as?` and `is`
503+ if (srcObject == nullptr ) {
504+ if (mayDeferChecks) {
505+ *reinterpret_cast <const void **>(destLocation) = nullptr ;
506+ return DynamicCastResult::SuccessViaCopy;
507+ } else {
508+ return DynamicCastResult::Failure;
509+ }
510+ }
468511 auto destObjCClass = destObjCType->Class ;
469512 if (auto resultObject
470513 = swift_dynamicCastObjCClass (srcObject, destObjCClass)) {
@@ -504,6 +547,19 @@ tryCastToForeignClass(
504547 case MetadataKind::ObjCClassWrapper: // Obj-C class => CF class
505548 case MetadataKind::ForeignClass: { // CF class => CF class
506549 auto srcObject = getNonNullSrcObject (srcValue, srcType, destType);
550+ // If srcObject is null, then we're in compatibility mode.
551+ // Earlier cast logic always succeeded `as!` casts of nil
552+ // class references. Yes, this is very dangerous, which
553+ // is why we no longer permit it.
554+ if (srcObject == nullptr ) {
555+ if (mayDeferChecks) {
556+ *reinterpret_cast <const void **>(destLocation) = nullptr ;
557+ return DynamicCastResult::SuccessViaCopy;
558+ } else {
559+ // `as?` and `is` checks always fail on nil sources
560+ return DynamicCastResult::Failure;
561+ }
562+ }
507563 if (auto resultObject
508564 = swift_dynamicCastForeignClass (srcObject, destClassType)) {
509565 *reinterpret_cast <const void **>(destLocation) = resultObject;
@@ -679,6 +735,10 @@ struct ObjCBridgeMemo {
679735 // Use the dynamic ISA type of the object always (Note that this
680736 // also implicitly gives us the ObjC type for a CF object.)
681737 void *srcObject = getNonNullSrcObject (srcValue, srcType, destType);
738+ // If srcObject is null, then we're in backwards compatibility mode.
739+ if (srcObject == nullptr ) {
740+ return DynamicCastResult::Failure;
741+ }
682742 Class srcObjCType = object_getClass ((id)srcObject);
683743 // Fail if the ObjC object is not a subclass of the bridge class.
684744 while (srcObjCType != targetBridgedObjCClass) {
@@ -1402,15 +1462,26 @@ tryCastToClassExistential(
14021462 case MetadataKind::ObjCClassWrapper:
14031463 case MetadataKind::Class:
14041464 case MetadataKind::ForeignClass: {
1405- auto object = getNonNullSrcObject (srcValue, srcType, destType);
1465+ auto srcObject = getNonNullSrcObject (srcValue, srcType, destType);
1466+ // If srcObject is null, then we're in compatibility mode.
1467+ // Earlier cast logic always succeeded `as!` casts of nil
1468+ // class references:
1469+ if (srcObject == nullptr ) {
1470+ if (mayDeferChecks) {
1471+ *reinterpret_cast <const void **>(destLocation) = nullptr ;
1472+ return DynamicCastResult::SuccessViaCopy;
1473+ } else {
1474+ return DynamicCastResult::Failure;
1475+ }
1476+ }
14061477 if (_conformsToProtocols (srcValue, srcType,
14071478 destExistentialType,
14081479 destExistentialLocation->getWitnessTables ())) {
1409- destExistentialLocation->Value = object ;
1480+ destExistentialLocation->Value = srcObject ;
14101481 if (takeOnSuccess) {
14111482 return DynamicCastResult::SuccessViaTake;
14121483 } else {
1413- swift_unknownObjectRetain (object );
1484+ swift_unknownObjectRetain (srcObject );
14141485 return DynamicCastResult::SuccessViaCopy;
14151486 }
14161487 }
@@ -1672,8 +1743,14 @@ tryCastToMetatype(
16721743 case MetadataKind::ObjCClassWrapper: {
16731744#if SWIFT_OBJC_INTEROP
16741745 // Some classes are actually metatypes
1675- void *object = getNonNullSrcObject (srcValue, srcType, destType);
1676- if (auto metatype = _getUnknownClassAsMetatype (object)) {
1746+ void *srcObject = getNonNullSrcObject (srcValue, srcType, destType);
1747+ // If object is null, then we're in compatibility mode.
1748+ // Continuing here at all is dangerous, but that's what the
1749+ // pre-Swift-5.4 casting logic did.
1750+ if (srcObject == nullptr ) {
1751+ return DynamicCastResult::Failure;
1752+ }
1753+ if (auto metatype = _getUnknownClassAsMetatype (srcObject)) {
16771754 auto srcInnerValue = reinterpret_cast <OpaqueValue *>(&metatype);
16781755 auto srcInnerType = swift_getMetatypeMetadata (metatype);
16791756 return tryCast (destLocation, destType, srcInnerValue, srcInnerType,
@@ -1783,6 +1860,12 @@ tryCastToExistentialMetatype(
17831860 // Some Obj-C classes are actually metatypes
17841861#if SWIFT_OBJC_INTEROP
17851862 void *srcObject = getNonNullSrcObject (srcValue, srcType, destType);
1863+ // If srcObject is null, we're in compatibility mode.
1864+ // Continuing here at al is dangerous, but that's what the
1865+ // pre-Swift-5.4 casting logic did.
1866+ if (srcObject == nullptr ) {
1867+ return DynamicCastResult::Failure;
1868+ }
17861869 if (auto metatype = _getUnknownClassAsMetatype (srcObject)) {
17871870 return _dynamicCastMetatypeToExistentialMetatype (
17881871 destLocation,
@@ -1947,14 +2030,19 @@ tryCast(
19472030 || srcKind == MetadataKind::ObjCClassWrapper
19482031 || srcKind == MetadataKind::ForeignClass) {
19492032 auto srcObject = getNonNullSrcObject (srcValue, srcType, destType);
1950- auto srcDynamicType = swift_getObjectType (srcObject);
1951- if (srcDynamicType != srcType) {
1952- srcFailureType = srcDynamicType;
1953- auto castResult = tryCastToDestType (
1954- destLocation, destType, srcValue, srcDynamicType,
1955- destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks);
1956- if (isSuccess (castResult)) {
1957- return castResult;
2033+ // If srcObject is null, we're in compability mode.
2034+ // But we can't lookup dynamic type for a null class reference, so
2035+ // just skip this in that case.
2036+ if (srcObject != nullptr ) {
2037+ auto srcDynamicType = swift_getObjectType (srcObject);
2038+ if (srcDynamicType != srcType) {
2039+ srcFailureType = srcDynamicType;
2040+ auto castResult = tryCastToDestType (
2041+ destLocation, destType, srcValue, srcDynamicType,
2042+ destFailureType, srcFailureType, takeOnSuccess, mayDeferChecks);
2043+ if (isSuccess (castResult)) {
2044+ return castResult;
2045+ }
19582046 }
19592047 }
19602048 }
0 commit comments