| Index: src/processor/stackwalker_amd64.cc
 | 
| diff --git a/src/processor/stackwalker_amd64.cc b/src/processor/stackwalker_amd64.cc
 | 
| index f252a33b71574e21dbf5b985978a20d12c9fcf07..8ccf73c42940d6fc6c278aebb05db4c5b14b024a 100644
 | 
| --- a/src/processor/stackwalker_amd64.cc
 | 
| +++ b/src/processor/stackwalker_amd64.cc
 | 
| @@ -147,6 +147,23 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByCFIFrameInfo(
 | 
|    return frame.release();
 | 
|  }
 | 
|  
 | 
| +bool StackwalkerAMD64::IsEndOfStack(uint64_t caller_rip, uint64_t caller_rsp,
 | 
| +                                    uint64_t callee_rsp) {
 | 
| +  // Treat an instruction address of 0 as end-of-stack.
 | 
| +  if (caller_rip == 0) {
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  // If the new stack pointer is at a lower address than the old, then
 | 
| +  // that's clearly incorrect. Treat this as end-of-stack to enforce
 | 
| +  // progress and avoid infinite loops.
 | 
| +  if (caller_rsp < callee_rsp) {
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
|  StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery(
 | 
|      const vector<StackFrame*>& frames) {
 | 
|    StackFrameAMD64* last_frame = static_cast<StackFrameAMD64*>(frames.back());
 | 
| @@ -175,8 +192,11 @@ StackFrameAMD64* StackwalkerAMD64::GetCallerByFramePointerRecovery(
 | 
|      uint64_t caller_rsp = last_rbp + 16;
 | 
|  
 | 
|      // Simple sanity check that the stack is growing downwards as expected.
 | 
| -    if (caller_rbp < last_rbp || caller_rsp < last_rsp)
 | 
| +    if (IsEndOfStack(caller_rip, caller_rsp, last_rsp) ||
 | 
| +        caller_rbp < last_rbp) {
 | 
| +      // Reached end-of-stack or stack is not growing downwards.
 | 
|        return NULL;
 | 
| +    }
 | 
|  
 | 
|      StackFrameAMD64* frame = new StackFrameAMD64();
 | 
|      frame->trust = StackFrame::FRAME_TRUST_FP;
 | 
| @@ -284,15 +304,11 @@ StackFrame* StackwalkerAMD64::GetCallerFrame(const CallStack* stack,
 | 
|      new_frame->context.rbp = static_cast<uint32_t>(new_frame->context.rbp);
 | 
|    }
 | 
|  
 | 
| -  // Treat an instruction address of 0 as end-of-stack.
 | 
| -  if (new_frame->context.rip == 0)
 | 
| -    return NULL;
 | 
| -
 | 
| -  // If the new stack pointer is at a lower address than the old, then
 | 
| -  // that's clearly incorrect. Treat this as end-of-stack to enforce
 | 
| -  // progress and avoid infinite loops.
 | 
| -  if (new_frame->context.rsp <= last_frame->context.rsp)
 | 
| +  if (IsEndOfStack(new_frame->context.rip, new_frame->context.rsp,
 | 
| +                   last_frame->context.rsp)) {
 | 
| +    // Reached end-of-stack.
 | 
|      return NULL;
 | 
| +  }
 | 
|  
 | 
|    // new_frame->context.rip is the return address, which is the instruction
 | 
|    // after the CALL that caused us to arrive at the callee. Set
 | 
| 
 |