Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fibrechannelscsi opened this issue Jun 3, 2023 · 8 comments · Fixed by #66800
Closed

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

fibrechannelscsi opened this issue Jun 3, 2023 · 8 comments · Fixed by #66800
Assignees
Labels
assertion failure Bug → crash: An assertion failure bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. closures Feature: closures compiler The Swift compiler itself crash Bug: A crash, i.e., an abnormal termination of software expressions Feature: expressions SIL verifier

Comments

@fibrechannelscsi
Copy link
Contributor

fibrechannelscsi commented Jun 3, 2023

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.

@fibrechannelscsi fibrechannelscsi added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels labels Jun 3, 2023
@fibrechannelscsi fibrechannelscsi changed the title SIL verification failure when evaluating $0 passed into certain closures. SIL verification failure when evaluating $0 in certain closures. Jun 3, 2023
@jkshtj
Copy link
Contributor

jkshtj commented Jun 20, 2023

The error seems to be originating in the SILVerifier, on this line specifically, where the SILVerifier calls the verifyFlowSensitiveRules function.

One of the things that the function does is ensure stack allocations and deallocations have a one to one mapping and it seems like the above generated SIL is not disciplined in that aspect.

Details regarding what went wrong, where it went wrong and steps to reproduce are included below.

@jkshtj
Copy link
Contributor

jkshtj commented Jun 20, 2023

Steps to determine the location of the compilation bug

  1. Run swift build -c release -vvv from package root. The build should fail and should show you the swiftc command that failed.
  2. Here is a minimal working version of the failing swiftc command. I have also added arguments that help us bisect on SIL optimizer pass counts to identify optimizer bugs.
<WORKSPACE_ROOT>/build/Ninja-RelWithDebInfoAssert/swift-macosx-arm64/bin/swiftc \
# Emits SIL generated after the high-level optimization passes
# This is also where the SIL verification is failing in the MRP above.
-emit-sil \
-O \
# The source file in the package that is failing to compile. 
Sources/ReproducerServer/A.swift \
-sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk \
-I /Users/kshitij/workspace/66312/.build/arm64-apple-macosx/release \
-I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib \
-F /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks \
-Xcc -I -Xcc /Users/kshitij/workspace/66312/.build/checkouts/swift-atomics/Sources/_AtomicsShims/include \
# Tells swiftc to run at most 13669 transformations (and 10 subtransformations) on
# the SIL (via optimization passes). This magic number was obtained via binary searching
# through the optimization passes and stopping on optimization pass number `n` such that
# the `n-1` optimization pass wasn't causing SIL verification issues.
-Xllvm -sil-opt-pass-count=13669.10 \
# Prints the name of the last optimization stage/pass we were in
# before the verification issue happened.
-Xllvm -sil-print-last \

@tbkka
Copy link
Contributor

tbkka commented Jun 20, 2023

CC: @nate-chandler

@jkshtj
Copy link
Contributor

jkshtj commented Jun 20, 2023

The above command should generate a stack trace and the full SIL for the associated function, like in the MRP. Additionally, it should also generate the before and after versions of the SIL, around optimization pass number 13699 (as specified in the command above).

The before and after versions of the SIL are pasted below.

Before

  *** SIL function before  #13668, stage HighLevel,Function+EarlyLoopOpt, pass: SILCombine (sil-combine), Function: $s6SQLKit16SQLInsertBuilderC5model_6prefix19keyEncodingStrategy03nilgH0ACXDx_SSSgAA15SQLQueryEncoderV03KeygH0OAJ03NilgH0OtKSERzlF1A1bOAOV_Tg5
  *** sub-pass 9 for   %9 = alloc_ref_dynamic [stack] [tail_elems $b.A * %5 : $Builtin.Word] %8 : $@thick _ContiguousArrayStorage<b.A>.Type, $_ContiguousArrayStorage<b.A> // users: %34, %27, %12
// specialized SQLInsertBuilder.model<A>(_:prefix:keyEncodingStrategy:nilEncodingStrategy:)
sil shared @$s6SQLKit16SQLInsertBuilderC5model_6prefix19keyEncodingStrategy03nilgH0ACXDx_SSSgAA15SQLQueryEncoderV03KeygH0OAJ03NilgH0OtKSERzlF1A1bOAOV_Tg5 : $@convention(method) (@in_guaranteed b.A, @guaranteed Optional<String>, @guaranteed SQLQueryEncoder.KeyEncodingStrategy, SQLQueryEncoder.NilEncodingStrategy, @guaranteed SQLInsertBuilder)
 -> (@owned SQLInsertBuilder, @error any Error) {
[%4: escape => %r, escape c*.v** -> %r.c*.v**]
// %0                                             // user: %17
// %1                                             // user: %21
// %2                                             // user: %21
// %3                                             // user: %21
// %4                                             // user: %21
bb0(%0 : $*b.A, %1 : $Optional<String>, %2 : $SQLQueryEncoder.KeyEncodingStrategy, %3 : $SQLQueryEncoder.NilEncodingStrategy, %4 : $SQLInsertBuilder):
  %5 = integer_literal $Builtin.Word, 1           // user: %9
  %6 = integer_literal $Builtin.Int64, 1          // user: %7
  %7 = struct $Int (%6 : $Builtin.Int64)          // user: %12
  %8 = metatype $@thick _ContiguousArrayStorage<b.A>.Type // user: %9
  %9 = alloc_ref_dynamic [stack] [tail_elems $b.A * %5 : $Builtin.Word] %8 : $@thick _ContiguousArrayStorage<b.A>.Type, $_ContiguousArrayStorage<b.A> // users: %34, %27, %12
  %10 = metatype $@thin Array<b.A>.Type           // user: %12
  // function_ref static Array._adoptStorage(_:count:)
  %11 = function_ref @$sSa13_adoptStorage_5countSayxG_SpyxGts016_ContiguousArrayB0CyxGn_SitFZ : $@convention(method) <τ_0_0> (@owned _ContiguousArrayStorage<τ_0_0>, Int, @thin Array<τ_0_0>.Type) -> (@owned Array<τ_0_0>, UnsafeMutablePointer<τ_0_0>) // user: %12
  %12 = apply %11<b.A>(%9, %7, %10) : $@convention(method) <τ_0_0> (@owned _ContiguousArrayStorage<τ_0_0>, Int, @thin Array<τ_0_0>.Type) -> (@owned Array<τ_0_0>, UnsafeMutablePointer<τ_0_0>) // users: %14, %13
  %13 = tuple_extract %12 : $(Array<b.A>, UnsafeMutablePointer<b.A>), 0 // user: %19
  %14 = tuple_extract %12 : $(Array<b.A>, UnsafeMutablePointer<b.A>), 1 // user: %15
  %15 = struct_extract %14 : $UnsafeMutablePointer<b.A>, #UnsafeMutablePointer._rawValue // user: %16
  %16 = pointer_to_address %15 : $Builtin.RawPointer to [strict] $*b.A // user: %17
  copy_addr %0 to [init] %16 : $*b.A              // id: %17
  // function_ref _finalizeUninitializedArray<A>(_:)
  %18 = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %19
  %19 = apply %18<b.A>(%13) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // users: %21, %30, %23
  // function_ref SQLInsertBuilder.models<A>(_:prefix:keyEncodingStrategy:nilEncodingStrategy:)
  %20 = function_ref @$s6SQLKit16SQLInsertBuilderC6models_6prefix19keyEncodingStrategy03nilgH0ACXDSayxG_SSSgAA15SQLQueryEncoderV03KeygH0OAK03NilgH0OtKSERzlF : $@convention(method) <τ_0_0 where τ_0_0 : Encodable> (@guaranteed Array<τ_0_0>, @guaranteed Optional<String>, @guaranteed SQLQueryEncoder.KeyEncodingStrategy, SQLQueryEncoder.NilEncodi
ngStrategy, @guaranteed SQLInsertBuilder) -> (@owned SQLInsertBuilder, @error any Error) // user: %21
  try_apply %20<b.A>(%19, %1, %2, %3, %4) : $@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: %21

// %22                                            // user: %28
bb1(%22 : $SQLInsertBuilder):                     // Preds: bb0
  %23 = struct_extract %19 : $Array<b.A>, #Array._buffer // user: %24
  %24 = struct_extract %23 : $_ArrayBuffer<b.A>, #_ArrayBuffer._storage // user: %25
  %25 = struct_extract %24 : $_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue // user: %26
  strong_release %25 : $Builtin.BridgeObject      // id: %26
  dealloc_stack_ref %9 : $_ContiguousArrayStorage<b.A> // id: %27
  return %22 : $SQLInsertBuilder                  // id: %28

// %29                                            // user: %35
bb2(%29 : $any Error):                            // Preds: bb0
  %30 = struct_extract %19 : $Array<b.A>, #Array._buffer // user: %31
  %31 = struct_extract %30 : $_ArrayBuffer<b.A>, #_ArrayBuffer._storage // user: %32
  %32 = struct_extract %31 : $_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue // user: %33
  strong_release %32 : $Builtin.BridgeObject      // id: %33
  dealloc_stack_ref %9 : $_ContiguousArrayStorage<b.A> // id: %34
  throw %29 : $any Error                          // id: %35
} // end sil function '$s6SQLKit16SQLInsertBuilderC5model_6prefix19keyEncodingStrategy03nilgH0ACXDx_SSSgAA15SQLQueryEncoderV03KeygH0OAJ03NilgH0OtKSERzlF1A1bOAOV_Tg5'

After

  *** SIL function after  #13668, stage HighLevel,Function+EarlyLoopOpt, pass 15: SILCombine (sil-combine)
// specialized SQLInsertBuilder.model<A>(_:prefix:keyEncodingStrategy:nilEncodingStrategy:)
sil shared @$s6SQLKit16SQLInsertBuilderC5model_6prefix19keyEncodingStrategy03nilgH0ACXDx_SSSgAA15SQLQueryEncoderV03KeygH0OAJ03NilgH0OtKSERzlF1A1bOAOV_Tg5 : $@convention(method) (@in_guaranteed b.A, @guaranteed Optional<String>, @guaranteed SQLQueryEncoder.KeyEncodingStrategy, SQLQueryEncoder.NilEncodingStrategy, @guaranteed SQLInsertBuilder)
 -> (@owned SQLInsertBuilder, @error any Error) {
[%4: escape => %r, escape c*.v** -> %r.c*.v**]
// %0                                             // user: %17
// %1                                             // user: %21
// %2                                             // user: %21
// %3                                             // user: %21
// %4                                             // user: %21
bb0(%0 : $*b.A, %1 : $Optional<String>, %2 : $SQLQueryEncoder.KeyEncodingStrategy, %3 : $SQLQueryEncoder.NilEncodingStrategy, %4 : $SQLInsertBuilder):
  %5 = integer_literal $Builtin.Word, 1           // user: %9
  %6 = integer_literal $Builtin.Int64, 1          // user: %7
  %7 = struct $Int (%6 : $Builtin.Int64)          // user: %12
  %8 = metatype $@thick _ContiguousArrayStorage<b.A>.Type
  %9 = alloc_ref [tail_elems $b.A * %5 : $Builtin.Word] $_ContiguousArrayStorage<b.A> // users: %12, %27, %34
  %10 = metatype $@thin Array<b.A>.Type           // user: %12
  // function_ref static Array._adoptStorage(_:count:)
  %11 = function_ref @$sSa13_adoptStorage_5countSayxG_SpyxGts016_ContiguousArrayB0CyxGn_SitFZ : $@convention(method) <τ_0_0> (@owned _ContiguousArrayStorage<τ_0_0>, Int, @thin Array<τ_0_0>.Type) -> (@owned Array<τ_0_0>, UnsafeMutablePointer<τ_0_0>) // user: %12
  %12 = apply %11<b.A>(%9, %7, %10) : $@convention(method) <τ_0_0> (@owned _ContiguousArrayStorage<τ_0_0>, Int, @thin Array<τ_0_0>.Type) -> (@owned Array<τ_0_0>, UnsafeMutablePointer<τ_0_0>) // users: %14, %13
  %13 = tuple_extract %12 : $(Array<b.A>, UnsafeMutablePointer<b.A>), 0 // user: %19
  %14 = tuple_extract %12 : $(Array<b.A>, UnsafeMutablePointer<b.A>), 1 // user: %15
  %15 = struct_extract %14 : $UnsafeMutablePointer<b.A>, #UnsafeMutablePointer._rawValue // user: %16
  %16 = pointer_to_address %15 : $Builtin.RawPointer to [strict] $*b.A // user: %17
  copy_addr %0 to [init] %16 : $*b.A              // id: %17
  // function_ref _finalizeUninitializedArray<A>(_:)
  %18 = function_ref @$ss27_finalizeUninitializedArrayySayxGABnlF : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // user: %19
  %19 = apply %18<b.A>(%13) : $@convention(thin) <τ_0_0> (@owned Array<τ_0_0>) -> @owned Array<τ_0_0> // users: %21, %30, %23
  // function_ref SQLInsertBuilder.models<A>(_:prefix:keyEncodingStrategy:nilEncodingStrategy:)
  %20 = function_ref @$s6SQLKit16SQLInsertBuilderC6models_6prefix19keyEncodingStrategy03nilgH0ACXDSayxG_SSSgAA15SQLQueryEncoderV03KeygH0OAK03NilgH0OtKSERzlF : $@convention(method) <τ_0_0 where τ_0_0 : Encodable> (@guaranteed Array<τ_0_0>, @guaranteed Optional<String>, @guaranteed SQLQueryEncoder.KeyEncodingStrategy, SQLQueryEncoder.NilEncodi
ngStrategy, @guaranteed SQLInsertBuilder) -> (@owned SQLInsertBuilder, @error any Error) // user: %21
  try_apply %20<b.A>(%19, %1, %2, %3, %4) : $@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: %21

// %22                                            // user: %28
bb1(%22 : $SQLInsertBuilder):                     // Preds: bb0
  %23 = struct_extract %19 : $Array<b.A>, #Array._buffer // user: %24
  %24 = struct_extract %23 : $_ArrayBuffer<b.A>, #_ArrayBuffer._storage // user: %25
  %25 = struct_extract %24 : $_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue // user: %26
  strong_release %25 : $Builtin.BridgeObject      // id: %26
  dealloc_stack_ref %9 : $_ContiguousArrayStorage<b.A> // id: %27
  return %22 : $SQLInsertBuilder                  // id: %28

// %29                                            // user: %35
bb2(%29 : $any Error):                            // Preds: bb0
  %30 = struct_extract %19 : $Array<b.A>, #Array._buffer // user: %31
  %31 = struct_extract %30 : $_ArrayBuffer<b.A>, #_ArrayBuffer._storage // user: %32
  %32 = struct_extract %31 : $_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue // user: %33
  strong_release %32 : $Builtin.BridgeObject      // id: %33
  dealloc_stack_ref %9 : $_ContiguousArrayStorage<b.A> // id: %34
  throw %29 : $any Error                          // id: %35
} // end sil function '$s6SQLKit16SQLInsertBuilderC5model_6prefix19keyEncodingStrategy03nilgH0ACXDx_SSSgAA15SQLQueryEncoderV03KeygH0OAJ03NilgH0OtKSERzlF1A1bOAOV_Tg5'

@jkshtj
Copy link
Contributor

jkshtj commented Jun 20, 2023

The difference in the before and after versions is -

// BEFORE
%9 = alloc_ref_dynamic [stack] [tail_elems $b.A * %5 : $Builtin.Word] %8 : $@thick _ContiguousArrayStorage<b.A>.Type, $_ContiguousArrayStorage<b.A> // users: %34, %27, %12

// AFTER
%9 = alloc_ref [tail_elems $b.A * %5 : $Builtin.Word] $_ContiguousArrayStorage<b.A> // users: %12, %27, %34

@jkshtj
Copy link
Contributor

jkshtj commented Jun 20, 2023

An alloc_ref_dynamic operation, annotated with the [stack] attribute, must be accompanied by a dealloc_stack_ref operation to deallocate the value that may be allocated on the stack. This is indeed happening in the "before" version on all control-flow paths.

However, optimization pass number 15 (transformation number ==> 13669.10) is swapping the alloc_ref_dynamic [stack] ... operation with an alloc_ref operation, asserting that the allocation must happen on the heap. But the previously existing dealloc_stack_ref operations are not being removed, which eventually leads to stack discipline violation and an error message saying -

SIL verification failed: stack dealloc with empty stack: !state.Stack.empty()
Verifying instruction:
     %9 = alloc_ref [tail_elems $b.A * %5 : $Builtin.Word] $_ContiguousArrayStorage<b.A> // users: %12, %27, %34
->   dealloc_stack_ref %9 : $_ContiguousArrayStorage<b.A> // id: %34

@tbkka
Copy link
Contributor

tbkka commented Jun 20, 2023

CC: @eeckstein

eeckstein added a commit to eeckstein/swift that referenced this issue Jun 21, 2023
…f_dynamic` with `alloc_ref`

Fixes a verifier crash.

swiftlang#66312
eeckstein added a commit to eeckstein/swift that referenced this issue Jun 21, 2023
…f_dynamic` with `alloc_ref`

Fixes a verifier crash.

swiftlang#66312
@eeckstein eeckstein self-assigned this Jun 21, 2023
@eeckstein
Copy link
Contributor

Thanks for reporting! It's unbelievable that we didn't hit this bug earlier. It's in the compiler since 7 years.
Fixed with #66800

eeckstein added a commit to eeckstein/swift that referenced this issue Jun 21, 2023
…f_dynamic` with `alloc_ref`

Fixes a verifier crash.

swiftlang#66312
@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler itself verifier crash Bug: A crash, i.e., an abnormal termination of software SIL assertion failure Bug → crash: An assertion failure closures Feature: closures expressions Feature: expressions and removed triage needed This issue needs more specific labels labels Jun 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assertion failure Bug → crash: An assertion failure bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. closures Feature: closures compiler The Swift compiler itself crash Bug: A crash, i.e., an abnormal termination of software expressions Feature: expressions SIL verifier
Projects
None yet
5 participants