diff --git a/contracts/utils/Arrays.sol b/contracts/utils/Arrays.sol index f837004ff92..9be765cf661 100644 --- a/contracts/utils/Arrays.sol +++ b/contracts/utils/Arrays.sol @@ -112,29 +112,43 @@ library Arrays { * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should * be used only if the limits are within a memory array. */ - function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure { - unchecked { + function _quickSort( + uint256 begin, + uint256 end, + function(uint256, uint256) pure returns (bool) comp +) private pure { + unchecked { + while (true) { if (end - begin < 0x40) return; - // Use first element as pivot uint256 pivot = _mload(begin); - // Position where the pivot should be at the end of the loop uint256 pos = begin; for (uint256 it = begin + 0x20; it < end; it += 0x20) { if (comp(_mload(it), pivot)) { - // If the value stored at the iterator's position comes before the pivot, we increment the - // position of the pivot and move the value there. pos += 0x20; _swap(pos, it); } } - _swap(begin, pos); // Swap pivot into place - _quickSort(begin, pos, comp); // Sort the left side of the pivot - _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot + _swap(begin, pos); + + // ──────────────────────────────────────────────────────────────── + // This is the actual fix: recurse ONLY on the SMALLER side + // ──────────────────────────────────────────────────────────────── + if (pos - begin < end - (pos + 0x20)) { + // left smaller → recurse left, loop on right + _quickSort(begin, pos, comp); + begin = pos + 0x20; + } else { + // right smaller or equal → recurse right, loop on left + _quickSort(pos + 0x20, end, comp); + end = pos; + } + // loop continues with updated bounds → no second recursion } } +} /** * @dev Pointer to the memory location of the first element of `array`. diff --git a/contracts/utils/my-fix-description.md b/contracts/utils/my-fix-description.md new file mode 100644 index 00000000000..c94f4c39cc8 --- /dev/null +++ b/contracts/utils/my-fix-description.md @@ -0,0 +1,5 @@ +--- +"@openzeppelin/contracts": patch +--- + +Fix: Prevent Stack Overflow in _quickSort by optimizing recursion and memory usage. \ No newline at end of file