Name: jl125535 Date: 01/27/2003
FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)
A DESCRIPTION OF THE PROBLEM :
java.sql.Date valueOf() is written making extensive use of
String's subString and indexOf to parse a JDBC Escaped Date
string into a java.sql.Date instance. Suggested enhancement
removes dependence on String and Integer.parseInt() and
makes one pass through a char buffer extracted from String
and directly parses the characters into an int array.
Previous code did little validation of the parsed values,
suggested enhancement code does quick but complete
validateion of the parsed values. Current code has a bug in
it that it will accept "2000-0--1" or "2000-0-0" or "2000-0-"
and return unpredicatable results.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
Current source code:
public static Date valueOf(String s) {
int year;
int month;
int day;
int firstDash;
int secondDash;
if (s == null) throw new java.lang.IllegalArgumentException();
firstDash = s.indexOf('-');
secondDash = s.indexOf('-', firstDash+1);
if ((firstDash > 0) & (secondDash > 0) & (secondDash < s.length()-1)) {
year = Integer.parseInt(s.substring(0, firstDash)) - 1900;
month = Integer.parseInt(s.substring(firstDash+1, secondDash)) - 1;
day = Integer.parseInt(s.substring(secondDash+1));
} else {
throw new java.lang.IllegalArgumentException();
}
return new Date(year, month, day);
}
Suggested enhancement:
public static Date valueOf(String s) {
if (s == null) {
throw new java.lang.IllegalArgumentException();
}
char buf[] = s.toCharArray();
int results[] = {0,0,0};
int r = 0; // results index to 0
int i=0; // buf index to 0
while (i < buf.length) {
char c = buf[i++];
if (c == '-') {
if (r++ >= results.length) {
throw new java.lang.IllegalArgumentException();
}
} else {
int digit = Character.digit(c, 10);
if (digit < 0) {
throw new NumberFormatException(s);
}
results[r] = (results[r] * 10) + digit;
if (results[r] > 9999) {
// None of the fields should exceed 9999
throw new NumberFormatException(s);
}
}
}
// Validate results
if (
// Diddn't reach end of buffer
(i != buf.length) ||
// Didn't parse all of our int's
(r != results.length - 1) ||
// No need to check year, already done above
// Month is too large
(results[1] > 11) ||
// Day out of range
((results[2] == 0) || (results[2] > 31))) {
throw new NumberFormatException(s);
}
// Create and return new Date
return new Date(results[0]-1900, results[1], results[2]);
}
---------- END SOURCE ----------
(Review ID: 153582)
======================================================================