From 1361c18ca045eab66091a767a46cf7d7fbb90afe Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 25 Oct 2023 10:20:18 -0500 Subject: [PATCH] Fix length handling in select!/reject! ensure The logic here had diverged somewhat from CRuby's logic, and did not reacquire the array's begin or length as in CRuby. This led to bad length calculation when there were additional mutations during the select!/reject! loop. Fixes #7976 --- core/src/main/java/org/jruby/RubyArray.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/jruby/RubyArray.java b/core/src/main/java/org/jruby/RubyArray.java index 70525ae0936..6bd4ce03b8d 100644 --- a/core/src/main/java/org/jruby/RubyArray.java +++ b/core/src/main/java/org/jruby/RubyArray.java @@ -2924,7 +2924,7 @@ public IRubyObject select_bang(ThreadContext context, Block block) { } finally { if (modified) checkFrozen(); - selectBangEnsure(runtime, len, beg, len0, len1); + selectBangEnsure(runtime, len0, len1); } } @@ -3082,17 +3082,20 @@ public IRubyObject rejectBang(ThreadContext context, Block block) { } finally { if (modified) checkFrozen(); - selectBangEnsure(runtime, realLength, beg, len0, len1); + selectBangEnsure(runtime, len0, len1); } } // MRI: select_bang_ensure - private void selectBangEnsure(final Ruby runtime, final int len, final int beg, - int i1, int i2) { - if (i2 < i1) { - realLength = len - i1 + i2; + private void selectBangEnsure(final Ruby runtime, int i1, int i2) { + int len = realLength; + + if (i2 < len && i2 < i1) { + int tail = 0; + int beg = begin; if (i1 < len) { - safeArrayCopy(runtime, values, beg + i1, values, beg + i2, len - i1); + tail = len - i1; + safeArrayCopy(runtime, values, beg + i1, values, beg + i2, tail); } else if (realLength > 0) { // nil out left-overs to avoid leaks (MRI doesn't) @@ -3102,6 +3105,7 @@ else if (realLength > 0) { throw concurrentModification(runtime, ex); } } + realLength = i2 + tail; } }