Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fix Py_Main/PySys_SetArgvEx(...) UCS4/PY3 no mem
Based on @dmitriyse work on:
dmitriyse@8a70f09
  • Loading branch information
dmitriyse authored and vmuriart committed Feb 25, 2017
commit 8ff338a0783bbe0f26a2196cea736849ea7c146c
5 changes: 0 additions & 5 deletions src/embed_tests/pyinitialize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")))
Expand Down
69 changes: 67 additions & 2 deletions src/runtime/runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)]
Expand Down