Program: 82336
Project: 82336
Buggy source:
/** 
 * Called by the servlet to query for for the next block to test.
 * @param clientId the ID of the client
 * @param userAgent the user agent property of the client
 * @param blockIndex the index of the test block to get
 * @param timeout how long to wait for an answer
 * @return the next test to run, or <code>null</code> if<code>timeout</code> is exceeded or the next test does not match <code>testClassName</code>
 */
public TestBlock getTestBlock(String clientId,String clientDesc,String userAgent,int blockIndex,long timeout) throws TimeoutException {
synchronized (clientStatusesLock) {
    userAgents.add(userAgent);
    ClientStatus clientStatus=ensureClientStatus(clientId,clientDesc);
    clientStatus.blockIndex=blockIndex;
    if (isLastTestBlockAvailable && blockIndex >= testBlocks.size()) {
      return null;
    }
    long startTime=System.currentTimeMillis();
    long stopTime=startTime + timeout;
    while (blockIndex >= testBlocks.size()) {
      long timeToWait=stopTime - System.currentTimeMillis();
      if (timeToWait < 1) {
        double elapsed=(System.currentTimeMillis() - startTime) / 1000.0;
        throw new TimeoutException("String_Node_Str" + "String_Node_Str" + timeout + "String_Node_Str"+ "String_Node_Str"+ clientId+ "String_Node_Str"+ "String_Node_Str"+ elapsed+ "String_Node_Str");
      }
      try {
        clientStatusesLock.wait(timeToWait);
      }
 catch (      InterruptedException e) {
        System.err.println("String_Node_Str");
        e.printStackTrace();
        return null;
      }
    }
    TestInfo[] tests=testBlocks.get(blockIndex);
    for (    TestInfo testInfo : tests) {
      ensureResults(testInfo).put(clientStatus,null);
    }
    return new TestBlock(tests,blockIndex);
  }
}

Fixed version (ground truth):
/** 
 * Called by the servlet to query for for the next block to test.
 * @param clientInfo information about the client
 * @param blockIndex the index of the test block to get
 * @param timeout how long to wait for an answer
 * @return the next test to run, or <code>null</code> if<code>timeout</code> is exceeded or the next test does not match <code>testClassName</code>
 */
public TestBlock getTestBlock(ClientInfoExt clientInfo,int blockIndex,long timeout) throws TimeoutException {
synchronized (clientStatusesLock) {
    userAgents.add(clientInfo.getUserAgent());
    ClientStatus clientStatus=ensureClientStatus(clientInfo);
    clientStatus.blockIndex=blockIndex;
    if (isLastTestBlockAvailable && blockIndex >= testBlocks.size()) {
      return null;
    }
    long startTime=System.currentTimeMillis();
    long stopTime=startTime + timeout;
    while (blockIndex >= testBlocks.size()) {
      long timeToWait=stopTime - System.currentTimeMillis();
      if (timeToWait < 1) {
        double elapsed=(System.currentTimeMillis() - startTime) / 1000.0;
        throw new TimeoutException("String_Node_Str" + "String_Node_Str" + timeout + "String_Node_Str"+ "String_Node_Str"+ clientInfo.getDesc()+ "String_Node_Str"+ "String_Node_Str"+ elapsed+ "String_Node_Str");
      }
      try {
        clientStatusesLock.wait(timeToWait);
      }
 catch (      InterruptedException e) {
        System.err.println("String_Node_Str");
        e.printStackTrace();
        return null;
      }
    }
    TestInfo[] tests=testBlocks.get(blockIndex);
    for (    TestInfo testInfo : tests) {
      ensureResults(testInfo).put(clientStatus,null);
    }
    return new TestBlock(tests,blockIndex);
  }
}