diff python/pydc/pydc.c @ 63:9b6cdffd30dd

- further fixes of inccorect overflow errors for int (and long on LLP64 systems) * prev commit had bugs * added overflow tests for also int, long, long long (for both, lp64 and llp64) - while at it, fixing a reference leak when not using python with utf8 caching
author Tassilo Philipp
date Sun, 19 May 2024 15:33:18 +0200
parents 4a9f6c7c09c1
children 75a4082f0fce
line wrap: on
line diff
--- a/python/pydc/pydc.c	Sat May 18 15:33:54 2024 +0200
+++ b/python/pydc/pydc.c	Sun May 19 15:33:18 2024 +0200
@@ -259,17 +259,21 @@
 	long long ll;
 	if ( !DcPyInt_Check(po) )
 		return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting an int", pos );
+#if ULONG_MAX < ULLONG_MAX
 	ll = (DClonglong) PyLong_AsLongLong(po);
-	if (u && (ll < 0 || ll > ULONG_MAX))  //@@@ on lp64, this is a bad comparison
+	if (u && (ll < 0 || ll > ULONG_MAX))
 		return PyErr_Format( PyExc_RuntimeError, "arg %lld out of range - expecting 0 <= arg <= %ld, got %lld", pos, ULONG_MAX, ll );
 	if (!u && (ll < LONG_MIN || ll > LONG_MAX))
 		return PyErr_Format( PyExc_RuntimeError, "arg %lld out of range - expecting %ld <= arg <= %ld, got %lld", pos, LONG_MIN, LONG_MAX, ll );
+#else
+	ll = u ? (DClonglong) PyLong_AsUnsignedLongLong(po) : (DClonglong) PyLong_AsLongLong(po);
+#endif
 
 	*l = (DClong)ll;
 	return po;
 }
 
-static inline PyObject* py2dclonglong(DClonglong* ll, PyObject* po, int pos)
+static inline PyObject* py2dclonglong(DClonglong* ll, PyObject* po, int u, int pos)
 {
 #if PY_MAJOR_VERSION < 3
 	if ( PyInt_Check(po) ) {
@@ -280,7 +284,8 @@
 	if ( !PyLong_Check(po) )
 		return PyErr_Format( PyExc_RuntimeError, "arg %d - expecting " EXPECT_LONG_TYPE_STR, pos );
 
-	*ll = (DClonglong) PyLong_AsLongLong(po);
+	*ll = u ? (DClonglong) PyLong_AsUnsignedLongLong(po) : (DClonglong) PyLong_AsLongLong(po);
+
 	return po;
 }
 
@@ -342,9 +347,6 @@
 		return PyErr_Format( PyExc_RuntimeError, "function pointer is NULL" );
 
 	// get signature
-#if !defined(PYUNICODE_CACHES_UTF8)
-	PyObject* sig_obj = NULL;
-#endif
 	PyObject* so = PyTuple_GetItem(args, pos++);
 	if ( PyUnicode_Check(so) )
 	{
@@ -352,8 +354,15 @@
 		sig_ptr = PyUnicode_AsUTF8(so);
 #else
 		// w/o PyUnicode_AsUTF8(), which caches the UTF-8 representation, itself, create new ref we'll dec below
-		if((sig_obj = PyUnicode_AsEncodedString(so, "utf-8", "strict")))  // !new ref!
-			sig_ptr = PyBytes_AS_STRING(sig_obj); // Borrowed pointer
+		PyObject* sig_obj = PyUnicode_AsEncodedString(so, "utf-8", "strict");  // !new ref!
+		if(sig_obj) {
+			const char *a = PyBytes_AS_STRING(sig_obj); // Borrowed pointer
+			if(a) {
+				sig_ptr = alloca(strlen(sig_ptr)+1);
+				strcpy(sig_ptr, a);
+			}
+			Py_DECREF(sig_obj);
+		}
 #endif
 	} else if ( DcPyString_Check(so) )
 		sig_ptr = DcPyString_AsString(so);
@@ -426,6 +435,7 @@
 						return NULL;
 					dcArgInt(gpCall, i);
 				}
+				break;
 
 			case DC_SIGCHAR_LONG:
 			case DC_SIGCHAR_ULONG:
@@ -435,12 +445,13 @@
 						return NULL;
 					dcArgLong(gpCall, l);
 				}
+				break;
 
 			case DC_SIGCHAR_LONGLONG:
 			case DC_SIGCHAR_ULONGLONG:
 				{
 					DClonglong ll;
-					if(!py2dclonglong(&ll, po, pos))
+					if(!py2dclonglong(&ll, po, ch == DC_SIGCHAR_ULONGLONG, pos))
 						return NULL;
 					dcArgLongLong(gpCall, ll);
 				}
@@ -516,7 +527,6 @@
 	if (ch == '\0')
 		return PyErr_Format( PyExc_RuntimeError, "return value missing in signature");
 
-
 	ch = *++sig_ptr;
 	switch(ch)
 	{
@@ -540,10 +550,6 @@
 		default:                   return PyErr_Format(PyExc_RuntimeError, "invalid return type signature");
 		// @@@ this could be handled via array lookups of a 256b array instead of switch/case, then share it with callback code if it makes sense
 	}
-
-#if !defined(PYUNICODE_CACHES_UTF8)
-	Py_XDECREF(sig_obj);
-#endif
 }
 
 
@@ -656,23 +662,16 @@
             
 					case DC_SIGCHAR_INT:
 					case DC_SIGCHAR_UINT:
-						if ( !DcPyInt_Check(po) )
-							PyErr_Format( PyExc_RuntimeError, "arg %d - expecting an int", -1 );
-						else
-							result->i = (DCint) DcPyInt_AS_LONG(po);
-						break;
+						py2dcint(&result->i, po, ch == DC_SIGCHAR_UINT, -1);
             
 					case DC_SIGCHAR_LONG:
 					case DC_SIGCHAR_ULONG:
-						if ( !DcPyInt_Check(po) )
-							PyErr_Format( PyExc_RuntimeError, "arg %d - expecting an int", -1 );
-						else
-							result->j = (DClong) PyLong_AsLong(po);
+						py2dclong(&result->j, po, ch == DC_SIGCHAR_ULONG, -1);
 						break;
             
 					case DC_SIGCHAR_LONGLONG:
 					case DC_SIGCHAR_ULONGLONG:
-						py2dclonglong(&result->l, po, -1);
+						py2dclonglong(&result->l, po, ch == DC_SIGCHAR_ULONGLONG, -1);
 						break;
             
 					case DC_SIGCHAR_FLOAT: