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-2167] Segfault when extending C-enum with Hashable w/o implementing hashValue #44775

Open
swift-ci opened this issue Jul 25, 2016 · 7 comments
Labels
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

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-2167
Radar None
Original Reporter paulstyrnol (JIRA User)
Type Bug
Environment

Xcode 8 beta 3, Swift 3
Xcode 7.3.1, Swift 2.2

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, ClangImporter, CompilerCrash
Assignee None
Priority Medium

md5: ad951f6ea9f3f654bd2860351c7c4bb8

is duplicated by:

  • SR-2223 Exit code 1 when making UIControlState conform to Hashable

Issue Description:

I stumbled upon this when I wanted to use enums adopting a protocol as dictionary keys w/o having using the enum type in the type declaration (e.g. [FooProtocolAdoptedByEnum: Any]). This is where the unintended workaround of subtyping Hashable and using the enum type as keys comes from. It works for real Swift enums but not for C-enums.

import AVFoundation

// compiles
enum SwiftEnum: Int {
    case foo, bar
}
extension SwiftEnum: Hashable { }

// segfault
extension AVCaptureFocusMode: Hashable { }

// compiles
extension AVCaptureFocusMode: Hashable {
    public var hashValue: Int { return 0 }
}

// compiles
public protocol HashableWorkaround: Hashable { }

extension AVCaptureFlashMode: HashableWorkaround {
    // use the enum type as a dict key in a property or function return type
    static let workaround: [AVCaptureFlashMode:Any] = [:]
}

// segfault
extension AVCaptureWhiteBalanceMode: Hashable {
    static let workaround_Nope: [AVCaptureWhiteBalanceMode:Any] = [:]
}

// segfault
extension AVCaptureExposureMode: HashableWorkaround {
    static let workaround_Nope: AVCaptureExposureMode = .locked // capitalize for 2.2
}

// segfault
extension AVCaptureTorchMode: HashableWorkaround { }

Edit:
The workaround variant compiles but there are issues when using the enum type in a different file:

FileA.swift:

public protocol HashableWorkaround: Hashable { }

extension AVCaptureFlashMode: HashableWorkaround {
    // use the enum type as a dict key in a property or function return type
    static let workaround: [AVCaptureFlashMode:Any] = [:]
}

FileB.swift

let x: [AVCaptureFlashMode: String] = [AVCaptureFlashMode.auto: "Auto"] // works
_ = [AVCaptureFlashMode.auto: "Auto"] // results in link error

Link error:

Undefined symbols for architecture x86_64:
  "protocol witness table for __C.AVCaptureFlashMode : Swift.Hashable in SegFaultTest", referenced from:
      SegFaultTest.ViewController.viewDidLoad () -> () in ViewController.o
ld: symbol(s) not found for architecture x86_64

In a large project I am working on I also get a link error about a duplicate symbol (__TFE21MyModuleNameOSC18AVCaptureFlashModeg9hashValueSi) in two files, but I am unable to repro this in a test project.

@belkadan
Copy link
Contributor

I think we already try to make them Hashable, which means we should just reject the conformance.

@swift-ci
Copy link
Collaborator Author

Comment by Paul Styrnol (JIRA)

Can you explain what you mean by reject? Would the following work (as long as the enum doesn't have cases with arguments)?

protocol MyEnumProtocol: Hashable { /* ... */ }

extension AVCaptureFlashMode: MyEnumProtocol {
    // implement MyEnumProtocol methods, but not hashValue
}

class MyClass<T: MyEnumProtocol> {
    func fn(arg: [T: Any]) {}
}

By the way, the more testing I do the stranger it gets:

In Xcode Xcode 7.3.1, Swift 2.2 either of the following extensions compiles as long it stands alone:

// compile one: ok, compile both: segfault
extension AVCaptureFocusMode: Hashable {}
extension AVCaptureWhiteBalanceMode: Hashable {}

In both environments I can remove Hashable as a supertype for my protocol as long as usage is limited to generic constraints in functions/methods:

protocol MyUnhashableEnumProtocol { /* ... */ }

extension AVCaptureFlashMode: MyUnhashableEnumProtocol {
    // implement MyUnhashableEnumProtocol methods, but not hashValue
}

func fn<T: MyUnhashableEnumProtocol>(arg: [T: Any]) {} // compiles

class MyClass<T: MyUnhashableEnumProtocol> {
    func generic<U: MyUnhashableEnumProtocol>(arg: [U: Any]) {} // compiles
    func fn(arg: [T: Any]) {} // error: Type T does not conform to protocol Hashable
}

@swift-ci
Copy link
Collaborator Author

Comment by Paul Styrnol (JIRA)

I added some more information about the workaround for the segfaults in the description. Let me know if any of this should go into a separate issue.
(Sorry for the update noise btw, wasn't aware of how inline editing works in JIRA)

@belkadan
Copy link
Contributor

I believe they're all already Hashable upon import.

import AVFoundation
var x = Set<AVCaptureFocusMode>()

@swift-ci
Copy link
Collaborator Author

Comment by Paul Styrnol (JIRA)

Consider the following usecase:

protocol MyEnumProtocol: Hashable { /* … */ }

extension AVCaptureFlashMode: MyEnumProtocol { /* … */ }

// if Hashable were to be rejected (or I just wouldn't use it as a super type) this doesn't work …
class Foo<T: MyEnumProtocol> {
    var map[T: String] = [:]
}

// … instead you would need to have a more complex generic constraint 
class Bar<T: MyEnumProtocol where T: Hashable> {
    var map[T: String]
}

The Foo variant already works with Swift enums.

@belkadan
Copy link
Contributor

Oh, yes, it's definitely a bug. I'm just pointing out that you shouldn't be able to extend a C enum with Hashable itself, just things that derive from Hashable.

@Dante-Broggi
Copy link
Contributor

Has this bug, and any related bugs demonstrated in this report, fixed? If so, then this report should be closed.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 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
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
Projects
None yet
Development

No branches or pull requests

4 participants