Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8ff338a

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

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)]
@@ -2087,9 +2120,41 @@ internal unsafe static extern IntPtr
20872120
internal unsafe static extern void
20882121
PySys_SetArgvEx(
20892122
int argc,
2090-
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] argv,
2123+
[MarshalAs(UnmanagedType.SysUInt)] IntPtr lplpargv,
20912124
int updatepath
20922125
);
2126+
2127+
internal static void PySys_SetArgvEx(int argc, string[] argv, int updatepath)
2128+
{
2129+
// Totally ignoring argc.
2130+
argc = argv.Length;
2131+
2132+
var allStringsLength = 0;
2133+
foreach (string x in argv)
2134+
{
2135+
allStringsLength += x.Length + 1;
2136+
}
2137+
int requiredSize = IntPtr.Size * argc + allStringsLength * UCS;
2138+
IntPtr mem = Marshal.AllocHGlobal(requiredSize);
2139+
try
2140+
{
2141+
// Preparing array of pointers to UTF32 strings.
2142+
IntPtr curStrPtr = mem + argc * IntPtr.Size;
2143+
for (var i = 0; i < argv.Length; i++)
2144+
{
2145+
Encoding enc = UCS == 2 ? Encoding.Unicode : Encoding.UTF32;
2146+
byte[] zstr = enc.GetBytes(argv[i] + "\0");
2147+
Marshal.Copy(zstr, 0, curStrPtr, zstr.Length);
2148+
Marshal.WriteIntPtr(mem + IntPtr.Size * i, curStrPtr);
2149+
curStrPtr += zstr.Length;
2150+
}
2151+
PySys_SetArgvEx(argc, mem, updatepath);
2152+
}
2153+
finally
2154+
{
2155+
Marshal.FreeHGlobal(mem);
2156+
}
2157+
}
20932158
#elif PYTHON2
20942159
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
20952160
ExactSpelling = true, CharSet = CharSet.Ansi)]

0 commit comments

Comments
 (0)