Skip to content

internal/dlopen: report dlerror() when no library can be opened - #528

Open
amccabe wants to merge 1 commit into
coreos:mainfrom
amccabe:dlopen-report-dlerror
Open

amccabe wants to merge 1 commit into
coreos:mainfrom
amccabe:dlopen-report-dlerror

Conversation

@amccabe

@amccabe amccabe commented Sep 18, 2026 •

Copy link
Copy Markdown

GetHandle returns the bare ErrSoNotFound sentinel when every dlopen attempt fails, discarding what dlerror() reported. GetSymbolPointer and Close in the same file already capture it. This makes GetHandle do the same for each name tried, and wraps the sentinel so errors.Is(err, ErrSoNotFound) still holds for existing callers.

History. The omission dates from the original dlopen package in coreos/pkg (5ec8ba6, 2016-02-02) and came across unchanged when it moved here as an internal package (3344f03, 2019-11-01). Every v22 tag, v22.0.0 through v22.7.0, carries it.

Why it matters. The sentinel makes a missing library indistinguishable from a transient loader failure, and the string has been reported downstream for years without the cause ever being named:

Impact on k3d on podman. podman machine runs with the journald log driver, so podman's container-logs endpoint opens the journal through sdjournal.NewJournal, which reaches GetHandle on the first request in each API service process. I hit a case where that first request, made by k3d seconds after starting a k3s node, was answered with a 500 carrying only this sentinel. k3d treats a failed log-stream open as a dead node and rolls the whole cluster back, so one unexplained dlopen failure cost a cluster create. The retry succeeded a minute later, and the reason for the first failure is unrecoverable because dlerror() was never read. With this change the journal would have said why.

Before, with libsystemd absent:

unable to open a handle to the library

After:

unable to open a handle to the library: libsystemd-journal.so.0: cannot open shared object file: No such file or directory; libsystemd-journal.so: cannot open shared object file: No such file or directory; libsystemd.so.0: cannot open shared object file: No such file or directory; libsystemd.so: cannot open shared object file: No such file or directory

The error is wrapped with %w, so errors.Is(err, ErrSoNotFound) would still pass. A caller comparing with == would fail after this change; none can: internal/dlopen is an internal package, so nothing outside this module can reference the sentinel, and the in-tree users pass the error through unchanged. The success path is unchanged apart from a thread lock for the duration of the call, matching the other two functions in dlopen.go. The new test asserts the sentinel is preserved and that each name tried appears in the message - it fails on main and passes here.

@amccabe

amccabe commented Sep 18, 2026

Copy link
Copy Markdown
Author

The lint failure here is the pinned golangci-lint v2.11 being unable to type-check Go 1.27, which go-version: stable now resolves to; it panics identically on main with the same toolchain. #529 bumps the linter to v2.13.2 and clears it.

@amccabe

amccabe commented Sep 18, 2026

Copy link
Copy Markdown
Author

The bullseye failures here are apt returning 404 for every package from the bullseye security pool, which left the mirror after Debian 11 reached end of life on 2026-08-31; the job exits before any Go is built. #530 moves the matrix to bookworm and ubuntu 22.04.

GetHandle returned the bare ErrSoNotFound sentinel after every dlopen
attempt failed, discarding what dlerror() had to say. A missing library
and a transient loader failure produced the same message, and callers
such as podman's journald log reader surfaced it to users with no way to
tell which it was. GetSymbolPointer and Close in the same file already
capture dlerror(); GetHandle now does the same, for each name tried, and
wraps the sentinel so errors.Is still holds.

Assisted-by: Claude:claude-fable-5-1 [claude-code]
Signed-off-by: Andrew McCabe <amccabe@users.noreply.github.com>
@amccabe

amccabe commented Sep 19, 2026

Copy link
Copy Markdown
Author

I was looking at prior PRs in this repo and I see this is a duplicate of #527. You should go with that one, it's the same change. The failed checks and the fixes for them in #529 and #530 are still necessary, and #531 should still be useful.

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.

1 participant