After thinking a bit more, it suffers from a similar edge case where the semaphore has been signaled, but process is terminated before it's had a chance to run, after changing to ifCurtailed and cleaning #terminate:
waiter := Semaphore new.
waiter2 := Semaphore new.
lock := Semaphore forMutualExclusion.
proc := [lock critical: [ Transcript crShow: '1 start'.
waiter wait.
Transcript crShow: '1 done'.]] newProcess.
proc priority: 70.
proc resume.
proc2 := [lock critical: [ Transcript crShow: '2 start'.
waiter2 wait.
Transcript crShow: '2 done'. ]] newProcess.
proc2 priority: 15.
proc2 resume.
"Yield for proc2 so it gets to waiting on lock"
1 second wait.
"Signal waiter and yield, causing proc1 to run, and release the lock. lock will then remove proc2 from waiting list"
waiter signal.
Processor yield.
"We have a higher pri than proc2, and will resume execution here before proc2 has chance to run"
proc2 terminate.
"proc2 has been curtailed before running, thus ifCurtailed: guard is still on stack and will be run as part of termination."
(lock instVarNamed: 'excessSignals') 0 "Should be 1"