Bug in String.indexOf()?! No way?!?

I was looking through Groovy JIRA and I run into GROOVY-5858 issue. In short it is about Groovy’s String.count() metamethod which hangs forever when it gets an empty string as an argument:

'any string'.count('')

I dug deeper into it and how surprised I was when it came out that Groovy’s String.count() method fails due to bug in Java String.indexOf(String str, int fromIndex) method. Basically the contract (by javadoc) for indexOf() method is that it returns the smallest index at which the next occurrence of str is found but not lower than fromIndex. If such an index does not exist (probably due to no more occurrences) than it shall return -1. So that is the theory – when it comes to practice user might expect that if the returned index is positive (what means that next occurrence is found) then it will not be lower than fromIndex passed as an argument to the method execution.
Here is the example that shows the above contract is not obeyed by String.indexOf() method:

// given
String strToLookIn = "bug";
String strToLookFor = "";
int fromIndex = 4;

// when
int k = strToLookIn.indexOf(strToLookFor, fromIndex);

// then
assertTrue((k == -1) || (k > fromIndex), String.format("k expected to be in [-1, %d..+oo] but is %d", fromIndex, k));

When the test is run it fails with the following description:

java.lang.AssertionError: k expected to be in [-1, 4..+oo] but is 3 expected [true] but found [false]

This proves that the most basic contract for String.indexOf() method is broken. More generally bug appears always when strToLookFor is empty and fromIndex is greater than length of string in which we look in.
Since Groovy developers trusted String.indexOf() contract they (and we all ;)) have a bug in Groovy now.
Just for a reference here is how Grooovy’s String.count() method is implemented:

public static int count(String self, String text) {
  int answer = 0;
  for (int idx = 0; true; idx++) {
    idx = self.indexOf(text, idx);
    if (idx >= 0) {
      ++answer;
    } else {
      break;
    }
  }
  return answer;
}

Exit condition from the above for loop is idx variable to become negative. Unfortunately due to the mentioned bug in String class it never happens for text variable being an empty string.
I’ve submitted a bug report to Oracle and hope it will be processed by the next end of the world which is 2018 😉 Personally I think it might never get fixed as the risk concerned with it might be simply too high. Basically up to now few billions of devices are running the broken String implementation and everyone is happy 😉
I used Oracle JDK 7u10 for the purpose of my investigation but probably the bug is present in (almost) all other versions. As it is quite obvious OpenJDK is impacted as well. Other vendors’ JDKs might not be impacted as they use completely different implementations for String.indexOf() method.

At Santa Claus of JetBrains

Dear Santa Claus,

I have been a well-behaving IDEA developer through the whole year. I was, I am and I will always be completely dedicated to spreading the word of Intellij IDEA religion around the world. Going from door to door armed only with my IDEA(s). There is nothing and noone to stop me from keeping the mission going.

There are no words that can describe how my life has changed since darkling days of me as misbeliever – as an eclipse cult blind follower. And there are actually no words that can express how great the IDEA is.

And this is where, I, beg you for help my dear Santa Cluas. I feel I am losing it all – my words and IDEA(s) are becoming obsolete as I am just writting to you. I had a really bad premonition that I will lost my powers as of January 4th. Please be so kind and bring my IDEA(s) to the ULTIMATE crispness… so I can spread the word among pagans as effectively as I was spreading it till now.

JetBrains IntelliJ IDEA devoted follower and evangelist,
Michał Mally