Uploaded image for project: 'Swift'
  1. Swift
  2. SR-8622

Nonnull Objective-C property that falsely returns nil causes inconsistent Swift behavior



    • Type: Bug
    • Status: Open
    • Priority: Medium
    • Resolution: Unresolved
    • Component/s: Compiler
    • Labels:
    • Environment:

      Swift 4.2, Xcode 10 beta 4, macOS 10.13.16. May be present in other versions.


      This looks like it might be related to SR-7300, but I don't see any explicit NSNull-related behavior so it could be different.

      If an Objective-C API that's declared nonnull does in fact return nil, then the behavior when called from Swift is inconsistent:

      • Assigning such a value to a variable produces a non-optional value of that type whose underlying pointer value is 0x0 (when viewed in the debugger)
      • Calling a method or getting/setting a property with that variable as the receiver does not trap, but instead exhibits Objective-C-like functionality (silently succeeding, returning bit pattern 0 in non-void cases)
      • Trying to print the value itself, however, crashes the program/interpreter

      This is of course a case where the API implementation is violating its own contract, but I would expect the first assignment above to be where Swift would trap, since there's no obvious way to guard against the unexpected nil result.

      Repro case:

      import Foundation

      // Despite its contract, this returns nil if there is no bundle ID
      // (e.g., in a command line app without an embedded Info.plist)
      let center = NSUserNotificationCenter.default
      print("got something for center")

      let delegate = center.delegate
      print("was able to call a getter, its value was (delegate)")

      center.delegate = nil
      print("was able to call a setter")

      print("now we'll try to print the value itself")
      print("this won't print because it crashed")

      When compiled and executed, the following output is produced:

      got something for center
      was able to call a getter, its value was nil
      was able to call a setter
      now we'll try to print the value itself
      [1] 58342 segmentation fault ./trap


      When executed under the interpreter, the backtrace gives a little more insight:


      0 swift 0x0000000104ebbb8a PrintStackTraceSignalHandler(void*) + 42
      1 swift 0x0000000104ebb32e SignalHandler(int) + 302
      2 libsystem_platform.dylib 0x00007fff576fbf5a _sigtramp + 26
      3 libsystem_platform.dylib 0x00007fe9b17a9238 _sigtramp + 1510658808
      4 libswiftCore.dylib 0x000000010ae71f25 findDynamicValueAndType(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*&, swift::TargetMetadata<swift::InProcess> const*&, bool&, bool, bool) + 245
      5 libswiftCore.dylib 0x000000010ae76687 _dynamicCastToExistential(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetExistentialTypeMetadata<swift::InProcess> const*, swift::DynamicCastFlags) + 135
      6 libswiftCore.dylib 0x000000010ac41c4a $Ss15_print_unlockedyyx_q_zts16TextOutputStreamR_r0_lF + 394
      7 libswiftCore.dylib 0x000000010ae1931a $Ss6_print_9separator10terminator2toySayypG_S2Sxzts16TextOutputStreamRzlFs7_StdoutV_Tg5Tf4nxxn_nTm + 250
      8 libswiftCore.dylib 0x000000010ae19c1f $Ss5print_9separator10terminatoryypd_S2StFTf4nxx_nTm + 271
      9 libswiftCore.dylib 0x000000010acedba0 $Ss5print_9separator10terminatoryypd_S2StF + 16
      10 libswiftCore.dylib 0x000000010882856d $Ss5print_9separator10terminatoryypd_S2StF + 4256410077
      11 swift 0x0000000101efa03d llvm::MCJIT::runFunction(llvm::Function*, llvm::ArrayRef<llvm::GenericValue>) + 365
      12 swift 0x0000000101f00a3c llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*, std::_1::vector<std::1::basic_string<char, std::1::char_traits<char>, std::1::allocator<char> >, std::1::allocator<std::1::basic_string<char, std::1::char_traits<char>, std::_1::allocator<char> > > > const&, char const* const*) + 1004
      13 swift 0x000000010117c593 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 52659
      14 swift 0x000000010116c2e5 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 7733
      15 swift 0x0000000101112155 main + 1349
      16 libdyld.dylib 0x00007fff573ed015 start + 1


      A radar has been filed separately for the NSUserNotificationCenter API's incorrect contract, although since it's deprecated it may not be a high priority fix: https://openradar.appspot.com/43645642


          Issue Links



              Unassigned Unassigned
              allevato Tony Allevato
              1 Vote for this issue
              4 Start watching this issue