So this is a blog post about a pet-peeve of mine. The claim: "Swift cannot have bugs like Apple's goto-fail bug."
This is rubbish!
The biggest problem I have with much of the analysis of this bug is the focus on the missing braces around the if-statements. No, the problem is that the code is terrible to begin with, and it obviously had no tests which were trivial to implement.
So, we have to start with the following assumptions to see just how we get this code in Swift:
- The code structure was just poor to begin with.
- Compiler settings were disabled so the "unreachable code paths" warning didn't show (or was ignored).
- Evidently tests were thought to be optional.
So, here's basically the same code in Swift:
enum SSLHashSHA1 {
static func update(inout hashCxt: Int, _ call: Int) -> OSStatus {
hashCxt = call
if call == 4 { return -1 }
return 0
}
}
func isAnyOneSafe() -> OSStatus {
var err: OSStatus = 0
var hashCtx: Int = 0
err = SSLHashSHA1.update(&hashCtx, 0)
if (err != 0) {
return err
}
err = SSLHashSHA1.update(&hashCtx, 1)
if (err != 0) {
return err
}
err = SSLHashSHA1.update(&hashCtx, 2)
if (err != 0) {
return err
}
err = SSLHashSHA1.update(&hashCtx, 3)
if (err != 0) {
return err
}
return err
err = SSLHashSHA1.update(&hashCtx, 4)
if (err != 0) {
return err
}
return err
}
isAnyOneSafe() // returns 0, should return -1 though
The point of this is post is to debunk the myth that you are immune to these same type of stupid errors just because you are writing code in Swift. That's just simply not true. A "merge error" or a "copy and paste error" like the above is pretty easy to do and miss if people aren't paying attention and not code reviewing changes.
Moral of the story: the compiler tells you jack squat about the correctness of your code; it only tells you that you have passed the rules to generate machine code based on the language rules. You still need to write tests to make sure that your code is actually functioning correctly.
P.S. If your counter-argument is that this is terrible code and you shouldn't write it that way to begin with! Of course it's terrible code! However, the fact is that the C-version is also terrible code and it shouldn't have been written that way either. Unfortunately, bad code happens regardless of language.
P.P.S. Swift does provide us a nice way to write this code that is, in my opinion, even better than some of the cleaned up C-versions from the links above:
enum ResultCode : ErrorType {
case Error
case Success
}
enum SSLHashSHA1 {
static func update(inout hashCxt: Int, _ call: Int) throws {
hashCxt = call
if call == 4 {
throw ResultCode.Error
}
throw ResultCode.Success
}
}
func isAnyOneSafe() throws {
var hashCtx: Int = 0
try SSLHashSHA1.update(&hashCtx, 0)
try SSLHashSHA1.update(&hashCtx, 1)
try SSLHashSHA1.update(&hashCtx, 2)
try SSLHashSHA1.update(&hashCtx, 3)
try SSLHashSHA1.update(&hashCtx, 4)
}
do {
try isAnyOneSafe()
}
catch {
print("yay!")
}