From 6616bc6e6a4c07aa2398373ee65563a3d80933bb Mon Sep 17 00:00:00 2001
From: clc5q <clc5q@git.zephyr-software.com>
Date: Sat, 1 Mar 2014 01:52:39 +0000
Subject: [PATCH] Fix crashes in ffmpeg and other 64-bit binaries.

---
 SMPBasicBlock.cpp |  2 +-
 SMPFunction.cpp   | 10 +++++++++-
 SMPFunction.h     |  3 +++
 SMPInstr.cpp      |  2 +-
 4 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/SMPBasicBlock.cpp b/SMPBasicBlock.cpp
index 1a8b76ea..4f5a05ff 100644
--- a/SMPBasicBlock.cpp
+++ b/SMPBasicBlock.cpp
@@ -3696,8 +3696,8 @@ bool SMPBasicBlock::IsDefInvolvedInAddition(ea_t DefAddr, op_t DefOp, ea_t &Addi
 	++UseInstIter;
 	while (UseInstIter != this->GetLastInst()) {
 		SMPInstr *UseInst = (*UseInstIter);
+		AdditionAddr = UseInst->GetAddr();
 		if (UseInst->FindUse(DefOp) != UseInst->GetLastUse()) {
-			AdditionAddr = UseInst->GetAddr();
 			if (UseInst->MDIsAddition()) {
 				// hash function value is accumulating in another DEF via addition.
 				return true;
diff --git a/SMPFunction.cpp b/SMPFunction.cpp
index 9350ffb9..8fcca2f7 100644
--- a/SMPFunction.cpp
+++ b/SMPFunction.cpp
@@ -2339,6 +2339,14 @@ void SMPFunction::SemiNaiveLocalVarID(void) {
 		//  our stack frame maps of maximum size, and MinStackDelta is used for normalizing offsets.
 		this->MinStackAccessOffset = this->MinStackDelta;
 	}
+	else if (this->MinStackAccessOffset < this->MinStackDelta) {
+		// x86-64 leaf functions are often optimized by not allocating a stack frame. Instead,
+		//  negative displacements from the stack pointer are used to access locals. So the
+		//  stack pointer (reflected in MinStackDelta) never goes down as far as the bottom of
+		//  the frame (reflected by MinStackAccessOffset). We need to record that such a function
+		//  has been detected so that we don't fail assertions unnecessarily later.
+		this->SetStackFrameExtendsPastStackTop();
+	}
 
 	// IDA Pro sometimes fails to add stack frame members for all incoming args, etc.
 	//  Find and correct these omissions by examining stack accesses in instructions
@@ -2680,7 +2688,7 @@ void SMPFunction::FindOutgoingArgsSize(void) {
 		ea_t InstAddr = CurrInst->GetAddr();
 		sval_t sp_delta = CurrInst->GetStackPtrOffset();
 		if (0 < sp_delta) {
-			// Stack underflow; about to assert
+			// Stack underflow.
 			SMP_msg("ERROR: Stack underflow at %lx %s sp_delta: %ld\n", (unsigned long) InstAddr,
 				CurrInst->GetDisasm(), (long) sp_delta);
 			this->OutgoingArgsComputed = false;
diff --git a/SMPFunction.h b/SMPFunction.h
index 6779103d..3f01b8f6 100644
--- a/SMPFunction.h
+++ b/SMPFunction.h
@@ -255,6 +255,7 @@ public:
 		return (KillSet.end() != KillSet.find(CurrOp));
 	}
 	bool IsInStackPtrCopySet(op_t CurrOp);
+	inline bool DoesStackFrameExtendPastStackTop(void) const { return StackFrameExtendsPastStackTop; };
 
 	// Printing methods
 	void Dump(void); // debug dump
@@ -337,6 +338,7 @@ private:
 	bool PossibleTailCallTarget; // function could be called by jump instruction acting as tail call
 	bool OutgoingArgsComputed; // Were able to compute OutgoingArgsSize
 	bool GoodLocalVarTable; // LocalVarTable was built successfully
+	bool StackFrameExtendsPastStackTop; // Locals are accessed from unallocated space beyond the top of stack.
 	bool IsSpeculative;	    // Have we started the speculative portion of the analysis for this function.
 	long TypedDefs;  // How many DEFs in instructions were not UNINIT type after InferTypes()
 	long UntypedDefs; // How many DEFs in instructions are UNINIT type after InferTypes()
@@ -438,6 +440,7 @@ private:
 	void UpdateMinMaxStackOffsets(SMPInstr *CurrInst, op_t TempOp); // Update MinStackAccessOffset and MaxStackAccessLimit if TempOp is stack access
 	bool AuditLocalVarTable(void); // Check and correct IDA Pro listing of local frame members.
 	void FindOutgoingArgsSize(void); // Find portion of local frame that is outgoing args
+	inline void SetStackFrameExtendsPastStackTop(void) { StackFrameExtendsPastStackTop = true; };
 	bool IndexedWritesAboveLocalFrame(op_t DestOp); // Is DestOp direct stack write to caller's frame?
 	bool MDGetStackOffsetAndSize(SMPInstr *Instr, op_t TempOp, sval_t BaseValue, ea_t &offset, size_t &DataSize,
 		bool &FP, bool &Indexed, bool &Signed, bool &Unsigned);  // Find any stack memory access in TempOp, return offset, size,
diff --git a/SMPInstr.cpp b/SMPInstr.cpp
index 03c0472d..f11162e9 100644
--- a/SMPInstr.cpp
+++ b/SMPInstr.cpp
@@ -2985,7 +2985,7 @@ void SMPInstr::MDGetUnnormalizedOp(op_t &NormOp) {
 			//  of a negative offset from the entry point of the function.
 			SignedOffset = (sval_t) NormOp.addr;
 			SignedOffset -= this->GetStackPtrOffset();
-			assert(0 <= SignedOffset);
+			assert((0 <= SignedOffset) || this->GetBlock()->GetFunc()->DoesStackFrameExtendPastStackTop());
 		}
 		NormOp.addr = (ea_t) SignedOffset;
 	}
-- 
GitLab