Skip to content

Commit 7a3107c

Browse files
authored
Fix conversions in _SimpleCData (#1912)
* Prefer `__index__` over `__int__` in ModuleOps * Fix conversions in `_SimpleCData` * Test for `Half` only on .NET
1 parent dd66f45 commit 7a3107c

File tree

6 files changed

+286
-111
lines changed

6 files changed

+286
-111
lines changed

src/core/IronPython.Modules/ModuleOps.cs

Lines changed: 45 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
namespace IronPython.Modules {
2323
/// <summary>
24-
/// Provides helper functions which need to be called from generated code to implement various
24+
/// Provides helper functions which need to be called from generated code to implement various
2525
/// portions of modules.
2626
/// </summary>
2727
public static partial class ModuleOps {
@@ -110,7 +110,7 @@ public static CTypes.CData CheckSimpleCDataType(object o, object type) {
110110
if (res == null && PythonOps.TryGetBoundAttr(o, "_as_parameter_", out object asParam)) {
111111
res = asParam as CTypes._CFuncPtr;
112112
}
113-
113+
114114
if (res == null || res.NativeType != type) {
115115
throw ArgumentError(type, ((PythonType)type).Name, o);
116116
}
@@ -298,9 +298,6 @@ public static IntPtr GetPointer(object value) {
298298
}
299299

300300
if (value is int iVal) {
301-
if(iVal > int.MaxValue) {
302-
iVal = -1;
303-
}
304301
return new IntPtr(iVal);
305302
}
306303

@@ -357,13 +354,8 @@ public static IntPtr GetObject(object value) {
357354
}
358355

359356
public static long GetSignedLongLong(object value, object type) {
360-
int? res = Converter.ImplicitConvertToInt32(value);
361-
if (res != null) {
362-
return res.Value;
363-
}
364-
365-
if (value is BigInteger) {
366-
return (long)(BigInteger)value;
357+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
358+
return unchecked((long)(ulong)(bi & ulong.MaxValue));
367359
}
368360

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

376-
public static long GetUnsignedLongLong(object value, object type) {
377-
int? res = Converter.ImplicitConvertToInt32(value);
378-
if (res != null && res.Value >= 0) {
379-
return res.Value;
380-
}
381-
382-
if (value is BigInteger) {
383-
return (long)(ulong)(BigInteger)value;
368+
public static ulong GetUnsignedLongLong(object value, object type) {
369+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
370+
return (ulong)(bi & ulong.MaxValue);
384371
}
385372

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

465452
public static int GetSignedLong(object value, object type) {
466-
if (value is int) {
467-
return (int)value;
468-
}
469-
470-
int? res = Converter.ImplicitConvertToInt32(value);
471-
if (res != null) {
472-
return res.Value;
473-
}
474-
475-
if (value is BigInteger && ((BigInteger)value).AsUInt32(out uint unsigned)) {
476-
return (int)unsigned;
453+
if (TryToIntStrict(value, out BigInteger bi)) {
454+
return unchecked((int)(uint)(bi & uint.MaxValue));
477455
}
478456

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

486-
public static int GetUnsignedLong(object value, object type) {
487-
int? res = Converter.ImplicitConvertToInt32(value);
488-
if (res != null) {
489-
return res.Value;
490-
}
491-
492-
if (value is BigInteger) {
493-
if (((BigInteger)value).AsUInt32(out uint ures)) {
494-
return (int)ures;
495-
}
464+
public static uint GetUnsignedLong(object value, object type) {
465+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
466+
return (uint)(bi & uint.MaxValue);
496467
}
497468

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

505-
public static int GetUnsignedInt(object value, object type) {
506-
int? res = Converter.ImplicitConvertToInt32(value);
507-
if (res != null && res.Value >= 0) {
508-
return res.Value;
476+
public static uint GetUnsignedInt(object value, object type) {
477+
if (TryToIntStrict(value, out BigInteger bi)) {
478+
return (uint)(bi & uint.MaxValue);
509479
}
510480

511481
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
512-
return GetUnsignedInt(type, asParam);
482+
return GetUnsignedInt(asParam, type);
513483
}
514484

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

518488
public static int GetSignedInt(object value, object type) {
519-
int? res = Converter.ImplicitConvertToInt32(value);
520-
if (res != null) {
521-
return res.Value;
489+
if (TryToIntStrict(value, out BigInteger bi)) {
490+
return unchecked((int)(bi & uint.MaxValue));
522491
}
492+
523493
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
524494
return GetSignedInt(asParam, type);
525495
}
@@ -528,13 +498,10 @@ public static int GetSignedInt(object value, object type) {
528498
}
529499

530500
public static ushort GetUnsignedShort(object value, object type) {
531-
int? res = Converter.ImplicitConvertToInt32(value);
532-
if (res != null) {
533-
int iVal = res.Value;
534-
if (iVal >= ushort.MinValue && iVal <= ushort.MaxValue) {
535-
return (ushort)iVal;
536-
}
501+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
502+
return (ushort)(bi & ushort.MaxValue);
537503
}
504+
538505
if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) {
539506
return GetUnsignedShort(asParam, type);
540507
}
@@ -543,12 +510,8 @@ public static ushort GetUnsignedShort(object value, object type) {
543510
}
544511

545512
public static short GetSignedShort(object value, object type) {
546-
int? res = Converter.ImplicitConvertToInt32(value);
547-
if (res != null) {
548-
int iVal = res.Value;
549-
return (short)iVal;
550-
} else if (value is BigInteger bigInt) {
551-
return (short)(int)(bigInt & 0xffff);
513+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
514+
return unchecked((short)(ushort)(bi & ushort.MaxValue));
552515
}
553516

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

565528
public static byte GetUnsignedByte(object value, object type) {
566-
int? res = Converter.ImplicitConvertToInt32(value);
567-
if (res != null) {
568-
return (byte)res.Value;
529+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
530+
return (byte)(bi & byte.MaxValue);
569531
}
570532

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

578540
public static sbyte GetSignedByte(object value, object type) {
579-
int? res = Converter.ImplicitConvertToInt32(value);
580-
if (res != null) {
581-
int iVal = res.Value;
582-
if (iVal >= sbyte.MinValue && iVal <= sbyte.MaxValue) {
583-
return (sbyte)iVal;
584-
}
541+
if (PythonOps.TryToInt(value, out BigInteger bi)) {
542+
return unchecked((sbyte)(byte)(bi & byte.MaxValue));
585543
}
586544

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

642-
throw PythonOps.TypeError("unicode string expected instead of {0} instance", PythonOps.GetPythonTypeName(value));
600+
throw PythonOps.TypeErrorForBadInstance("unicode string expected instead of {0} instance", value);
643601
}
644602

645603
public static object IntPtrToObject(IntPtr address) {
@@ -650,6 +608,22 @@ public static object IntPtrToObject(IntPtr address) {
650608
return res;
651609
}
652610

611+
internal static bool TryToIntStrict(object value, out BigInteger bi) {
612+
// When IronPython upgrades to Python 3.10, this method becomes obsolete
613+
// and can be replaced with PythonOps.TryToIndex(value, out bi)
614+
if (IsFloatingPoint(value)) {
615+
throw PythonOps.TypeErrorForBadInstance("int expected instead of {0}", value);
616+
}
617+
618+
return PythonOps.TryToInt(value, out bi);
619+
}
620+
621+
internal static bool IsFloatingPoint(object value)
622+
=> value is double or float
623+
#if NETCOREAPP
624+
or Half
625+
#endif
626+
;
653627
}
654628
}
655629
#endif

src/core/IronPython.Modules/_ctypes/SimpleCData.cs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Runtime.CompilerServices;
1111

1212
using Microsoft.Scripting.Runtime;
13+
using Microsoft.Scripting.Utils;
1314

1415
using IronPython.Runtime;
1516
using IronPython.Runtime.Operations;
@@ -41,12 +42,8 @@ public void __init__(CodeContext/*!*/ context, object value) {
4142
{
4243
if (value is IList<byte> t && t.Count == 1) {
4344
value = Bytes.FromByte(t[0]);
44-
} else if (value is int i) {
45-
try {
46-
value = Bytes.FromByte(checked((byte)i));
47-
} catch (OverflowException) {
48-
throw PythonOps.TypeError("one character bytes, bytearray or integer expected");
49-
}
45+
} else if (Converter.TryConvertToByte(value, out byte b) && !ModuleOps.IsFloatingPoint(value)) {
46+
value = Bytes.FromByte(b);
5047
} else {
5148
throw PythonOps.TypeError("one character bytes, bytearray or integer expected");
5249
}
@@ -60,25 +57,20 @@ public void __init__(CodeContext/*!*/ context, object value) {
6057
}
6158
}
6259
break;
60+
case SimpleTypeKind.SignedByte:
6361
case SimpleTypeKind.SignedInt:
6462
case SimpleTypeKind.SignedLong:
6563
case SimpleTypeKind.SignedLongLong:
6664
case SimpleTypeKind.SignedShort:
65+
case SimpleTypeKind.UnsignedByte:
6766
case SimpleTypeKind.UnsignedInt:
6867
case SimpleTypeKind.UnsignedLong:
6968
case SimpleTypeKind.UnsignedLongLong:
7069
case SimpleTypeKind.UnsignedShort: {
71-
object __int__ = null;
72-
if (value is float || value is double) {
73-
throw PythonOps.TypeError("int expected instead of float");
74-
}
75-
76-
if (!(value is int || value is BigInteger || PythonOps.TryGetBoundAttr(value, "__int__", out __int__))) {
77-
throw PythonOps.TypeError("an integer is required");
78-
}
79-
80-
if (__int__ != null) {
81-
value = PythonOps.CallWithContext(context, __int__);
70+
if (ModuleOps.TryToIntStrict(value, out BigInteger bi)) {
71+
value = bi;
72+
} else {
73+
throw PythonOps.TypeErrorForBadInstance("an integer is required (got type {0})", value);
8274
}
8375
}
8476
break;
@@ -92,7 +84,7 @@ public void __init__(CodeContext/*!*/ context, object value) {
9284

9385
if (value is BigInteger x) {
9486
if (x > (BigInteger)double.MaxValue) {
95-
throw PythonOps.OverflowError("long int too large to convert to float");
87+
throw PythonOps.OverflowError("Python int too large to convert to float");
9688
}
9789
}
9890

0 commit comments

Comments
 (0)