Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix conversions in _SimpleCData #1912

Merged
merged 4 commits into from
Feb 17, 2025
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
116 changes: 45 additions & 71 deletions src/core/IronPython.Modules/ModuleOps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

namespace IronPython.Modules {
/// <summary>
/// Provides helper functions which need to be called from generated code to implement various
/// Provides helper functions which need to be called from generated code to implement various
/// portions of modules.
/// </summary>
public static partial class ModuleOps {
Expand Down Expand Up @@ -110,7 +110,7 @@ public static CTypes.CData CheckSimpleCDataType(object o, object type) {
if (res == null && PythonOps.TryGetBoundAttr(o, "_as_parameter_", out object asParam)) {
res = asParam as CTypes._CFuncPtr;
}

if (res == null || res.NativeType != type) {
throw ArgumentError(type, ((PythonType)type).Name, o);
}
Expand Down Expand Up @@ -298,9 +298,6 @@ public static IntPtr GetPointer(object value) {
}

if (value is int iVal) {
if(iVal > int.MaxValue) {
iVal = -1;
}
return new IntPtr(iVal);
}

Expand Down Expand Up @@ -357,13 +354,8 @@ public static IntPtr GetObject(object value) {
}

public static long GetSignedLongLong(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
return res.Value;
}

if (value is BigInteger) {
return (long)(BigInteger)value;
if (PythonOps.TryToInt(value, out BigInteger bi)) {
return unchecked((long)(ulong)(bi & ulong.MaxValue));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this will no longer throw if the value is too big for a long. Not too familiar with these methods, but just confirming that this is the intended behaviour?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess test_conversions_overflow answers my question...

}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
Expand All @@ -373,14 +365,9 @@ public static long GetSignedLongLong(object value, object type) {
throw PythonOps.TypeErrorForTypeMismatch("signed long long ", value);
}

public static long GetUnsignedLongLong(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null && res.Value >= 0) {
return res.Value;
}

if (value is BigInteger) {
return (long)(ulong)(BigInteger)value;
public static ulong GetUnsignedLongLong(object value, object type) {
if (PythonOps.TryToInt(value, out BigInteger bi)) {
return (ulong)(bi & ulong.MaxValue);
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
Expand Down Expand Up @@ -463,17 +450,8 @@ public static int GetSingleBits(object value) {
}

public static int GetSignedLong(object value, object type) {
if (value is int) {
return (int)value;
}

int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
return res.Value;
}

if (value is BigInteger && ((BigInteger)value).AsUInt32(out uint unsigned)) {
return (int)unsigned;
if (TryToIntStrict(value, out BigInteger bi)) {
return unchecked((int)(uint)(bi & uint.MaxValue));
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
Expand All @@ -483,16 +461,9 @@ public static int GetSignedLong(object value, object type) {
throw PythonOps.TypeErrorForTypeMismatch("signed long", value);
}

public static int GetUnsignedLong(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
return res.Value;
}

if (value is BigInteger) {
if (((BigInteger)value).AsUInt32(out uint ures)) {
return (int)ures;
}
public static uint GetUnsignedLong(object value, object type) {
if (PythonOps.TryToInt(value, out BigInteger bi)) {
return (uint)(bi & uint.MaxValue);
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
Expand All @@ -502,24 +473,23 @@ public static int GetUnsignedLong(object value, object type) {
throw PythonOps.TypeErrorForTypeMismatch("unsigned long", value);
}

public static int GetUnsignedInt(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null && res.Value >= 0) {
return res.Value;
public static uint GetUnsignedInt(object value, object type) {
if (TryToIntStrict(value, out BigInteger bi)) {
return (uint)(bi & uint.MaxValue);
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
return GetUnsignedInt(type, asParam);
return GetUnsignedInt(asParam, type);
}

throw PythonOps.TypeErrorForTypeMismatch("unsigned int", value);
}

public static int GetSignedInt(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
return res.Value;
if (TryToIntStrict(value, out BigInteger bi)) {
return unchecked((int)(bi & uint.MaxValue));
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
return GetSignedInt(asParam, type);
}
Expand All @@ -528,13 +498,10 @@ public static int GetSignedInt(object value, object type) {
}

public static ushort GetUnsignedShort(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
int iVal = res.Value;
if (iVal >= ushort.MinValue && iVal <= ushort.MaxValue) {
return (ushort)iVal;
}
if (PythonOps.TryToInt(value, out BigInteger bi)) {
return (ushort)(bi & ushort.MaxValue);
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
return GetUnsignedShort(asParam, type);
}
Expand All @@ -543,12 +510,8 @@ public static ushort GetUnsignedShort(object value, object type) {
}

public static short GetSignedShort(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
int iVal = res.Value;
return (short)iVal;
} else if (value is BigInteger bigInt) {
return (short)(int)(bigInt & 0xffff);
if (PythonOps.TryToInt(value, out BigInteger bi)) {
return unchecked((short)(ushort)(bi & ushort.MaxValue));
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
Expand All @@ -563,9 +526,8 @@ public static int GetVariantBool(object value, object type) {
}

public static byte GetUnsignedByte(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
return (byte)res.Value;
if (PythonOps.TryToInt(value, out BigInteger bi)) {
return (byte)(bi & byte.MaxValue);
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
Expand All @@ -576,12 +538,8 @@ public static byte GetUnsignedByte(object value, object type) {
}

public static sbyte GetSignedByte(object value, object type) {
int? res = Converter.ImplicitConvertToInt32(value);
if (res != null) {
int iVal = res.Value;
if (iVal >= sbyte.MinValue && iVal <= sbyte.MaxValue) {
return (sbyte)iVal;
}
if (PythonOps.TryToInt(value, out BigInteger bi)) {
return unchecked((sbyte)(byte)(bi & byte.MaxValue));
}

if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
Expand Down Expand Up @@ -639,7 +597,7 @@ public static char GetWChar(object value, object type) {
return GetWChar(asParam, type);
}

throw PythonOps.TypeError("unicode string expected instead of {0} instance", PythonOps.GetPythonTypeName(value));
throw PythonOps.TypeErrorForBadInstance("unicode string expected instead of {0} instance", value);
}

public static object IntPtrToObject(IntPtr address) {
Expand All @@ -650,6 +608,22 @@ public static object IntPtrToObject(IntPtr address) {
return res;
}

internal static bool TryToIntStrict(object value, out BigInteger bi) {
// When IronPython upgrades to Python 3.10, this method becomes obsolete
// and can be replaced with PythonOps.TryToIndex(value, out bi)
if (IsFloatingPoint(value)) {
throw PythonOps.TypeErrorForBadInstance("int expected instead of {0}", value);
}

return PythonOps.TryToInt(value, out bi);
}

internal static bool IsFloatingPoint(object value)
=> value is double or float
#if NETCOREAPP
or Half
#endif
;
}
}
#endif
28 changes: 10 additions & 18 deletions src/core/IronPython.Modules/_ctypes/SimpleCData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Runtime.CompilerServices;

using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Utils;

using IronPython.Runtime;
using IronPython.Runtime.Operations;
Expand Down Expand Up @@ -41,12 +42,8 @@ public void __init__(CodeContext/*!*/ context, object value) {
{
if (value is IList<byte> t && t.Count == 1) {
value = Bytes.FromByte(t[0]);
} else if (value is int i) {
try {
value = Bytes.FromByte(checked((byte)i));
} catch (OverflowException) {
throw PythonOps.TypeError("one character bytes, bytearray or integer expected");
}
} else if (Converter.TryConvertToByte(value, out byte b) && !ModuleOps.IsFloatingPoint(value)) {
value = Bytes.FromByte(b);
} else {
throw PythonOps.TypeError("one character bytes, bytearray or integer expected");
}
Expand All @@ -60,25 +57,20 @@ public void __init__(CodeContext/*!*/ context, object value) {
}
}
break;
case SimpleTypeKind.SignedByte:
case SimpleTypeKind.SignedInt:
case SimpleTypeKind.SignedLong:
case SimpleTypeKind.SignedLongLong:
case SimpleTypeKind.SignedShort:
case SimpleTypeKind.UnsignedByte:
case SimpleTypeKind.UnsignedInt:
case SimpleTypeKind.UnsignedLong:
case SimpleTypeKind.UnsignedLongLong:
case SimpleTypeKind.UnsignedShort: {
object __int__ = null;
if (value is float || value is double) {
throw PythonOps.TypeError("int expected instead of float");
}

if (!(value is int || value is BigInteger || PythonOps.TryGetBoundAttr(value, "__int__", out __int__))) {
throw PythonOps.TypeError("an integer is required");
}

if (__int__ != null) {
value = PythonOps.CallWithContext(context, __int__);
if (ModuleOps.TryToIntStrict(value, out BigInteger bi)) {
value = bi;
} else {
throw PythonOps.TypeErrorForBadInstance("an integer is required (got type {0})", value);
}
}
break;
Expand All @@ -92,7 +84,7 @@ public void __init__(CodeContext/*!*/ context, object value) {

if (value is BigInteger x) {
if (x > (BigInteger)double.MaxValue) {
throw PythonOps.OverflowError("long int too large to convert to float");
throw PythonOps.OverflowError("Python int too large to convert to float");
}
}

Expand Down
Loading