fsharp
fsharp copied to clipboard
CLR Crashes when running program, which uses constrained calls
Compile and run the following:
module Dispose
open System
open System.IO
[<RequireQualifiedAccess>]
module Dispose =
let inline action<'a when 'a: (member Dispose: unit -> unit) and 'a :> IDisposable>(a: 'a) = a.Dispose()
[<EntryPoint>]
let main argv =
let ms = new MemoryStream()
ms |> Dispose.action
0
Observe segfault:
Fatal error. Internal CLR error. (0x80131506)
at Program.main(System.String[])
// ildasm trunk-20251112+a12ecf93aedc8f111ec8cc5a8f6f51c899413d9e
// .NET IL Disassembler. Version 10.0.0-rc.1.25562.99
// Metadata version: v4.0.30319
.assembly extern System.Runtime
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 10:0:0:0
}
.assembly extern FSharp.Core
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 10:0:0:0
}
.assembly CompilerExplorer
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.FSharpInterfaceDataVersionAttribute::.ctor(int32,
int32,
int32) = ( 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 )
.custom instance void [System.Runtime]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 19 2E 4E 45 54 43 6F 72 65 41 70 70 2C 56 // ....NETCoreApp,V
65 72 73 69 6F 6E 3D 76 31 30 2E 30 01 00 54 0E // ersion=v10.0..T.
14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 // .FrameworkDispla
79 4E 61 6D 65 09 2E 4E 45 54 20 31 30 2E 30 ) // yName..NET 10.0
.custom instance void [System.Runtime]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 10 43 6F 6D 70 69 6C 65 72 45 78 70 6C 6F // ...CompilerExplo
72 65 72 00 00 ) // rer..
.custom instance void [System.Runtime]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 07 52 65 6C 65 61 73 65 00 00 ) // ...Release..
.custom instance void [System.Runtime]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0..
.custom instance void [System.Runtime]System.Reflection.AssemblyInformationalVersionAttribute::.ctor(string) = ( 01 00 05 31 2E 30 2E 30 00 00 ) // ...1.0.0..
.custom instance void [System.Runtime]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 10 43 6F 6D 70 69 6C 65 72 45 78 70 6C 6F // ...CompilerExplo
72 65 72 00 00 ) // rer..
.custom instance void [System.Runtime]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 10 43 6F 6D 70 69 6C 65 72 45 78 70 6C 6F // ...CompilerExplo
72 65 72 00 00 ) // rer..
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.mresource public FSharpSignatureCompressedData.CompilerExplorer
{
// Offset: 0x00000000 Length: 0x00000366
}
.mresource public FSharpSignatureCompressedDataB.CompilerExplorer
{
// Offset: 0x00000370 Length: 0x00000017
}
.mresource public FSharpOptimizationCompressedData.CompilerExplorer
{
// Offset: 0x00000390 Length: 0x00000129
}
.mresource public FSharpOptimizationCompressedDataB.CompilerExplorer
{
// Offset: 0x000004C0 Length: 0x00000013
}
.module CompilerExplorer.dll
// MVID: {d14beb53-375f-ecee-9d15-3fb047922301}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x0x738e19259000
// =============== CLASS MEMBERS DECLARATION ===================
.class public abstract auto ansi sealed Dispose
extends [System.Runtime]System.Object
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
.class abstract auto ansi sealed nested public Dispose
extends [System.Runtime]System.Object
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.RequireQualifiedAccessAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 )
.method public static void action<([System.Runtime]System.IDisposable) a>(!!a a) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: constrained. !!a
IL_0007: callvirt instance void [System.Runtime]System.IDisposable::Dispose()
IL_000c: ret
} // end of method Dispose::action
.method public static void action$W<([System.Runtime]System.IDisposable) a>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!!a,class [FSharp.Core]Microsoft.FSharp.Core.Unit> dispose,
!!a a) cil managed
{
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.1
IL_0001: constrained. !!a
IL_0007: callvirt instance void [System.Runtime]System.IDisposable::Dispose()
IL_000c: ret
} // end of method Dispose::action$W
} // end of class Dispose
.method public static int32 main(string[] argv) cil managed
{
.custom instance void [FSharp.Core]Microsoft.FSharp.Core.EntryPointAttribute::.ctor() = ( 01 00 00 00 )
// Code size 20 (0x14)
.maxstack 3
.locals init (class [System.Runtime]System.IO.MemoryStream V_0)
IL_0000: newobj instance void [System.Runtime]System.IO.MemoryStream::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: constrained. [System.Runtime]System.IO.MemoryStream
IL_000d: callvirt instance void [System.Runtime]System.IDisposable::Dispose()
IL_0012: ldc.i4.0
IL_0013: ret
} // end of method Dispose::main
} // end of class Dispose
.class private abstract auto ansi sealed '<StartupCode$CompilerExplorer>'.$Dispose
extends [System.Runtime]System.Object
{
} // end of class '<StartupCode$CompilerExplorer>'.$Dispose
.class private abstract auto ansi sealed '<StartupCode$CompilerExplorer>'.$AssemblyInfo
extends [System.Runtime]System.Object
{
} // end of class '<StartupCode$CompilerExplorer>'.$AssemblyInfo
.class private abstract auto ansi sealed '<StartupCode$CompilerExplorer>'.$VersionInfo
extends [System.Runtime]System.Object
{
} // end of class '<StartupCode$CompilerExplorer>'.$VersionInfo
https://godbolt.org/z/oxYo5Ge7P
It is generating invalid constrained call, removing IDisposable constraint fixes the issue.
Another issue with runtime error caused by the witness (which is only needed for quotations, not for the regular run). The issue can be fixing by targeting the wrong IL piece like in this case, but it feels the witness codegen is having a more fundamental flaw allowing to generate code which normal F# would not allow.