Repository navigation
[OpenTelemetry] Avoid hash collisions for wide metric tag values - #7979
Merged
Merged
Conversation
Compare overflow lookups for colliding long values with ordinary long, string, and integer values using BenchmarkDotNet. Discovered by Anthropic's OSS Scanner, as bug ANT-2026-WNPGQ6JU.
Hash the full equality-relevant bits of built-in wide metric tag values before folding to a dictionary hash. Preserve equal-value hashes across floating-point, decimal, date, and time representations on all targets. Add regression coverage for collision scans and equality compatibility. Discovered by Anthropic's OSS Scanner, as bug ANT-2026-WNPGQ6JU.
Use the existing managed explicit-layout pattern to read all Guid bits without a temporary array on legacy targets. Verify every Guid byte and measure existing-series and overflow costs for Guid and decimal tags. Discovered by Anthropic's OSS Scanner, as bug ANT-2026-WNPGQ6JU.
Document the corrected wide metric tag hash behavior under Unreleased and link the entry to PR open-telemetry#7979. Discovered by Anthropic's OSS Scanner, as bug ANT-2026-WNPGQ6JU.
Pull request dashboard statusMerged · refreshed 2026-10-19 17:53 UTC Status above doesn't look right?
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7979 +/- ##
==========================================
+ Coverage 90.19% 90.20% +0.01%
==========================================
Files 366 366
Lines 21440 21496 +56
Branches 3943 3949 +6
==========================================
+ Hits 19337 19390 +53
- Misses 1525 1528 +3
Partials 578 578
Flags with carried forward coverage won't be shown. Click here to find out more.
|
Kielek
marked this pull request as ready for review
October 19, 2026 11:13
Keep the measured before/after evidence and permanent regression tests, while removing the two point-in-time benchmark harnesses from the PR. Discovered by Anthropic's OSS Scanner, as bug ANT-2026-WNPGQ6JU.
Move equal wide-value representations into a static TheoryData method and run each group through MemberData, preserving all hash and equality checks. Discovered by Anthropic's OSS Scanner, as bug ANT-2026-WNPGQ6JU.
martincostello
approved these changes
Oct 19, 2026
matt-hensley
approved these changes
Oct 19, 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.
This fix addresses a ANT-2026-WNPGQ6JU finding from Anthropic's OSS Scanner.
Project enrollment: anthropics/oss-scanner#117.
Changes
Distinct wide metric tag values can share their built-in 32-bit hash. Their
metric lookups then scan one bucket up to the cardinality limit. Hash the full
equality-relevant bits of
long,ulong,double,decimal,Guid,DateTime,DateTimeOffset, andTimeSpanbefore the seeded 32-bit fold.Normalize equivalent floating-point, decimal, and timestamp representations.
Both ordinary and alternate span lookup use the corrected hash on every target.
No public or experimental API changes; API tracking updates are not applicable.
Regressions show 2000 missing-key comparisons before the fix and at most eight
afterward for all eight types, then verify all existing entries. Additional
coverage checks equal representations, word cancellation, span consistency,
and every Guid byte. The final full SDK Release suite passes on net10.0,
net9.0, net8.0, and net472: 6792 passed, 17 existing skips, 0 failures.
The complete Release solution builds with zero warnings/errors. Explicit
netstandard2.0 and netstandard2.1 asset probes pass on CoreCLR. Non-Windows
runtimes were not tested. Formatting verification exits zero with workspace
reference-loading warnings and unsupported F# formatting. The unmodified
source sanity check passes in a tracked-source snapshot using CI line endings;
the native post-build run encounters generated Windows CRLF files.
Benchmark comparison
Both comparisons use the repository's unmodified
benchmark.ps1, default job,MemoryDiagnoser, and identical benchmark source at each paired ref. Values are
boxed during setup. Each executed SDK assembly's ProductVersion contains its
requested commit. Results below are verbatim BenchmarkDotNet GitHub reports;
ratios are within each report, not baseline-versus-fix ratios.
.NET 10 compares benchmark-only baseline d94ac21
with 6f5e47a. The final follow-up changes
only legacy Guid hashing, so the measured modern long path is unchanged.
Colliding-long overflow falls from 26335.70 to 53.97 ns, with no measured
allocation in these four cases. Ordinary-long and string controls are noisy
on this hybrid CPU; no small control improvement or regression is inferred.
.NET 10 original SDK
.NET 10 fix
The legacy comparison uses final fix 37f09f0
and benchmark-only baseline a5dad5ba78022761f06135d0210f80dabedddf84, net472
on .NET Framework 4.8.1, affinity mask 1. Guid has no measured allocation.
Decimal retains the portable
GetBitsarray API on non-NET targets(net462/netstandard2.0/netstandard2.1), adding 40 B per record here.
Modern NET decimal extraction uses a 16-byte stack buffer. Ordinary-value CPU
costs are visible alongside collision improvements in the tables. The Guid
managed explicit-layout extractor follows the existing MetricPointValueStorage
pattern; no decimal private layout or unsafe code is used. No arithmetic
alternative was proposed or measured. Maintainers should weigh these explicit
compatibility costs; no allocation-free claim is made for legacy decimal.
Framework original SDK
Framework fix
Merge requirement checklist
CHANGELOG.mdfile(s) updated for non-trivial changesNote
This PR description was generated with OpenAI Codex.
Footnotes
Yes, I can answer maintainer questions about the content of this PR without using AI. ↩