I am hashing user data on an Apple Watch using SHA1 and when running the SHA1Bytes
function, I get the following error:
Thread1: exc_breakpoint(code=exc_arm_breakpoint,subcode=0xe7ffdefe). This specific line gives me the error:
j = ( UInt32((msg[i]<<24) | (msg[i+1]<<16) | (msg[i+2]<<8) | msg[i+3]) )
This is the piece of code from which the above line is extracted:
class func SHA1Bytes(msg: [Int])->String{
func rotateLeft(number: UInt32, rotateBy: UInt32)->UInt32{
return ((number << rotateBy) | (number>>(32-rotateBy)))
}
func cvt_hex(value: UInt32)->String{
var str = ""
for i:UInt32 in stride(from: 7, through: 0, by: -1){
let v: UInt32 = (value >> (i*4)&0x0f)
str += String(v,radix: 16, uppercase: false)
}
return str
}
var W = [UInt32](repeating: 0, count: 80)
var H0 = UInt32("67452301",radix: 16)!
var H1 = UInt32("EFCDAB89",radix: 16)!
var H2 = UInt32("98BADCFE",radix: 16)!
var H3 = UInt32("10325476",radix: 16)!
var H4 = UInt32("C3D2E1F0",radix: 16)!
var wordArray = [UInt32]()
for k in stride(from: 0, to: msg.count-3, by: 4) {
let j = ( UInt32((msg[k]<<24) | (msg[k+1]<<16) | (msg[k+2]<<8) | msg[k+3]) )
wordArray.append(j)
}
...
return encoded.uppercased()
}
The exact same code runs perfectly in an iOS Playground, but crashes when running on a first generation Apple Watch. I have checked and the input array exists, I am trying to access existing elements of it and the result of j
should not overflow.
The code fails with the following variable values:
j=(UInt32) 2308511418, k=(Int)48, msg=([Int])56values
and these are the values of msg:
[47] Int 217
[48] Int 137
[49] Int 153
[50] Int 22
[51] Int 186
[52] Int 163
[53] Int 41
[54] Int 208
[55] Int 104
I managed to figure out that the simulator is not crashing even if a UInt32 overflows, however, the 32bit Apple Watch does crash in this case.
The solution was to use an overflow operator, which only exists for addition, subtraction and multiplication. Hence, I changed bitwise left shift to multiplication by 2^(number of bits to be shifted).
This is the correct solution: UInt32(msg[k])&*UInt32(1<<24)
let j = (UInt32(msg[k])&*UInt32(1<<24))|UInt32(msg[k+1]&*(1<<16))|UInt32(msg[k+2]&*(1<<8))|UInt32(msg[k+3])