Skip to content

SIL verification failure when evaluating $0 in certain closures. #66312

Closed
@fibrechannelscsi

Description

@fibrechannelscsi

Description
There is a SIL verification failure when attempting to build the following project in Release mode.
Much like this issue: #64642
it requires an internal Package to reproduce. If all the code is present in a single file, then the code will compile successfully.

The error message provided is:
SIL verification failed: stack dealloc with empty stack: !state.Stack.empty()
More details are shown below.

Steps to reproduce
This reproducer requires four files: two Package.swift files (one is for an internal package), and two regular Swift source files.
The directory tree looks like this:

./Package.swift
./Sources/InternalPackage/Package.swift
./Sources/InternalPackage/Sources/InternalPackage/U.swift
./Sources/ReproducerServer/A.swift

Listing for ./Package.swift:

// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
    name: "Reproducer",
    platforms: [.macOS(.v12),],
    products: [
        .library(
            name: "Reproducer",
            targets: ["ReproducerServer"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/vapor/jwt.git", "4.0.0" ..< "5.0.0"),
        .package(url: "https://github.com/vapor/vapor.git", "4.0.0" ..< "5.0.0"),
        .package(url: "https://github.com/vapor/leaf-kit.git", "1.0.0" ..< "2.0.0"),
        .package(url: "https://github.com/vapor/leaf.git", "4.0.0" ..< "5.0.0"),
        .package(url: "https://github.com/apple/swift-nio.git", "2.0.0" ..< "3.0.0"),
        .package(url: "https://github.com/mczachurski/Swiftgger.git", "1.0.0" ..< "2.0.0"),
        .package(name: "InternalPackage", path: "./Sources/InternalPackage"),
    ],
    targets: [
        .target(
            name: "ReproducerServer",
            dependencies: [
                .product(name: "JWT", package: "jwt"),
                .product(name: "Vapor", package: "vapor"),
                .product(name: "InternalPackage", package: "InternalPackage"),
                .product(name: "Leaf", package: "leaf"),
                .product(name: "LeafKit", package: "leaf-kit"),
                .product(name: "NIOCore", package: "swift-nio"),
                .product(name: "Swiftgger", package: "Swiftgger"),
            ],
            swiftSettings: [.unsafeFlags([], .when(platforms: [.macOS, .linux], configuration: .release))]
        )
    ]
)

Listing for ./Sources/InternalPackage/Package.swift:

// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
    name: "InternalPackage",
    platforms: [
        .macOS(.v12),
        .iOS(.v15),
    ],
    products: [
        .library(
            name: "InternalPackage",
            targets: ["InternalPackage"]
        )
    ],
    dependencies: [
        .package(
            url: "https://github.com/apple/swift-collections.git",
            from: "1.0.3"
        ),
        .package(url: "https://github.com/apple/swift-log.git", from: "1.4.2"),
        .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.13.1"),
        .package(url: "https://github.com/vapor/async-kit.git", from: "1.14.0"),
        .package(url: "https://github.com/vapor/sql-kit.git", from: "3.18.0"),
        .package(url: "https://github.com/apple/swift-nio.git", from: "2.38.0"),

    ],
    targets: [
        .target(
            name: "InternalPackage",
            dependencies: [
                .product(name: "Collections", package: "swift-collections"),
                .product(name: "AsyncKit", package: "async-kit"),
                .product(name: "SQLKit", package: "sql-kit"),
                .product(name: "NIO", package: "swift-nio")
            ]
        )
    ]
)

Listing for ./Sources/InternalPackage/Sources/InternalPackage/U.swift:

import Collections; import Foundation; import NIO; import SQLKit; import AsyncKit
public class S {
    public let e: EventLoopGroup; let d: any D
    public init(d: any D, e: EventLoopGroup) {self.d = d; self.e = e}
    public func w<T>(_ closure: @escaping ((S) -> EventLoopFuture<T>)) -> EventLoopFuture<T> {return self.e.next().makePromise(of: T.self).futureResult}
    public func s() -> SQLDatabase {d.s()}
}
public protocol D {func s() -> SQLDatabase}

Listing for ./Sources/ReproducerServer/A.swift:

import Foundation; import SQLKit; import NIO; import InternalPackage
public extension Q {
    static var v: Q {
        Q(
            r: { u in
                u.w { u in
                    let u = u.s()
                    return u.select().columns("*").from(T.v.A).all(decoding: b.A.self).tryFlatMap { h in try h.map {try u.insert(into: "s").model($0).run()}.flatten(on: MultiThreadedEventLoopGroup(numberOfThreads: 1).next())}
                }
            }
        )
    }
}
public enum T {enum v {static let A = "A"}}
protocol I {var ID: UUID { get }}
enum b {struct A: Codable, Hashable, I {let ID: UUID}   }
public struct Q{public let r: (S) -> EventLoopFuture<Void>}

Expected behavior
The program should compile successfully.

Environment

  • Swift compiler version info: Toolchains 2023-05-09a and 2023-05-31a exhibit this issue.
  • Xcode version info: 14.2
  • Deployment target: M1

Additional context

The full SIL-related error is as follows:

SIL verification failed: stack dealloc with empty stack: !state.Stack.empty()
Verifying instruction:
     %21 = alloc_ref [stack] [tail_elems $b.A * %6 : $Builtin.Word] $_ContiguousArrayStorage<b.A> // users: %51, %50, %40, %92, %91, %81, %80, %39, %31, %22, %53, %94, %93, %52
->   dealloc_stack_ref %21 : $_ContiguousArrayStorage<b.A> // id: %94
In function:
// closure #1 in closure #1 in closure #1 in closure #1 in static Q.v.getter
sil private @$s16ReproducerServer1QV1vACvgZ7NIOCore15EventLoopFutureCyytG15InternalPackage1SCcfU_AhKcfU_AHSayAA1bO1AVGKcfU_AhOKXEfU_ : $@convention(thin) @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @in_guaranteed any SQLDatabase) -> (@out τ_0_1, @error any Error) for <b.A, EventLoopFuture<()>> {
[%0: noescape **, write v**]
[%1: read v**, copy v**]
[%2: read v**, copy v**]
[global: read,write,copy,destroy,allocate,deinit_barrier]
// %0 "$return_value"                             // user: %76
// %1 "$0"                                        // users: %30, %3
// %2 "u"                                         // users: %5, %4
bb0(%0 : $*EventLoopFuture<()>, %1 : $*b.A, %2 : @closureCapture $*any SQLDatabase):
  debug_value %1 : $*b.A, let, name "$0", argno 1, implicit, expr op_deref // id: %3
  debug_value %2 : $*any SQLDatabase, let, name "u", argno 3, expr op_deref // id: %4
  %5 = open_existential_addr immutable_access %2 : $*any SQLDatabase to $*@opened("478FA0AE-01A2-11EE-86A3-FE6D09CC5DCC", any SQLDatabase) Self // users: %16, %16
  %6 = integer_literal $Builtin.Word, 1           // user: %21
  %7 = integer_literal $Builtin.Int64, 1          // user: %20
  %8 = integer_literal $Builtin.Int64, 115        // user: %9
  %9 = struct $UInt64 (%8 : $Builtin.Int64)       // user: %12
  %10 = integer_literal $Builtin.Int64, -2233785415175766016 // user: %11
  %11 = value_to_bridge_object %10 : $Builtin.Int64 // user: %12
  %12 = struct $_StringObject (%9 : $UInt64, %11 : $Builtin.BridgeObject) // user: %13
  %13 = struct $_StringGuts (%12 : $_StringObject) // user: %14
  %14 = struct $String (%13 : $_StringGuts)       // user: %16
  // function_ref SQLDatabase.insert(into:)
  %15 = function_ref @$s6SQLKit11SQLDatabasePAAE6insert4intoAA16SQLInsertBuilderCSS_tF : $@convention(method) <τ_0_0 where τ_0_0 : SQLDatabase> (@guaranteed String, @in_guaranteed τ_0_0) -> @owned SQLInsertBuilder // user: %16
  %16 = apply %15<@opened("478FA0AE-01A2-11EE-86A3-FE6D09CC5DCC", any SQLDatabase) Self>(%14, %5) : $@convention(method) <τ_0_0 where τ_0_0 : SQLDatabase> (@guaranteed String, @in_guaranteed τ_0_0) -> @owned SQLInsertBuilder // type-defs: %5; users: %95, %54, %37
  %17 = enum $Optional<String>, #Optional.none!enumelt // user: %37
  %18 = enum $SQLQueryEncoder.KeyEncodingStrategy, #SQLQueryEncoder.KeyEncodingStrategy.useDefaultKeys!enumelt // user: %37
  %19 = enum $SQLQueryEncoder.NilEncodingStrategy, #SQLQueryEncoder.NilEncodingStrategy.`default`!enumelt // user: %37
  %20 = struct $Int (%7 : $Builtin.Int64)         // user: %25
  %21 = alloc_ref [stack] [tail_elems $b.A * %6 : $Builtin.Word] $_ContiguousArrayStorage<b.A> // users: %51, %50, %40, %92, %91, %81, %80, %39, %31, %22, %53, %94, %93, %52
  %22 = upcast %21 : $_ContiguousArrayStorage<b.A> to $__ContiguousArrayStorageBase // users: %29, %27
  %23 = integer_literal $Builtin.Int64, 2         // user: %24
  %24 = struct $UInt (%23 : $Builtin.Int64)       // user: %25
  %25 = struct $_SwiftArrayBodyStorage (%20 : $Int, %24 : $UInt) // user: %26
  %26 = struct $_ArrayBody (%25 : $_SwiftArrayBodyStorage) // user: %28
  %27 = ref_element_addr %22 : $__ContiguousArrayStorageBase, #__ContiguousArrayStorageBase.countAndCapacity // users: %83, %42, %28
  store %26 to %27 : $*_ArrayBody                 // id: %28
  %29 = ref_tail_addr %22 : $__ContiguousArrayStorageBase, $b.A // user: %30
  copy_addr %1 to [init] %29 : $*b.A              // id: %30
  %31 = end_cow_mutation %21 : $_ContiguousArrayStorage<b.A> // user: %32
  %32 = unchecked_ref_cast %31 : $_ContiguousArrayStorage<b.A> to $Builtin.BridgeObject // user: %33
  %33 = struct $_BridgeStorage<__ContiguousArrayStorageBase> (%32 : $Builtin.BridgeObject) // user: %34
  %34 = struct $_ArrayBuffer<b.A> (%33 : $_BridgeStorage<__ContiguousArrayStorageBase>) // user: %35
  %35 = struct $Array<b.A> (%34 : $_ArrayBuffer<b.A>) // user: %37
  // function_ref SQLInsertBuilder.models<A>(_:prefix:keyEncodingStrategy:nilEncodingStrategy:)
  %36 = function_ref @$s6SQLKit16SQLInsertBuilderC6models_6prefix19keyEncodingStrategy03nilgH0ACXDSayxG_SSSgAA15SQLQueryEncoderV03KeygH0OAK03NilgH0OtKSERzlF : $@convention(method) <τ_0_0 where τ_0_0 : Encodable> (@guaranteed Array<τ_0_0>, @guaranteed Optional<String>, @guaranteed SQLQueryEncoder.KeyEncodingStrategy, SQLQueryEncoder.NilEncodingStrategy, @guaranteed SQLInsertBuilder) -> (@owned SQLInsertBuilder, @error any Error) // user: %37
  try_apply %36<b.A>(%35, %17, %18, %19, %16) : $@convention(method) <τ_0_0 where τ_0_0 : Encodable> (@guaranteed Array<τ_0_0>, @guaranteed Optional<String>, @guaranteed SQLQueryEncoder.KeyEncodingStrategy, SQLQueryEncoder.NilEncodingStrategy, @guaranteed SQLInsertBuilder) -> (@owned SQLInsertBuilder, @error any Error), normal bb1, error bb2 // id: %37

// %38                                            // users: %74, %56, %62
bb1(%38 : $SQLInsertBuilder):                     // Preds: bb0
  set_deallocating %21 : $_ContiguousArrayStorage<b.A> // id: %39
  %40 = ref_tail_addr %21 : $_ContiguousArrayStorage<b.A>, $b.A // user: %41
  %41 = address_to_pointer %40 : $*b.A to $Builtin.RawPointer // user: %49
  %42 = struct_element_addr %27 : $*_ArrayBody, #_ArrayBody._storage // user: %43
  %43 = struct_element_addr %42 : $*_SwiftArrayBodyStorage, #_SwiftArrayBodyStorage.count // user: %44
  %44 = struct_element_addr %43 : $*Int, #Int._value // user: %45
  %45 = load %44 : $*Builtin.Int64                // user: %46
  %46 = builtin "assumeNonNegative_Int64"(%45 : $Builtin.Int64) : $Builtin.Int64 // user: %48
  %47 = metatype $@thick b.A.Type                 // user: %49
  %48 = builtin "truncOrBitCast_Int64_Word"(%46 : $Builtin.Int64) : $Builtin.Word // user: %49
  %49 = builtin "destroyArray"<b.A>(%47 : $@thick b.A.Type, %41 : $Builtin.RawPointer, %48 : $Builtin.Word) : $()
  fix_lifetime %21 : $_ContiguousArrayStorage<b.A> // id: %50
  dealloc_ref %21 : $_ContiguousArrayStorage<b.A> // id: %51
  dealloc_stack_ref %21 : $_ContiguousArrayStorage<b.A> // id: %52
  dealloc_stack_ref %21 : $_ContiguousArrayStorage<b.A> // id: %53
  strong_release %16 : $SQLInsertBuilder          // id: %54
  %55 = alloc_stack $any SQLDatabase              // users: %75, %73, %60, %58
  %56 = ref_element_addr %38 : $SQLInsertBuilder, #SQLInsertBuilder.database // user: %57
  %57 = begin_access [read] [dynamic] [no_nested_conflict] %56 : $*any SQLDatabase // users: %59, %58
  copy_addr %57 to [init] %55 : $*any SQLDatabase // id: %58
  end_access %57 : $*any SQLDatabase              // id: %59
  %60 = open_existential_addr immutable_access %55 : $*any SQLDatabase to $*@opened("47A70E4C-01A2-11EE-86A3-FE6D09CC5DCC", any SQLDatabase) Self // users: %70, %70, %69
  %61 = alloc_stack $any SQLExpression            // users: %72, %71, %70, %64
  %62 = ref_element_addr %38 : $SQLInsertBuilder, #SQLInsertBuilder.insert // user: %63
  %63 = begin_access [read] [dynamic] [no_nested_conflict] %62 : $*SQLInsert // users: %66, %65
  %64 = init_existential_addr %61 : $*any SQLExpression, $SQLInsert // user: %65
  copy_addr %63 to [init] %64 : $*SQLInsert       // id: %65
  end_access %63 : $*SQLInsert                    // id: %66
  // function_ref closure #1 in SQLQueryBuilder.run()
  %67 = function_ref @$s6SQLKit15SQLQueryBuilderPAAE3run7NIOCore15EventLoopFutureCyytGyFyAA6SQLRow_pcfU_ : $@convention(thin) (@in_guaranteed any SQLRow) -> () // user: %68
  %68 = thin_to_thick_function %67 : $@convention(thin) (@in_guaranteed any SQLRow) -> () to $@callee_guaranteed (@in_guaranteed any SQLRow) -> () // user: %70
  %69 = witness_method $@opened("47A70E4C-01A2-11EE-86A3-FE6D09CC5DCC", any SQLDatabase) Self, #SQLDatabase.execute : <Self where Self : SQLKit.SQLDatabase> (Self) -> (any SQLKit.SQLExpression, @escaping (any SQLKit.SQLRow) -> ()) -> NIOCore.EventLoopFuture<()>, %60 : $*@opened("47A70E4C-01A2-11EE-86A3-FE6D09CC5DCC", any SQLDatabase) Self : $@convention(witness_method: SQLDatabase) <τ_0_0 where τ_0_0 : SQLDatabase> (@in_guaranteed any SQLExpression, @guaranteed @callee_guaranteed (@in_guaranteed any SQLRow) -> (), @in_guaranteed τ_0_0) -> @owned EventLoopFuture<()> // type-defs: %60; user: %70
  %70 = apply %69<@opened("47A70E4C-01A2-11EE-86A3-FE6D09CC5DCC", any SQLDatabase) Self>(%61, %68, %60) : $@convention(witness_method: SQLDatabase) <τ_0_0 where τ_0_0 : SQLDatabase> (@in_guaranteed any SQLExpression, @guaranteed @callee_guaranteed (@in_guaranteed any SQLRow) -> (), @in_guaranteed τ_0_0) -> @owned EventLoopFuture<()> // type-defs: %60; user: %76
  destroy_addr %61 : $*any SQLExpression          // id: %71
  dealloc_stack %61 : $*any SQLExpression         // id: %72
  destroy_addr %55 : $*any SQLDatabase            // id: %73
  strong_release %38 : $SQLInsertBuilder          // id: %74
  dealloc_stack %55 : $*any SQLDatabase           // id: %75
  store %70 to %0 : $*EventLoopFuture<()>         // id: %76
  %77 = tuple ()                                  // user: %78
  return %77 : $()                                // id: %78

// %79                                            // user: %96
bb2(%79 : $any Error):                            // Preds: bb0
  set_deallocating %21 : $_ContiguousArrayStorage<b.A> // id: %80
  %81 = ref_tail_addr %21 : $_ContiguousArrayStorage<b.A>, $b.A // user: %82
  %82 = address_to_pointer %81 : $*b.A to $Builtin.RawPointer // user: %90
  %83 = struct_element_addr %27 : $*_ArrayBody, #_ArrayBody._storage // user: %84
  %84 = struct_element_addr %83 : $*_SwiftArrayBodyStorage, #_SwiftArrayBodyStorage.count // user: %85
  %85 = struct_element_addr %84 : $*Int, #Int._value // user: %86
  %86 = load %85 : $*Builtin.Int64                // user: %87
  %87 = builtin "assumeNonNegative_Int64"(%86 : $Builtin.Int64) : $Builtin.Int64 // user: %89
  %88 = metatype $@thick b.A.Type                 // user: %90
  %89 = builtin "truncOrBitCast_Int64_Word"(%87 : $Builtin.Int64) : $Builtin.Word // user: %90
  %90 = builtin "destroyArray"<b.A>(%88 : $@thick b.A.Type, %82 : $Builtin.RawPointer, %89 : $Builtin.Word) : $()
  fix_lifetime %21 : $_ContiguousArrayStorage<b.A> // id: %91
  dealloc_ref %21 : $_ContiguousArrayStorage<b.A> // id: %92
  dealloc_stack_ref %21 : $_ContiguousArrayStorage<b.A> // id: %93
  dealloc_stack_ref %21 : $_ContiguousArrayStorage<b.A> // id: %94
  strong_release %16 : $SQLInsertBuilder          // id: %95
  throw %79 : $any Error                          // id: %96
} // end sil function '$s16ReproducerServer1QV1vACvgZ7NIOCore15EventLoopFutureCyytG15InternalPackage1SCcfU_AhKcfU_AHSayAA1bO1AVGKcfU_AhOKXEfU_'

Stack trace:

1.	Apple Swift version 5.9-dev (LLVM 5c02e17d873dc13, Swift 049c367900f9b51)
2.	Compiling with the current language version
3.	While verifying SIL function "@$s16ReproducerServer1QV1vACvgZ7NIOCore15EventLoopFutureCyytG15InternalPackage1SCcfU_AhKcfU_AHSayAA1bO1AVGKcfU_AhOKXEfU_".
 for expression at [/Users/user/playground/64642/Sources/ReproducerServer/Auth.swift:8:116 - line:8:156] RangeText="{try u.insert(into: "s").model($0).run()"
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x0000000109098f44 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x00000001090982e8 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x0000000109099584 SignalHandler(int) + 304
3  libsystem_platform.dylib 0x000000018b2c2a84 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000018b293c28 pthread_kill + 288
5  libsystem_c.dylib        0x000000018b1a1ae8 abort + 180
6  swift-frontend           0x0000000105161118 (anonymous namespace)::SILVerifier::_require(bool, llvm::Twine const&, std::__1::function<void ()> const&) + 1476
7  swift-frontend           0x00000001051628d0 (anonymous namespace)::SILVerifier::visitSILFunction(swift::SILFunction*) + 4440
8  swift-frontend           0x000000010515d6e0 swift::SILFunction::verify(swift::SILPassManager*, bool, bool, bool) const + 204
9  swift-frontend           0x00000001051605a4 swift::SILModule::verify(swift::SILPassManager*, bool, bool) const + 184
10 swift-frontend           0x00000001051604b4 swift::SILModule::verify(bool, bool) const + 88
11 swift-frontend           0x0000000104589678 swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 616
12 swift-frontend           0x00000001043f77d4 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 788
13 swift-frontend           0x00000001043f7118 swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1116
14 swift-frontend           0x0000000104406018 withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 160
15 swift-frontend           0x00000001043f9940 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 620
16 swift-frontend           0x00000001043f894c swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 2428
17 swift-frontend           0x000000010425c1ac swift::mainEntry(int, char const**) + 2144
18 dyld                     0x000000018af3bf28 start + 2236

Note that the above was built via Xcode.
If I attempt to perform a command-line build using swift build -c release with the 2023-05-30a toolchain, I get a different error message:
Assertion failed: (CastInst::castIsValid(opc, C, Ty) && "Invalid constantexpr cast!"), function getCast, file Constants.cpp, line 1951.
when attempting to build files identical to, or in the same directory as:
Compiling NIOSSL ByteBufferBIO.swift.
This will be reported as a separate issue.

Metadata

Metadata

Assignees

Labels

SILassertion failureBug → crash: An assertion failurebugA deviation from expected or documented behavior. Also: expected but undesirable behavior.closuresFeature: closurescompilerThe Swift compiler itselfcrashBug: A crash, i.e., an abnormal termination of softwareexpressionsFeature: expressionsverifier

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions