changeset 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 6c494834e52a
files python/pydc/pydc.c python/pydc/test/Makefile python/pydc/test/types_test.py
diffstat 3 files changed, 106 insertions(+), 58 deletions(-) [+]
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:
--- a/python/pydc/test/Makefile	Sat May 18 15:33:54 2024 +0200
+++ b/python/pydc/test/Makefile	Sun May 19 15:33:18 2024 +0200
@@ -4,6 +4,8 @@
 	(for i in char 'unsigned char' short 'unsigned short' int 'unsigned int' long 'unsigned long' 'long long' 'unsigned long long' float double 'const char*'; do \
 		echo "$$i `echo $$i | sed -E 's/\*/ p/;s/(^| )([a-z])[^ ]*/\2/g'`_plus_one($$i v) { return v+1; }"; \
 	done; \
-	echo 'void cp_head_incr(char* v) { v[0]+=1; }') | ${CC} -`[ \`uname\` = Darwin ] && echo dynamiclib || echo shared` -x c - -o $@
+	echo 'void cp_head_incr(char* v) { v[0]+=1; }'; \
+	echo 'int llp64() { return sizeof(int) == sizeof(long); }') | \
+		${CC} -`[ \`uname\` = Darwin ] && echo dynamiclib || echo shared` -x c - -o $@
 	@echo Done! Now you can run types_test.py
 
--- a/python/pydc/test/types_test.py	Sat May 18 15:33:54 2024 +0200
+++ b/python/pydc/test/types_test.py	Sun May 19 15:33:18 2024 +0200
@@ -8,7 +8,7 @@
 
 def theader(title):
   print("\n"+title)
-  print('%8s %20s %16s %-20s %11s %-16s -> %16s %-16s %12s %-16s  # %s' % ('DC_SIG', 'C_RET_T', 'C_FSYM', 'C_PARAMLIST', 'PY_ARG_T', 'IN_ARGS', 'RET_VAL', 'PY_RET_T', 'OUT_ARGS_T', 'OUT_ARGS', 'NOTES'))
+  print('%8s %20s %16s %-20s %11s %-20s -> %20s %-20s %12s %-20s  # %s' % ('DC_SIG', 'C_RET_T', 'C_FSYM', 'C_PARAMLIST', 'PY_ARG_T', 'IN_ARGS', 'RET_VAL', 'PY_RET_T', 'OUT_ARGS_T', 'OUT_ARGS', 'NOTES'))
 
 
 def t(lib, dcsig, c_rtype, c_fsym, c_paramlist, extra_msg, **kwargs):
@@ -37,7 +37,7 @@
   # after call
   outarg_types = '('+','.join(map(lambda x: type(x).__name__, args))+')'
   outargs = ','.join(map(str, args))
-  print('%s%8s %20s %16s %-20s %11s \033[33m%-16s\033[39m -> \033[32m%16.16s\033[39m %-16s %12s \033[32m%-16s\033[0m  # %s' % (err_sgr, dcsig, c_rtype, c_fsym, c_paramlist, inarg_types, inargs_str, str(r), '('+rt+')', outarg_types, outargs, extra_msg))
+  print('%s%8s %20s %16s %-20s %11s \033[33m%-20s\033[39m -> \033[32m%20.20s\033[39m %-20s %12s \033[32m%-20s\033[0m  # %s' % (err_sgr, dcsig, c_rtype, c_fsym, c_paramlist, inarg_types, inargs_str, str(r), '('+rt+')', outarg_types, outargs, extra_msg))
 
   return r
 
@@ -104,6 +104,10 @@
 
 l = pydc.load(sys.path[0]+"/test.so")
 
+# detect if C sizeof(long) == sizeof(int)
+llp64 = pydc.call(pydc.find(l, "llp64"), ")i")
+
+
 # "long" typed test value use for Python 2
 long_i = 11234
 long_h = 0xdeadc0de
@@ -167,35 +171,78 @@
 
 # tested checked value conversions
 theader('ARG & RET TYPE CONVERSION TESTS FOR RANGE CHECKED TYPES:')
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '        "~" =>    127',            i=( '~',), r=127)
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '        "~" =>    127',            i=( '~',), r=127)
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '         "" => input exc:',        i=(  '',), r=Exception)
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '         "" => input exc:',        i=(  '',), r=Exception)
-t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '       "ab" => input exc:',        i=('ab',), r=Exception)
-t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '       "ab" => input exc:',        i=('ab',), r=Exception)
-                                                                                                                    
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '       -128 =>   -127',            i=(-128,), r=-127)
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '        127 =>   -128 (wrapped)',  i=( 127,), r=-128)
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '       -129 => input exc:',        i=(-129,), r=Exception)
-t(l, "c)c", "char",                 "c_plus_one", "(char)",               '        128 => input exc:',        i=( 128,), r=Exception)
-                                                                                                                     
-t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '          0 =>      1',            i=(   0,), r=1)
-t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '        255 =>      0 (wrapped)',  i=( 255,), r=0)
-t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '         -1 => input exc:',        i=(  -1,), r=Exception)
-t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '        256 => input exc:',        i=( 256,), r=Exception)
-                                                                                                                     
-t(l, "s)s", "short",                "s_plus_one", "(short)",              '     -32768 => -32767',          i=(-32768,), r=-32767)
-t(l, "s)s", "short",                "s_plus_one", "(short)",              '      32767 => -32768 (wrapped)',i=( 32767,), r=-32768)
-t(l, "s)s", "short",                "s_plus_one", "(short)",              '     -32769 => input exc:',      i=(-32769,), r=Exception)
-t(l, "s)s", "short",                "s_plus_one", "(short)",              '      32768 => input exc:',      i=( 32768,), r=Exception)
-                                                                                                                     
-t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '          0 =>     1',            i=(    0,), r=1)
-t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '      65535 =>     0 (wrapped)',  i=(65535,), r=0)
-t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '         -1 => input exc:',       i=(   -1,), r=Exception)
-t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '      65536 => input exc:',       i=(65536,), r=Exception)
-                                                                                                                    
-t(l, "p)Z", "const char*",        "ccp_plus_one", "(const char*)",        '"w/pointer" => input exc:',i=( 'w/pointer',), r=Exception) # string object, not passable as 'p'ointer
-t(l, "p)Z", "const char*",        "ccp_plus_one", "(const char*)",        '"X_unicode" => input exc:',i=(u'X_unicode',), r=Exception) # string object (unicode in Python 2), not passable as 'p'ointer
-t(l, "p)Z", "const char*",        "ccp_plus_one", "(const char*)",        '"1less/ptr" => input exc:',i=(b'1less/ptr',), r=Exception) # bytes object, not passable as 'p'ointer
-t(l, "p)p", "const char*",        "ccp_plus_one", "(const char*)",        '        "x" => input exc:',i=(         'x',), r=Exception) # string object, not passable as 'p'ointer
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                 "~" =>    127',                                        i=( '~',), r=127)
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                 "~" =>    127',                                        i=( '~',), r=127)
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                  "" => input exc:',                                    i=(  '',), r=Exception)
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                  "" => input exc:',                                    i=(  '',), r=Exception)
+t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '                "ab" => input exc:',                                    i=('ab',), r=Exception)
+t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '                "ab" => input exc:',                                    i=('ab',), r=Exception)
+
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                -128 =>   -127',                                        i=(-128,), r=-127)
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                 127 =>   -128 (wrapped)',                              i=( 127,), r=-128)
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                -129 => input exc:',                                    i=(-129,), r=Exception)
+t(l, "c)c", "char",                 "c_plus_one", "(char)",               '                 128 => input exc:',                                    i=( 128,), r=Exception)
+
+t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '                   0 =>      1',                                        i=(   0,), r=1)
+t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '                 255 =>      0 (wrapped)',                              i=( 255,), r=0)
+t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '                  -1 => input exc:',                                    i=(  -1,), r=Exception)
+t(l, "C)C", "unsigned char",       "uc_plus_one", "(unsigned char)",      '                 256 => input exc:',                                    i=( 256,), r=Exception)
+
+t(l, "s)s", "short",                "s_plus_one", "(short)",              '              -32768 => -32767',                                      i=(-32768,), r=-32767)
+t(l, "s)s", "short",                "s_plus_one", "(short)",              '               32767 => -32768 (wrapped)',                            i=( 32767,), r=-32768)
+t(l, "s)s", "short",                "s_plus_one", "(short)",              '              -32769 => input exc:',                                  i=(-32769,), r=Exception)
+t(l, "s)s", "short",                "s_plus_one", "(short)",              '               32768 => input exc:',                                  i=( 32768,), r=Exception)
+
+t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '                   0 =>     1',                                        i=(    0,), r=1)
+t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '               65535 =>     0 (wrapped)',                              i=(65535,), r=0)
+t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '                  -1 => input exc:',                                   i=(   -1,), r=Exception)
+t(l, "S)S", "unsigned short",      "us_plus_one", "(unsigned short)",     '               65536 => input exc:',                                   i=(65536,), r=Exception)
+
+t(l, "i)i", "int",                  "i_plus_one", "(int)",                '         -2147483648 => -2147483647',                            i=(-2147483648,), r=-2147483647)
+t(l, "i)i", "int",                  "i_plus_one", "(int)",                '          2147483647 => -2147483648 (wrapped)',                  i=( 2147483647,), r=-2147483648)
+t(l, "i)i", "int",                  "i_plus_one", "(int)",                '         -2147483649 => input exc:',                             i=(-2147483649,), r=Exception)
+t(l, "i)i", "int",                  "i_plus_one", "(int)",                '          2147483648 => input exc:',                             i=( 2147483648,), r=Exception)
+
+t(l, "I)I", "unsigned int",        "ui_plus_one", "(unsigned int)",       '                   0 =>     1',                                        i=(    0,), r=1)
+t(l, "I)I", "unsigned int",        "ui_plus_one", "(unsigned int)",       '          4294967295 =>     0 (wrapped)',                         i=(4294967295,), r=0)
+t(l, "I)I", "unsigned int",        "ui_plus_one", "(unsigned int)",       '                  -1 => input exc:',                                   i=(   -1,), r=Exception)
+t(l, "I)I", "unsigned int",        "ui_plus_one", "(unsigned int)",       '          4294967296 => input exc:',                              i=(4294967296,), r=Exception)
 
+if llp64:
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               '         -2147483648 => -2147483647',                            i=(-2147483648,), r=-2147483647)
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               '          2147483647 => -2147483648 (wrapped)',                  i=( 2147483647,), r=-2147483648)
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               '         -2147483649 => input exc:',                             i=(-2147483649,), r=Exception)
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               '          2147483648 => input exc:',                             i=( 2147483648,), r=Exception)
+                                                                               
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '                   0 =>     1',                                        i=(    0,), r=1)
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '          4294967295 =>     0 (wrapped)',                         i=(4294967295,), r=0)
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '                  -1 => input exc:',                                   i=(   -1,), r=Exception)
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '          4294967296 => input exc:',                              i=(4294967296,), r=Exception)
+
+else:
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               '-9223372036854775808 => -9223372036854775807',          i=(-9223372036854775808,), r=-9223372036854775807)
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               ' 9223372036854775807 => -9223372036854775808 (wrapped)',i=( 9223372036854775807,), r=-9223372036854775808)
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               '-9223372036854775809 => input exc:',                    i=(-9223372036854775809,), r=Exception)
+    t(l, "j)j", "long",             "l_plus_one", "(long)",               ' 9223372036854775808 => input exc:',                    i=( 9223372036854775808,), r=Exception)
+
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '                   0 =>     1',                                        i=(    0,), r=1)
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '18446744073709551615 =>     0 (wrapped)',               i=(18446744073709551615,), r=0)
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '                  -1 => input exc:',                                   i=(   -1,), r=Exception)
+    t(l, "J)J", "unsigned long",   "ul_plus_one", "(unsigned long)",      '18446744073709551616 => input exc:',                    i=(18446744073709551616,), r=Exception)
+
+
+t(l, "l)l", "long long",           "ll_plus_one", "(long long)",          '-9223372036854775808 => -9223372036854775807',          i=(-9223372036854775808,), r=-9223372036854775807)
+t(l, "l)l", "long long",           "ll_plus_one", "(long long)",          ' 9223372036854775807 => -9223372036854775808 (wrapped)',i=( 9223372036854775807,), r=-9223372036854775808)
+t(l, "l)l", "long long",           "ll_plus_one", "(long long)",          '-9223372036854775809 => input exc:',                    i=(-9223372036854775809,), r=Exception)
+t(l, "l)l", "long long",           "ll_plus_one", "(long long)",          ' 9223372036854775808 => input exc:',                    i=( 9223372036854775808,), r=Exception)
+
+t(l, "L)L", "unsigned long long", "ull_plus_one", "(unsigned long long)", '                   0 =>     1',                                        i=(    0,), r=1)
+t(l, "L)L", "unsigned long long", "ull_plus_one", "(unsigned long long)", '18446744073709551615 =>     0 (wrapped)',               i=(18446744073709551615,), r=0)
+t(l, "L)L", "unsigned long long", "ull_plus_one", "(unsigned long long)", '                  -1 => input exc:',                                   i=(   -1,), r=Exception)
+t(l, "L)L", "unsigned long long", "ull_plus_one", "(unsigned long long)", '18446744073709551616 => input exc:',                    i=(18446744073709551616,), r=Exception)
+
+t(l, "p)Z", "const char*",        "ccp_plus_one", "(const char*)",        '         "w/pointer" => input exc:',                            i=( 'w/pointer',), r=Exception) # string object, not passable as 'p'ointer
+t(l, "p)Z", "const char*",        "ccp_plus_one", "(const char*)",        '         "X_unicode" => input exc:',                            i=(u'X_unicode',), r=Exception) # string object (unicode in Python 2), not passable as 'p'ointer
+t(l, "p)Z", "const char*",        "ccp_plus_one", "(const char*)",        '         "1less/ptr" => input exc:',                            i=(b'1less/ptr',), r=Exception) # bytes object, not passable as 'p'ointer
+t(l, "p)p", "const char*",        "ccp_plus_one", "(const char*)",        '                 "x" => input exc:',                            i=(         'x',), r=Exception) # string object, not passable as 'p'ointer
+