|
15 | 15 | //===----------------------------------------------------------------------===//
|
16 | 16 |
|
17 | 17 | #include "swift/Runtime/Bincompat.h"
|
| 18 | +#include <stdint.h> |
| 19 | + |
| 20 | +// If this is an Apple OS, use the Apple binary compatibility rules |
| 21 | +#if __has_include(<mach-o/dyld_priv.h>) |
| 22 | + #include <mach-o/dyld_priv.h> |
| 23 | + #ifndef BINARY_COMPATIBILITY_APPLE |
| 24 | + #define BINARY_COMPATIBILITY_APPLE 1 |
| 25 | + #endif |
| 26 | +#else |
| 27 | + #undef BINARY_COMPATIBILITY_APPLE |
| 28 | +#endif |
18 | 29 |
|
19 | 30 | namespace swift {
|
20 | 31 |
|
21 | 32 | namespace runtime {
|
22 | 33 |
|
23 | 34 | namespace bincompat {
|
24 | 35 |
|
25 |
| -bool workaroundProtocolConformanceReverseIteration() { return false; } |
| 36 | +// Should we mimic the old override behavior when scanning protocol conformance records? |
| 37 | + |
| 38 | +// Old apps expect protocol conformances to override each other in a particular |
| 39 | +// order. Starting with Swift 5.4, that order has changed as a result of |
| 40 | +// significant performance improvements to protocol conformance scanning. If |
| 41 | +// this returns `true`, the protocol conformance scan will do extra work to |
| 42 | +// mimic the old override behavior. |
| 43 | +bool workaroundProtocolConformanceReverseIteration() { |
| 44 | +#if BINARY_COMPATIBILITY_APPLE |
| 45 | + // If this is a newer Apple OS ... |
| 46 | + if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) { |
| 47 | + const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301}; |
| 48 | + // ... but the app was compiled before Spring 2021, use the legacy behavior. |
| 49 | + return !dyld_program_sdk_at_least(spring_2021_os_versions); |
| 50 | + } else { |
| 51 | + return false; // Use new (non-legacy) behavior on old Apple OSes |
| 52 | + } |
| 53 | +#else |
| 54 | + return false; // Never use the legacy behavior on non-Apple OSes |
| 55 | +#endif |
| 56 | +} |
| 57 | + |
| 58 | +// Should the dynamic cast operation crash when it sees |
| 59 | +// a non-nullable Obj-C pointer with a null value? |
| 60 | + |
| 61 | +// Obj-C does not strictly enforce non-nullability in all cases, so it is |
| 62 | +// possible for Obj-C code to pass null pointers into Swift code even when |
| 63 | +// declared non-nullable. Such null pointers can lead to undefined behavior |
| 64 | +// later on. Starting in Swift 5.4, these unexpected null pointers are fatal |
| 65 | +// runtime errors, but this is selectively disabled for old apps. |
| 66 | +bool unexpectedObjCNullWhileCastingIsFatal() { |
| 67 | +#if BINARY_COMPATIBILITY_APPLE |
| 68 | + // If this is a new enough Apple OS ... |
| 69 | + if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) { |
| 70 | + const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301}; |
| 71 | + // ... use strict behavior for apps compiled on or after Spring 2021. |
| 72 | + return dyld_program_sdk_at_least(spring_2021_os_versions); |
| 73 | + } else { |
| 74 | + return false; // Use permissive behavior on old Apple OS |
| 75 | + } |
| 76 | +#else |
| 77 | + return true; // Always use the strict behavior on non-Apple OSes |
| 78 | +#endif |
| 79 | +} |
| 80 | + |
| 81 | +// Should casting a nil optional to another optional |
| 82 | +// use the legacy semantics? |
| 83 | + |
| 84 | +// For consistency, starting with Swift 5.4, casting Optional<Int> to |
| 85 | +// Optional<Optional<Int>> always wraps the source in another layer |
| 86 | +// of Optional. |
| 87 | +// Earlier versions of the Swift runtime did not do this if the source |
| 88 | +// optional was nil. In that case, the outer target optional would be |
| 89 | +// set to nil. |
| 90 | +bool useLegacyOptionalNilInjection() { |
| 91 | +#if BINARY_COMPATIBILITY_APPLE |
| 92 | + // If this is a new enough Apple OS ... |
| 93 | + if (__builtin_available(macOS 11.3, iOS 14.5, tvOS 14.5, watchOS 7.4, *)) { |
| 94 | + const dyld_build_version_t spring_2021_os_versions = {0xffffffff, 0x007e50301}; |
| 95 | + // It's using Spring 2021 or later SDK, so don't use the legacy behavior. |
| 96 | + return !dyld_program_sdk_at_least(spring_2021_os_versions); |
| 97 | + } else { |
| 98 | + return true; // Use the legacy behavior on old Apple OS |
| 99 | + } |
| 100 | +#else |
| 101 | + return false; // Always use the 5.4 behavior on non-Apple OSes |
| 102 | +#endif |
| 103 | +} |
26 | 104 |
|
27 | 105 | } // namespace bincompat
|
28 | 106 |
|
|
0 commit comments