Skip to content

Fix dangling stack references in ParseGuid and subscription parsing - #8

Merged
ritchiecarroll merged 1 commit into
mainfrom
fix/dangling-guid-references
Oct 7, 2026
Merged

ritchiecarroll merged 1 commit into
mainfrom
fix/dangling-guid-references

Conversation

@ritchiecarroll

Copy link
Copy Markdown
Member

Summary

Fixes two uses of stack memory after its lifetime ended (undefined behavior). Both are one-line changes.

ParseGuid(const uint8_t* data, bool swapEndianness) — src/lib/Convert.cpp

swappedBytes[16] was declared inside the if (swapEndianness) block, encodedBytes was pointed at it, and the bytes were read through encodedBytes after the block had ended. With g++ 10.5 at -O2 the swapped bytes are never stored, so every .NET-ordered Guid decodes as garbage; unoptimized builds happen to work. The array is now declared at function scope.

No code in this repository calls ParseGuid with swapEndianness = true, so this only affects consumers of the public API. It was found in a port of this code (snapdb/cppapi), where Release builds decoded every Guid incorrectly.

SubscriberConnection::ParseSubscriptionRequest — src/lib/transport/SubscriberConnection.cpp

const Guid& signalID = row->ValueAsGuid(signalIDColumn).GetValueOrDefault();

ValueAsGuid returns a temporary Nullable<Guid> and GetValueOrDefault returns a reference to its member, so signalID dangled once the statement ended. It was then passed to SignalIndexCache::AddMeasurementKey. This is publisher side: it determines the signal IDs placed in a subscriber's signal index cache. signalID is now held by value.

The existing tests pass in Release with or without this change; it was only caught by AddressSanitizer.

Testing

Check Linux (g++ 10.5, Boost 1.92, Release) Windows (VS 2026 v145, Release x64)
Library and all samples build OK OK, 0 warnings
ParseGuid(…, true) before Fails at -O2 (garbage / all-zero Guids), passes at -O0 Passes
ParseGuid(…, true) after Passes Passes
FilterExpressionTests, PublisherCacheIndexTest, ConfigurationFramesTest, SubscriberStartupTest Pass Pass
SimpleSubscribe against a local openHistorian Subscribed with 14 signals Not run

AddressSanitizer (-fsanitize=address -fsanitize-address-use-after-scope, Linux):

  • Original ParseGuid: stack-use-after-scope at Convert.cpp:604; clean after the fix.
  • PublisherCacheIndexTest: aborted with stack-use-after-scope under SubscriberConnection.cpp:1410 before the fix; clean after.
  • The other samples listed above report nothing.

Not included

  • No regression test is added for ParseGuid(…, true); it was checked with a throwaway program linked against the built library.
  • No version bump.
  • Debug and Win32 configurations were not built.
  • The vendored antlr4 runtime and pugixml were not reviewed for the same pattern.

🤖 Generated with Claude Code

- ParseGuid(data, swapEndianness = true) read through a pointer to a block-scoped
  array after the block ended; optimized g++ builds returned garbage Guids
- ParseSubscriptionRequest bound a const Guid& into a temporary Nullable<Guid>
  and used it when building the subscriber signal index cache

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ritchiecarroll
ritchiecarroll merged commit 4cc60c2 into main Oct 7, 2026
2 checks passed
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