Skip to content

Commit d2a9ae8

Browse files
committed
[GR-19220] Fix bounds checking issues with MatchData#[Integer, Integer] (#2638)
PullRequest: truffleruby/3278
2 parents 79ec0de + d2e1176 commit d2a9ae8

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ New features:
66
Bug fixes:
77

88
* Fix `rb_id2name` to ensure the native string will have the same lifetime as the id (#2630, @aardvark179).
9+
* Fix `MatchData#[]` exception when passing a length argument larger than the number of match values (#2636, @nirvdrum).
10+
* Fix `MatchData#[]` exception when supplying a large negative index along with a length argument (@nirvdrum).
911

1012
Compatibility:
1113

@@ -82,7 +84,7 @@ Performance:
8284
* Reduce memory footprint by tracking `VALUE`s created during C extension init separately (@aardvark179).
8385
* Rewrote `ArrayEachIteratorNode` to optimize performance for a constant-sized array and reduce specializations to 1 general case (#2587, @MattAlp)
8486
* Reduce conversion of `VALUE`s to native handle during common operations in C extensions (@aardvark179).
85-
* Improved performance of regex boolean matches (e.g., `Regexp#match?`) by avoiding match data allocation in TRegex (#2558, @nirvdrum).
87+
* Improved performance of regex boolean matches (e.g., `Regexp#match?`) by avoiding match data allocation in TRegex (#2588, @nirvdrum).
8688
* Remove overhead when getting using `RDATA_PTR` (@aardvark179).
8789
* Additional copy operations have been reduced when performing IO (#2536, @aardvark179).
8890

spec/ruby/core/matchdata/element_reference_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
it "supports accessors [start, length]" do
1717
/(.)(.)(\d+)(\d)/.match("THX1138.")[1, 2].should == %w|H X|
1818
/(.)(.)(\d+)(\d)/.match("THX1138.")[-3, 2].should == %w|X 113|
19+
20+
# negative index is larger than the number of match values
21+
/(.)(.)(\d+)(\d)/.match("THX1138.")[-30, 2].should == nil
22+
23+
# length argument larger than number of match values is capped to match value length
24+
/(.)(.)(\d+)(\d)/.match("THX1138.")[3, 10].should == %w|113 8|
1925
end
2026

2127
it "supports ranges [start..end]" do

src/main/java/org/truffleruby/core/regexp/MatchDataNodes.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,27 @@ protected Object getIndex(RubyMatchData matchData, int index, NotProvided length
285285
}
286286

287287
@Specialization
288-
protected RubyArray getIndex(RubyMatchData matchData, int index, int length,
289-
@Cached ConditionProfile normalizedIndexProfile) {
290-
// TODO BJF 15-May-2015 Need to handle negative indexes and lengths and out of bounds
288+
protected Object getIndex(RubyMatchData matchData, int index, int length,
289+
@Cached ConditionProfile normalizedIndexProfile,
290+
@Cached ConditionProfile indexOutOfBoundsProfile,
291+
@Cached ConditionProfile tooLargeTotalProfile) {
291292
final Object[] values = getValuesNode.execute(matchData);
293+
292294
if (normalizedIndexProfile.profile(index < 0)) {
293295
index += values.length;
296+
297+
if (indexOutOfBoundsProfile.profile(index < 0)) {
298+
return nil;
299+
}
300+
}
301+
302+
int endIndex = index + length;
303+
if (tooLargeTotalProfile.profile(endIndex > values.length)) {
304+
endIndex = values.length;
294305
}
295-
final Object[] store = Arrays.copyOfRange(values, index, index + length);
306+
307+
final Object[] store = Arrays.copyOfRange(values, index, endIndex);
308+
296309
return createArray(store);
297310
}
298311

0 commit comments

Comments
 (0)