From 3e8af7e981085c45aaf955b15f7f46488f107622 Mon Sep 17 00:00:00 2001
From: clc5q <clc5q@git.zephyr-software.com>
Date: Wed, 3 Jul 2013 21:38:37 +0000
Subject: [PATCH] Generalize SINKMALLOC detection and increase precision.

---
 SMPBasicBlock.cpp | 129 ++++++++++++++++++++++++++++++++++++++++------
 SMPBasicBlock.h   |   2 +-
 SMPInstr.cpp      |  10 +++-
 SMPInstr.h        |   2 +-
 4 files changed, 123 insertions(+), 20 deletions(-)

diff --git a/SMPBasicBlock.cpp b/SMPBasicBlock.cpp
index 50056e15..3af1da43 100644
--- a/SMPBasicBlock.cpp
+++ b/SMPBasicBlock.cpp
@@ -4380,19 +4380,22 @@ bool SMPBasicBlock::IsDefMasked(op_t DefOp, int DefSSANum, ea_t DefAddr) {
 //  Recurse through successor blocks if needed to find all USEs of the DEF.
 bool SMPBasicBlock::IsCriticalSink(op_t DefOp, int DefSSANum, std::string &SinkString) {
 	// Call recursive helper that finds argument-passing USEs of the DEF.
-	bool FoundSink = this->UseHasCriticalSink(DefOp, DefSSANum, SinkString);
+	op_t AlternateDefOp = InitOp;
+	bool FoundSink = this->UseHasCriticalSink(DefOp, DefSSANum, AlternateDefOp, SMP_SSA_UNINIT, SinkString);
 
 	return FoundSink;
 } // end of SMPBasicBlock::IsCriticalSink()
 
 // Can we find USE being passed to a critical system or library call?
-bool SMPBasicBlock::UseHasCriticalSink(op_t UseOp, int DefSSANum, std::string &SinkString) {
+bool SMPBasicBlock::UseHasCriticalSink(op_t DefOp, int DefSSANum, op_t DefOp2, int DefSSANum2, std::string &SinkString) {
 	bool FoundSink = false;
 	list<SMPInstr *>::iterator InstIter;
-	set<DefOrUse, LessDefUse>::iterator UseIter;
+	set<DefOrUse, LessDefUse>::iterator UseIter, DefIter;
 	bool FoundArgPass = false;
 	int SearchSSANum = DefSSANum;
+	int SearchSSANum2 = DefSSANum2;
 	ea_t InstAddr; // for debugging, breakpoints, etc.
+	size_t ArgumentNumber = 7; // init to bad number
 
 	// avoid infinite recursion
 	if (this->IsProcessed()) {
@@ -4400,12 +4403,12 @@ bool SMPBasicBlock::UseHasCriticalSink(op_t UseOp, int DefSSANum, std::string &S
 	}
 	this->SetProcessed(true); 
 
-	// We need to make the recursion robust by finding UseOp in Phi functions
+	// We need to make the recursion robust by finding DefOp in Phi functions
 	//  and altering the DefSSANum we are searching for.
-	set<SMPPhiFunction, LessPhi>::iterator CurrPhi = this->FindPhi(UseOp);
+	set<SMPPhiFunction, LessPhi>::iterator CurrPhi = this->FindPhi(DefOp);
 	if (CurrPhi != this->GetLastPhi()) {
-		// Found Phi function for UseOp. That means we will not be finding DefSSANum for
-		//  UseOp in this block or its successors, because the Phi function will redefine
+		// Found Phi function for DefOp. That means we will not be finding DefSSANum for
+		//  DefOp in this block or its successors, because the Phi function will redefine
 		//  to a new SSA number.
 		size_t PhiNumUses = CurrPhi->GetPhiListSize();
 		bool FoundPhiUse = false;
@@ -4416,24 +4419,108 @@ bool SMPBasicBlock::UseHasCriticalSink(op_t UseOp, int DefSSANum, std::string &S
 				break;
 			}
 		}
-		if (!FoundPhiUse)
-			return false;
-		SearchSSANum = CurrPhi->GetDefSSANum();  // new SSA name to search for is Phi DEF
+		if (FoundPhiUse) {
+			SearchSSANum = CurrPhi->GetDefSSANum();  // new SSA name to search for is Phi DEF
+		}
+	}
+
+	// Do the same for DefOp2/DefSSANum2.
+	if (o_void != DefOp2.type) {
+		CurrPhi = this->FindPhi(DefOp2);
+		if (CurrPhi != this->GetLastPhi()) {
+			// Found Phi function for DefOp2. That means we will not be finding DefSSANum2 for
+			//  DefOp2 in this block or its successors, because the Phi function will redefine
+			//  to a new SSA number.
+			size_t PhiNumUses = CurrPhi->GetPhiListSize();
+			bool FoundPhiUse = false;
+			for (size_t i = 0; i < PhiNumUses; ++i) {
+				// Confirm that DefSSANum2 was actually a Phi USE in this block.
+				if (CurrPhi->GetUseSSANum(i) == DefSSANum2) {
+					FoundPhiUse = true;
+					break;
+				}
+			}
+			if (FoundPhiUse) {
+				SearchSSANum2 = CurrPhi->GetDefSSANum();  // new SSA name to search for is Phi DEF
+			}
+		}
 	}
 
+
 	for (InstIter = this->GetFirstInstr(); InstIter != this->GetLastInstr(); ++InstIter) {
 		SMPInstr *CurrInst = (*InstIter);
 		InstAddr = CurrInst->GetAddr();
 		// Two stage search: Find argument pass, then find next call instruction.
 		if (!FoundArgPass) {
-			UseIter = CurrInst->FindUse(UseOp);
+			UseIter = CurrInst->FindUse(DefOp);
 			if (UseIter != CurrInst->GetLastUse()) {
 				int UseSSANum = UseIter->GetSSANum();
 				if (UseSSANum == SearchSSANum) {
 					// Found a use that matches the DEF. Is it passed as an argument?
-					if (CurrInst->MDIsArgumentPass()) {
+					if (CurrInst->MDIsArgumentPass(ArgumentNumber)) {
 						FoundArgPass = true;
 					}
+					else if (CurrInst->MDIsMoveInstr() && (o_void == DefOp2.type)) {
+						// DefOp is getting stored, but not as an argument pass.
+						//  Hard to say if we should keep following DefOp or follow
+						//  the stored copy. Let's try following the stored copy also if
+						//  it is a register or stack location.
+						DefIter = CurrInst->GetFirstNonFlagsDef();
+						assert(DefIter != CurrInst->GetLastDef());
+						op_t NewDefOp = DefIter->GetOp();
+						if (MDIsDataFlowOpnd(NewDefOp, this->GetFunc()->UsesFramePointer())) {
+							// Follow NewDefOp from now on in addition to DefOp.
+							CanonicalizeOpnd(NewDefOp);
+							DefOp2 = NewDefOp;
+							SearchSSANum2 = DefIter->GetSSANum();
+						}
+					}
+					else { // Stop searching for DefOp if it gets redefined.
+						DefIter = CurrInst->FindDef(DefOp);
+						if (DefIter != CurrInst->GetLastDef()) {
+							// DefOp was USE and DEF in CurrInst.
+							if (o_void != DefOp2.type) {
+								// We have an alternate DEF to search for. Make it primary.
+								DefOp = DefOp2;
+								SearchSSANum = SearchSSANum2;
+								DefOp2 = InitOp; // No more alternate.
+								SearchSSANum2 = SMP_SSA_UNINIT;
+							}
+							else { // No alternate to search for; search has failed.
+								break;
+							}
+						}
+					}
+				}
+			}
+			else if (o_void != DefOp2.type) { // DefOp is not used; search for DefOp2
+				UseIter = CurrInst->FindUse(DefOp2);
+				if (UseIter != CurrInst->GetLastUse()) {
+					int UseSSANum = UseIter->GetSSANum();
+					if (UseSSANum == SearchSSANum2) {
+						// Found a use that matches the DEF. Is it passed as an argument?
+						if (CurrInst->MDIsArgumentPass(ArgumentNumber)) {
+							FoundArgPass = true;
+						}
+						else if (CurrInst->MDIsMoveInstr()) { // DefOp2 is copied somewhere
+							// We cannot follow a third location currently, but we can see
+							//  if DefOp2 is redefining DefOp in this move, and get a new
+							//  SearchSSANum for DefOp in that case.
+							DefIter = CurrInst->FindDef(DefOp);
+							if (DefIter != CurrInst->GetLastDef()) {
+								// DefOp2 was copied to DefOp.
+								SearchSSANum = DefIter->GetSSANum(); // new DefOp/DefSSANum pair to search for.
+							}
+						}
+						else { // Stop searching for DefOp2 if it gets redefined.
+							DefIter = CurrInst->FindDef(DefOp2);
+							if (DefIter != CurrInst->GetLastDef()) {
+								// DefOp2 was USE and DEF in CurrInst.
+								DefOp2 = InitOp; // No more alternate.
+								SearchSSANum2 = SMP_SSA_UNINIT;
+							}
+						}
+					}
 				}
 			}
 		}
@@ -4443,19 +4530,29 @@ bool SMPBasicBlock::UseHasCriticalSink(op_t UseOp, int DefSSANum, std::string &S
 				if (!(CalleeName.empty())) {
 					GetSinkStringForCallName(CalleeName, SinkString);
 					if (!(SinkString.empty())) {
-						FoundSink = true;
+						// ArgumentNumber needs to be 0 for malloc(), 0 or 1 for calloc(),
+						//  and 1 for realloc.
+						if (ArgumentNumber < 2) {
+							bool FoundMalloc = (0 == CalleeName.compare("malloc"));
+							bool FoundCalloc = (0 == CalleeName.compare("calloc"));
+							bool FoundRealloc = (0 == CalleeName.compare("realloc"));
+							if (((ArgumentNumber == 0) && (FoundMalloc || FoundCalloc))
+								|| ((ArgumentNumber == 1) && (FoundCalloc || FoundRealloc))) {
+								FoundSink = true;
+							}
+						}
 					}
-					break;
 				}
+				break;
 			}
 		}
 	} // end for all instructions
 
-	if (!FoundArgPass) {
+	if (!FoundArgPass && (this->IsLiveOut(DefOp) || ((o_void != DefOp2.type) && this->IsLiveOut(DefOp2)))) {
 		// Need to recurse through successor blocks to keep searching for arg pass.
 		list<SMPBasicBlock *>::iterator SuccIter;
 		for (SuccIter = this->GetFirstSucc(); SuccIter != this->GetLastSucc(); ++SuccIter) {
-			if ((*SuccIter)->UseHasCriticalSink(UseOp, SearchSSANum, SinkString)) {
+			if ((*SuccIter)->UseHasCriticalSink(DefOp, SearchSSANum, DefOp2, SearchSSANum2, SinkString)) {
 				FoundSink = true;
 				break;
 			}
diff --git a/SMPBasicBlock.h b/SMPBasicBlock.h
index e2382050..82bb7d71 100644
--- a/SMPBasicBlock.h
+++ b/SMPBasicBlock.h
@@ -377,7 +377,7 @@ private:
 	set<SMPPhiFunction, LessPhi>::iterator InferPhiDefType(set<SMPPhiFunction, LessPhi>::iterator DefPhi, bool &changed); // infer, propagate to all uses
 	unsigned int GetLocalDUIndex(op_t DefOp, int SSANum);
 	unsigned int GetGlobalDUIndex(op_t DefOp, ea_t DefAddr);
-	bool UseHasCriticalSink(op_t UseOp, int DefSSANum, string &SinkString); // USE is passed as arg to critical system or lib call
+	bool UseHasCriticalSink(op_t DefOp, int DefSSANum, op_t DefOp2, int DefSSANum2, string &SinkString); // DefOp or DefOp2 is passed as arg to critical system or lib call
 	bool IsBranchSignednessUnreliable(void); // Is branch signedness misleading due to odd code generation idiom or hand coding?
 }; 
 
diff --git a/SMPInstr.cpp b/SMPInstr.cpp
index 12e73eeb..06b5a791 100644
--- a/SMPInstr.cpp
+++ b/SMPInstr.cpp
@@ -5046,8 +5046,8 @@ bool SMPInstr::SkipSignednessCheckOnStackWrite(int DefSSANum) {
 	return SkipCheck;
 } // end of SMPInstr::SkipSignednessCheckOnStackWrite()
 
-// Does inst pass an outgoing argument?
-bool SMPInstr::MDIsArgumentPass(void) {
+// Does inst pass an outgoing argument? If so, pass back argument position #, starting at zero for [esp], 1 for [esp+4], etc.
+bool SMPInstr::MDIsArgumentPass(size_t &ArgumentNumber) {
 	bool OutArgPass = false;
 
 	// Current model is writing outargs to stack. For other compiler targets in the
@@ -5056,6 +5056,12 @@ bool SMPInstr::MDIsArgumentPass(void) {
 		if (this->GetBlock()->GetFunc()->OutArgsRegionComputed()) {
 			op_t DefOp = this->DEFMemOp;
 			OutArgPass = this->GetBlock()->GetFunc()->IsInOutgoingArgsRegion(DefOp);
+			if (OutArgPass) {
+				op_t UnnormalizedDefOp = DefOp;
+				this->MDGetUnnormalizedOp(UnnormalizedDefOp);
+				size_t StandardByteSize = (MD_NORMAL_MACHINE_BITWIDTH / 8);
+				ArgumentNumber = (UnnormalizedDefOp.addr / StandardByteSize);
+			}
 		}
 	}
 	return OutArgPass;
diff --git a/SMPInstr.h b/SMPInstr.h
index 14229d8c..c9d9aff2 100644
--- a/SMPInstr.h
+++ b/SMPInstr.h
@@ -543,7 +543,7 @@ public:
 	void SyncAllRTs(bool UseFP, sval_t FPDelta); // calls SyncRTLDefUse() for all RTs in RTL
 	op_t GetPushedOpnd(void); // Extract source operand from PUSH RTL
 	int MDGetImmedUse(void); // Get immed value from USE list of inst
-	bool MDIsArgumentPass(void); // Does inst pass an outgoing argument?
+	bool MDIsArgumentPass(size_t &ArgumentNumber); // Does inst pass an outgoing argument?
 	bool OperandTransfersValueToDef(op_t UseOp); // Does UseOp arithmetically affect the value of the NonFlagsDef for this inst?
 	string GetTrimmedCalledFunctionName(void); // Get funcname from call inst and remove "." and "_" prefices
 	void SetImmedTypes(bool UseFP); // type all immediate operands as NUMERIC, CODEPTR, GLOBALPTR
-- 
GitLab