From ad9a59f3b0c6d99e60c71fe7977ac25b6a3afcdc Mon Sep 17 00:00:00 2001
From: "SND\\ussrhero_cp"
 <SND\ussrhero_cp@9b283d60-5439-405e-af05-b73fd8c4d996>
Date: Tue, 21 Feb 2017 22:08:25 +0000
Subject: [PATCH] [pykd_ext_2.0] fixed : issue #14058, 14060, 14061

git-svn-id: https://pykd.svn.codeplex.com/svn@91172 9b283d60-5439-405e-af05-b73fd8c4d996
---
 pykd_ext/dbgout.h        |   4 +-
 pykd_ext/export.def      |   1 +
 pykd_ext/pyinterpret.cpp |   3 --
 pykd_ext/version.h       |   2 +-
 pykd_ext/windbgext.cpp   | 102 +++++++++++++++++++++++++++------------
 5 files changed, 75 insertions(+), 37 deletions(-)

diff --git a/pykd_ext/dbgout.h b/pykd_ext/dbgout.h
index 238e326..1585e4e 100644
--- a/pykd_ext/dbgout.h
+++ b/pykd_ext/dbgout.h
@@ -26,7 +26,7 @@ public:
         AutoRestorePyState  pystate;
 
         m_control->ControlledOutputWide(
-            DEBUG_OUTCTL_THIS_CLIENT,
+            DEBUG_OUTCTL_ALL_CLIENTS,
             DEBUG_OUTPUT_NORMAL,
             L"%ws",
             str.c_str()
@@ -39,7 +39,7 @@ public:
         AutoRestorePyState  pystate;
 
         m_control->ControlledOutputWide(
-            DEBUG_OUTCTL_THIS_CLIENT | DEBUG_OUTCTL_DML,
+            DEBUG_OUTCTL_ALL_CLIENTS | DEBUG_OUTCTL_DML,
             DEBUG_OUTPUT_NORMAL,
             L"%ws",
             str.c_str()
diff --git a/pykd_ext/export.def b/pykd_ext/export.def
index f029bfc..3f4e5c2 100644
--- a/pykd_ext/export.def
+++ b/pykd_ext/export.def
@@ -5,3 +5,4 @@ EXPORTS
 	info
 	pip
 	help
+	select = selectVersion
diff --git a/pykd_ext/pyinterpret.cpp b/pykd_ext/pyinterpret.cpp
index ae80557..8dca41d 100644
--- a/pykd_ext/pyinterpret.cpp
+++ b/pykd_ext/pyinterpret.cpp
@@ -157,10 +157,7 @@ public:
 
         m_module->PyImport_Cleanup();
 
-        while (PyGC_Collect() > 0);
-
         m_module->Py_EndInterpreter(m_state);
-
     }
 
     PyModule*  m_module;
diff --git a/pykd_ext/version.h b/pykd_ext/version.h
index ddc7f4e..e991b1f 100644
--- a/pykd_ext/version.h
+++ b/pykd_ext/version.h
@@ -3,7 +3,7 @@
 #define PYKDEXT_VERSION_MAJOR      2
 #define PYKDEXT_VERSION_MINOR      0
 #define PYKDEXT_VERSION_SUBVERSION 0
-#define PYKDEXT_VERSION_BUILDNO    6
+#define PYKDEXT_VERSION_BUILDNO    8
 
 #define __VER_STR2__(x) #x
 #define __VER_STR1__(x) __VER_STR2__(x)
diff --git a/pykd_ext/windbgext.cpp b/pykd_ext/windbgext.cpp
index 2781575..d75a285 100644
--- a/pykd_ext/windbgext.cpp
+++ b/pykd_ext/windbgext.cpp
@@ -15,6 +15,10 @@
 #include "pyclass.h"
 #include "version.h"
 
+//////////////////////////////////////////////////////////////////////////////
+
+static int  defaultMajorVersion = 2;
+static int  defaultMinorVersion = 7;
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -199,6 +203,32 @@ info(
 
 //////////////////////////////////////////////////////////////////////////////
 
+extern "C"
+HRESULT
+CALLBACK
+selectVersion(
+    PDEBUG_CLIENT client,
+    PCSTR args
+)
+{
+    Options  opts(args);
+
+    int  majorVersion = opts.pyMajorVersion;
+    int  minorVersion = opts.pyMinorVersion;
+
+    getPythonVersion(majorVersion, minorVersion);
+
+    if ( opts.pyMajorVersion == majorVersion && opts.pyMinorVersion == minorVersion )
+    {
+        defaultMajorVersion = majorVersion;
+        defaultMinorVersion = minorVersion;
+    }
+
+    return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
 static const char  printUsageMsg[] =
     "\n"
     "usage:\n"
@@ -209,6 +239,9 @@ static const char  printUsageMsg[] =
     "!info\n"
     "\tlist installed python interpreters\n"
     "\n"
+    "!select version\n"
+    "\tchange default version of a python interpreter\n"
+    "\n"
     "!py [version] [options] [file]\n"
     "\trun python script or REPL\n"
     "\n"
@@ -270,6 +303,8 @@ help(
 
 static const std::regex  shebangRe("^#!\\s*python([2,3])(?:\\.(\\d))?$");
 
+static volatile long recursiveGuard = 0L;
+
 extern "C"
 HRESULT
 CALLBACK
@@ -278,12 +313,16 @@ py(
     PCSTR args
 )
 {
+
     ULONG   oldMask;
     client->GetOutputMask(&oldMask);
-    client->SetOutputMask(DEBUG_OUTPUT_NORMAL | DEBUG_OUTPUT_ERROR);
+    client->SetOutputMask(DEBUG_OUTPUT_NORMAL|DEBUG_OUTPUT_ERROR|DEBUG_OUTPUT_WARNING|DEBUG_OUTPUT_DEBUGGEE );
 
     try {
 
+        if ( 1 < ++recursiveGuard  )
+            throw std::exception( "can not run !py command recursive\n");
+
         Options  opts(args);
 
         if (opts.showHelp)
@@ -296,17 +335,21 @@ py(
         {
             std::ifstream  scriptFile(opts.args[0]);
 
-            std::string  firstline;
-            std::getline(scriptFile, firstline);
-
-            std::smatch  mres;
-            if (std::regex_match(firstline, mres, shebangRe))
+            if ( scriptFile.is_open() )
             {
-                majorVersion = atol(std::string(mres[1].first, mres[1].second).c_str());
 
-                if (mres[2].matched)
+                std::string  firstline;
+                std::getline(scriptFile, firstline);
+
+                std::smatch  mres;
+                if (std::regex_match(firstline, mres, shebangRe))
                 {
-                    minorVersion = atol(std::string(mres[2].first, mres[2].second).c_str());
+                    majorVersion = atol(std::string(mres[1].first, mres[1].second).c_str());
+
+                    if (mres[2].matched)
+                    {
+                        minorVersion = atol(std::string(mres[2].first, mres[2].second).c_str());
+                    }
                 }
             }
         }
@@ -376,7 +419,7 @@ py(
 
                 PySys_SetArgv((int)opts.args.size(), &pythonArgs[0]);
 
-                PyObjectRef  pyfile = PyFile_FromString(pythonArgs[0], "r");
+                PyObjectRef  pyfile = PyFile_FromString(const_cast<char*>(scriptFileName.c_str()), "r");
                 if (!pyfile)
                     throw std::invalid_argument("script not found\n");
 
@@ -396,7 +439,7 @@ py(
         CComQIPtr<IDebugControl>  control = client;
 
         control->ControlledOutput(
-            DEBUG_OUTCTL_THIS_CLIENT,
+            DEBUG_OUTCTL_ALL_CLIENTS,
             DEBUG_OUTPUT_ERROR,
             e.what()
             );
@@ -404,6 +447,8 @@ py(
 
     client->SetOutputMask(oldMask);
 
+    --recursiveGuard;
+
     return S_OK;
 }
 
@@ -420,6 +465,9 @@ pip(
 
     try {
 
+        if ( 1 < ++recursiveGuard  )
+            throw std::exception( "can not run !pip command recursive\n");
+
         Options  opts(args);
 
         int  majorVersion = opts.pyMajorVersion;
@@ -461,12 +509,14 @@ pip(
         CComQIPtr<IDebugControl>  control = client;
 
         control->ControlledOutput(
-            DEBUG_OUTCTL_THIS_CLIENT,
+            DEBUG_OUTCTL_ALL_CLIENTS,
             DEBUG_OUTPUT_ERROR,
             e.what()
             );
     }
 
+    --recursiveGuard;
+
     return S_OK;
 }
 
@@ -634,6 +684,8 @@ void getPythonVersion(int&  majorVersion, int& minorVersion)
 
 ///////////////////////////////////////////////////////////////////////////////
 
+
+
 void getDefaultPythonVersion(int& majorVersion, int& minorVersion)
 {
     std::list<InterpreterDesc>   interpreterList = getInstalledInterpreter();
@@ -644,31 +696,20 @@ void getDefaultPythonVersion(int& majorVersion, int& minorVersion)
     
     for (auto interpret : interpreterList)
     {
-        if (2 == interpret.majorVersion && 7 == interpret.minorVersion)
+        if (defaultMajorVersion == interpret.majorVersion && defaultMinorVersion == interpret.minorVersion)
         {
-            majorVersion = 2;
-            minorVersion = 7;
+            majorVersion = defaultMajorVersion;
+            minorVersion = defaultMinorVersion;
             return;
         }
     }
 
     for (auto interpret : interpreterList)
     {
-        if (3 == interpret.majorVersion && 5 == interpret.minorVersion)
-        {
-            majorVersion = 3;
-            minorVersion = 5;
-            return;
-        }
-    }
-
-    for (auto interpret : interpreterList)
-    {
-        if (2 == interpret.majorVersion &&
-            minorVersion <= interpret.minorVersion )
+        if (2 == interpret.majorVersion &&  minorVersion <= interpret.minorVersion )
         {
             found = true;
-            majorVersion = 2;
+            majorVersion = interpret.majorVersion;
             minorVersion = interpret.minorVersion;
         }
     }
@@ -678,11 +719,10 @@ void getDefaultPythonVersion(int& majorVersion, int& minorVersion)
 
     for (auto interpret : interpreterList)
     {
-        if (3 == interpret.majorVersion &&
-            minorVersion <= interpret.minorVersion )
+        if (3 == interpret.majorVersion && minorVersion <= interpret.minorVersion )
         {
             found = true;
-            majorVersion = 3;
+            majorVersion = interpret.majorVersion;
             minorVersion = interpret.minorVersion;
         }
     }