JDK-6421039 : String.replaceFirst() crashes with java.lang.StringIndexOutOfBoundsException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.regex
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2006-05-03
  • Updated: 2011-02-16
  • Resolved: 2006-05-03
Description
FULL PRODUCT VERSION :
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
This code

public class Test1 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		String str = "%id Data directory name: `%m' ";
		String chr = "%m";
		String msg = "F:\\projects\\eclipse_workspace\\fred_for_fixes\\data\\";
		str = str.replaceFirst(chr, msg);
	}

}

reproduces the problem. By using this line instead

String msg = "F:\\\\projects\\\\eclipse_workspace\\\\fred_for_fixes\\\\data\\\\";

we can circumvent the problem and get the proper behavior, however, I think this should not happen in the first place.

Cheers,
  Nik

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Just run this:

public class Test1 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		String str = "%id Data directory name: `%m' ";
		String chr = "%m";
		String msg = "F:\\projects\\eclipse_workspace\\fred_for_fixes\\data\\";
		str = str.replaceFirst(chr, msg);
	}

}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
str should have value
"
%id Data directory name: `F:\projects\eclipse_workspace\fred_for_fixes\data\'
"
ACTUAL -
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 50
	at java.lang.String.charAt(String.java:558)
	at java.util.regex.Matcher.appendReplacement(Matcher.java:696)
	at java.util.regex.Matcher.replaceFirst(Matcher.java:848)
	at java.lang.String.replaceFirst(String.java:1967)
	at Test1.main(Test1.java:13)


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 50
	at java.lang.String.charAt(String.java:558)
	at java.util.regex.Matcher.appendReplacement(Matcher.java:696)
	at java.util.regex.Matcher.replaceFirst(Matcher.java:848)
	at java.lang.String.replaceFirst(String.java:1967)
	at Test1.main(Test1.java:13)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Test1 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		String str = "%id Data directory name: `%m' ";
		String chr = "%m";
		String msg = "F:\\projects\\eclipse_workspace\\fred_for_fixes\\data\\";
		str = str.replaceFirst(chr, msg);
	}

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Use "\\\\" instead of "\\".

Comments
EVALUATION Backslash and dollar sign have special meaning in "replacement" for String.replaceFirst/All, use Matcher.quoteReplacement()suppress it is not desired. The API for these methods in 6.0 has been updated to make this more clear, a copy/paste of the update is ... An invocation of this method of the form str.replaceFirst(regex, repl) yields exactly the same result as the expression Pattern.compile(regex).matcher(str).replaceFirst(repl) Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string; see Matcher.replaceFirst(java.lang.String). Use Matcher.quoteReplacement(java.lang.String) to suppress the special meaning of these characters, if desired. ... Closed as "not a defect".
03-05-2006