Repository navigation
Combination of transformations and reductions leads to model data corruption #1177
Description
Activity
I can reproduce the fault, but it's non-deterministic. This keeps trying until it breaks:
import time import control def main(): i = 1 while True: print(f'\riter {i} ...', end='') K_dk = control.rss(21, 1, 2, strictly_proper=True) K_arduino = reduce(K_dk,100,6) print(' done', end='') #time.sleep(0.1) i += 1 def reduce(K,limit,order): K,_ = control.modal_form(K) fast_modes = list() n = K.A.shape[0] for i in range(n): fast = False for j,k in [(i,i-1),(i,i),(i,i+1),(i-1,i),(i+1,i)]: if j>=0 and k>=0 and j<n and k<n and abs(K.A[j,k]) > limit: fast = True if fast: fast_modes.append(i) return control.balanced_reduction(control.model_reduction(K,fast_modes),order,method="matchdc") if __name__ == "__main__": main()
Sample output:
work) rory@rory-latitude:~/projects/pycontrol/gh1177$ python ex1.py iter 184 ...Segmentation fault (core dumped) (work) rory@rory-latitude:~/projects/pycontrol/gh1177$ python ex1.py iter 44 ...corrupted size vs. prev_size Aborted (core dumped) (work) rory@rory-latitude:~/projects/pycontrol/gh1177$ python ex1.py iter 44 ...corrupted double-linked list Aborted (core dumped) (work) rory@rory-latitude:~/projects/pycontrol/gh1177$ python ex1.py iter 170 ...Segmentation fault (core dumped) (work) rory@rory-latitude:~/projects/pycontrol/gh1177$ python ex1.py iter 9 ...Segmentation fault (core dumped) (work) rory@rory-latitude:~/projects/pycontrol/gh1177$ python ex1.py iter 9 ...corrupted size vs. prev_size Aborted (core dumped) (work) rory@rory-latitude:~/projects/pycontrol/gh1177$ python ex1.py iter 184 ...Segmentation fault (core dumped)I've attached the Conda environment config file, whence likely important versions:
- control=0.10.2=pyhd8ed1ab_0 - cpython=3.12.11=py312hd8ed1ab_0 - libblas=3.9.0=32_h59b9bed_openblas - libcblas=3.9.0=32_he106b2a_openblas - liblapack=3.9.0=32_h7ac8fdf_openblas - libopenblas=0.3.30=pthreads_h94d23a6_1 - numpy=2.3.2=py312h33ff503_0 - slycot=0.6.0=py312hb6c5a0b_2My system:
(work) rory@rory-latitude:~/projects/pycontrol/gh1177$ uname -a Linux rory-latitude 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 x86_64 x86_64 GNU/Linuxrunning a simpler, single-invocation of the test case under valgrind gives the output below. Command
valgrind --log-file=valgrind2.out python ex2.py;ex2.pyis at the end.I'm not sure where the first problem ("Conditional jump...") is, but it looks like the next one ("Invalid write ...") happens starting from
ab09ndwhich is in SLICOT, so called via Slycot.==120208== Memcheck, a memory error detector ==120208== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==120208== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==120208== Command: python ex2.py ==120208== Parent PID: 20410 ==120208== ==120208== Conditional jump or move depends on uninitialised value(s) ==120208== at 0x383D0B: PyUnicode_Decode (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x377EDE: unicode_new (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x314C7C: _PyObject_MakeTpCall (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21BF1F: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x317719: _PyObject_FastCallDictTstate (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x342C52: slot_tp_init (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x314D5B: _PyObject_MakeTpCall (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21BF1F: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3CF6FD: PyEval_EvalCode (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3EA9CC: builtin_exec (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x329F15: cfunction_vectorcall_FASTCALL_KEYWORDS (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21CC53: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== ==120208== Invalid write of size 4 ==120208== at 0x69D3F2F: dgetf2_k (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x6651130: dgetrf_ (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x3349A655: ab09dd_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x33499DBF: ab09bx_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x3349BB90: ab09nd_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x334605CA: f2py_rout__wrapper_ab09nd (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x314D8A: _PyObject_MakeTpCall (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21BF1F: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3CF6FD: PyEval_EvalCode (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3F37B9: run_eval_code_obj (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3EEA9A: run_mod (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x4077AF: pyrun_file (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== Address 0x2c0a2558 is 0 bytes after a block of size 8 alloc'd ==120208== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==120208== by 0x5D8F00E: PyDataMem_UserNEW (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DAEA84: PyArray_NewFromDescr_int (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DB2D55: PyArray_NewLikeArrayWithShape (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DB30BD: PyArray_NewLikeArray (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DF4C5F: array_astype (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x329F15: cfunction_vectorcall_FASTCALL_KEYWORDS (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x5D1B363: gentype_generic_method (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x3376A0: method_vectorcall_VARARGS_KEYWORDS (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x329C9E: PyObject_Vectorcall (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21BF1F: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3CF6FD: PyEval_EvalCode (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== ==120208== Invalid read of size 4 ==120208== at 0x69D3E05: dgetf2_k (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x6651130: dgetrf_ (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x3349A655: ab09dd_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x33499DBF: ab09bx_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x3349BB90: ab09nd_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x334605CA: f2py_rout__wrapper_ab09nd (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x314D8A: _PyObject_MakeTpCall (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21BF1F: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3CF6FD: PyEval_EvalCode (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3F37B9: run_eval_code_obj (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3EEA9A: run_mod (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x4077AF: pyrun_file (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== Address 0x2c0a2558 is 0 bytes after a block of size 8 alloc'd ==120208== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==120208== by 0x5D8F00E: PyDataMem_UserNEW (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DAEA84: PyArray_NewFromDescr_int (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DB2D55: PyArray_NewLikeArrayWithShape (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DB30BD: PyArray_NewLikeArray (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x5DF4C5F: array_astype (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x329F15: cfunction_vectorcall_FASTCALL_KEYWORDS (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x5D1B363: gentype_generic_method (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/numpy/_core/_multiarray_umath.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x3376A0: method_vectorcall_VARARGS_KEYWORDS (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x329C9E: PyObject_Vectorcall (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21BF1F: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3CF6FD: PyEval_EvalCode (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== ==120208== at 0x58046FFA: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x58047127: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x580472CB: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x580514B4: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x5803DE9A: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x5803CD9F: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x58041F04: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x5803C1D8: ??? (in /usr/lib/x86_64-linux-gnu/valgrind/memcheck-amd64-linux) ==120208== by 0x101022653A: ??? ==120208== by 0x1002EB9F2F: ??? ==120208== by 0x1002EB9F17: ??? ==120208== by 0x1002EB9F2F: ??? ==120208== by 0x1002EB9F3F: ??? ==120208== at 0x81C9661: dlacn2_ (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x818112C: dgecon_ (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x3349A6BA: ab09dd_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x33499DBF: ab09bx_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x3349BB90: ab09nd_ (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x334605CA: f2py_rout__wrapper_ab09nd (in /home/rory/miniforge3/envs/work/lib/python3.12/site-packages/slycot/_wrapper.cpython-312-x86_64-linux-gnu.so) ==120208== by 0x314D8A: _PyObject_MakeTpCall (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x21BF1F: _PyEval_EvalFrameDefault.cold (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3CF6FD: PyEval_EvalCode (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3F37B9: run_eval_code_obj (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3EEA9A: run_mod (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x4077AF: pyrun_file (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x4072FD: _PyRun_SimpleFileObject (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x406A43: _PyRun_AnyFileObject (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3FF1E1: Py_RunMain (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x3B7FA6: Py_BytesMain (in /home/rory/miniforge3/envs/work/bin/python3.12) ==120208== by 0x4A13082: (below main) (libc-start.c:308) ==120208== at 0x69C545C: blas_thread_server (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x4878608: start_thread (pthread_create.c:477) ==120208== by 0x4B0E352: clone (clone.S:95) ==120208== at 0x487F376: futex_wait_cancelable (futex-internal.h:183) ==120208== by 0x487F376: __pthread_cond_wait_common (pthread_cond_wait.c:508) ==120208== by 0x487F376: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:647) ==120208== by 0x69C54AB: blas_thread_server (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x4878608: start_thread (pthread_create.c:477) ==120208== by 0x4B0E352: clone (clone.S:95) ==120208== at 0x487F376: futex_wait_cancelable (futex-internal.h:183) ==120208== by 0x487F376: __pthread_cond_wait_common (pthread_cond_wait.c:508) ==120208== by 0x487F376: pthread_cond_wait@@GLIBC_2.3.2 (pthread_cond_wait.c:647) ==120208== by 0x69C54AB: blas_thread_server (in /home/rory/miniforge3/envs/work/lib/libopenblasp-r0.3.30.so) ==120208== by 0x4878608: start_thread (pthread_create.c:477) ==120208== by 0x4B0E352: clone (clone.S:95)import control def reduce(K,limit,order): K,_ = control.modal_form(K) fast_modes = list() n = K.A.shape[0] for i in range(n): fast = False for j,k in [(i,i-1),(i,i),(i,i+1),(i-1,i),(i+1,i)]: if j>=0 and k>=0 and j<n and k<n and abs(K.A[j,k]) > limit: fast = True if fast: fast_modes.append(i) return control.balanced_reduction(control.model_reduction(K,fast_modes),order,method="matchdc") K_dk = control.rss(21, 1, 2, strictly_proper=True) K_arduino = reduce(K_dk,100,6)
think this is a Slycot bug; see python-control/Slycot#245 for Slycot-only segfault-producing code.
It turns out this was fixed in python-control/Slycot#243, but we haven't made a Slycot release in a while.
If I run tests with python-control 0.10.2 and Slycot master, I can't reproduce this.
This issue can be closed, and I'll open a Slycot issue to discuss making a release.
I can reproduce the fault, but it's non-deterministic.
I don't know exactly what you mean by deterministic, but the original long code that produced this bug fails everytime (albeit with different errors).
This issue can be closed, and I'll open a Slycot issue to discuss making a release.
is there a workaround in the meantime?
is there a workaround in the meantime?
If you have a FORTRAN compiler on your system, you could check out the development version of slycot from github and do a local installation.
If you have a FORTRAN compiler on your system, you could check out the development version of slycot from github and do a local installation.
:) ok so nothing easy then, thanks
issue was opened in dkpy(decargroup/dkpy#48), but does not appear to be dkpy specific.
in particular note that @sdahdah created a more minimal example that does not use dkpy at all