From 166f75d91f180d0ac45f0b8ee7c3a1b6742209fa Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 6 Jun 2012 16:38:16 -0400
Subject: [PATCH] MAINT-1144: Defend against NULL
 LLPluginProcessParent::mProcess. The change from LLProcessLauncher to
 LLProcess introduces the possibility of a NULL (default-constructed)
 LLProcessPtr. Add certain static LLProcess methods accepting LLProcessPtr,
 forwarding to nonstatic method when non-NULL but doing something reasonable
 with NULL. Use these methods in LLPLuginProcessParent.

---
 indra/llcommon/llprocess.cpp             | 38 ++++++++++++++++++++++++
 indra/llcommon/llprocess.h               | 11 +++++--
 indra/llplugin/llpluginprocessparent.cpp | 13 ++++----
 3 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 9667e4e0336..715df36f399 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -819,16 +819,43 @@ bool LLProcess::kill(const std::string& who)
 	return ! isRunning();
 }
 
+//static
+bool LLProcess::kill(const LLProcessPtr& p, const std::string& who)
+{
+	if (! p)
+		return true;                // process dead! (was never running)
+	return p->kill(who);
+}
+
 bool LLProcess::isRunning() const
 {
 	return getStatus().mState == RUNNING;
 }
 
+//static
+bool LLProcess::isRunning(const LLProcessPtr& p)
+{
+	if (! p)
+		return false;
+	return p->isRunning();
+}
+
 LLProcess::Status LLProcess::getStatus() const
 {
 	return mStatus;
 }
 
+//static
+LLProcess::Status LLProcess::getStatus(const LLProcessPtr& p)
+{
+	if (! p)
+	{
+		// default-constructed Status has mState == UNSTARTED
+		return Status();
+	}
+	return p->getStatus();
+}
+
 std::string LLProcess::getStatusString() const
 {
 	return getStatusString(getStatus());
@@ -839,6 +866,17 @@ std::string LLProcess::getStatusString(const Status& status) const
 	return getStatusString(mDesc, status);
 }
 
+//static
+std::string LLProcess::getStatusString(const std::string& desc, const LLProcessPtr& p)
+{
+	if (! p)
+	{
+		// default-constructed Status has mState == UNSTARTED
+		return getStatusString(desc, Status());
+	}
+	return desc + " " + p->getStatusString();
+}
+
 //static
 std::string LLProcess::getStatusString(const std::string& desc, const Status& status)
 {
diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h
index 51010966f9d..d711ce2f743 100644
--- a/indra/llcommon/llprocess.h
+++ b/indra/llcommon/llprocess.h
@@ -239,6 +239,10 @@ class LL_COMMON_API LLProcess: public boost::noncopyable
 
 	/// Is child process still running?
 	bool isRunning() const;
+	// static isRunning(LLProcessPtr), getStatus(LLProcessPtr),
+	// getStatusString(LLProcessPtr), kill(LLProcessPtr) handle the case in
+	// which the passed LLProcessPtr might be NULL (default-constructed).
+	static bool isRunning(const LLProcessPtr&);
 
 	/**
 	 * State of child process
@@ -272,8 +276,10 @@ class LL_COMMON_API LLProcess: public boost::noncopyable
 
 	/// Status query
 	Status getStatus() const;
+	static Status getStatus(const LLProcessPtr&);
 	/// English Status string query, for logging etc.
 	std::string getStatusString() const;
+	static std::string getStatusString(const std::string& desc, const LLProcessPtr&);
 	/// English Status string query for previously-captured Status
 	std::string getStatusString(const Status& status) const;
 	/// static English Status string query
@@ -282,6 +288,7 @@ class LL_COMMON_API LLProcess: public boost::noncopyable
 	// Attempt to kill the process -- returns true if the process is no longer running when it returns.
 	// Note that even if this returns false, the process may exit some time after it's called.
 	bool kill(const std::string& who="");
+	static bool kill(const LLProcessPtr& p, const std::string& who="");
 
 #if LL_WINDOWS
 	typedef int id;                 ///< as returned by getProcessID()
@@ -314,10 +321,10 @@ class LL_COMMON_API LLProcess: public boost::noncopyable
 	 * New functionality should be added as nonstatic members operating on
 	 * the same data as getProcessHandle().
 	 *
-	 * In particular, if child termination is detected by static isRunning()
+	 * In particular, if child termination is detected by this static isRunning()
 	 * rather than by nonstatic isRunning(), the LLProcess object won't be
 	 * aware of the child's changed status and may encounter OS errors trying
-	 * to obtain it. static isRunning() is only intended for after the
+	 * to obtain it. This static isRunning() is only intended for after the
 	 * launching LLProcess object has been destroyed.
 	 */
 	static handle isRunning(handle, const std::string& desc="");
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index f10eaee5b48..71a6145b581 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -134,11 +134,8 @@ LLPluginProcessParent::~LLPluginProcessParent()
 		// and remove it from our map
 		mSharedMemoryRegions.erase(iter);
 	}
-	
-	if (mProcess)
-	{
-		mProcess->kill();
-	}
+
+	LLProcess::kill(mProcess);
 	killSockets();
 }
 
@@ -471,7 +468,7 @@ void LLPluginProcessParent::idle(void)
 			break;
 			
 			case STATE_EXITING:
-				if (! mProcess->isRunning())
+				if (! LLProcess::isRunning(mProcess))
 				{
 					setState(STATE_CLEANUP);
 				}
@@ -499,7 +496,7 @@ void LLPluginProcessParent::idle(void)
 			break;
 			
 			case STATE_CLEANUP:
-				mProcess->kill();
+				LLProcess::kill(mProcess);
 				killSockets();
 				setState(STATE_DONE);
 			break;
@@ -1078,7 +1075,7 @@ bool LLPluginProcessParent::pluginLockedUpOrQuit()
 {
 	bool result = false;
 	
-	if (! mProcess->isRunning())
+	if (! LLProcess::isRunning(mProcess))
 	{
 		LL_WARNS("Plugin") << "child exited" << LL_ENDL;
 		result = true;
-- 
GitLab