Skip to content
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

[SR-9176] Object Over-Released when enum case with associated value T is passed as closure to function operating over a generic specializing T #51667

Open
swift-ci opened this issue Nov 3, 2018 · 1 comment
Labels
access control Feature → modifiers: Access control and access levels bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software regression run-time crash Bug → crash: Swift code crashed during execution swift 4.2

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Nov 3, 2018

Previous ID SR-9176
Radar rdar://problem/45962437
Original Reporter pacheco (JIRA User)
Type Bug

Attachment: Download

Environment

Xcode 10.1 (10B61)

Swift 4.0, 4.2

macOS 10.13.6, 10.14

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, 4.2Regression, RunTimeCrash
Assignee None
Priority Medium

md5: e3edd86a852ba61276c0ea3eb81b3582

Issue Description:

Sorry if my description is not the most accurate, but it's not an easy one to describe 😛

When passing an enum's case with associated value T as a closure to another function (i.e. to "wrap" a T and create a new enum instance), if the type T is an associatedtype on a protocol (specialized in the generic of the function's parent type), an over-release is made, causing a EXC_BAD_ACCESS runtime crash.

I've only observed this issue since Xcode 10 (also present in 10.1), in both Swift 4 and Swift 4.2 modes. On Xcode 9 the same code worked without any issues, and since the code is valid Swift I am led to believe that this is most likely a compiler regression.

When this issue started occurring I analyzed the app with the Zombies Instrument and discovered that an additional release was being generated when the enum's case is used as a parameter.

I've managed to create a reduced example which demonstrates the issue:

enum Result<T, E: Error> {
    case success(T)
    case failure(E)

    func mapError<E2: Error>(_ f: (E) -> E2) -> Result<T, E2> {
        switch self {
        case .success(let value): return .success(value)
        case .failure(let error): return .failure(f(error))
        }
    }
}

protocol Store {
    associatedtype E: Error

    func fetch(_ completion: (Result<Void, E>) -> Void)
}

// specializing using a value type doesn't crash
enum EnumError: Error { case error }
struct StructError: Error {}

// only specializing using a reference type crashes
class ClassError: Error {}

final class MyStore: Store {
    typealias E = ClassError

    func fetch(_ completion: (Result<Void, ClassError>) -> Void) {
        completion(.failure(ClassError()))
    }
}

enum ServiceError: Error {
    case fetch(Error)
}

struct MyService<S: Store> {
    let store: S

    func fetch(_ completion: (Result<Void, ServiceError>) -> Void) {
        store.fetch { result in
            completion(result.mapError(ServiceError.fetch))
        }
    }

    func explicitFetch(_ completion: (Result<Void, ServiceError>) -> Void) {
        store.fetch { result in
            completion(result.mapError { ServiceError.fetch($0) })
        }
    }
}

// test

let store = MyStore()
let service = MyService(store: store)

// doesn't crash
// store.fetch { print($0) }

// crashes
service.fetch { print($0) }

// doesn't crash
// service.explicitFetch { print($0) }

I've atached a demo app demonstrating the issue, but it's also manifested on a playground (even though it may require a small change so that the result lives a bit longer).

@belkadan
Copy link
Contributor

belkadan commented Nov 5, 2018

Yikes! Thanks. cc @jckarter, @gottesmm

@swift-ci create

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added regression swift 4.2 access control Feature → modifiers: Access control and access levels and removed 4.2 regression labels Nov 19, 2022
@AnthonyLatsis AnthonyLatsis added the crash Bug: A crash, i.e., an abnormal termination of software label Dec 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
access control Feature → modifiers: Access control and access levels bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software regression run-time crash Bug → crash: Swift code crashed during execution swift 4.2
Projects
None yet
Development

No branches or pull requests

3 participants