From de3328cb3b62258baaea23ef69be10c3bc6cf9af Mon Sep 17 00:00:00 2001 From: "Lee, Jeong Han" Date: Sat, 31 Aug 2024 21:13:06 -0700 Subject: [PATCH 01/15] pull_39, issues_37, debian 13 - gcc 14.2.0 compile error --- devsupApp/src/dbapi.c | 4 ++-- devsupApp/src/dbfield.c | 6 +++++- makehelper.py | 17 +++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/devsupApp/src/dbapi.c b/devsupApp/src/dbapi.c index f859cd6..ccbc69c 100644 --- a/devsupApp/src/dbapi.c +++ b/devsupApp/src/dbapi.c @@ -289,11 +289,11 @@ static struct PyMethodDef dbapimethod[] = { #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef dbapimodule = { - PyModuleDef_HEAD_INIT, + PyModuleDef_HEAD_INIT, "devsup._dbapi", NULL, -1, - &dbapimethod + dbapimethod }; #endif diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 4a03cba..1b5c9a8 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -40,6 +40,10 @@ static const int dbf2np_map[DBF_MENU+1] = { NPY_INT16, // DBF_MENU }; static PyArray_Descr* dbf2np[DBF_MENU+1]; +#if NPY_ABI_VERSION < 0x02000000 + #define PyDataType_ELSIZE(descr) ((descr)->elsize) + #define PyDataType_SET_ELSIZE(descr, size) (descr)->elsize = size +#endif #endif typedef struct { @@ -98,7 +102,7 @@ static PyObject* build_array(PyObject* obj, void *data, unsigned short ftype, un desc = dbf2np[ftype]; if(ftype==DBF_STRING) { - desc->elsize = MAX_STRING_SIZE; + PyDataType_SET_ELSIZE(desc, MAX_STRING_SIZE); } Py_XINCREF(desc); diff --git a/makehelper.py b/makehelper.py index ef36d63..8420df7 100644 --- a/makehelper.py +++ b/makehelper.py @@ -26,15 +26,24 @@ pass out = open(sys.argv[1], 'w') -from distutils.sysconfig import get_config_var, get_python_inc +if sys.version_info >= (3,10,): + from sysconfig import get_config_var, get_path + incdirs = [get_path("include")] +else: + from distutils.sysconfig import get_config_var, get_python_inc + incdirs = [get_python_inc()] -incdirs = [get_python_inc()] libdir = get_config_var('LIBDIR') or '' have_np='NO' try: - from numpy.distutils.misc_util import get_numpy_include_dirs - incdirs = get_numpy_include_dirs()+incdirs + if sys.version_info >= (3,10,): + from numpy import get_include + numpy_dir = [get_include()] + else: + from numpy.distutils.misc_util import get_numpy_include_dirs + numpy_dir = get_numpy_include_dirs() + incdirs = numpy_dir+incdirs have_np='YES' except ImportError: pass From 4e6f05551a3563c761d31108f6ae660f46087c43 Mon Sep 17 00:00:00 2001 From: "Lee, Jeong Han" Date: Sat, 31 Aug 2024 21:40:17 -0700 Subject: [PATCH 02/15] more clean up for makehelper.py --- makehelper.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/makehelper.py b/makehelper.py index 8420df7..144476c 100644 --- a/makehelper.py +++ b/makehelper.py @@ -26,6 +26,12 @@ pass out = open(sys.argv[1], 'w') +""" +3.2, sysconfig +3.10, sysconfig.get_pathi +3.10.13 distutils is deprecated. +3.12, distutils was removed. +""" if sys.version_info >= (3,10,): from sysconfig import get_config_var, get_path incdirs = [get_path("include")] @@ -36,13 +42,12 @@ libdir = get_config_var('LIBDIR') or '' have_np='NO' +""" +Since numpy 1.18, numpy.get_include() exists. +""" try: - if sys.version_info >= (3,10,): - from numpy import get_include - numpy_dir = [get_include()] - else: - from numpy.distutils.misc_util import get_numpy_include_dirs - numpy_dir = get_numpy_include_dirs() + from numpy import get_include + numpy_dir = [get_include()] incdirs = numpy_dir+incdirs have_np='YES' except ImportError: From 796f7d7af6367a8b622f14b5b01062726e5a8c90 Mon Sep 17 00:00:00 2001 From: "Lee, Jeong Han" Date: Sat, 31 Aug 2024 21:50:27 -0700 Subject: [PATCH 03/15] add the min. version of numpy to requirements-latest --- makehelper.py | 11 ++++++----- requirements-latest.txt | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/makehelper.py b/makehelper.py index 144476c..05fd147 100644 --- a/makehelper.py +++ b/makehelper.py @@ -27,10 +27,10 @@ out = open(sys.argv[1], 'w') """ -3.2, sysconfig -3.10, sysconfig.get_pathi -3.10.13 distutils is deprecated. -3.12, distutils was removed. +3.2 sysconfig +3.10 sysconfig.get_path +3.10.13 distutils is deprecated. +3.12 distutils was removed. """ if sys.version_info >= (3,10,): from sysconfig import get_config_var, get_path @@ -42,8 +42,9 @@ libdir = get_config_var('LIBDIR') or '' have_np='NO' + """ -Since numpy 1.18, numpy.get_include() exists. +numpy 1.18, numpy.get_include() """ try: from numpy import get_include diff --git a/requirements-latest.txt b/requirements-latest.txt index 99ce0ab..5b989fd 100644 --- a/requirements-latest.txt +++ b/requirements-latest.txt @@ -1,2 +1,2 @@ -numpy +numpy>=1.18 nose2 From 898bc8453fb813641b55bb0c49b0722ffd46ed83 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Thu, 2 Oct 2025 01:18:17 -0700 Subject: [PATCH 04/15] update ci scripts version --- .ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci b/.ci index 899b183..4e4f33e 160000 --- a/.ci +++ b/.ci @@ -1 +1 @@ -Subproject commit 899b18336b4ce3bd9328fd30c33621224c78a4d7 +Subproject commit 4e4f33e54f59343c77342200a95800073661e7ac From fa45a3c5dbfdfe7c4dc4bef522a94ba5b7f2426f Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Thu, 2 Oct 2025 01:21:54 -0700 Subject: [PATCH 05/15] Update CI jobs to include deb 11, 12, 13 and py3.6 to py3.13 --- .github/workflows/ci-scripts-build.yml | 73 +++++++++++++++++++++++++- requirements-deb11.txt | 2 + requirements-deb12.txt | 2 + requirements-deb13.txt | 2 + 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 requirements-deb11.txt create mode 100644 requirements-deb12.txt create mode 100644 requirements-deb13.txt diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 6729366..86b13bc 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -11,8 +11,9 @@ env: jobs: build-base: - name: ${{ matrix.base }}/${{ matrix.os }}/${{ matrix.python }}/${{ matrix.extra }} + name: ${{ matrix.base }}/${{ matrix.os }}/${{ matrix.profile }}/${{ matrix.python }}/${{ matrix.extra }} runs-on: ${{ matrix.os }} + container: ${{ matrix.container }} # Set environment variables from matrix parameters env: CMP: ${{ matrix.cmp }} @@ -33,6 +34,49 @@ jobs: base: "7.0" python: "3.7" profile: deb10 + container: "python:3.7" + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.9" + profile: deb11 + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.11" + profile: deb12 + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.13" + profile: deb13 + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.6" + container: "python:3.6" + profile: latest + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.7" + container: "python:3.7" + profile: latest test: yes - os: ubuntu-latest @@ -59,6 +103,30 @@ jobs: profile: latest test: yes + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.11" + profile: latest + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.12" + profile: latest + test: yes + + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "7.0" + python: "3.13" + profile: latest + test: yes + - os: macos-latest cmp: gcc configuration: default @@ -72,6 +140,7 @@ jobs: configuration: default base: "3.15" python: "3.7" + container: "python:3.7" profile: deb10 test: yes @@ -80,12 +149,14 @@ jobs: configuration: default base: "3.14" python: "3.7" + container: "python:3.7" profile: deb10 steps: - uses: actions/checkout@v3 with: submodules: true - name: Set up Python ${{ matrix.python }} + if: ${{ !matrix.container }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} diff --git a/requirements-deb11.txt b/requirements-deb11.txt new file mode 100644 index 0000000..bc9b6d9 --- /dev/null +++ b/requirements-deb11.txt @@ -0,0 +1,2 @@ +numpy==1.19.5 +nose2==0.9.2 diff --git a/requirements-deb12.txt b/requirements-deb12.txt new file mode 100644 index 0000000..13118a8 --- /dev/null +++ b/requirements-deb12.txt @@ -0,0 +1,2 @@ +numpy==1.24.2 +nose2==0.12.0 diff --git a/requirements-deb13.txt b/requirements-deb13.txt new file mode 100644 index 0000000..abb51c7 --- /dev/null +++ b/requirements-deb13.txt @@ -0,0 +1,2 @@ +numpy==2.2.4 +nose2==0.15.1 From 19d5a5ba7d39fb9154da17475d6e78475af07ae6 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Thu, 2 Oct 2025 01:26:10 -0700 Subject: [PATCH 06/15] Fix numpy compatability between v1 and v2 for NPY_CARRAY and NPY_CARRAY --- devsupApp/src/dbfield.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 1b5c9a8..d909815 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -44,6 +44,12 @@ static PyArray_Descr* dbf2np[DBF_MENU+1]; #define PyDataType_ELSIZE(descr) ((descr)->elsize) #define PyDataType_SET_ELSIZE(descr, size) (descr)->elsize = size #endif +#ifndef NPY_CARRAY_RO + #define NPY_CARRAY_RO NPY_ARRAY_CARRAY_RO +#endif +#ifndef NPY_CARRAY + #define NPY_CARRAY NPY_ARRAY_CARRAY +#endif #endif typedef struct { From 0550f167cfc0393faa870bf927d91244e80eda88 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Thu, 2 Oct 2025 01:27:44 -0700 Subject: [PATCH 07/15] Add python 3.13 to base 3.15 CI --- .github/workflows/ci-scripts-build.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 86b13bc..c46ce43 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -144,6 +144,14 @@ jobs: profile: deb10 test: yes + - os: ubuntu-latest + cmp: gcc + configuration: default + base: "3.15" + python: "3.13" + profile: deb13 + test: yes + - os: ubuntu-latest cmp: gcc configuration: default From 44a16fd735f1e8309c120f5155d3f3c5250adbe1 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sun, 5 Oct 2025 17:15:41 -0400 Subject: [PATCH 08/15] FIX: Cast to PyArrayObject *, warning of comparsion integers of npy_intp with ulong. --- devsupApp/src/dbfield.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index d909815..1d8ae4a 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -130,17 +130,19 @@ static int assign_array(DBADDR *paddr, PyObject *arr) PyArray_Descr *desc = dbf2np[paddr->field_type]; if(paddr->field_type==DBF_STRING && - (PyArray_NDIM(arr)!=2 || PyArray_DIM(arr,0)>maxlen || PyArray_DIM(arr,1)!=MAX_STRING_SIZE)) + (PyArray_NDIM((PyArrayObject *)arr) != 2 || + PyArray_DIM((PyArrayObject *)arr, 0) > (npy_intp) maxlen || + PyArray_DIM((PyArrayObject *)arr, 1) != MAX_STRING_SIZE)) { PyErr_Format(PyExc_ValueError, "String array has incorrect shape or is too large"); return 1; - } else if(PyArray_NDIM(arr)!=1 || PyArray_DIM(arr,0)>maxlen) { + } else if(PyArray_NDIM((PyArrayObject *)arr) != 1 || PyArray_DIM((PyArrayObject *)arr, 0) > (npy_intp) maxlen) { PyErr_Format(PyExc_ValueError, "Array has incorrect shape or is too large"); return 1; } - insize = PyArray_DIM(arr, 0); + insize = PyArray_DIM((PyArrayObject *)arr, 0); if(paddr->special==SPC_DBADDR && (prset=dbGetRset(paddr)) && @@ -165,13 +167,13 @@ static int assign_array(DBADDR *paddr, PyObject *arr) if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_CARRAY, arr))) return 1; - if(elemsize!=PyArray_ITEMSIZE(aval)) { + if(elemsize!=PyArray_ITEMSIZE((PyArrayObject *)aval)) { PyErr_Format(PyExc_AssertionError, "item size mismatch %u %u", - elemsize, (unsigned)PyArray_ITEMSIZE(aval) ); + elemsize, (unsigned)PyArray_ITEMSIZE((PyArrayObject *)aval) ); return 1; } - memcpy(rawfield, PyArray_GETPTR1(aval, 0), insize*elemsize); + memcpy(rawfield, PyArray_GETPTR1((PyArrayObject *)aval, 0), insize*elemsize); Py_DECREF(aval); From f2d5c8df958038c6d9e6cee560e1a39e6b89406b Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Mon, 6 Oct 2025 10:56:13 -0700 Subject: [PATCH 09/15] Update requirements to remove numpy version --- requirements-latest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-latest.txt b/requirements-latest.txt index 5b989fd..99ce0ab 100644 --- a/requirements-latest.txt +++ b/requirements-latest.txt @@ -1,2 +1,2 @@ -numpy>=1.18 +numpy nose2 From 1b7047dd3f073492514e4e81cfc8914f80b771c5 Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Wed, 29 Oct 2025 11:51:11 -0700 Subject: [PATCH 10/15] Original author is Peter Heesterman - Fixed problem with NPY_CARRAY and NPY_CARRAY_RO being unavailable in newer versions of numpy. --- devsupApp/src/dbfield.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 1d8ae4a..7267169 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -44,12 +44,6 @@ static PyArray_Descr* dbf2np[DBF_MENU+1]; #define PyDataType_ELSIZE(descr) ((descr)->elsize) #define PyDataType_SET_ELSIZE(descr, size) (descr)->elsize = size #endif -#ifndef NPY_CARRAY_RO - #define NPY_CARRAY_RO NPY_ARRAY_CARRAY_RO -#endif -#ifndef NPY_CARRAY - #define NPY_CARRAY NPY_ARRAY_CARRAY -#endif #endif typedef struct { @@ -164,7 +158,7 @@ static int assign_array(DBADDR *paddr, PyObject *arr) } Py_XINCREF(desc); - if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_CARRAY, arr))) + if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) return 1; if(elemsize!=PyArray_ITEMSIZE((PyArrayObject *)aval)) { @@ -219,7 +213,7 @@ static PyObject* pyField_getval(pyField *self) if(self->addr.no_elements>1) { return build_array((PyObject*)self, rawfield, self->addr.field_type, - noe, NPY_CARRAY_RO); + noe, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED); } } @@ -374,7 +368,7 @@ static PyObject *pyField_getarray(pyField *self) } else data = self->addr.pfield; - return build_array((PyObject*)self, data, self->addr.field_type, self->addr.no_elements, NPY_CARRAY); + return build_array((PyObject*)self, data, self->addr.field_type, self->addr.no_elements, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE); } static PyObject *pyField_getlen(pyField *self) From 5993a6c0dfe2e6f05736fc8f2a627e47708a5bcd Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Wed, 29 Oct 2025 11:55:30 -0700 Subject: [PATCH 11/15] update docs to specify python 3.6 as minimum version --- documentation/environment.rst | 14 +++++++------- documentation/gettingstarted.rst | 2 +- documentation/index.rst | 2 +- iocBoot/iocapplmon/st.cmd | 2 +- iocBoot/iocarchivemon/st.cmd | 2 +- iocBoot/iocarchivemon/st.cmd.main | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/documentation/environment.rst b/documentation/environment.rst index a33677b..076d7cb 100644 --- a/documentation/environment.rst +++ b/documentation/environment.rst @@ -4,7 +4,7 @@ Runtime Environment The pyDevSup module initializes the interpreter during the registration phase of IOC startup with the *pySetupReg* registrar function. :: - #!../../bin/linux-x86_64/softIocPy2.7 + #!../../bin/linux-x86_64/softIocPy3.6 # Interpreter not started dbLoadDatabase("../../dbd/softIocPy.dbd",0,0) softIocPy_registerRecordDeviceDriver(pdbbase) @@ -51,7 +51,7 @@ file. :: The default or preferred Python version can be specificed in *configure/CONFIG_SITE* :: - PY_VER ?= 2.7 + PY_VER ?= 3.6 The following should be added to individual EPICS Makefiles. :: @@ -64,8 +64,8 @@ The following should be added to individual EPICS Makefiles. :: This will add or amend several make variables. The ``USR_*FLAGS`` variables may be extended with appropriate flags for building python modules. The ``PY_VER`` -variable is defined with the Python version number found in install directories (eg "2.7"). -The ``PY_LD_VER`` variable is defined with the python library version number (eg "3.2mu"), +variable is defined with the Python version number found in install directories (eg "3.6"). +The ``PY_LD_VER`` variable is defined with the python library version number (eg "3.6mu"), which may be the same as ``PY_VER``. Include pyDevSup in your IOC @@ -113,11 +113,11 @@ Installing for several Python versions The recipe for building and installing the pyDevSup module for several python version side by side is :: - make PY_VER=2.6 + make PY_VER=3.6 make clean - make PY_VER=2.7 + make PY_VER=3.10 make clean - make PY_VER=3.2 + make PY_VER=3.14 make clean The ``PYTHON`` make variable can be specified if the interpreter executable diff --git a/documentation/gettingstarted.rst b/documentation/gettingstarted.rst index ef542ef..294494a 100644 --- a/documentation/gettingstarted.rst +++ b/documentation/gettingstarted.rst @@ -24,7 +24,7 @@ The :py:meth:`process ` method increments the *VAL* field Start this IOC with. :: - $ ./bin/linux-x86_64/softIocPy2.7 -d cntrec.db + $ ./bin/linux-x86_64/softIocPy3.6 -d cntrec.db Starting iocInit ... iocRun: All initialization complete diff --git a/documentation/index.rst b/documentation/index.rst index 2acf7b1..e3a86d1 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -8,7 +8,7 @@ pydevsup documentation *pyDevSup* is a means of writing EPICS device support code in Python. -It currently supports EPICS >=3.14.12 and python versions: 2.7, and >=3.2. +It currently supports EPICS >=3.14.12 and python versions >=3.6 The numpy package is also required. The source can be found at http://github.com/mdavidsaver/pyDevSup diff --git a/iocBoot/iocapplmon/st.cmd b/iocBoot/iocapplmon/st.cmd index c931fb9..142d051 100755 --- a/iocBoot/iocapplmon/st.cmd +++ b/iocBoot/iocapplmon/st.cmd @@ -1,4 +1,4 @@ -#!../../bin/linux-x86/softIocPy2.7 +#!../../bin/linux-x86/softIocPy3.6 < envPaths diff --git a/iocBoot/iocarchivemon/st.cmd b/iocBoot/iocarchivemon/st.cmd index 20fef52..be83af7 100755 --- a/iocBoot/iocarchivemon/st.cmd +++ b/iocBoot/iocarchivemon/st.cmd @@ -1,4 +1,4 @@ -#!../../bin/linux-x86/softIocPy2.7 +#!../../bin/linux-x86/softIocPy3.6 < envPaths diff --git a/iocBoot/iocarchivemon/st.cmd.main b/iocBoot/iocarchivemon/st.cmd.main index df00b9c..ea10a94 100755 --- a/iocBoot/iocarchivemon/st.cmd.main +++ b/iocBoot/iocarchivemon/st.cmd.main @@ -1,4 +1,4 @@ -#!../../bin/linux-x86_64/softIocPy2.7 +#!../../bin/linux-x86_64/softIocPy3.6 < envPaths From f198e163f373a713a2073eb2207b9558b66abcbf Mon Sep 17 00:00:00 2001 From: Tynan Ford Date: Wed, 5 Nov 2025 00:53:32 -0800 Subject: [PATCH 12/15] Change to a single cast for arr to PyArrayObject in dbfield --- devsupApp/src/dbfield.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 7267169..1f46e07 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -119,24 +119,25 @@ static int assign_array(DBADDR *paddr, PyObject *arr) void *rawfield = paddr->pfield; rset *prset; PyObject *aval; + PyArrayObject * array = (PyArrayObject *)arr; unsigned elemsize = dbValueSize(paddr->field_type); unsigned long maxlen = paddr->no_elements, insize; PyArray_Descr *desc = dbf2np[paddr->field_type]; if(paddr->field_type==DBF_STRING && - (PyArray_NDIM((PyArrayObject *)arr) != 2 || - PyArray_DIM((PyArrayObject *)arr, 0) > (npy_intp) maxlen || - PyArray_DIM((PyArrayObject *)arr, 1) != MAX_STRING_SIZE)) + (PyArray_NDIM(array) != 2 || + PyArray_DIM(array, 0) > (npy_intp) maxlen || + PyArray_DIM(array, 1) != MAX_STRING_SIZE)) { PyErr_Format(PyExc_ValueError, "String array has incorrect shape or is too large"); return 1; - } else if(PyArray_NDIM((PyArrayObject *)arr) != 1 || PyArray_DIM((PyArrayObject *)arr, 0) > (npy_intp) maxlen) { + } else if(PyArray_NDIM(array) != 1 || PyArray_DIM(array, 0) > (npy_intp) maxlen) { PyErr_Format(PyExc_ValueError, "Array has incorrect shape or is too large"); return 1; } - insize = PyArray_DIM((PyArrayObject *)arr, 0); + insize = PyArray_DIM(array, 0); if(paddr->special==SPC_DBADDR && (prset=dbGetRset(paddr)) && From eafb208c4f0d5404968bb949a8028bcd60f40735 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Wed, 5 Nov 2025 11:36:47 -0500 Subject: [PATCH 13/15] FIX: Handle potential mem leak by properly DECREF. --- devsupApp/src/dbfield.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 1f46e07..2b3f843 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -106,7 +106,12 @@ static PyObject* build_array(PyObject* obj, void *data, unsigned short ftype, un } Py_XINCREF(desc); - return PyArray_NewFromDescr(&PyArray_Type, desc, ndims, dims, NULL, data, flags, (PyObject*)obj); + PyObject *out_arr = PyArray_NewFromDescr(&PyArray_Type, desc, ndims, dims, NULL, data, flags, (PyObject*)obj); + if(!out_arr) { + Py_XDECREF(desc); + return NULL; + } + return out_arr; #else PyErr_SetNone(PyExc_NotImplementedError); return NULL; @@ -119,7 +124,7 @@ static int assign_array(DBADDR *paddr, PyObject *arr) void *rawfield = paddr->pfield; rset *prset; PyObject *aval; - PyArrayObject * array = (PyArrayObject *)arr; + PyArrayObject *array = (PyArrayObject *)arr; unsigned elemsize = dbValueSize(paddr->field_type); unsigned long maxlen = paddr->no_elements, insize; PyArray_Descr *desc = dbf2np[paddr->field_type]; @@ -159,18 +164,23 @@ static int assign_array(DBADDR *paddr, PyObject *arr) } Py_XINCREF(desc); - if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) + if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) { + Py_XDECREF(desc); return 1; + } if(elemsize!=PyArray_ITEMSIZE((PyArrayObject *)aval)) { PyErr_Format(PyExc_AssertionError, "item size mismatch %u %u", elemsize, (unsigned)PyArray_ITEMSIZE((PyArrayObject *)aval) ); + Py_DECREF(aval); + Py_XDECREF(desc); return 1; } memcpy(rawfield, PyArray_GETPTR1((PyArrayObject *)aval, 0), insize*elemsize); Py_DECREF(aval); + Py_XDECREF(desc); if(paddr->special==SPC_DBADDR && (prset=dbGetRset(paddr)) && From 2171fedacacac26fb64dba2138dd537db310588b Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Wed, 5 Nov 2025 14:31:48 -0500 Subject: [PATCH 14/15] REF: DECREF of 'aval' if elemsize is not correct before return. - PyArray_FromAny handles the refcnt of descr. --- devsupApp/src/dbfield.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 2b3f843..93f7263 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -164,23 +164,19 @@ static int assign_array(DBADDR *paddr, PyObject *arr) } Py_XINCREF(desc); - if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) { - Py_XDECREF(desc); + if(!(aval = PyArray_FromAny(arr, desc, 1, 2, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED | NPY_ARRAY_WRITEABLE, arr))) return 1; - } if(elemsize!=PyArray_ITEMSIZE((PyArrayObject *)aval)) { PyErr_Format(PyExc_AssertionError, "item size mismatch %u %u", - elemsize, (unsigned)PyArray_ITEMSIZE((PyArrayObject *)aval) ); + elemsize, (unsigned)PyArray_ITEMSIZE((PyArrayObject *)aval)); Py_DECREF(aval); - Py_XDECREF(desc); return 1; } memcpy(rawfield, PyArray_GETPTR1((PyArrayObject *)aval, 0), insize*elemsize); Py_DECREF(aval); - Py_XDECREF(desc); if(paddr->special==SPC_DBADDR && (prset=dbGetRset(paddr)) && From d4d18298310950bea132e72c0e5160aa32d5c674 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Thu, 6 Nov 2025 15:13:42 -0500 Subject: [PATCH 15/15] REF: No need to XDECREF, added a comment as Michael suggested. --- devsupApp/src/dbfield.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/devsupApp/src/dbfield.c b/devsupApp/src/dbfield.c index 93f7263..94da410 100644 --- a/devsupApp/src/dbfield.c +++ b/devsupApp/src/dbfield.c @@ -105,13 +105,8 @@ static PyObject* build_array(PyObject* obj, void *data, unsigned short ftype, un PyDataType_SET_ELSIZE(desc, MAX_STRING_SIZE); } - Py_XINCREF(desc); - PyObject *out_arr = PyArray_NewFromDescr(&PyArray_Type, desc, ndims, dims, NULL, data, flags, (PyObject*)obj); - if(!out_arr) { - Py_XDECREF(desc); - return NULL; - } - return out_arr; + Py_XINCREF(desc); // take a reference for PyArray_NewFromDescr() to steal + return PyArray_NewFromDescr(&PyArray_Type, desc, ndims, dims, NULL, data, flags, (PyObject*)obj); #else PyErr_SetNone(PyExc_NotImplementedError); return NULL;