Read GError.message at its real offset on 64-bit Linux [patch] - #172
Merged
Merged
Conversation
ThrowIfError read the message pointer at IntPtr.Size * 2, which is offset
16 on x64: past the end of glib's GError { guint32 domain; gint code;
gchar *message; }, whose message sits at offset 8. Every libsecret failure
produced a garbage message or faulted in PtrToStringUTF8.
GError is now declared as a sequential struct and the message read through
it, so the layout is written down rather than hand-computed.
Fixes #163
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UnqwfbU2boDDiUoqRZSY2D
SonarCloud flagged the ThrowIfError call site as uncovered new code. The new test has glib build a real GError and checks that ThrowIfError reports its message. It runs on Linux, where glib is present, and reports inconclusive elsewhere. With the old IntPtr.Size * 2 offset it kills the test host with an AccessViolationException. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UnqwfbU2boDDiUoqRZSY2D
|
This was referenced Sep 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes #163
Problem
LinuxSecretServiceCredentialStore.ThrowIfErrorread the message pointer atIntPtr.Size * 2. On x64 that is offset 16, which is past the end of glib'sGError { guint32 domain; gint code; gchar *message; }. The message actually sits at offset 8. So every libsecret failure on 64-bit Linux produced a garbage message, or faulted insidePtrToStringUTF8. That includes the common case of a headless machine with no Secret Service.Change
Storage/GError.csdeclaresGErroras a[StructLayout(Sequential)]struct, which is the approach the triage comment preferred.GError.ReadMessage(IntPtr)reads the message throughMarshal.PtrToStructure<GError>.ThrowIfErrornow callsGError.ReadMessage. It still frees the error and throws the same way. It changed from private to internal so a test can reach it.IntPtr.Size * noffsets in the Linux store, as the triage comment suggested. There are none.Tests
New file:
CredentialCache.Test/GErrorTests.cs.ReadMessageReturnsTheMessageFieldandReadMessageReturnsNullForANullMessage: hand-build aGErrorin unmanaged memory, so they run on every platform. The buffer is zeroed and one pointer longer than the struct, so a read past the end finds null rather than whatever memory follows. With the old offset, both fail.ThrowIfErrorReportsTheMessageOfARealGError: runs on Linux only and reports inconclusive elsewhere. glib's owng_error_new_literalbuilds the error, and the test asserts theCredentialStoreExceptioncarries its message. With the old offset, this test kills the test host with anAccessViolationException, which is the crash described in the issue.The full suite: 64 passed, 5 skipped. Those 5 skips are native-store tests that were already skipped before this change. CI is green on all three OSes, and SonarCloud reports 100% coverage on new code.
Not covered: exercising libsecret itself with no D-Bus session. That needs libsecret and a Secret Service setup on the runner.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UnqwfbU2boDDiUoqRZSY2D