Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
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
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,
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