Bug 2365907 - python-cvxopt fails to build with Python 3.14: tests/test_dsdp.py::TestDSDP::test_options Fatal Python error: Segmentation fault
Summary: python-cvxopt fails to build with Python 3.14: tests/test_dsdp.py::TestDSDP::...
Keywords:
Status: CLOSED ERRATA
Alias: None
Product: Fedora
Classification: Fedora
Component: python-cvxopt
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Jerry James
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: PYTHON3.14
TreeView+ depends on / blocked
 
Reported: 2025-05-13 12:21 UTC by Karolina Surma
Modified: 2025-06-01 01:54 UTC (History)
4 users (show)

Fixed In Version: python-cvxopt-1.3.2-10.fc42 python-cvxopt-1.3.2-9.fc41
Clone Of:
Environment:
Last Closed: 2025-06-01 01:23:00 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Github cvxopt cvxopt pull 261 0 None open Fix dsdp.sdp() reference counting 2025-05-22 23:57:44 UTC

Description Karolina Surma 2025-05-13 12:21:10 UTC
python-cvxopt fails to build with Python 3.14.0b1.

tests/test_dsdp.py::TestDSDP::test_options Fatal Python error: Segmentation fault
The other tests pass.

https://docs.python.org/3.14/whatsnew/3.14.html

For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.14-b1/fedora-rawhide-x86_64/09027056-python-cvxopt/

For all our attempts to build python-cvxopt with Python 3.14, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.14-b1/package/python-cvxopt/

Testing and mass rebuild of packages is happening in copr.
You can follow these instructions to test locally in mock if your package builds with Python 3.14:
https://copr.fedorainfracloud.org/coprs/g/python/python3.14-b1/

Let us know here if you have any questions.

Python 3.14 is planned to be included in Fedora 43.
To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.14.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires),
so if this package is required a lot, it's important for us to get it fixed soon.

We'd appreciate help from the people who know this package best,
but if you don't want to work on this now, let us know so we can try to work around it on our side.

Comment 1 Jerry James 2025-05-22 16:09:47 UTC
I think I need some help with this one.  After making debug symbols available, here are the first few frames of the backtrace:

Thread 1 "python3" received signal SIGSEGV, Segmentation fault.
dict_merge.isra.0 (a=<unknown at remote 0x7ffff55d023c>, b={'green': True}, override=2, interp=<optimized out>)
    at /usr/src/debug/python3.14-3.14.0~b1-2.fc43.x86_64/Objects/dictobject.c:3910
3910        if (a == NULL || !PyDict_Check(a) || b == NULL) {
(gdb) bt
#0  dict_merge.isra.0 (a=<unknown at remote 0x7ffff55d023c>, b={'green': True}, override=2, interp=<optimized out>)
    at /usr/src/debug/python3.14-3.14.0~b1-2.fc43.x86_64/Objects/dictobject.c:3910
#1  0x00007ffff796c399 in _PyDict_MergeEx (a=<optimized out>, b=<optimized out>, override=<optimized out>)
    at /usr/src/debug/python3.14-3.14.0~b1-2.fc43.x86_64/Objects/dictobject.c:4017
#2  _PyEval_EvalFrameDefault (tstate=0x7ffff7d951a0 <_PyRuntime+315456>, frame=0x7ffff7e5f338, throwflag=2)
    at /usr/src/debug/python3.14-3.14.0~b1-2.fc43.x86_64/Python/generated_cases.c.h:5400
#3  0x00007ffff79628a5 in _PyEval_EvalFrame (tstate=0x7ffff7d951a0 <_PyRuntime+315456>, frame=0x7ffff7e5f338, 
    throwflag=0) at /usr/src/debug/python3.14-3.14.0~b1-2.fc43.x86_64/Include/internal/pycore_ceval.h:119

The 'a' dictionary has a bogus ob_type pointer:
(gdb) print *a
$1 = {{ob_refcnt_full = 1, {ob_refcnt = 1, ob_overflow = 0, ob_flags = 0}}, ob_type = 0xf7d189a000007fff}
(gdb) print *b
$2 = {{ob_refcnt_full = 1, {ob_refcnt = 1, ob_overflow = 0, ob_flags = 0}}, ob_type = 0x7ffff7d189a0 <PyDict_Type>}
(gdb) print *$1.ob_type
Cannot access memory at address 0xf7d189a000007fff

Look closely at that bogus pointer: it is word-reversed.  Swap the first 32 bits with the last 32 bits and you have the PyDict_Type pointer.  I have no idea how that pointer could have gotten reversed in the first place.

Comment 2 Victor Stinner 2025-05-22 20:46:59 UTC
Using python3.14-debug, I get an assertion error in new_dict(): Assertion `Py_IS_TYPE(mp, &PyDict_Type)' failed.

=============================================================== test session starts ================================================================
platform linux -- Python 3.14.0b1, pytest-8.3.5, pluggy-1.5.0
rootdir: /builddir/build/BUILD/python-cvxopt-1.3.2-build/cvxopt-1.3.2
configfile: setup.cfg
collected 2 items                                                                                                                                  

tests/test_dsdp.py python3.14d: /builddir/build/BUILD/python3.14-3.14.0_b1-build/Python-3.14.0b1/Objects/dictobject.c:886: new_dict: Assertion `Py_IS_TYPE(mp, &PyDict_Type)' failed.

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
44            return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;

(gdb) where
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007ffff7482cf3 in __pthread_kill_internal (threadid=<optimized out>, signo=6) at pthread_kill.c:89
#2  0x00007ffff7428abe in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff74106d0 in __GI_abort () at abort.c:73
#4  0x00007ffff7410639 in __assert_fail_base (fmt=<optimized out>, assertion=0x7ffff7ba3792 "Py_IS_TYPE(mp, &PyDict_Type)", file=<optimized out>, 
    line=<optimized out>, function=<optimized out>) at assert.c:118
#5  0x00007ffff774f8cd in new_dict () from /lib64/libpython3.14d.so.1.0
#6  0x00007ffff774fca6 in PyDict_New () from /lib64/libpython3.14d.so.1.0
#7  0x00007ffff775225d in dict_new_presized () from /lib64/libpython3.14d.so.1.0
#8  0x00007ffff77523b9 in _PyDict_FromItems () from /lib64/libpython3.14d.so.1.0
#9  0x00007ffff78c8c24 in _PyEval_EvalFrameDefault () from /lib64/libpython3.14d.so.1.0

Comment 3 Victor Stinner 2025-05-22 23:24:51 UTC
According to git bisect, the regression was introduced by: https://github.com/python/cpython/commit/8c22eba877225ab29cd64672dcb97f09a5f7336f

commit 8c22eba877225ab29cd64672dcb97f09a5f7336f
Author: Sergey B Kirpichev <skirpichev>
Date:   Thu Oct 31 13:37:03 2024 +0300

    gh-90370: Argument Clinic: avoid temporary tuple creation for varargs (#126064)
    
    Avoid temporary tuple creation when all arguments either positional-only
    or vararg.
    
    Objects/setobject.c and Modules/gcmodule.c adapted. This fixes slight
    performance regression for set methods, introduced by gh-115112.

Comment 4 Victor Stinner 2025-05-22 23:45:13 UTC
On Python 3.13 built in debug mode (with assertions), I get an error on Py_DECREF() when clearing the 4th argument of a function call, when calling sdp():

---------------------------------
Program received signal SIGABRT, Aborted.

(gdb) frame 10
#10 0x00000000006634ff in _PyEval_EvalFrameDefault (tstate=0xa9fff0 <_PyRuntime+294032>, frame=0x7ffff7fb3578, throwflag=0)
    at Python/generated_cases.c.h:1525
1525	                Py_DECREF(args[i]);
(gdb) p callable
$3 = <built-in method sdp of module object at remote 0x7fffe8ca1250>
(gdb) p i
$4 = 3

(gdb) where
#0  __pthread_kill_implementation (threadid=<optimized out>, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007ffff7d331e3 in __pthread_kill_internal (threadid=<optimized out>, signo=6) at pthread_kill.c:89
#2  0x00007ffff7cd9afe in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#3  0x00007ffff7cc16d0 in __GI_abort () at abort.c:73
#4  0x0000000000705888 in fatal_error_exit (status=-1) at Python/pylifecycle.c:2894
#5  0x0000000000705d0e in fatal_error (fd=2, header=1, prefix=0x82f6f0 <__func__.6> "_PyObject_AssertFailed", 
    msg=0x82f17e "_PyObject_AssertFailed", status=-1) at Python/pylifecycle.c:3076
#6  0x0000000000705d86 in _Py_FatalErrorFunc (func=0x82f6f0 <__func__.6> "_PyObject_AssertFailed", msg=0x82f17e "_PyObject_AssertFailed")
    at Python/pylifecycle.c:3092
#7  0x000000000054cff7 in _PyObject_AssertFailed (obj={}, expr=0x0, msg=0x82e5e4 "object has negative ref count", 
    file=0x87c12d "Python/generated_cases.c.h", line=1525, function=0x82f2a0 <__func__.45> "_Py_NegativeRefcount") at Objects/object.c:2827
#8  0x0000000000549396 in _Py_NegativeRefcount (filename=0x87c12d "Python/generated_cases.c.h", lineno=1525, op={}) at Objects/object.c:223
#9  0x000000000065978a in Py_DECREF (filename=0x87c12d "Python/generated_cases.c.h", lineno=1525, op={}) at ./Include/object.h:924
#10 0x00000000006634ff in _PyEval_EvalFrameDefault (tstate=0xa9fff0 <_PyRuntime+294032>, frame=0x7ffff7fb3578, throwflag=0)
    at Python/generated_cases.c.h:1525
#11 0x000000000065b2b1 in _PyEval_EvalFrame (tstate=0xa9fff0 <_PyRuntime+294032>, frame=0x7ffff7fb3430, throwflag=0)
    at ./Include/internal/pycore_ceval.h:119
...


(gdb) py-bt
Traceback (most recent call first):
  File "/home/vstinner/dev/cvxopt/tests/test_dsdp.py", line 43, in test_options
    sol2 = dsdp.sdp(c,Gs=Gs,hs=hs,options={})
  File "/home/vstinner/python/main/Lib/unittest/case.py", line 606, in _callTestMethod
    if method() is not None:
  File "/home/vstinner/python/main/Lib/unittest/case.py", line 651, in run
    self._callTestMethod(testMethod)
  File "/home/vstinner/python/main/Lib/unittest/case.py", line 707, in __call__
    return self.run(*args, **kwds)
  File "/home/vstinner/dev/cvxopt/env/lib/python3.13/site-packages/_pytest/unittest.py", line 351, in runtest
    testcase(result=self)
  ...
---------------------------------

Comment 5 Victor Stinner 2025-05-22 23:57:44 UTC
There is an old reference count bug in dsdp.sdp() function. The bug became more visible with Python 3.14.

I proposed a fix upstream: https://github.com/cvxopt/cvxopt/pull/261

Comment 6 Jerry James 2025-05-23 15:32:59 UTC
Thank you for the analysis and fix, Victor!  I will add your change as a downstream patch until upstream releases a fixed version.

Comment 7 Fedora Update System 2025-05-23 16:19:51 UTC
FEDORA-2025-c2644a9421 (python-cvxopt-1.3.2-10.fc42) has been submitted as an update to Fedora 42.
https://bodhi.fedoraproject.org/updates/FEDORA-2025-c2644a9421

Comment 8 Fedora Update System 2025-05-23 16:19:52 UTC
FEDORA-2025-3a445c96f7 (python-cvxopt-1.3.2-9.fc41) has been submitted as an update to Fedora 41.
https://bodhi.fedoraproject.org/updates/FEDORA-2025-3a445c96f7

Comment 9 Fedora Update System 2025-05-24 02:13:06 UTC
FEDORA-2025-3a445c96f7 has been pushed to the Fedora 41 testing repository.
Soon you'll be able to install the update with the following command:
`sudo dnf upgrade --enablerepo=updates-testing --refresh --advisory=FEDORA-2025-3a445c96f7`
You can provide feedback for this update here: https://bodhi.fedoraproject.org/updates/FEDORA-2025-3a445c96f7

See also https://fedoraproject.org/wiki/QA:Updates_Testing for more information on how to test updates.

Comment 10 Fedora Update System 2025-05-24 02:57:04 UTC
FEDORA-2025-c2644a9421 has been pushed to the Fedora 42 testing repository.
Soon you'll be able to install the update with the following command:
`sudo dnf upgrade --enablerepo=updates-testing --refresh --advisory=FEDORA-2025-c2644a9421`
You can provide feedback for this update here: https://bodhi.fedoraproject.org/updates/FEDORA-2025-c2644a9421

See also https://fedoraproject.org/wiki/QA:Updates_Testing for more information on how to test updates.

Comment 11 Fedora Update System 2025-06-01 01:23:00 UTC
FEDORA-2025-c2644a9421 (python-cvxopt-1.3.2-10.fc42) has been pushed to the Fedora 42 stable repository.
If problem still persists, please make note of it in this bug report.

Comment 12 Fedora Update System 2025-06-01 01:54:41 UTC
FEDORA-2025-3a445c96f7 (python-cvxopt-1.3.2-9.fc41) has been pushed to the Fedora 41 stable repository.
If problem still persists, please make note of it in this bug report.


Note You need to log in before you can comment on or make changes to this bug.