Fix possible synchronization issue in TaskThunk. When cancel is called, it is executed in the caller thread, which is different from the thread run() is executing on. Only one thread may use the context at a time, so a big lock is needed around the two methods. Change-Id: I41c203761cef5ca84914c3ace8e33b704212cdc2
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java index 0327fb8..6e0d60a 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -379,55 +379,59 @@ @Override public void cancel() { - final Context old = SshScope.set(context); - try { - onExit(STATUS_CANCEL); - } finally { - SshScope.set(old); + synchronized (this) { + final Context old = SshScope.set(context); + try { + onExit(STATUS_CANCEL); + } finally { + SshScope.set(old); + } } } @Override public void run() { - final Thread thisThread = Thread.currentThread(); - final String thisName = thisThread.getName(); - int rc = 0; - final Context old = SshScope.set(context); - try { - context.started = System.currentTimeMillis(); - thisThread.setName("SSH " + taskName); - - if (thunk instanceof ProjectCommandRunnable) { - ((ProjectCommandRunnable) thunk).executeParseCommand(); - projectName = ((ProjectCommandRunnable) thunk).getProjectName(); - } - + synchronized (this) { + final Thread thisThread = Thread.currentThread(); + final String thisName = thisThread.getName(); + int rc = 0; + final Context old = SshScope.set(context); try { - thunk.run(); - } catch (NoSuchProjectException e) { - throw new UnloggedFailure(1, e.getMessage() + " no such project"); - } catch (NoSuchChangeException e) { - throw new UnloggedFailure(1, e.getMessage() + " no such change"); - } + context.started = System.currentTimeMillis(); + thisThread.setName("SSH " + taskName); - out.flush(); - err.flush(); - } catch (Throwable e) { - try { + if (thunk instanceof ProjectCommandRunnable) { + ((ProjectCommandRunnable) thunk).executeParseCommand(); + projectName = ((ProjectCommandRunnable) thunk).getProjectName(); + } + + try { + thunk.run(); + } catch (NoSuchProjectException e) { + throw new UnloggedFailure(1, e.getMessage() + " no such project"); + } catch (NoSuchChangeException e) { + throw new UnloggedFailure(1, e.getMessage() + " no such change"); + } + out.flush(); - } catch (Throwable e2) { - } - try { err.flush(); - } catch (Throwable e2) { - } - rc = handleError(e); - } finally { - try { - onExit(rc); + } catch (Throwable e) { + try { + out.flush(); + } catch (Throwable e2) { + } + try { + err.flush(); + } catch (Throwable e2) { + } + rc = handleError(e); } finally { - SshScope.set(old); - thisThread.setName(thisName); + try { + onExit(rc); + } finally { + SshScope.set(old); + thisThread.setName(thisName); + } } } }