Skip to content

Incorrect codegen for Debug build with srtp and mutable struct #16292

@ghost

Description

The showIt function in the following has incorrect code in Debug builds (the bug exists in both F# 7 and 8):

open System
open System.Buffers
open System.Text

let inline forEach<'C, 'E, 'I
                        when 'C: (member GetEnumerator: unit -> 'I)
                        and  'I: struct
                        and  'I: (member MoveNext: unit -> bool)
                        and  'I: (member Current : 'E) >
        ([<InlineIfLambda>] f: 'E -> unit) (container: 'C)  =
    let mutable iter = container.GetEnumerator()
    while iter.MoveNext() do
        f iter.Current

let showIt (buffer: ReadOnlySequence<byte>) =
    buffer |> forEach (fun segment ->
        let s = Encoding.ASCII.GetString(segment.Span)
        Console.Write(s)
    )

Using ILSpy, here's a (correct) Release build:

public static void showIt(ReadOnlySequence<byte> buffer)
{
	ReadOnlySequence<byte>.Enumerator enumerator = buffer.GetEnumerator();
	while (enumerator.MoveNext())
	{
		ReadOnlyMemory<byte> current = enumerator.Current;
		Console.Write(Encoding.ASCII.GetString(current.Span));
	}
}

Below is the incorrect Debug build. The problem is that enumerator2 is always reinitialized in the loop (using the value of enumerator). enumerator2.MoveNext() will then mutate enumerator2, but this mutation will be lost when enumerator2 is reinitialized:

public static void showIt(ReadOnlySequence<byte> buffer)
{
	ReadOnlySequence<byte> readOnlySequence = buffer;
	ReadOnlySequence<byte>.Enumerator enumerator = readOnlySequence.GetEnumerator();
	while (true)
	{
		ReadOnlySequence<byte>.Enumerator enumerator2 = enumerator;
		if (enumerator2.MoveNext())
		{
			ReadOnlyMemory<byte> segment = enumerator.Current;
			string s = Encoding.ASCII.GetString(segment.Span);
			Console.Write(s);
			continue;
		}
		break;
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-Compiler-CodeGenIlxGen, ilwrite and things at the backendBugImpact-Low(Internal MS Team use only) Describes an issue with limited impact on existing code.

    Type

    No fields configured for Bug.

    Projects

    Status
    New

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions