Debug Compiler Directive in Swift Package causes runtime crash

Summary

I'm facing a crash when using #if DEBUG directives in a Swift Package that is linked (but not embedded) to a release build of a static library. If the static library and the Package's library target are then embedded into an App a runtime crash occurs.

If the App target is also build in release or my static library compiles in debug, the crash doesn't occur. Similarly, when I remove all #if DEBUG directives from the public code in the Swift Package, the App runs fine (in debug, whereas the library can stay in release).

Reproduction

I have created a sample project on GitHub that provides a setup to reproduce this issue.

The SampleProject consists of:

  • an App Target called SampleApp
  • a Framework Target called SampleFramework
  • a local Swift Package called SamplePackage

The Dependency Graph looks like this:

SampleApp
└── embeds SampleFramework
    └── links to SamplePackage
└── embeds SamplePackage

If we compile SampleFramework in release configuration and add the binary from the build directory to SampleApp, the following crash be witnessed:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0xfffffffffffffff0
Exception Codes: 0x0000000000000001, 0xfffffffffffffff0
VM Region Info: 0xfffffffffffffff0 is not in any region.  Bytes after previous region: 18446638520056414193  
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      MALLOC_NANO (reserved)   600018000000-600020000000 [128.0M] rw-/rwx SM=NUL  ...(unallocated)
--->  
      UNUSED SPACE AT END
Termination Reason: SIGNAL 11 Segmentation fault: 11
Terminating Process: exc handler [50054]

Triggered by Thread:  0

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libswiftCore.dylib            	       0x18bf8620c _swift_release_dealloc + 16
1   libswiftCore.dylib            	       0x18bf86df4 bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1>>::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 128
2   SampleApp                     	       0x100c4de3c outlined destroy of SampleView + 36
3   SampleApp                     	       0x100c4da60 closure #1 in SampleAppApp.body.getter + 108 (SampleApp.swift:15)
4   SwiftUI                       	       0x105cd1b6c 0x1050d4000 + 12573548
5   SampleApp                     	       0x100c4d900 SampleAppApp.body.getter + 144 (SampleApp.swift:14)
6   SampleApp                     	       0x100c4dd98 protocol witness for App.body.getter in conformance SampleAppApp + 12

Questions

This crash raises the following questions for me and I haven't been able to find any answers?

  • Should Compiler Directives like #if DEBUG not be distributed in the public code of a Swift Package and are known to cause crashes when linked to binary frameworks?
  • What kind of references to a Swift Package dependency are compiled into a static library by Xcode, when the Package is only added via Target Dependencies, but not to Frameworks, Libraries and Embedded Content?

The crash looks to me like the static library, when compiled in release configuration always assumes its dependency (in this case the Swift Package) to be compiled and linked in the same configuration. When the App integrates both, but compiles the Swift Package's code in debug the static library doesn't seem to like that. But this can't be right?