Skip to content

NotSupportedException in memory-mapped-file optimization when copying ReadOnlyMemory into MemoryMappedFileViewStream #20263

Description

@xperiandri

Problem

While debugging the F# compiler in VS, the compiler crashes with a System.NotSupportedException when it tries to use the memory-mapped-file fast path for ReadOnlyMemory<byte> data.

The exception is:

This operation is not supported for an UnmanagedMemoryStream created from a SafeBuffer.

Location

The failing code is in:

  • src/Compiler/Utilities/FileSystem.fs

The relevant code path is:

static member TryFromMemory(bytes: ReadOnlyMemory<byte>) =
    let length = int64 bytes.Length

    trymmf length (fun stream ->
        let span = Span<byte>(stream.PositionPointer |> NativePtr.toVoidPtr, int length)
        bytes.Span.CopyTo(span)
        stream.Position <- stream.Position + length)

This is reached from:

  • ByteStorage.FromMemoryAndCopy(..., useBackingMemoryMappedFile = true)
  • CompilerImports.PickleToResource
  • CompilerImports.WriteSignatureData
  • CompilerImports.EncodeSignatureData

Stack trace

The debugger shows:

System.NotSupportedException
This operation is not supported for an UnmanagedMemoryStream created from a SafeBuffer.

[1] mscorlib.dll!System.IO.UnmanagedMemoryStream.PositionPointer.get
[2] FSharp.Compiler.Service.dll!FSharp.Compiler.IO.MemoryMappedFileExtensions.MemoryMappedFile-TryFromMemory-Static@392.Invoke

with the current statement at:

src\Compiler\Utilities\FileSystem.fs
392: trymmf length (fun stream ->
393:     let span = Span<byte>(stream.PositionPointer |> NativePtr.toVoidPtr, int length)
394:     bytes.Span.CopyTo(span)
395:     stream.Position <- stream.Position + length)

Root cause

MemoryMappedFile.CreateViewStream(...) creates a stream backed by a SafeBuffer (the underlying mapped view). On .NET, accessing PositionPointer on that stream type is not supported and throws NotSupportedException.

The compiler optimization is assuming that the stream is a generic UnmanagedMemoryStream that supports PositionPointer, but this is not true for MemoryMappedFileViewStream.

Why this matters

This is a compiler bug in the memory-mapped-file optimization path, not a user code bug. It can fail while serializing compiler metadata/resources and prevents the compiler from completing the in-memory resource generation path.

Expected behavior

The code should copy the byte payload via the stream API (stream.Write) or another supported safe mechanism, without touching PositionPointer on a SafeBuffer-backed mapped view.

Additional context

Observed in the current debugging session inside the local repo:

  • C:\Users\Andrii\DevArchive\fsharp
  • branch: fix-project-options-async-debounce
  • repo: dotnet/fsharp

This appears to be in the compiler utility path used for metadata/resource pickling and memory-backed streaming.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    New

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions