Program: 110509
Project: 110509
Buggy source:
/** 
 * Download the output files and directory trees of a remotely executed action to the local machine, as well stdin / stdout to the given files. <p>In case of failure, this method deletes any output files it might have already created.
 * @throws IOException in case of a cache miss or if the remote cache is unavailable.
 * @throws ExecException in case clean up after a failed download failed.
 */
public void download(ActionResult result,Path execRoot,FileOutErr outErr) throws ExecException, IOException, InterruptedException {
  try {
    Context ctx=Context.current();
    List<FuturePathBooleanTuple> fileDownloads=Collections.synchronizedList(new ArrayList<>(result.getOutputFilesCount() + result.getOutputDirectoriesCount()));
    for (    OutputFile file : result.getOutputFilesList()) {
      Path path=execRoot.getRelative(file.getPath());
      ListenableFuture<Void> download=retrier.executeAsync(() -> ctx.call(() -> downloadFile(path,file.getDigest(),file.getContent())));
      fileDownloads.add(new FuturePathBooleanTuple(download,path,file.getIsExecutable()));
    }
    List<ListenableFuture<Void>> dirDownloads=new ArrayList<>(result.getOutputDirectoriesCount());
    for (    OutputDirectory dir : result.getOutputDirectoriesList()) {
      SettableFuture<Void> dirDownload=SettableFuture.create();
      ListenableFuture<byte[]> protoDownload=retrier.executeAsync(() -> ctx.call(() -> downloadBlob(dir.getTreeDigest())));
      Futures.addCallback(protoDownload,new FutureCallback<byte[]>(){
        @Override public void onSuccess(        byte[] b){
          try {
            Tree tree=Tree.parseFrom(b);
            Map<Digest,Directory> childrenMap=new HashMap<>();
            for (            Directory child : tree.getChildrenList()) {
              childrenMap.put(digestUtil.compute(child),child);
            }
            Path path=execRoot.getRelative(dir.getPath());
            fileDownloads.addAll(downloadDirectory(path,tree.getRoot(),childrenMap,ctx));
            dirDownload.set(null);
          }
 catch (          IOException e) {
            dirDownload.setException(e);
          }
        }
        @Override public void onFailure(        Throwable t){
          dirDownload.setException(t);
        }
      }
,MoreExecutors.directExecutor());
      dirDownloads.add(dirDownload);
    }
    fileDownloads.addAll(downloadOutErr(result,outErr,ctx));
    for (    ListenableFuture<Void> dirDownload : dirDownloads) {
      getFromFuture(dirDownload);
    }
    for (    FuturePathBooleanTuple download : fileDownloads) {
      getFromFuture(download.getFuture());
      if (download.getPath() != null) {
        download.getPath().setExecutable(download.isExecutable());
      }
    }
  }
 catch (  IOException downloadException) {
    try {
      for (      OutputFile file : result.getOutputFilesList()) {
        execRoot.getRelative(file.getPath()).delete();
      }
      for (      OutputDirectory directory : result.getOutputDirectoriesList()) {
        FileSystemUtils.deleteTree(execRoot.getRelative(directory.getPath()));
      }
      if (outErr != null) {
        outErr.getOutputPath().delete();
        outErr.getErrorPath().delete();
      }
    }
 catch (    IOException e) {
      throw new EnvironmentalExecException("String_Node_Str" + "String_Node_Str",e,true);
    }
    throw downloadException;
  }
}

Fixed version (ground truth):
/** 
 * Download the output files and directory trees of a remotely executed action to the local machine, as well stdin / stdout to the given files. <p>In case of failure, this method deletes any output files it might have already created.
 * @throws IOException in case of a cache miss or if the remote cache is unavailable.
 * @throws ExecException in case clean up after a failed download failed.
 */
public void download(ActionResult result,Path execRoot,FileOutErr outErr) throws ExecException, IOException, InterruptedException {
  Context ctx=Context.current();
  List<FuturePathBooleanTuple> fileDownloads=Collections.synchronizedList(new ArrayList<>(result.getOutputFilesCount() + result.getOutputDirectoriesCount()));
  for (  OutputFile file : result.getOutputFilesList()) {
    Path path=execRoot.getRelative(file.getPath());
    ListenableFuture<Void> download=retrier.executeAsync(() -> ctx.call(() -> downloadFile(path,file.getDigest(),file.getContent())));
    fileDownloads.add(new FuturePathBooleanTuple(download,path,file.getIsExecutable()));
  }
  List<ListenableFuture<Void>> dirDownloads=new ArrayList<>(result.getOutputDirectoriesCount());
  for (  OutputDirectory dir : result.getOutputDirectoriesList()) {
    SettableFuture<Void> dirDownload=SettableFuture.create();
    ListenableFuture<byte[]> protoDownload=retrier.executeAsync(() -> ctx.call(() -> downloadBlob(dir.getTreeDigest())));
    Futures.addCallback(protoDownload,new FutureCallback<byte[]>(){
      @Override public void onSuccess(      byte[] b){
        try {
          Tree tree=Tree.parseFrom(b);
          Map<Digest,Directory> childrenMap=new HashMap<>();
          for (          Directory child : tree.getChildrenList()) {
            childrenMap.put(digestUtil.compute(child),child);
          }
          Path path=execRoot.getRelative(dir.getPath());
          fileDownloads.addAll(downloadDirectory(path,tree.getRoot(),childrenMap,ctx));
          dirDownload.set(null);
        }
 catch (        IOException e) {
          dirDownload.setException(e);
        }
      }
      @Override public void onFailure(      Throwable t){
        dirDownload.setException(t);
      }
    }
,MoreExecutors.directExecutor());
    dirDownloads.add(dirDownload);
  }
  IOException downloadException=null;
  try {
    fileDownloads.addAll(downloadOutErr(result,outErr,ctx));
  }
 catch (  IOException e) {
    downloadException=e;
  }
  for (  ListenableFuture<Void> dirDownload : dirDownloads) {
    try {
      getFromFuture(dirDownload);
    }
 catch (    IOException e) {
      downloadException=downloadException == null ? e : downloadException;
    }
  }
  for (  FuturePathBooleanTuple download : fileDownloads) {
    try {
      getFromFuture(download.getFuture());
      if (download.getPath() != null) {
        download.getPath().setExecutable(download.isExecutable());
      }
    }
 catch (    IOException e) {
      downloadException=downloadException == null ? e : downloadException;
    }
  }
  if (downloadException != null) {
    try {
      for (      OutputFile file : result.getOutputFilesList()) {
        execRoot.getRelative(file.getPath()).delete();
      }
      for (      OutputDirectory directory : result.getOutputDirectoriesList()) {
        FileSystemUtils.deleteTree(execRoot.getRelative(directory.getPath()));
      }
      if (outErr != null) {
        outErr.getOutputPath().delete();
        outErr.getErrorPath().delete();
      }
    }
 catch (    IOException e) {
      throw new EnvironmentalExecException("String_Node_Str" + "String_Node_Str",e,true);
    }
    throw downloadException;
  }
}