dotnet / dotnet/fsharp

Too many `&` and `|` patterns cause Visual Studio/Ionide to use up all available memory

Open
#15,086 3 comments 1 reaction 0 assignees View on GitHub
Area-Compiler-Checking Area-Compiler-PatternMatching Bug Impact-Medium Regression Theme-Performance
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 11h
Merged PRs (30d)
131

Description

Opening a file with too many `&` and nested `|` patterns (inside of a single match branch?) causes Visual Studio or Ionide to use up all available memory and can eventually cause Windows to crash. It will continue to use up more and more memory even if you remove enough patterns to be under the "too many" threshold or close the file. More repetitions of this type of pattern will increase the rate at which memory is consumed.

**Repro steps**

This is likely not a perfectly minimal repro, but maybe it's good enough to hint at what the problem might be.

1. Write code that uses a fair number of `&` and nested `|` patterns inside of a single pattern-matching branch.

This is not enough to cause a problem[^1]:

```fsharp
// Fine.
let f g x =
let (|A|_|) x = if g x then Some x else None
let (|B|C|) x = if g x then B x else C x
match x with
| A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
-> true
| _ -> false
```

This, however, is (the number of repetitions required to trigger the behavior is not exact; it's somewhere between the examples above and below):
> 💥 **Be careful pasting this into VS/VS Code without being prepared to kill it before it uses all your memory**. Note that closing the file is not enough—you must close or kill Visual Studio/Code.

```fsharp
// 💥 Will use up all your memory.
let f g x =
let (|A|_|) x = if g x then Some x else None
let (|B|C|) x = if g x then B x else C x
match x with
| A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
& A (B _ | C _)
-> true
| _ -> false
```

You will notice faster consumption of memory if you add more repetitions.
2. Visual Studio will eventually use up all available memory without further interaction. I have not let total memory usage go beyond 99% before killing VS, but a coworker's Windows machine eventually crashed on him when he did.

![image](https://user-images.githubusercontent.com/14795984/231902854-0174aba1-5d47-405a-8303-8e25cf781db9.png)

**Expected behavior**

I expect Visual Studio/Code not to use up all of my computer's memory—and certainly not gradually, in the background, without additional interaction.

**Actual behavior**

Visual Studio/Code uses up all of my computer's memory.

**Known workarounds**

None.

**Related information**

Both Visual Studio 17.5.4 and Visual Studio Code 1.77.3 + Ionide 7.5.2 on Windows 10 and 11.

[^1]: This is a simplified example. The real code where we first ran into this bug did not actually repeat identical matches.

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.