Skip to content

Commit bc39a0a

Browse files
committedFeb 8, 2018
align C ported memsearch code - need to handle array[length] properly
... otherwise code doing utf8 str scan might fail with array-out-of-index resolves GH-2036
1 parent edd18dd commit bc39a0a

File tree

3 files changed

+26
-7
lines changed

3 files changed

+26
-7
lines changed
 

‎core/src/main/java/org/jruby/RubyString.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -2728,7 +2728,6 @@ private IRubyObject indexCommon19(Ruby runtime, ThreadContext context, IRubyObje
27282728

27292729
// MRI: rb_strseq_index
27302730
private int strseqIndex(final RubyString sub, int offset, boolean inBytes) {
2731-
byte[] sBytes = value.unsafeBytes();
27322731
int s, sptr, e;
27332732
int pos, len, slen;
27342733
boolean single_byte = singleByteOptimizable();
@@ -2745,6 +2744,7 @@ private int strseqIndex(final RubyString sub, int offset, boolean inBytes) {
27452744
}
27462745
if (len - offset < slen) return -1;
27472746

2747+
byte[] sBytes = value.unsafeBytes();
27482748
s = value.begin();
27492749
e = s + value.realSize();
27502750
if (offset != 0) {
@@ -3811,7 +3811,7 @@ public IRubyObject scan19(ThreadContext context, IRubyObject pat, Block block) {
38113811
mustnotBroken(context);
38123812
if (!block.isGiven()) {
38133813
RubyArray ary = null;
3814-
while (!(result = scanOnce(context, str, pat, startp)).isNil()) {
3814+
while ((result = scanOnce(context, str, pat, startp)) != context.nil) {
38153815
last = prev;
38163816
prev = startp[0];
38173817
if (ary == null) ary = context.runtime.newArray(4);
@@ -3824,7 +3824,7 @@ public IRubyObject scan19(ThreadContext context, IRubyObject pat, Block block) {
38243824
final byte[] pBytes = value.unsafeBytes();
38253825
final int len = value.realSize();
38263826

3827-
while (!(result = scanOnce(context, str, pat, startp)).isNil()) {
3827+
while ((result = scanOnce(context, str, pat, startp)) != context.nil) {
38283828
last = prev;
38293829
prev = startp[0];
38303830
block.yieldSpecific(context, result);

‎core/src/main/java/org/jruby/util/StringSupport.java

+10-4
Original file line numberDiff line numberDiff line change
@@ -2297,9 +2297,15 @@ private static int rb_memsearch_qs(byte[] xsBytes, int xs, int m, byte[] ysBytes
22972297
return -1;
22982298
}
22992299

2300-
private static int rb_memsearch_qs_utf8_hash(byte[] xBytes, int x) {
2301-
int mix = 8353;
2302-
int h = xBytes[x] & 0xFF;
2300+
private static int rb_memsearch_qs_utf8_hash(byte[] xBytes, final int x) {
2301+
final int mix = 8353;
2302+
int h;
2303+
if (x != xBytes.length) {
2304+
h = xBytes[x] & 0xFF;
2305+
}
2306+
else {
2307+
h = '\0'; // (C) ary end - due y+m at rb_memsearch_qs_utf8
2308+
}
23032309
if (h < 0xC0) {
23042310
return h + 256;
23052311
}
@@ -2337,7 +2343,7 @@ private static int rb_memsearch_qs_utf8(byte[] xsBytes, int xs, int m, byte[] ys
23372343
for (; x < xe; ++x) {
23382344
qstable[rb_memsearch_qs_utf8_hash(xsBytes, x)] = xe - x;
23392345
}
2340-
/* Searching */
2346+
/* Searching */ // due y+m <= ... (y+m) might == ary.length
23412347
for (; y + m <= ys + n; y += qstable[rb_memsearch_qs_utf8_hash(ysBytes, y+m)]) {
23422348
if (xsBytes[xs] == ysBytes[y] && ByteList.memcmp(xsBytes, xs, ysBytes, y, m) == 0)
23432349
return y - ys;

‎test/jruby/test_string.rb

+13
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,17 @@ def try(obj, *a, &b) # ~ AS 4.2
135135
end
136136
end
137137

138+
public
139+
140+
def test_scan_error
141+
string = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
142+
assert_equal [], 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'.scan('d....r........')
143+
144+
('a'..'z').to_a.each do |c1|
145+
('a'..'z').to_a.each do |c2|
146+
string.downcase.scan("#{c1}....#{c2}........") # does not blow with ArrayIndexOutOfBoundsException
147+
end
148+
end
149+
end
150+
138151
end

0 commit comments

Comments
 (0)