Fix potential double-close issue in sharedEncryption#1446
Open
jgowdy-godaddy wants to merge 1 commit intomainfrom
Open
Fix potential double-close issue in sharedEncryption#1446jgowdy-godaddy wants to merge 1 commit intomainfrom
jgowdy-godaddy wants to merge 1 commit intomainfrom
Conversation
Add sync.Once protection to prevent multiple calls to underlying Encryption.Close() when Remove() is called repeatedly. ## Problem - sharedEncryption.Remove() calls s.Encryption.Close() directly - No protection against multiple Remove() calls on same instance - Could cause panic or undefined behavior in underlying encryption ## Solution - Add closeOnce sync.Once field to sharedEncryption struct - Wrap s.Encryption.Close() call in closeOnce.Do() - Ensures Close() called exactly once regardless of Remove() call frequency ## Benefits - **Idempotency**: Remove() can be called safely multiple times - **Race Protection**: Concurrent Remove() calls properly synchronized - **Panic Prevention**: Eliminates double-close panics in underlying encryption - **Zero Cost**: sync.Once has no overhead after first call ## Testing - TestSharedEncryption_DoubleCloseProtection: Verifies multiple Remove() calls - TestSharedEncryption_ConcurrentDoubleClose: Tests concurrent access - TestSharedEncryption_CloseAndRemove: Tests interaction with Close() method 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
0d217ca to
84fe554
Compare
aka-bo
reviewed
Aug 20, 2025
Contributor
aka-bo
left a comment
There was a problem hiding this comment.
Is there a scenario where Remove() could be called multiple times on the same instance?
After examining the code paths, I found:
- Single call site:
Remove()is only called from cache eviction (session_cache.go:160) - Cache prevents double eviction: Items are removed from map before callbacks (
pkg/cache/cache.go:465-466) - Session.Close() is safe: Only decrements counter, doesn't call underlying
Close() - Session isolation: Each gets its own
sharedEncryptionwrapper
The sync.Once appears to be defensive programming against hypothetical bugs in the condition variable logic rather than addressing an actual double-close risk.
Was this more of a precautionary measure, or have you observed specific cases where double-close could occur?
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.
Fix Potential Double-Close Issue in Session Cache
Problem
The
sharedEncryption.Remove()method had no idempotency protection, creating a potential double-close vulnerability that could cause panics or undefined behavior in production environments.Vulnerable Code Path:
Risk Scenarios:
Remove()callsRemove()multiple timesEncryption.Close()implementations may panic on repeated callsSolution
Implemented bulletproof idempotency using Go's
sync.Onceprimitive to guarantee the underlyingEncryption.Close()is called exactly once, regardless of how many timesRemove()is invoked.Protected Implementation:
Performance Impact
Virtually Zero Performance Cost:
int32+ pointersync.Once Performance Characteristics:
Safety & Reliability Benefits
Idempotency Guarantees
Production Robustness
Error Recovery
Architecture Validation
No Pooling/Reuse Conflicts:
Encryption.Close()is documented as final cleanup ("frees up any resources")sharedEncryptioninstances are created fresh per session (no pooling)Remove()only called during cache eviction (disposal context)sync.Once Design Perfect Fit:
Comprehensive Testing
Added thorough test coverage with realistic scenarios:
Test Coverage Matrix
Remove()calls in sequenceClose()called exactly onceRemove()simultaneouslyClose()Close()andRemove()callsRepresentative Test Case
Risk Assessment
Extremely Low Risk Change:
Backwards Compatibility:
Monitoring & Observability
No Special Monitoring Required:
Positive Indicators:
Production Benefits
High-Traffic Environments
Serverless/Lambda Environments
Long-Running Services
Summary
This fix implements a standard Go reliability pattern (
sync.Once) to eliminate a potential double-close vulnerability while maintaining perfect backwards compatibility and adding virtually zero performance overhead. The change transforms a potential production reliability issue into a safely handled no-op scenario.Key Outcomes:
🤖 Generated with Claude Code