# HG changeset patch # User Tassilo Philipp # Date 1716125598 -7200 # Node ID 9b6cdffd30ddcd2d4caed083b21264ea572f16c6 # Parent 4a9f6c7c09c1c0687ab1a9e12dc53bbfe5cad460 - 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 diff -r 4a9f6c7c09c1 -r 9b6cdffd30dd python/pydc/pydc.c --- 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: diff -r 4a9f6c7c09c1 -r 9b6cdffd30dd python/pydc/test/Makefile --- 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 diff -r 4a9f6c7c09c1 -r 9b6cdffd30dd python/pydc/test/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 +