FINDINGS:
- Individual yoga tests pass (19/19 tests)
- Multiple test files together cause ASAN heap-use-after-free in YGNodeFree
- Root cause: YGNodeFree assumes child/parent nodes are valid, but GC can free them in arbitrary order
- Crash occurs in facebook::yoga::Node::setOwner() when YGNodeFree tries to clean up children
CHANGES:
- Enhanced JSYogaNode with WriteBarrier children array for GC references (mirrors React Native _reactSubviews)
- Fixed clone() method to avoid double YGNode creation that caused ownership conflicts
- TEMPORARY: Skip YGNodeFree during JS finalizer to prevent crashes (causes memory leaks)
- Moved yoga tests to test/js/bun/yoga/ directory
STATUS: All tests now pass, but memory leaks need to be addressed with proper YGNode lifecycle management
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace DECLARE_VISIT_CHILDREN with visitAdditionalChildren pattern for proper GC integration
- Implement visitOutputConstraints for objects with volatile marking behavior (following WebKit guide)
- Add opaque root management for YogaNodeImpl* pointers to ensure GC reachability
- Create separate JSYogaConfigOwner to fix WeakHandleOwner type confusion bug
- Fix ownership tracking with m_ownsYogaNode flag to prevent double-freeing during cloning
- Add safe YGNodeFree tracking to prevent heap-use-after-free in complex scenarios
- Implement hierarchy-aware node freeing (only free root nodes, let Yoga handle children)
- Individual Yoga tests pass; multi-test scenarios have remaining ASAN issues under investigation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Created separate JSYogaConfigOwner to properly handle YogaConfigImpl objects
instead of incorrectly using JSYogaNodeOwner which expects YogaNodeImpl.
The issue was:
- YogaConfigImpl used jsYogaNodeOwner() WeakHandleOwner
- JSYogaNodeOwner::isReachableFromOpaqueRoots cast context to YogaNodeImpl*
- When called with YogaConfigImpl*, this caused type confusion and potential memory corruption
Fix:
- Created JSYogaConfigOwner with proper YogaConfigImpl handling
- YogaConfigImpl now uses jsYogaConfigOwner() instead of jsYogaNodeOwner()
- JSYogaConfigOwner doesn't use opaque roots (configs don't need them)
Progress:
- ✅ 2-3 yoga test files: All combinations work without ASAN errors
- ❌ 4+ yoga test files: Still ASAN error, possibly related to yoga-node-extended.test.js
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Based on WebKit GC guide, replaced DECLARE_VISIT_CHILDREN with proper
visitAdditionalChildren pattern for RefCounted C++ objects with opaque roots.
Changes:
- Replace DECLARE_VISIT_CHILDREN with template<typename Visitor> visitAdditionalChildren
- Use DEFINE_VISIT_ADDITIONAL_CHILDREN instead of DEFINE_VISIT_CHILDREN
- Remove Base::visitChildren calls (handled automatically by JSC)
- Keep opaque root management for yoga node hierarchy
Issue: ASAN heap-buffer-overflow still occurs when running multiple
Yoga test files together, suggesting deeper memory management issue
beyond GC visitation pattern.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Prevent double-ref when setJSWrapper is called multiple times on the same instance.
Only increment ref count if we don't already have a wrapper.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Migrated JSYogaNode to use RefCounted<YogaNodeImpl> pattern
- Migrated JSYogaConfig to use RefCounted<YogaConfigImpl> pattern
- Both JS wrappers now use impl() and do minimal work
- Implemented proper opaque root GC lifecycle management
- Added WeakHandleOwner with finalize() that derefs C++ wrappers
- Updated all API calls to use impl().yogaNode() / impl().yogaConfig()
The core RefCounted architecture is complete. Some compilation issues remain
that need header includes and method name fixes.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This implements the proper C++ wrapper lifecycle management pattern for Yoga nodes:
- Created YogaNodeImpl class that inherits from RefCounted<YogaNodeImpl>
- Updated JSYogaNode to hold Ref<YogaNodeImpl> instead of direct YGNodeRef
- Added JSC::Weak<JSYogaNode> to YogaNodeImpl for JS wrapper tracking
- Implemented JSYogaNodeOwner with proper opaque root GC lifecycle
- Added opaque root handling using root Yoga node traversal
- Finalize function properly derefs the C++ wrapper
This follows WebKit DOM patterns for proper GC lifecycle management.
Still needs some cleanup in JSYogaPrototype.cpp method calls.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>