Skip to content

Set 512KiB to thread stack size for static Linux binary#6291

Merged
SimplyDanny merged 4 commits intorealm:mainfrom
ainame:increase-stack-size
Oct 12, 2025
Merged

Set 512KiB to thread stack size for static Linux binary#6291
SimplyDanny merged 4 commits intorealm:mainfrom
ainame:increase-stack-size

Conversation

@ainame
Copy link
Contributor

@ainame ainame commented Oct 11, 2025

Closes #6287

Background

In #6287, I reported crashes occurred with 0.61.0's new fully static Linux binaries.
Since then I managed to replicate the crashes on GitHub Actions.

In short, it's easy to replicate if you run swiftlint-static against https://github.com/apple/swift-nio or https://github.com/pointfreeco/isowords repos.
https://github.com/ainame/swiftlint-static-test/actions/runs/18432502301

I also did debug swiftlint-static with lldb and identified the root cause, which was stack exhaustion.
#6287 (comment)

What

Static Linux SDK comes with musl and musl has limited thread stack size by default - 128KiB, which is smaller than the default size for Darwin's pthread 512KiB.

musl provides a default thread stack size of 128k (80k prior to 1.1.21).

https://wiki.musl-libc.org/functional-differences-from-glibc.html

// Default stack size is 512KB; independent of the main thread's stack size.
#define DEFAULT_STACK_SIZE (size_t)(512 * 1024)

https://github.com/apple-oss-distributions/libpthread/blob/1ebf56b3a702df53213c2996e5e128a535d2577e/src/pthread.c#L84-L85

I think SwiftLint running on Linux should have the same default stack size as on macOS,
so it can lint source files of equivalent complexity.

How

Since 1.1.21, musl supports increasing the default thread stack size via the PT_GNU_STACK program header, which can be set at link time via -Wl,-z,stack-size=N.

Thanks to this we can specify default thread stack size via swift build command.
I updated release.yml to use 512KiB, like below

swift build \
  -c release \
  --product swiftlint \
  --swift-sdk ${{ matrix.swift_sdk }} \
  -Xswiftc -DSWIFTLINT_DISABLE_SOURCEKIT \
  -Xlinker -z -Xlinker stack-size=0x80000 # 512KiB

Test

https://github.com/ainame/swiftlint-static-test/actions/runs/18432924761

There are four jobs in matrix

  • 0.61.0's swiftlint-static for x86_64
  • 0.61.0's swiftlint-static for aarch64
  • Manually built and patched swiftlint-static for x86_64 with stack-size set to 512KiB
  • Manually built and patched swiftlint-static for aarch64 with stack-size set to 512KiB
    (see details of the compile options and the patch here https://github.com/ainame/swiftlint-static-test/releases/tag/test3)

If swiftlint-static lint successfully exit (0 or 2), the job succeeds.
And thanks to the small patch, you can actually see 512KiB stack size is used for each DispatchQueue.

Run cd swift-nio-main
Linting Swift files in current working directory
[dispatch queue main]: pthread stack size = 526912 bytes (≈ 0.50 MiB)
[dispatch queue 0]: pthread stack size = 526912 bytes (≈ 0.50 MiB)

@ainame ainame marked this pull request as ready for review October 11, 2025 18:10
@ainame ainame marked this pull request as draft October 11, 2025 18:12
@ainame ainame force-pushed the increase-stack-size branch from 251a4e4 to 92a7d25 Compare October 11, 2025 18:13
@ainame ainame marked this pull request as ready for review October 11, 2025 18:21
@ainame ainame changed the title Set 512KiB to thread stack size when making static linux binary Set 512KiB to thread stack size for static linux binary Oct 11, 2025
@ainame ainame changed the title Set 512KiB to thread stack size for static linux binary Set 512KiB to thread stack size for static Linux binary Oct 11, 2025
Copy link
Collaborator

@SimplyDanny SimplyDanny left a comment

Choose a reason for hiding this comment

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

That's awesome @ainame! Thank you so much for the analysis. That wasn't an easy one.

Would you like to add a changelog entry as well? It's the only form of credit I can offer you. 🙏

--product swiftlint \
--swift-sdk ${{ matrix.swift_sdk }} \
-Xswiftc -DSWIFTLINT_DISABLE_SOURCEKIT \
-Xlinker -z -Xlinker stack-size=0x80000 # 512KiB
Copy link
Collaborator

Choose a reason for hiding this comment

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

Did you try to run this on a Linux machine? It doesn't work on macOS, because the linker expects different arguments to set the stack size.

Copy link
Contributor Author

@ainame ainame Oct 11, 2025

Choose a reason for hiding this comment

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

Yes I have created this page's binaries with this command on Ubuntu (VM).
https://github.com/ainame/swiftlint-static-test/releases/tag/test3

-z stack-size=VALUE format is supported by ld. Apple's ld64 doesn't support it unfortunately. But that's okay since the binary will be built on ubuntu-24.04/ubuntu-24.04-arm runner, right?

% lld --help
lld is a generic driver.
Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld (WebAssembly) instead
% ld64.lld --help | grep stack
%

stack-size=value
Specify a stack size for an ELF "PT_GNU_STACK" segment. Specifying zero will override any
default non-zero sized "PT_GNU_STACK" segment creation.

https://manpages.ubuntu.com/manpages/plucky/man1/ld.1.html

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, that's totally fine. I build the binaries on macOS from time to time for testing purposes. So far they worked without the stack size increase. For the release, that's Ubuntu's job. I may trigger a new release right after merging your PR, so that we can verify the binaries again.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh -Xlinker -z -Xlinker stack-size=0x80000 worked with other project indeed.

I assume that the current toolchains might have applied the linker options for SwiftLintCoreMacros target, which is built and run for macOS? and failed. I haven't checked logs or any though.

Copy link
Collaborator

@SimplyDanny SimplyDanny Oct 12, 2025

Choose a reason for hiding this comment

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

Yes, it exactly failed while linking the macro tool. I'm not sure how to configure the flags in more detail in order to determine to which steps they should be applied to with SPM.

@ainame
Copy link
Contributor Author

ainame commented Oct 11, 2025

I updated CHANGELOG.md as well🙏

@ainame ainame force-pushed the increase-stack-size branch from 46857ce to cb50fe2 Compare October 11, 2025 22:08
--product swiftlint \
--swift-sdk ${{ matrix.swift_sdk }} \
-Xswiftc -DSWIFTLINT_DISABLE_SOURCEKIT \
-Xlinker -z -Xlinker stack-size=0x80000 # 512KiB
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, that's totally fine. I build the binaries on macOS from time to time for testing purposes. So far they worked without the stack size increase. For the release, that's Ubuntu's job. I may trigger a new release right after merging your PR, so that we can verify the binaries again.

@SimplyDanny SimplyDanny enabled auto-merge (squash) October 12, 2025 07:15
@SimplyDanny SimplyDanny merged commit f67943d into realm:main Oct 12, 2025
26 of 27 checks passed
@ainame ainame deleted the increase-stack-size branch October 12, 2025 10:26
@SimplyDanny
Copy link
Collaborator

There we go. I noticed that the static binaries lint significantly slower than the dynamic ones. That's also something requiring attention before they can leave their experimental state.

@ainame
Copy link
Contributor Author

ainame commented Oct 13, 2025

I did casual benchmark and tried a potential fix https://github.com/microsoft/mimalloc. It's promising already.
I can try some investigation if you don't mind

#6298

@SimplyDanny
Copy link
Collaborator

I can try some investigation if you don't mind

That'd be highly appreciated! Please go ahead. 🙏

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.

The new binaries built with Static Linux SDK crashes

2 participants