dotnet / dotnet/fsharp

Diagnostic for `NativePtr.stackalloc` in positions where `localloc` can never be valid IL

Open
#20,295 2 comments 0 reactions 0 assignees View on GitHub
Area-Diagnostics Feature Improvement Needs-Triage
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 11h
Merged PRs (30d)
131

Description

The following snippets are accepted by the F# compiler but throw `System.InvalidProgramException` at load, before any user code runs. Follow-up to #8083 (general case fixed by #20302).

**1. `localloc` in an exception handler**

```fsharp
open Microsoft.FSharp.NativeInterop
try () with _ -> NativePtr.stackalloc 1 |> ignore
```

**2. `localloc` while `this` is uninitialized (chained base constructor)**

```fsharp
open Microsoft.FSharp.NativeInterop
type A(p: nativeptr) = class end
type B() = inherit A(NativePtr.stackalloc 1)
B() |> ignore
```

Suggest rejecting them in `PostInferenceChecks` (dsyme's suggestion on #8083) — a compile-time error instead of an `InvalidProgramException` at JIT time.

Details

Fixed for the general case by #20302: `IlxGen` spills the pending stack, emits `localloc` at an empty stack, then reloads the pending values under the result pointer.

**Case 1 (handler).** The CoreCLR importer rejects `localloc` when `block->hasHndIndex()` (`dotnet/runtime`, `jit/importer.cpp`) — that is, inside a `catch`, `finally`, or `filter` handler, not a `try` body. This is why the `for .. in seq` shape in fsharp/fslang-suggestions#1469 works. `eenv.withinSEH` does not yet separate a handler from a `try` body, so the diagnostic needs a new flag.

**Case 2 (uninitialized `this`).** ECMA forbids spilling an uninitialized `this`, so `EmitLocallocCode` falls back to a plain emit when `uninitializedThisOnStackCount > 0`. The code is a use-after-free regardless: the stack memory dies when the constructor returns. A real fix, instead of a diagnostic, would hoist the base-constructor arguments into locals before `this` is pushed.

Contributor guide

Open the contributing guide

Research direction

Start in PostInferenceChecks and trace the NativePtr.stackalloc path into IlxGen and EmitLocallocCode. Investigate how handler context and uninitializedThisOnStackCount are represented, using the two snippets as reproductions. Done means both invalid localloc positions produce compile-time diagnostics instead of InvalidProgramException at load or JIT time.

Written by the indexing model from the issue text.

Assessment

Tech stack
fsharp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.