dotnet / dotnet/fsharp

Returning a voidptr option throws at runtime

Open
#9,994 10 comments 1 reaction 1 assignee Claimed by @TIHan View on GitHub
Area-Compiler-Checking Area-Compiler-Checking-Byref Bug Impact-Medium
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 11h
Merged PRs (30d)
131

Description

When a function returns `Some x` where `x` is of type `voidptr`, the code compiles but throws at runtime.

**Repro steps**

Simple repro:

```f#
let check () =
let mutable tmp = IntPtr.Zero
let mutable handle = NativeInterop.NativePtr.toVoidPtr &&tmp
Some handle

[]
let main argv =
// this throws at runtime
check() |> ignore
```

A similar approach that also fails (but succeeds with `|> ignore`):

```f#
let check () =
let mutable tmp = IntPtr.Zero
let mutable handle = NativeInterop.NativePtr.toVoidPtr &&tmp
handle

[]
let main argv =
// this throws at runtime
printfn "Handle: %A" (check())
```

**Expected behavior**

Either a compile error if this is illegal, or a valid result.

**Actual behavior**

The following error is output to the console:

> Unhandled exception. System.TypeLoadException: The generic type 'Microsoft.FSharp.Core.FSharpOption`1' was used with an invalid instantiation in assembly 'FSharp.Core, Version=4.7.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
> at Program.main(String[] argv)

**Known workarounds**

None. Though using your own DU allows this to run with `|> ignore`, it doesn't allow it to deconstruct. I.e.

This doesn't throw:

```f#
type Handle = Handle of voidptr

let check () =
let mutable tmp = IntPtr.Zero
let mutable handle = NativeInterop.NativePtr.toVoidPtr &&tmp
Handle handle

[]
let main argv =
check() |> ignore
```

But this does:

```f#
let main argv =
// this throws at runtime
match check() with
| Handle x -> printfn "Handle: %A" x
```

**Related information**

Seen on any recent version of VS / F#.

Note that I don't know if `voidptr` is allowed as field. ~Probably not, which would make it understandable that this fails, though a compile-time error would be better.~ EDIT: see below, it works in several scenarios, just not with (v)options.

A possible use-case to allow this (if there're no CLS restrictions) is that returned void pointers are often NULL or valid, and options are a good way to wrap such returns.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.