Skip to content

Conversation

@sixcolors
Copy link
Member

Description

This PR extends the defensive copying fix from #3828 to the storage implementation and removes now-redundant defensive copying from middleware that rely on these storage layers.

Background

PR #3828 fixed memory corruption in (the interface implementation) by adding defensive copying for string keys and values. However, the same issue exists in , which is used by cache, limiter, and CSRF middleware.

Changes

1. internal/memory/memory.go

Applies the same defensive copying pattern as #3828:

  • Copy string keys in Set() using utils.CopyString()
  • Copy []byte values in Set() to prevent input corruption
  • Copy []byte values in Get() to prevent output mutation
  • Added comprehensive package documentation explaining safety guarantees
  • Other types (structs, ints) retain zero-copy performance

2. internal/storage/memory/memory.go

3. Middleware Cleanup

Now that storage layers handle defensive copying, removed redundant operations:

CSRF (middleware/csrf/storage_manager.go):

  • Removed utils.CopyString(key) and utils.CopyBytes(raw) before m.memory.Set()
  • Storage layer now handles this automatically

Idempotency (middleware/idempotency/idempotency.go):

  • Removed utils.CopyBytes(c.Response().Body()) before marshaling
  • Marshaling already creates new bytes, so pre-copy was redundant

Cache (middleware/cache/cache.go):

  • Kept defensive copying for nested []byte fields in structs
  • Storage only handles top-level []byte values, not fields inside structs

Why This Matters

The Problem

Fiber uses sync.Pool for buffer reuse. When strings or []byte slices backed by pooled buffers are stored directly in maps without copying:

  1. The map holds references to pooled memory
  2. When buffers return to the pool and get reused
  3. Map keys/values become corrupted
  4. Results in intermittent data loss and failures

The Solution

Defensive copying at the storage layer ensures:

  • All stored data is independent of pooled buffers
  • Middleware doesn't need to worry about pooling safety
  • Centralized fix prevents future issues

Performance Impact

  • Minimal: Only affects string keys and []byte values
  • Structs, integers, and other types remain zero-copy
  • Trade-off: Small allocation overhead for correctness and safety

Related

Breaking Changes

None - this is a bug fix that makes storage implementations behave correctly and simplifies middleware code.

- Add defensive copying for string keys and []byte values in internal/memory
- Add defensive copying for string keys and []byte values in internal/storage/memory
- Remove redundant defensive copying from CSRF middleware (storage handles it)
- Remove redundant defensive copying from idempotency middleware (msgp marshaling creates new bytes)
- Update package documentation to explain safety guarantees

This prevents memory corruption from sync.Pool buffer reuse when keys or values
backed by pooled buffers are stored in maps. The storage layers now handle
defensive copying automatically, eliminating the need for middleware to perform
this operation.
Copilot AI review requested due to automatic review settings October 31, 2025 13:30
@sixcolors sixcolors requested a review from a team as a code owner October 31, 2025 13:30
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 31, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Get/Set in internal memory storage now defensively copy keys and byte-slice values; CSRF middleware stopped copying keys/values and forwards raw data to storage; idempotency middleware stopped copying the response body and uses the original response body slice.

Changes

Cohort / File(s) Change Summary
Internal memory storage
internal/memory/memory.go, internal/storage/memory/memory.go
Get now returns defensive copies for []byte values. Set copies the string key and []byte values before storing and stores using the copied key. Added/expanded comments documenting defensive-copy behavior.
CSRF middleware storage
middleware/csrf/storage_manager.go
Removed utils-based copying in setRaw (now stores provided key and raw value directly). Fixed a comment typo.
Idempotency middleware
middleware/idempotency/idempotency.go
Response construction uses the original response body slice (Body: c.Response().Body()) instead of a copied byte slice.

Sequence Diagram(s)

(Skipped — changes are local, focusing on defensive-copying and value flow rather than altering control flow.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Pay attention to internal/memory/memory.go and internal/storage/memory/memory.go for correct defensive-copy implementation and consistent key usage.
  • Verify middleware/csrf/storage_manager.go no longer relying on prior copying still meets safety expectations when using the memory storage.
  • Confirm middleware/idempotency/idempotency.go change does not introduce pooled-buffer reuse or unintended aliasing.

Possibly related PRs

Suggested labels

codex

Suggested reviewers

  • gaby
  • ReneWerner87
  • efectn

Poem

🐰 I copy bytes and tuck them tight,
So pooled buffers don't change by night.
Keys snugged safe beneath my paw,
Middleware passes what it saw —
The burrow's data sleeps polite.

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly addresses the main change: fixing defensive copying of keys/values in internal/memory, which is the core focus across all modified files.
Description check ✅ Passed The description is comprehensive, covering background, specific changes to each file, rationale, performance impact, and breaking changes. It exceeds template requirements with detailed technical context.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-memory-corruption-defensive-copying

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a61888c and 0e744b9.

📒 Files selected for processing (2)
  • internal/memory/memory.go (2 hunks)
  • internal/storage/memory/memory.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/memory/memory.go
  • internal/storage/memory/memory.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint
  • GitHub Check: repeated
  • GitHub Check: unit (1.25.x, windows-latest)
  • GitHub Check: Compare

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @sixcolors, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical memory corruption issue stemming from the reuse of sync.Pool buffers, which could lead to intermittent data loss in various middleware. It centralizes defensive copying mechanisms within the internal/memory and internal/storage/memory packages, ensuring that string keys and byte slice values are always copied when stored or retrieved. This change eliminates the need for redundant copying in middleware like CSRF and Idempotency, simplifying their code while significantly enhancing the overall memory safety and reliability of the application.

Highlights

  • Defensive Copying Extension: Extended defensive copying mechanisms to both internal/memory and internal/storage/memory packages to prevent memory corruption issues.
  • Middleware Simplification: Removed redundant defensive copying logic from CSRF and Idempotency middleware, as the underlying storage layers now handle these operations centrally.
  • Enhanced Memory Safety: Centralized the fix for sync.Pool related memory corruption by ensuring all stored string keys and []byte values are defensively copied upon storage and retrieval.
  • Documentation Update: Added comprehensive package documentation to internal/memory explaining its safety guarantees and defensive copying behavior.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors defensive copying logic in memory storage implementations by moving the responsibility from callers to the storage layer itself. The changes ensure data integrity while eliminating redundant copying operations.

Key changes:

  • Moved defensive copying of keys and byte values into the storage Set and Get methods
  • Removed now-redundant copying calls from middleware that uses these storage implementations
  • Enhanced documentation explaining safety guarantees and when defensive copies occur

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
middleware/idempotency/idempotency.go Removed redundant utils.CopyBytes call for response body since storage now handles copying
middleware/csrf/storage_manager.go Removed redundant utils.CopyString and utils.CopyBytes calls, fixed typo "too" → "to", removed unused utils import
internal/storage/memory/memory.go Added defensive copying in Set for keys/values and in Get for values to prevent external mutation
internal/memory/memory.go Added defensive copying for string keys and []byte values in Set and Get, enhanced package documentation
Comments suppressed due to low confidence (1)

internal/memory/memory.go:99

  • The Delete method uses the original key parameter to look up entries, but Set now stores entries using utils.CopyString(key). If the original key is pooled and reused, the string values may differ, causing Delete to fail to find and remove the entry. The key should be copied here as well: keyCopy := utils.CopyString(key) then use delete(s.data, keyCopy).
func (s *Storage) Delete(key string) {
	s.Lock()
	delete(s.data, key)
	s.Unlock()

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively addresses potential memory corruption issues by extending defensive copying to the internal/memory and internal/storage/memory packages. The changes, which involve copying string keys and []byte values, are implemented correctly and consistently. The removal of now-redundant copying logic from the CSRF and Idempotency middleware is a logical consequence that simplifies the codebase. The new package-level documentation in internal/memory/memory.go is particularly noteworthy, as it clearly outlines the safety guarantees and responsibilities of the caller. Overall, this is a high-quality contribution that enhances the framework's robustness and maintainability.

@gaby
Copy link
Member

gaby commented Oct 31, 2025

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@codecov
Copy link

codecov bot commented Nov 1, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.19%. Comparing base (0edd81d) to head (0e744b9).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3829      +/-   ##
==========================================
- Coverage   92.26%   92.19%   -0.07%     
==========================================
  Files         115      115              
  Lines        9742     9742              
==========================================
- Hits         8988     8982       -6     
- Misses        480      485       +5     
- Partials      274      275       +1     
Flag Coverage Δ
unittests 92.19% <100.00%> (-0.07%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 7f2946c Previous: 6ef6de5 Ratio
Benchmark_Memory/fiber_memory 255927 ns/op 126443 B/op 6000 allocs/op 141180 ns/op 24023 B/op 1000 allocs/op 1.81
Benchmark_Memory/fiber_memory - ns/op 255927 ns/op 141180 ns/op 1.81
Benchmark_Memory/fiber_memory - B/op 126443 B/op 24023 B/op 5.26
Benchmark_Memory/fiber_memory - allocs/op 6000 allocs/op 1000 allocs/op 6
Benchmark_Limiter - B/op 16 B/op 8 B/op 2
Benchmark_Limiter - allocs/op 2 allocs/op 1 allocs/op 2

This comment was automatically generated by workflow using github-action-benchmark.

@gaby gaby changed the title 🐛 Extend defensive copying to internal/memory and remove middleware redundancy 🐛 bug: fix copying of key/values in internal/memory Nov 1, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 29edcaa and a61888c.

📒 Files selected for processing (3)
  • internal/memory/memory.go (2 hunks)
  • internal/storage/memory/memory.go (2 hunks)
  • middleware/idempotency/idempotency.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/memory/memory.go
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Apply formatting using gofumpt (Make target: format)
Optimize struct field alignment using betteralign (Make target: betteralign)
Modernize code using gopls modernize (Make target: modernize)

Files:

  • middleware/idempotency/idempotency.go
  • internal/storage/memory/memory.go
🪛 GitHub Actions: golangci-lint
internal/storage/memory/memory.go

[error] 93-93: undefined: entry (typecheck) reported by golangci-lint during 'golangci-lint run'.

🪛 GitHub Actions: Modernize Lint
internal/storage/memory/memory.go

[error] 93-93: undefined: entry

🪛 GitHub Actions: Run govulncheck
internal/storage/memory/memory.go

[error] 93-93: govulncheck failed: undefined: entry in memory.go:93

🪛 GitHub Check: govulncheck-check
internal/storage/memory/memory.go

[failure] 93-93:
undefined: entry

🪛 GitHub Check: lint
internal/storage/memory/memory.go

[failure] 93-93:
undefined: entry (typecheck)

🪛 GitHub Check: modernize
internal/storage/memory/memory.go

[failure] 93-93:
undefined: entry


[failure] 93-93:
undefined: entry

🪛 GitHub Check: unit (1.25.x, macos-latest)
internal/storage/memory/memory.go

[failure] 93-93:
undefined: entry

🪛 GitHub Check: unit (1.25.x, ubuntu-latest)
internal/storage/memory/memory.go

[failure] 93-93:
undefined: entry

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: repeated
  • GitHub Check: Compare
🔇 Additional comments (1)
middleware/idempotency/idempotency.go (1)

138-138: LGTM! Redundant copy correctly removed.

Removing utils.CopyBytes before marshaling is appropriate since res.MarshalMsg(nil) on line 161 allocates new memory. The storage layer now handles defensive copying of the marshaled bytes.

- Use the exported Entry type when inserting into storage (fixes incorrect `entry` identifier).
- Clean up unnecessary blank lines in internal memory implementations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants