Skip to content

fix(net): pad GetExtendedTcpTable buffer to prevent GC thrashing on Windows - #2108

Merged
shirou merged 4 commits into
shirou:masterfrom
HarshalPatel1972:patch-gopsutil
Jul 11, 2026
Merged

fix(net): pad GetExtendedTcpTable buffer to prevent GC thrashing on Windows#2108
shirou merged 4 commits into
shirou:masterfrom
HarshalPatel1972:patch-gopsutil

Conversation

@HarshalPatel1972

Copy link
Copy Markdown
Contributor

Problem

Under heavy network load, querying the Windows TCP/UDP tables can trigger a near-infinite ERROR_INSUFFICIENT_BUFFER spin-loop. Because the Go wrapper naively allocates the exact required size returned by the Win32 API, any new connections spawned by the OS before the next iteration cause the subsequent API call to fail again. This rapid, tight reallocation cycle completely overwhelms the Go Garbage Collector, mimicking a severe memory leak and causing massive CPU spikes.

Fix

  • Added a 4KB (4096 byte) padding to the requested size before reallocating the buffer in both getTCPConnections and getUDPConnections.
  • This padding safely absorbs concurrent connection growth between the failed API call and the next iteration, allowing the retry loop to exit cleanly and preventing GC thrashing.

Verification

  • Validated via go test -v ./net/.... Struct alignment and parsing remain intact.

Copilot AI review requested due to automatic review settings June 30, 2026 13:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Under heavy load, querying the Windows TCP/UDP tables can trigger an infinite
ERROR_INSUFFICIENT_BUFFER loop. Because the exact required size is allocated,
any new connections spawned before the next iteration cause the call to fail
again. This rapid reallocation cycle overwhelms the Go GC, mimicking a severe
memory leak.

Adding a 4KB padding buffer to the requested size absorbs concurrent connection
growth, allowing the retry loop to succeed and preventing GC thrashing.

Signed-off-by: Harshal Patel <hp842484@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread net/net_windows.go Outdated
Comment thread net/net_windows.go Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@shirou

shirou commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Thanks for the fix! The approach makes sense. One thing:

Could you make the TCP and UDP changes consistent? Copilot's comment about the uint32 overflow applies to both paths, but the guard was only added on the TCP side. Personally I'd lean toward dropping the guard in both places — a table size near 4 GiB can't realistically happen, and on 32-bit builds make would panic above MaxInt32 before the guard helps anyway. But if you prefer keeping it, please add the same guard (with the shared constant) to the UDP side too.

Optionally, a small retry limit on the loop might be worth considering, since very heavy churn could in theory still keep it spinning.

@HarshalPatel1972

Copy link
Copy Markdown
Contributor Author

Thanks for the fix! The approach makes sense. One thing:

Could you make the TCP and UDP changes consistent? Copilot's comment about the uint32 overflow applies to both paths, but the guard was only added on the TCP side. Personally I'd lean toward dropping the guard in both places — a table size near 4 GiB can't realistically happen, and on 32-bit builds make would panic above MaxInt32 before the guard helps anyway. But if you prefer keeping it, please add the same guard (with the shared constant) to the UDP side too.

Optionally, a small retry limit on the loop might be worth considering, since very heavy churn could in theory still keep it spinning.

@shirou Thanks for the feedback!

You are completely right about the uint32 overflow guard being overkill. I've just pushed a new commit that rips it out entirely, making the TCP and UDP logic perfectly consistent.

I also took your advice and wrapped both buffer allocation loops with a hard 10-retry limit (for retry := 0; retry < 10; retry++). If the OS manages to churn the TCP/UDP tables so violently that we can't allocate a sufficient buffer after 10 tries, it now cleanly bails out with an error rather than spinning infinitely.

Let me know if this looks good to merge.

Signed-off-by: Harshal Patel <hp842484@gmail.com>

@shirou shirou left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for the update. LGTM! I appreciate your contribution!

@shirou
shirou merged commit b6da089 into shirou:master Jul 11, 2026
51 checks passed
@HarshalPatel1972

Copy link
Copy Markdown
Contributor Author

Thanks for the update. LGTM! I appreciate your contribution!

Thanks for the guidance throughout.

mergify Bot added a commit to ArcadeData/arcadedb that referenced this pull request Aug 5, 2026
…p ci]

Bumps the go-modules group in /e2e-go with 2 updates: [github.com/moby/go-archive](https://github.com/moby/go-archive) and [github.com/shirou/gopsutil/v4](https://github.com/shirou/gopsutil).
Updates `github.com/moby/go-archive` from 0.2.1 to 0.3.2
Release notes

*Sourced from [github.com/moby/go-archive's releases](https://github.com/moby/go-archive/releases).*

> v0.3.2
> ------
>
> What's Changed
> --------------
>
> Fix a regression introduced in v0.3.0 that caused archive extraction to fail when paths traversed absolute symlinks inside the destination root, such as `var/run -> /run`. Absolute symlink targets are now resolved relative to the extraction root while relative symlink escapes remain rejected. [moby/go-archive#93](https://redirect.github.com/moby/go-archive/pull/93)
>
> **Full Changelog**: <moby/go-archive@v0.3.1...v0.3.2>
>
> v0.3.1
> ------
>
> Fixes
> -----
>
> This patch release fixes a regression introduced in v0.2.1 where archive extraction could fail when an archive omitted explicit entries for parent directories. For example, extracting `etc/dnf/` without a preceding `etc/` entry could return `mkdirat etc/dnf: no such file or directory`.
>
> This prevented affected images from being extracted. Archive extraction now creates implied parent directories for both file and directory entries.
>
> What's Changed
> --------------
>
> * archive: create implied parents for directory entries [moby/go-archive#92](https://redirect.github.com/moby/go-archive/pull/92)
> * archive: Tarballer.Go: suppress io.ErrClosedPipe logs on close [moby/go-archive#94](https://redirect.github.com/moby/go-archive/pull/94)
>
> **Full Changelog**: <moby/go-archive@v0.3.0...v0.3.1>
>
> v0.3.0
> ------
>
> Security
> --------
>
> This release fixes **CVE-2026-17106** / **[GHSA-hfg8-hc9c-6c3h](https://github.com/moby/go-archive/security/advisories/GHSA-hfg8-hc9c-6c3h)**, where a crafted tar archive could use links to cause extraction operations to create or overwrite files outside the intended destination directory.
>
> The issue affected `Unpack`, `UnpackLayer`, `Untar`, `UntarUncompressed`, and the `ApplyLayer` helpers. Users should upgrade and avoid extracting untrusted archives with earlier versions.
>
> What's Changed
> --------------
>
> * archive: harden tar extraction against path traversal [moby/go-archive#45](https://redirect.github.com/moby/go-archive/pull/45)
> * archive: do not follow reparse points in chtimes [moby/go-archive#90](https://redirect.github.com/moby/go-archive/pull/90)
> * archive: fix creation time updates on Windows [moby/go-archive#79](https://redirect.github.com/moby/go-archive/pull/79)
> * archive: minor cleanups and godoc touch-up [moby/go-archive#87](https://redirect.github.com/moby/go-archive/pull/87)
> * archive: RebaseArchiveEntries: fix archive path rebasing [moby/go-archive#43](https://redirect.github.com/moby/go-archive/pull/43)
>
> Test and CI changes
> -------------------
>
> * ci: enable dependabot for actions [moby/go-archive#81](https://redirect.github.com/moby/go-archive/pull/81)
> * archive: make breakoutErr unwrap its cause [moby/go-archive#91](https://redirect.github.com/moby/go-archive/pull/91)
> * archive: use filepath for filesystem paths in tests [moby/go-archive#80](https://redirect.github.com/moby/go-archive/pull/80)
> * archive: use filepath for filesystem paths in tests [moby/go-archive#80](https://redirect.github.com/moby/go-archive/pull/80)
>
> **Full Changelog**: <moby/go-archive@v0.2.1...v0.3.0>


Commits

* [`9e6d2c7`](moby/go-archive@9e6d2c7) Merge pull request [#93](https://redirect.github.com/moby/go-archive/issues/93) from thaJeztah/fix\_absolute\_symlinks
* [`4f6cd58`](moby/go-archive@4f6cd58) archive: resolve hardlinks through absolute symlinks
* [`e564ecc`](moby/go-archive@e564ecc) archive: resolve absolute symlinks within extraction root
* [`5bb8a45`](moby/go-archive@5bb8a45) Merge pull request [#94](https://redirect.github.com/moby/go-archive/issues/94) from thaJeztah/denoise
* [`1bec7ec`](moby/go-archive@1bec7ec) archive: Tarballer.Go: suppress io.ErrClosedPipe logs on close
* [`279fa6d`](moby/go-archive@279fa6d) Merge pull request [#92](https://redirect.github.com/moby/go-archive/issues/92) from thaJeztah/fix\_implied\_directories
* [`517985a`](moby/go-archive@517985a) archive: create implied parents for directory entries
* [`1c23372`](moby/go-archive@1c23372) Merge pull request [#43](https://redirect.github.com/moby/go-archive/issues/43) from thaJeztah/fix\_rebase\_from\_root
* [`8829a25`](moby/go-archive@8829a25) RebaseArchiveEntries: fix archive path rebasing
* [`c583b20`](moby/go-archive@c583b20) Merge pull request [#90](https://redirect.github.com/moby/go-archive/issues/90) from thaJeztah/chtimes\_nofollow
* Additional commits viewable in [compare view](moby/go-archive@v0.2.1...v0.3.2)
  
Updates `github.com/shirou/gopsutil/v4` from 4.26.6 to 4.26.7
Release notes

*Sourced from [github.com/shirou/gopsutil/v4's releases](https://github.com/shirou/gopsutil/releases).*

> v4.26.7
> -------
>
> What's Changed
> --------------
>
> ### cpu
>
> * fix: harden parsers against malformed/truncated input by [`@​shirou`](https://github.com/shirou) in [shirou/gopsutil#2109](https://redirect.github.com/shirou/gopsutil/pull/2109)
> * [cpu][windows]: compute cpu-total times from integer ticks by [`@​skartikey`](https://github.com/skartikey) in [shirou/gopsutil#2111](https://redirect.github.com/shirou/gopsutil/pull/2111)
> * [darwin][process]: fix errno handling and library lifetime on darwin by [`@​shirou`](https://github.com/shirou) in [shirou/gopsutil#2119](https://redirect.github.com/shirou/gopsutil/pull/2119)
> * [cpu][windows]: compute total counters from individual stats to handle processor groups correctly by [`@​srebhan`](https://github.com/srebhan) in [shirou/gopsutil#2125](https://redirect.github.com/shirou/gopsutil/pull/2125)
> * [cpu][windows]: harden the cpu-total computation added in [#2125](https://redirect.github.com/shirou/gopsutil/issues/2125) by [`@​shirou`](https://github.com/shirou) in [shirou/gopsutil#2128](https://redirect.github.com/shirou/gopsutil/pull/2128)
>
> ### net
>
> * fix(net): pad GetExtendedTcpTable buffer to prevent GC thrashing on Windows by [`@​HarshalPatel1972`](https://github.com/HarshalPatel1972) in [shirou/gopsutil#2108](https://redirect.github.com/shirou/gopsutil/pull/2108)
>
> ### process
>
> * process: implement Darwin IOCounters via proc\_pid\_rusage by [`@​DavRack`](https://github.com/DavRack) in [shirou/gopsutil#2117](https://redirect.github.com/shirou/gopsutil/pull/2117)
>
> ### other
>
> * feat: add psutil comparison tests for cpu, mem and load by [`@​shirou`](https://github.com/shirou) in [shirou/gopsutil#2114](https://redirect.github.com/shirou/gopsutil/pull/2114)
>
> New Contributors
> ----------------
>
> * [`@​DavRack`](https://github.com/DavRack) made their first contribution in [shirou/gopsutil#2117](https://redirect.github.com/shirou/gopsutil/pull/2117)
> * [`@​srebhan`](https://github.com/srebhan) made their first contribution in [shirou/gopsutil#2125](https://redirect.github.com/shirou/gopsutil/pull/2125)
>
> **Full Changelog**: <shirou/gopsutil@v4.26.6...v4.26.7>


Commits

* [`52a24c8`](shirou/gopsutil@52a24c8) Merge pull request [#2128](https://redirect.github.com/shirou/gopsutil/issues/2128) from shirou/feat/follow-up-2125
* [`268a953`](shirou/gopsutil@268a953) [cpu][windows]: harden the cpu-total computation added in [#2125](https://redirect.github.com/shirou/gopsutil/issues/2125)
* [`1e34da6`](shirou/gopsutil@1e34da6) Merge pull request [#2125](https://redirect.github.com/shirou/gopsutil/issues/2125) from srebhan/fix\_cpu\_windows\_total
* [`61f8802`](shirou/gopsutil@61f8802) Merge pull request [#2122](https://redirect.github.com/shirou/gopsutil/issues/2122) from shirou/dependabot/github\_actions/actions/checko...
* [`7fb4dcf`](shirou/gopsutil@7fb4dcf) Merge pull request [#2123](https://redirect.github.com/shirou/gopsutil/issues/2123) from shirou/dependabot/github\_actions/actions/setup-...
* [`ae7d91a`](shirou/gopsutil@ae7d91a) Merge pull request [#2119](https://redirect.github.com/shirou/gopsutil/issues/2119) from shirou/fix/darwin-errno-and-libcache
* [`49052a1`](shirou/gopsutil@49052a1) [darwin][process]: use a PID above PID\_MAX in the not-running tests
* [`991b238`](shirou/gopsutil@991b238) [darwin]: pass the remaining Go pointers as unsafe.Pointer on darwin
* [`b9930e2`](shirou/gopsutil@b9930e2) Merge pull request [#2124](https://redirect.github.com/shirou/gopsutil/issues/2124) from shirou/dependabot/github\_actions/actions/labele...
* [`38a01b4`](shirou/gopsutil@38a01b4) [cpu][windows]: compute total counters from individual stats to handle proces...
* Additional commits viewable in [compare view](shirou/gopsutil@v4.26.6...v4.26.7)
  
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore  major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore  minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore  ` will remove the ignore condition of the specified dependency and ignore conditions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants