X Tutup
Skip to content

Commit 9512475

Browse files
dmitriysevmuriart
authored andcommitted
Fix Py_Main/PySys_SetArgvEx(...) UCS4/PY3 no mem
Based on @dmitriyse work on: dmitriyse@8a70f09
1 parent 30be9c9 commit 9512475

File tree

2 files changed

+67
-7
lines changed

2 files changed

+67
-7
lines changed

src/embed_tests/pyinitialize.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,6 @@ public static void LoadDefaultArgs()
3333
[Test]
3434
public static void LoadSpecificArgs()
3535
{
36-
if (Environment.GetEnvironmentVariable("TRAVIS") == "true" &&
37-
Environment.GetEnvironmentVariable("TRAVIS_PYTHON_VERSION") != "2.7")
38-
{
39-
Assert.Ignore("FIXME: Fails on Travis/PY3+: Fatal Python error: no mem for sys.argv");
40-
}
4136
var args = new[] { "test1", "test2" };
4237
using (new PythonEngine(args))
4338
using (var argv = new PyList(Runtime.Runtime.PySys_GetObject("argv")))

src/runtime/runtime.cs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,41 @@ internal unsafe static extern IntPtr
667667
public unsafe static extern int
668668
Py_Main(
669669
int argc,
670-
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] argv
670+
[MarshalAs(UnmanagedType.SysUInt)] IntPtr lplpargv
671671
);
672+
673+
public static int Py_Main(int argc, string[] argv)
674+
{
675+
// Totally ignoring argc.
676+
argc = argv.Length;
677+
678+
var allStringsLength = 0;
679+
foreach (string x in argv)
680+
{
681+
allStringsLength += x.Length + 1;
682+
}
683+
int requiredSize = IntPtr.Size * argc + allStringsLength * UCS;
684+
IntPtr mem = Marshal.AllocHGlobal(requiredSize);
685+
try
686+
{
687+
// Preparing array of pointers to UTF32 strings.
688+
IntPtr curStrPtr = mem + argc * IntPtr.Size;
689+
for (var i = 0; i < argv.Length; i++)
690+
{
691+
// Unicode or UTF8 work
692+
Encoding enc = UCS == 2 ? Encoding.Unicode : Encoding.UTF32;
693+
byte[] zstr = enc.GetBytes(argv[i] + "\0");
694+
Marshal.Copy(zstr, 0, curStrPtr, zstr.Length);
695+
Marshal.WriteIntPtr(mem + IntPtr.Size * i, curStrPtr);
696+
curStrPtr += zstr.Length;
697+
}
698+
return Py_Main(argc, mem);
699+
}
700+
finally
701+
{
702+
Marshal.FreeHGlobal(mem);
703+
}
704+
}
672705
#elif PYTHON2
673706
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
674707
ExactSpelling = true, CharSet = CharSet.Ansi)]
@@ -2084,9 +2117,41 @@ internal unsafe static extern IntPtr
20842117
internal unsafe static extern void
20852118
PySys_SetArgvEx(
20862119
int argc,
2087-
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] argv,
2120+
[MarshalAs(UnmanagedType.SysUInt)] IntPtr lplpargv,
20882121
int updatepath
20892122
);
2123+
2124+
internal static void PySys_SetArgvEx(int argc, string[] argv, int updatepath)
2125+
{
2126+
// Totally ignoring argc.
2127+
argc = argv.Length;
2128+
2129+
var allStringsLength = 0;
2130+
foreach (string x in argv)
2131+
{
2132+
allStringsLength += x.Length + 1;
2133+
}
2134+
int requiredSize = IntPtr.Size * argc + allStringsLength * UCS;
2135+
IntPtr mem = Marshal.AllocHGlobal(requiredSize);
2136+
try
2137+
{
2138+
// Preparing array of pointers to UTF32 strings.
2139+
IntPtr curStrPtr = mem + argc * IntPtr.Size;
2140+
for (var i = 0; i < argv.Length; i++)
2141+
{
2142+
Encoding enc = UCS == 2 ? Encoding.Unicode : Encoding.UTF32;
2143+
byte[] zstr = enc.GetBytes(argv[i] + "\0");
2144+
Marshal.Copy(zstr, 0, curStrPtr, zstr.Length);
2145+
Marshal.WriteIntPtr(mem + IntPtr.Size * i, curStrPtr);
2146+
curStrPtr += zstr.Length;
2147+
}
2148+
PySys_SetArgvEx(argc, mem, updatepath);
2149+
}
2150+
finally
2151+
{
2152+
Marshal.FreeHGlobal(mem);
2153+
}
2154+
}
20902155
#elif PYTHON2
20912156
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
20922157
ExactSpelling = true, CharSet = CharSet.Ansi)]

0 commit comments

Comments
 (0)
X Tutup