From 2048616678e171f121935ccd48e7c71c377032be Mon Sep 17 00:00:00 2001
From: jmlidbetter <53430310+jmlidbetter@users.noreply.github.com>
Date: Tue, 24 Sep 2019 13:46:04 +0100
Subject: [PATCH 1/5] Detect python interpreter arch
---
src/runtime/runtime.cs | 45 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index 75f11492f..fd89798e6 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -155,6 +155,11 @@ public class Runtime
///
public static string MachineName { get; private set; }
+ ///
+ /// Gets the architecture the python interpreter is using as reported by python's struct.calcsize("P")
+ ///
+ public static MachineType PythonArchitecture { get; private set; }
+
internal static bool IsPython2 = pyversionnumber < 30;
internal static bool IsPython3 = pyversionnumber >= 30;
@@ -192,6 +197,9 @@ internal static void Initialize(bool initSigs = false)
IntPtr op;
IntPtr dict;
+
+ InitializePythonArch();
+
if (IsPython3)
{
op = PyImport_ImportModule("builtins");
@@ -371,6 +379,43 @@ private static void InitializePlatformData()
Machine = MType;
}
+ ///
+ /// Initializes the architecture used within the python interpreter
+ ///
+ /// For various reasons the python interpreter often has a different
+ /// architecture to that of the machine. For example on a 64 bit Windows
+ /// platform the CPython interpreter is compiled with 32 bit longs.
+ /// This method will allow pythonnet to determine at runtime how big
+ /// python's longs are.
+ ///
+ private static void InitializePythonArch()
+ {
+ IntPtr structModule = PyImport_ImportModule("struct");
+ IntPtr calcsizeMethod = PyObject_GetAttrString(structModule, "calcsize");
+ IntPtr methodArgs = PyTuple_New(1);
+ IntPtr pString = PyString_FromString("P");
+
+ if(PyTuple_SetItem(methodArgs, 0, pString) != 0)
+ {
+ PythonArchitecture = MachineType.Other;
+ return;
+ }
+
+ var result = PyLong_AsLong(PyObject_Call(calcsizeMethod, methodArgs, IntPtr.Zero));
+
+ switch(result){
+ case 4:
+ PythonArchitecture = MachineType.i386;
+ break;
+ case 8:
+ PythonArchitecture = MachineType.x86_64;
+ break;
+ default:
+ PythonArchitecture = MachineType.Other;
+ break;
+ }
+ }
+
internal static void Shutdown()
{
AssemblyManager.Shutdown();
From d8040fa7a9782620e6b252c9650419c56722eea1 Mon Sep 17 00:00:00 2001
From: jmlidbetter <53430310+jmlidbetter@users.noreply.github.com>
Date: Tue, 24 Sep 2019 14:34:39 +0100
Subject: [PATCH 2/5] Updates PyLong_FromUnsignedLong to be interpreter arch
aware
---
src/runtime/runtime.cs | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index fd89798e6..536f0e052 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -1081,8 +1081,24 @@ internal static bool PyLong_Check(IntPtr ob)
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyLong_FromLong(long value);
- [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
- internal static extern IntPtr PyLong_FromUnsignedLong(uint value);
+ [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyLong_FromUnsignedLong")]
+ internal static extern IntPtr PyLong_FromUnsignedLong32(uint value);
+
+ [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyLong_FromUnsignedLong")]
+ internal static extern IntPtr PyLong_FromUnsignedLong64(ulong value);
+
+ internal static IntPtr PyLong_FromUnsignedLong(object value)
+ {
+ if(PythonArchitecture == MachineType.i386)
+ return PyLong_FromUnsignedLong32(Convert.ToUInt32(value));
+ else if(PythonArchitecture == MachineType.x86_64)
+ return PyLong_FromUnsignedLong64(Convert.ToUInt64(value));
+ else
+ // Couldn't determine interpreter arch, try 64 bit
+ return PyLong_FromUnsignedLong64(Convert.ToUInt64(value));
+ }
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyLong_FromDouble(double value);
From c337688033f16dad6e12cafd7fa09e3a4759a395 Mon Sep 17 00:00:00 2001
From: jmlidbetter <53430310+jmlidbetter@users.noreply.github.com>
Date: Tue, 24 Sep 2019 15:23:39 +0100
Subject: [PATCH 3/5] Makes PyLong_AsUnsignedLong interpreter arch aware
---
src/runtime/converter.cs | 15 ++++++++++++++-
src/runtime/runtime.cs | 21 +++++++++++++++++++--
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs
index 5d8769a73..e7e047419 100644
--- a/src/runtime/converter.cs
+++ b/src/runtime/converter.cs
@@ -728,7 +728,20 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo
}
goto type_error;
}
- uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op);
+
+ uint ui;
+ try
+ {
+ ui = Convert.ToUInt32(Runtime.PyLong_AsUnsignedLong(op));
+ } catch (OverflowException)
+ {
+ // Probably wasn't an overflow in python but was in C# (e.g. if cpython
+ // longs are 64 bit then 0xFFFFFFFF + 1 will not overflow in
+ // PyLong_AsUnsignedLong)
+ Runtime.XDecref(op);
+ goto overflow;
+ }
+
if (Exceptions.ErrorOccurred())
{
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index 536f0e052..b45aff894 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -1115,8 +1115,25 @@ internal static IntPtr PyLong_FromUnsignedLong(object value)
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PyLong_AsLong(IntPtr value);
- [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
- internal static extern uint PyLong_AsUnsignedLong(IntPtr value);
+ [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyLong_AsUnsignedLong")]
+ internal static extern uint PyLong_AsUnsignedLong32(IntPtr value);
+
+ [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyLong_AsUnsignedLong")]
+ internal static extern ulong PyLong_AsUnsignedLong64(IntPtr value);
+
+ internal static object PyLong_AsUnsignedLong(IntPtr value)
+ {
+ if (PythonArchitecture == MachineType.i386)
+ return PyLong_AsUnsignedLong32(value);
+ else if (PythonArchitecture == MachineType.x86_64)
+ return PyLong_AsUnsignedLong64(value);
+ else
+ return PyLong_AsUnsignedLong64(value);
+ }
+
+
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern long PyLong_AsLongLong(IntPtr value);
From fb1e1adbd4427a58f792136326009e2705323fa2 Mon Sep 17 00:00:00 2001
From: jmlidbetter <53430310+jmlidbetter@users.noreply.github.com>
Date: Wed, 25 Sep 2019 14:21:06 +0100
Subject: [PATCH 4/5] Updates CHANGELOG.md
---
CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5cb0ea96c..b5b11cd77 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
- Fixed runtime that fails loading when using pythonnet in an environment
together with Nuitka
- Fixes bug where delegates get casts (dotnetcore)
+- Determine size of interpreter longs at runtime
## [2.4.0][]
From ac9294d6c30bf5c74947c61fcaadebe50fc7acb0 Mon Sep 17 00:00:00 2001
From: jmlidbetter <53430310+jmlidbetter@users.noreply.github.com>
Date: Tue, 1 Oct 2019 13:52:06 +0100
Subject: [PATCH 5/5] Gets size of C long from Is32Bit and IsWindows
---
src/runtime/runtime.cs | 58 +++---------------------------------------
1 file changed, 3 insertions(+), 55 deletions(-)
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index b45aff894..4985a57f5 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -155,11 +155,6 @@ public class Runtime
///
public static string MachineName { get; private set; }
- ///
- /// Gets the architecture the python interpreter is using as reported by python's struct.calcsize("P")
- ///
- public static MachineType PythonArchitecture { get; private set; }
-
internal static bool IsPython2 = pyversionnumber < 30;
internal static bool IsPython3 = pyversionnumber >= 30;
@@ -197,9 +192,6 @@ internal static void Initialize(bool initSigs = false)
IntPtr op;
IntPtr dict;
-
- InitializePythonArch();
-
if (IsPython3)
{
op = PyImport_ImportModule("builtins");
@@ -379,43 +371,6 @@ private static void InitializePlatformData()
Machine = MType;
}
- ///
- /// Initializes the architecture used within the python interpreter
- ///
- /// For various reasons the python interpreter often has a different
- /// architecture to that of the machine. For example on a 64 bit Windows
- /// platform the CPython interpreter is compiled with 32 bit longs.
- /// This method will allow pythonnet to determine at runtime how big
- /// python's longs are.
- ///
- private static void InitializePythonArch()
- {
- IntPtr structModule = PyImport_ImportModule("struct");
- IntPtr calcsizeMethod = PyObject_GetAttrString(structModule, "calcsize");
- IntPtr methodArgs = PyTuple_New(1);
- IntPtr pString = PyString_FromString("P");
-
- if(PyTuple_SetItem(methodArgs, 0, pString) != 0)
- {
- PythonArchitecture = MachineType.Other;
- return;
- }
-
- var result = PyLong_AsLong(PyObject_Call(calcsizeMethod, methodArgs, IntPtr.Zero));
-
- switch(result){
- case 4:
- PythonArchitecture = MachineType.i386;
- break;
- case 8:
- PythonArchitecture = MachineType.x86_64;
- break;
- default:
- PythonArchitecture = MachineType.Other;
- break;
- }
- }
-
internal static void Shutdown()
{
AssemblyManager.Shutdown();
@@ -1091,12 +1046,9 @@ internal static bool PyLong_Check(IntPtr ob)
internal static IntPtr PyLong_FromUnsignedLong(object value)
{
- if(PythonArchitecture == MachineType.i386)
+ if(Is32Bit || IsWindows)
return PyLong_FromUnsignedLong32(Convert.ToUInt32(value));
- else if(PythonArchitecture == MachineType.x86_64)
- return PyLong_FromUnsignedLong64(Convert.ToUInt64(value));
else
- // Couldn't determine interpreter arch, try 64 bit
return PyLong_FromUnsignedLong64(Convert.ToUInt64(value));
}
@@ -1125,16 +1077,12 @@ internal static IntPtr PyLong_FromUnsignedLong(object value)
internal static object PyLong_AsUnsignedLong(IntPtr value)
{
- if (PythonArchitecture == MachineType.i386)
+ if (Is32Bit || IsWindows)
return PyLong_AsUnsignedLong32(value);
- else if (PythonArchitecture == MachineType.x86_64)
- return PyLong_AsUnsignedLong64(value);
- else
+ else
return PyLong_AsUnsignedLong64(value);
}
-
-
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern long PyLong_AsLongLong(IntPtr value);