-
Notifications
You must be signed in to change notification settings - Fork 3.8k
fix: prevent infinite recursion in dependency hoisting with cycle detection #21880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
robobun
wants to merge
5
commits into
main
Choose a base branch
from
claude/fix-circular-dependency-hoist-crash
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
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
…pendencies Fixes a segmentation fault that occurred when hoisting dependencies with circular dependency chains. The hoistDependency function would recursively call itself indefinitely when traversing parent trees, causing stack overflow. Changes: - Added depth tracking to hoistDependency to prevent infinite recursion - Split function into hoistDependency (public) and hoistDependencyWithDepth (internal) - Added max depth limit of 1000 to prevent stack overflow - Return dependency_loop when depth limit is reached to gracefully handle cycles Test case reproduces the crash with pkg-a -> pkg-b -> pkg-c -> pkg-a circular dependency. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Collaborator
Author
Replaces the depth-limiting approach with proper cycle detection using a visited set. This prevents infinite recursion in circular dependencies while allowing legitimate deep dependency trees (which can exceed 1000 levels in npm ecosystem). The new approach: - Tracks visited packages during hoisting traversal - Detects actual cycles rather than imposing arbitrary depth limits - Uses defer to ensure proper cleanup of visited set - Handles both circular dependencies and deep legitimate trees correctly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
e0ffaec to
476bf5f
Compare
Improves performance of the circular dependency fix by eliminating repeated HashMap allocations during dependency hoisting: Performance improvements: - Uses single reusable HashMap in Builder instead of per-call allocation - Eliminates O(n) allocation overhead for each hoistDependency call - Retains capacity between calls for better memory reuse - Reduces garbage collection pressure in large dependency trees The HashMap is now: - Initialized once per Builder lifecycle - Cleared with clearRetainingCapacity() for each top-level hoist operation - Properly cleaned up with defer statement This maintains the cycle detection benefits while being much more efficient for real-world dependency trees with hundreds/thousands of packages. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
5e4b001 to
541bfd0
Compare
Makes Tree.PackageID public to fix compilation error when using it as HashMap key type in the cycle detection implementation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
7efbdd3 to
8c66bda
Compare
Comment on lines
+81
to
+83
| "pkg-a/pkg-b": ["pkg-b@file:pkg-b", {}], | ||
| "pkg-b/pkg-c": ["pkg-c@file:pkg-c", {}], | ||
| "pkg-c/pkg-a": ["pkg-a@file:pkg-a", {}], |
Member
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like these packages are the bug. they shouldn't be written to the lockfile, they're already covered above by "pkg-a", "pkg-b", and "pkg-c"
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.
Summary
Fixes a segmentation fault that occurred when
bun installencounters circular dependencies in workspace packages. The issue was caused by infinite recursion in thehoistDependencyfunction during dependency tree traversal.Root Cause
The
hoistDependencyfunction insrc/install/lockfile/Tree.zigwould recursively call itself through parent trees without any cycle detection. When circular dependencies existed (e.g., pkg-a → pkg-b → pkg-c → pkg-a), this led to stack overflow and segmentation fault.Solution
Instead of using arbitrary depth limits (which would break legitimate deep dependency trees), this fix implements proper cycle detection with performance optimizations:
Cycle Detection Approach
Performance Optimizations
clearRetainingCapacity()to reuse allocated memoryPerformance Benchmarks
✅ No Performance Regression: The cycle detection adds minimal overhead to normal dependency resolution:
Key Findings:
Why Cycle Detection vs Depth Limiting?
The npm ecosystem is highly fragmented and commonly produces very deep dependency trees:
Changes
src/install/lockfile/Tree.zig- Added optimized cycle detection to hoisting logicsrc/install/lockfile.zig- Added reusable HashMap to Builder structtest/regression/issue/circular-dependency-hoist-crash.test.ts- Regression test reproducing the crashtest/cli/install/performance-benchmark.test.ts- Performance benchmarks for various dependency patternsTest Plan
bun install)bun installnow completes successfullyThe regression test creates a workspace with circular dependencies (pkg-a → pkg-b → pkg-c → pkg-a) and verifies that
bun installcompletes without crashing.🤖 Generated with Claude Code