Name: saf@russia Date: 08/07/96
This bug was found by St.Petersburg Java SQE team (by Michael A. Gorshenev).
========== Here is the part of language secification =========
===== (Pre-Release Version 1.0, Draft 5.2 - July 3, 1996) ====
Java API Documentation
1.0.2
Part. 1.16
"
REGIONMATCHES
public boolean
regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len)
Determines if two string regions are equal.
If toffset or ooffset is negative, or if toffset+length is greater than the length of this string, or if
ooffset+length is greater than the length of the string argument, then this
method returns false.
Parameters:
ignoreCase - if true, ignore case when comparing characters
toffset - starting offset of the subregion in this string
other - string argument
ooffset - starting offset of the subregion in the string argument
len - the number of characters to compare
Returns:
true if the specified subregion of this string matches the specified subregion of the string
argument; false otherwise. Whether the matching is exact or case insensitive depends on the
ignoreCase argument.
"
"
20.12.19 public boolean regionMatches(boolean ignoreCase,
int toffset, String other, int ooffset, int len)
throws NullPointerException
A substring of this String object is compared to a substring of the
argument other. The result is true if these substrings represent
character sequences that are the same, ignoring case if and only
if ignoreCase is true. The substring of this String object to be
compared begins at index toffset and has length len. The substring
of other to be compared begins at index ooffset and has length len.
The result is false if and only if at least one of the following is
true:
toffset is negative.
ooffset is negative.
toffset+len is greater than the length of this String object.
ooffset+len is greater than the length of the other argument.
There is some nonnegative integer k less than len such that:
this.charAt(toffset+k) != other.charAt(ooffset+k)
ignoreCase is true and there is some nonnegative integer k
less than len such that:
Character.toLowerCase(this.charAt(toffset+k)) !=
Character.toLowerCase(other.charAt(ooffset+k))
and:
Character.toUpperCase(this.charAt(toffset+k)) !=
Character.toUpperCase(other.charAt(ooffset+k))
If other is null, then a NullPointerException is thrown.
"
The bug in Java API 1.0.2 is as follows:
The method
java.lang.String.regionMatches(boolean, int, String, int, int)
may return incorrect value.
Actually the bug is in assignment "int plim = po + other.count;"
(please see the source code for the method).
There must be "int plim = other.offset + other.count;" instead.
=============== Here is the test fragment ===================
String s1 = "regionMatches() test !!!";
String s2 = s1.substring(0,20);
int toffset = 16;
int ooffset = 16;
int len = 7;
/* s2 will be "regionMatches() test"
s2.length() will be 20
*/
boolean b=s1.regionMatches(false, toffset,s2,ooffset,len);
/* ooffset + len > s2.length
=> b must be false
*/
System.out.println("b="+b); // but will return true!
=============== Here is the test output =====================
b=true
===== Here is the part of java.lang.String source code ======
public boolean regionMatches(boolean ignoreCase,
int toffset,
String other, int ooffset, int len) {
char ta[] = value;
int to = offset + toffset;
int tlim = offset + count;
char pa[] = other.value;
int po = other.offset + ooffset;
int plim = po + other.count;
if ((ooffset < 0) || (toffset < 0) || (to + len > tlim) ||
(po + len > plim)) {
return false;
}
while (len-- > 0) {
char c1 = ta[to++];
char c2 = pa[po++];
if (c1 == c2)
continue;
if (ignoreCase) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2)
continue;
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
continue;
}
return false;
}
return true;
}
==============================================================