From 8ff338a0783bbe0f26a2196cea736849ea7c146c Mon Sep 17 00:00:00 2001 From: dse Date: Tue, 21 Feb 2017 22:24:49 -0700 Subject: [PATCH 1/2] Fix Py_Main/PySys_SetArgvEx(...) UCS4/PY3 no mem Based on @dmitriyse work on: https://github.com/dmitriyse/pythonnet/commit/8a70f09cb8faa9461d13480fb9ee2ee60b5b9acc --- src/embed_tests/pyinitialize.cs | 5 --- src/runtime/runtime.cs | 69 ++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/embed_tests/pyinitialize.cs b/src/embed_tests/pyinitialize.cs index 2bfbd1a41..2f9aae2c7 100644 --- a/src/embed_tests/pyinitialize.cs +++ b/src/embed_tests/pyinitialize.cs @@ -33,11 +33,6 @@ public static void LoadDefaultArgs() [Test] public static void LoadSpecificArgs() { - if (Environment.GetEnvironmentVariable("TRAVIS") == "true" && - Environment.GetEnvironmentVariable("TRAVIS_PYTHON_VERSION") != "2.7") - { - Assert.Ignore("FIXME: Fails on Travis/PY3+: Fatal Python error: no mem for sys.argv"); - } var args = new[] { "test1", "test2" }; using (new PythonEngine(args)) using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv"))) diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index d0960222c..3f30f86ce 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -667,8 +667,41 @@ internal unsafe static extern IntPtr public unsafe static extern int Py_Main( int argc, - [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] argv + [MarshalAs(UnmanagedType.SysUInt)] IntPtr lplpargv ); + + public static int Py_Main(int argc, string[] argv) + { + // Totally ignoring argc. + argc = argv.Length; + + var allStringsLength = 0; + foreach (string x in argv) + { + allStringsLength += x.Length + 1; + } + int requiredSize = IntPtr.Size * argc + allStringsLength * UCS; + IntPtr mem = Marshal.AllocHGlobal(requiredSize); + try + { + // Preparing array of pointers to UTF32 strings. + IntPtr curStrPtr = mem + argc * IntPtr.Size; + for (var i = 0; i < argv.Length; i++) + { + // Unicode or UTF8 work + Encoding enc = UCS == 2 ? Encoding.Unicode : Encoding.UTF32; + byte[] zstr = enc.GetBytes(argv[i] + "\0"); + Marshal.Copy(zstr, 0, curStrPtr, zstr.Length); + Marshal.WriteIntPtr(mem + IntPtr.Size * i, curStrPtr); + curStrPtr += zstr.Length; + } + return Py_Main(argc, mem); + } + finally + { + Marshal.FreeHGlobal(mem); + } + } #elif PYTHON2 [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, CharSet = CharSet.Ansi)] @@ -2087,9 +2120,41 @@ internal unsafe static extern IntPtr internal unsafe static extern void PySys_SetArgvEx( int argc, - [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] argv, + [MarshalAs(UnmanagedType.SysUInt)] IntPtr lplpargv, int updatepath ); + + internal static void PySys_SetArgvEx(int argc, string[] argv, int updatepath) + { + // Totally ignoring argc. + argc = argv.Length; + + var allStringsLength = 0; + foreach (string x in argv) + { + allStringsLength += x.Length + 1; + } + int requiredSize = IntPtr.Size * argc + allStringsLength * UCS; + IntPtr mem = Marshal.AllocHGlobal(requiredSize); + try + { + // Preparing array of pointers to UTF32 strings. + IntPtr curStrPtr = mem + argc * IntPtr.Size; + for (var i = 0; i < argv.Length; i++) + { + Encoding enc = UCS == 2 ? Encoding.Unicode : Encoding.UTF32; + byte[] zstr = enc.GetBytes(argv[i] + "\0"); + Marshal.Copy(zstr, 0, curStrPtr, zstr.Length); + Marshal.WriteIntPtr(mem + IntPtr.Size * i, curStrPtr); + curStrPtr += zstr.Length; + } + PySys_SetArgvEx(argc, mem, updatepath); + } + finally + { + Marshal.FreeHGlobal(mem); + } + } #elif PYTHON2 [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, CharSet = CharSet.Ansi)] From 9b7089209f7466a8aebe23c981186bc5a69867a4 Mon Sep 17 00:00:00 2001 From: Victor Uriarte Date: Fri, 24 Feb 2017 17:03:57 -0700 Subject: [PATCH 2/2] Update CHANGELOG, remove extra MarshalAs --- CHANGELOG.md | 1 + src/runtime/runtime.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d2d05bc4..6b9e3d8fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Fixed wrong version number in `conda.recipe` (#398) - Fixed fixture location for Python tests and `Embedded_Tests` - Fixed `PythonException` crash during Shutdown (#400) +- Fixed `Py_Main` & `PySys_SetArgvEx` no mem error on `UCS4/PY3` (#399) ### Removed diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 3f30f86ce..6398d3345 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -667,7 +667,7 @@ internal unsafe static extern IntPtr public unsafe static extern int Py_Main( int argc, - [MarshalAs(UnmanagedType.SysUInt)] IntPtr lplpargv + IntPtr lplpargv ); public static int Py_Main(int argc, string[] argv) @@ -2120,7 +2120,7 @@ internal unsafe static extern IntPtr internal unsafe static extern void PySys_SetArgvEx( int argc, - [MarshalAs(UnmanagedType.SysUInt)] IntPtr lplpargv, + IntPtr lplpargv, int updatepath );