Skip to content

[CollectLinux] Fix no-tty crash with console capability aware ProgressWriter#5771

Merged
hoyosjs merged 2 commits intodotnet:mainfrom
mdh1418:fix/collect-linux-cursor-position-crash
Apr 2, 2026
Merged

[CollectLinux] Fix no-tty crash with console capability aware ProgressWriter#5771
hoyosjs merged 2 commits intodotnet:mainfrom
mdh1418:fix/collect-linux-cursor-position-crash

Conversation

@mdh1418
Copy link
Copy Markdown
Member

@mdh1418 mdh1418 commented Mar 19, 2026

When CursorTop is 0 (e.g., in environments where cursor positioning isn't available), LineToClear was set to -1, causing SetCursorPosition to throw ArgumentOutOfRangeException on progress callbacks.

Extract the progress display concern from OutputHandler into a nested ProgressWriter class that:

  • Probes console capability on first Update() call
  • Interactive: rewrites status line in-place with 1s throttle
  • Non-interactive: prints a static message once, silently no-ops after
  • Owns LineRewriter and LineToClear internally

OutputHandler's status block reduces to progressWriter.Update(), fully decoupling it from LineRewriter. Matches CollectCommand's pattern of probing capability upfront and gating on it.

Also adds bounds validation to MockConsole.SetCursorPosition and a regression test for the CursorTop=0 case.

…riter

When CursorTop is 0 (e.g., in environments where cursor positioning
isn't available), LineToClear was set to -1, causing SetCursorPosition
to throw ArgumentOutOfRangeException on progress callbacks.

Extract the progress display concern from OutputHandler into a nested
ProgressWriter class that:
- Probes console capability once at construction
- Interactive: rewrites status line in-place with 1s throttle
- Non-interactive: prints a static message once, silently no-ops after
- Owns LineRewriter and LineToClear internally

OutputHandler's status block reduces to progressWriter.Update(), fully
decoupling it from LineRewriter. Matches CollectCommand's pattern of
probing capability upfront and gating on it.

Also adds bounds validation to MockConsole.SetCursorPosition and two
regression tests for the CursorTop=0 case.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mdh1418 mdh1418 requested a review from a team as a code owner March 19, 2026 16:34
Copilot AI review requested due to automatic review settings March 19, 2026 16:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a crash in dotnet-trace collect-linux progress callbacks in environments where console cursor positioning isn’t available (or behaves unexpectedly), by centralizing progress output behavior behind a capability-aware writer.

Changes:

  • Refactors progress/status rendering in CollectLinuxCommand into a nested ProgressWriter that gates rewrites and throttles updates.
  • Adds functional regression tests intended to cover CursorTop == 0 / unsupported cursor repositioning scenarios.
  • Tightens MockConsole.SetCursorPosition by adding row bounds validation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/Tools/dotnet-trace/CommandLine/Commands/CollectLinuxCommand.cs Introduces ProgressWriter to manage progress output and console rewrite capability checks.
src/tests/dotnet-trace/CollectLinuxCommandFunctionalTests.cs Adds regression tests for cursor-top/cursor-repositioning edge cases.
src/tests/Common/MockConsole.cs Adds bounds checking to better surface invalid cursor positioning in tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

noahfalk
noahfalk previously approved these changes Mar 19, 2026
- Make LineRewriter._isSetCursorPositionSupported instance-scoped so each
  LineRewriter probes independently with its own LineToClear value
- Guard lineToClear < 0 in ProgressWriter.Initialize before constructing
  LineRewriter, avoiding probing with an invalid row
- Add Thread.Sleep(1100) between callbacks in regression tests to exceed
  the 1-second throttle, ensuring RewriteConsoleLine is actually invoked
  (verified: test fails without the lineToClear guard)
- Standardize Ctrl-C to Ctrl+C across status messages and test data
- Add column bounds validation to MockConsole.SetCursorPosition

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@hoyosjs hoyosjs merged commit 767b7c0 into dotnet:main Apr 2, 2026
19 checks passed
hoyosjs added a commit that referenced this pull request Apr 2, 2026
Copilot aided release notes for user facing changes

---------------------------------------------------------------------

Breaking Changes

- COMPLUS_* environment variable references removed from SOS — use
DOTNET_* equivalents (#5714)
- !name2ee and !token2ee output is now less verbose; modules that don't
contain the requested type are no longer listed (#5719)

dotnet-dump / SOS

New features:

- Add -stat flag to !threadpool to summarize queued work items by type
(#5737)
 - Add sort-by-count option to !dumpheap (#5722)
- Add -noprogress flag to !dumpheap and !verifyheap to suppress progress
reporting (#5773)
- Add -all flag to DumpMT to show class details and method descriptors
in one command (#5701)
- !DumpStackObjects now finds objects correctly during stack overflow
scenarios on Linux (#5723)
- Warn when loading a dump not collected by createdump, as SOS commands
may produce incomplete results (#5720)
- SOS output is now captured correctly by LLDB Python scripts and tools
like lldb-dap (#5728)

Bug fixes:

 - Fix !u failing on IL stubs (#5726)
- Fix DumpIL showing a cryptic error on IL stubs — now explains IL is
unavailable (#5731)
- Fix clrstack -l displaying incorrect values for ushort locals ≥ 0x8000
(#5721)

dotnet-trace / collect-linux

- Enable callstack capture for .NET runtime events in collect-linux —
exception and GC stacks now include resolved frames (#5756)
- collect-linux --probe now gracefully handles unreachable processes
instead of throwing (#5705)
- Fix crash in collect-linux in environments without terminal cursor
support (#5771)
- Fix collect-linux throwing when stdin/stdout are redirected (e.g.
piped or scripted) (#5745)
- Fix terminal cursor not being restored after collect-linux exits
(#5747, #5707)

dotnet-counters

- Add --noAbbreviateValues option to monitor to display full-precision
values without K/M/G abbreviation (#5734)

Diagnostic Tools (general)

- Fix WriteDump failing when the dump path contains spaces on Windows
(#5593)
- Diagnostic tools now work from sidecar containers — dotnet-trace,
dotnet-counters, dotnet-stack, and dotnet-dump can attach to processes
in other containers without manual socket configuration (#5735)

Libraries

- Improved symbol resolution performance by caching failed lookups
(#5729)
- Symbol server key generation now supports ELF binaries from custom
toolchains (#5736)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants