Closed
Description
If the caller performs a bounds check on a span, the runtime will not elide future bounds checks satisfied by that condition if a method call occurs between the original check and the subsequent access. The following repro code demonstrates this issue.
using System;
public class MyClass {
public int SomeField;
public int SomeProperty => 42;
public int SomeMethod() => 42;
private void Foo(Span<int> destination)
{
if (!destination.IsEmpty)
{
destination[0] = SomeProperty;
}
}
private void Bar(Span<int> destination)
{
if (!destination.IsEmpty)
{
destination[0] = SomeField;
}
}
private void Baz(Span<int> destination)
{
if (!destination.IsEmpty)
{
destination[0] = SomeMethod();
}
}
}
x64 codegen, courtesy SharpLab:
MyClass.Foo(System.Span`1<Int32>)
L0000: sub rsp, 0x28
L0004: mov rax, [rdx]
L0007: mov edx, [rdx+8]
L000a: test edx, edx ; call to destination.IsEmpty
L000c: jbe short L0019
L000e: cmp edx, 0 ; bounds check should've been elided
L0011: jbe short L001e
L0013: mov dword ptr [rax], 0x2a
L0019: add rsp, 0x28
L001d: ret
L001e: call 0x00007ff9f75fbab0
L0023: int3
MyClass.Bar(System.Span`1<Int32>)
L0000: mov rax, [rdx]
L0003: mov edx, [rdx+8]
L0006: test edx, edx ; call to destination.IsEmpty
L0008: jbe short L000f
L000a: mov edx, [rcx+8]
L000d: mov [rax], edx ; no bounds check before writing field value to destination
L000f: ret
MyClass.Baz(System.Span`1<Int32>)
L0000: sub rsp, 0x28
L0004: mov rax, [rdx]
L0007: mov edx, [rdx+8]
L000a: test edx, edx ; call to destination.IsEmpty
L000c: jbe short L0019
L000e: cmp edx, 0 ; bounds check should've been elided
L0011: jbe short L001e
L0013: mov dword ptr [rax], 0x2a
L0019: add rsp, 0x28
L001d: ret
L001e: call 0x00007ff9f75fbab0
L0023: int3
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Done