App sometimes crashes when inserting String into Set with assertion ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS

Xcode downloaded a crash report for my app that crashed when trying to insert a String into a Set<String>. Apparently there was an assertion failure ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS. I assume that this assertion failure happened because the hash of the new element didn't match the hash of an equal already inserted element, but regardless, I don't understand how inserting a simple string could trigger this assertion.

Here is essentially the code that leads to the crash. path is any file system directory, and basePath is a directory higher in the hierarchy, or path itself.

var scanErrorPaths = Set<String>()

func main() {
    let path = "/path/to/directory"
    let basePath = "/path"
    let fileDescriptor = open(path, O_RDONLY)
    if fileDescriptor < 0 {
        if (try? URL(fileURLWithPath: path, isDirectory: false).checkResourceIsReachable()) == true {
            scanErrorPaths.insert(path.relativePath(from: basePath)!)
        return
    }
}

extension String {

    func relativePath(from basePath: String) -> String? {
        if basePath == "" {
            return self
        }
        guard let index = range(of: basePath, options: .anchored)?.upperBound else {
            return nil
        }
        return if index == endIndex || basePath == "/" {
            String(self[index...])
        } else if let index = self[index...].range(of: "/", options: .anchored)?.upperBound {
            String(self[index...])
        } else {
            nil
        }
    }

}

Answered by DTS Engineer in 862956022

The last time I helped someone with this trap, it was caused by a concurrency bug in their code. See this thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I miss something:

  • relativePath may return nil
  • you force unwrap, which could cause a crash
            scanErrorPaths.insert(path.relativePath(from: basePath)!)

Could you try replacing by:

        guard let index = range(of: basePath, options: .anchored)?.upperBound else {
            return ""
        }

and have relativePath return a String, not optional ?

In theory it could cause a crash, but in practice it shouldn't happen as one is always a subfile of the other.

I'm specifically interested about the crash I talked about, which is also shown in the crash report I attached at the end, and which I have no idea what it's caused by.

I notice the exception is on:

NativeSet.insertNew(_:at:isUnique:) + 376 (/:0)

Looking at this thread: https://forums.swift.org/t/substring-violates-hashables-requirements-stdlib-compiler-bug/58046/7

I wonder if the compiler is not confused and considering you try to insert a substring.

To make sure, could you try:

        let sub = self[index...] // a substring
        let theStr = String(sub)
        return if index == endIndex || basePath == "/" {
            theStr // String(self[index...]) // for sure, a String
        } else if let index = self[index...].range(of: "/", options: .anchored)?.upperBound {
            theStr // String(self[index...])
        } else {
            nil
        }

If that works, you should file a bug report.

I don't see what your code would fix or change, other than creating an extra variable. It also changes the program behaviour, because now the variable created in if let index is never used.

I should also specify that I was never able to reproduce this crash myself.

The last time I helped someone with this trap, it was caused by a concurrency bug in their code. See this thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Such an elegant solution. There is potential for a data race, so that must be it. Thank you.

(It's strange that Google doesn't show that other topic even when searching for the assertion name. Only this topic is found, on this website and on another website vmhkb.mspwftt.com. Do you know what that is?)

Do you know what that is?

What what is? The vmhkb.mspwftt.com website? Nope, no idea.

FWIW, a DuckDuckGo search for "ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS" (with the quotes) turns up this thread [1] and a related thread on Swift Forums.

Amusingly, a DevForums search for the same string gives exactly the results you’d hope for (-:

The search button on the Developer website proper is not as helpful )-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Well, indirectly. It actually takes you to the Programming Languages > Swift subtopic.

App sometimes crashes when inserting String into Set with assertion ELEMENT_TYPE_OF_SET_VIOLATES_HASHABLE_REQUIREMENTS
 
 
Q