-
Notifications
You must be signed in to change notification settings - Fork 10.6k
Description
Previous ID | SR-12805 |
Radar | None |
Original Reporter | @karwa |
Type | Bug |
Additional Detail from JIRA
Votes | 0 |
Component/s | Compiler, Standard Library |
Labels | Bug |
Assignee | None |
Priority | Medium |
md5: adf743091ada51cb01f5ef12b82ccd74
Issue Description:
Test case:
func containsFortyTwo(_ input: UnsafeBufferPointer<UInt8>) -> Bool {
var idx = input.startIndex
while idx != input.endIndex {
if input[idx] == 42 { return false }
idx = input.index(after: idx)
}
return true
}
Results in overflow checks:
output.containsFortyTwo(Swift.UnsafeBufferPointer<Swift.UInt8>) -> Swift.Bool:
push rbp
mov rbp, rsp
mov al, 1
test rsi, rsi
je .LBB1_7
cmp byte ptr [rdi], 42
je .LBB1_6
xor ecx, ecx
.LBB1_3:
mov rdx, rcx
inc rdx
jo .LBB1_8 ; <------- Here
cmp rdx, rsi
je .LBB1_7
add rcx, 1
cmp byte ptr [rdi + rdx], 42
jne .LBB1_3
.LBB1_6:
xor eax, eax
.LBB1_7:
pop rbp
ret
.LBB1_8:
ud2
Now, in practice, the only way this code could possibly overflow is if UnsafeBufferPointer<T>.count were negative (i.e. endIndex < startIndex, which violates the Collection protocol semantics but is nonetheless possible to write).
Fortunately, UBP validates its count in all initialisers, which is the only time it is set (or it copies the count of something which is known to also validate its count), so this situation will never happen. Unfortunately, the compiler doesn't know this, and must assume that a value of type `Int` may be negative.
The result is that we pay in code size and runtime performance, and there is no way to eliminate it (other than -Ounchecked, which is not practical; it is not possible on a per-file basis in SwiftPM projects, for instance).
Could we perhaps add some kind of attribute or property wrapper which validates that a value of type "Int" is never negative? The compiler could then use that knowledge to treat the value as effectively unsigned and eliminate the above overflow check. Alternatively (at least for the unsafe pointers), it seems reasonable to add a version of "index(after🙂" which uses wrapping arithmetic.