Description
We have identified a scenario where an assumed pinned array is moved before being copied, resulting in an AccessVioloationException. It can be reproduced with net48, net8.0, and netstandard 2.0 when compiled with Tailcalls true
(only tested on Windows), SDK version 9.0.203.
In particular, it escapes from an extension method like this:
static member Set<'T when 'T : unmanaged>(this : IBuffer, src : 'T[]) =
use ptr = fixed src
this.Set(ptr |> NativePtr.toNativeInt, nativeint src.Length * nativeint sizeof<'T>)
You can find a repository with a minimal example here:
https://github.com/luithefirst/TailCallEscape
It will crash in about 1 min. Originally, I could also see a TailCallHelperStub stack frame in WinDbg, but it is gone now in my minimal example. Still, if Tailcalls
is set to false in the fsproj file, the issue cannot be reproduced.
A colleague also recalled a possible similar issue back in net 5, but I could not find any details on it.
This is where the issue actually occurs in our framework:
https://github.com/aardvark-platform/aardvark.rendering/blob/646d165829283a3a0ba03cb4badc465245fbc670/src/Aardvark.Rendering/Resources/Adaptive/ManagedBuffer.fs#L105
https://github.com/aardvark-platform/aardvark.base/blob/5b0b5c0507ca20238899260d2a08d252e6a4f1e8/src/Aardvark.Base.FSharp/Utilities/Interop/FSLibExtensions.fs#L529
There, it is implemented in a netstandard 2.0 library, and when consumed by net48 the issue occurs (but for some reason not in net8.0). Also, when disabling Tailcalls in the library, it can be avoided.
Expected behaviour: The compiler should be aware that a stackframe is pinning an object and therefore should not generate a tailcall.
Workaround: Use GCHandle + AddrOfPinnedObject
Metadata
Metadata
Assignees
Type
Projects
Status