#13505 closed defect (fixed)
Trac dies with segmentation fault in Python 3.11.0
Reported by: | seino | Owned by: | Jun Omae |
---|---|---|---|
Priority: | normal | Milestone: | 1.5.4 |
Component: | database backend | Version: | |
Severity: | critical | Keywords: | python3.11 sqlite |
Cc: | Branch: | ||
Release Notes: |
Fixed SEGV raised from SQLite cursor with Python 3.11. |
||
API Changes: | |||
Internal Changes: |
Description
In existence Trac environments /path/to/tracenv
, tracd
dies with segmentation fault.
$ python3 --version Python 3.11.0 $ cd /path/to/tracenv $ tracd -p 8000 . Server starting in PID 2152. Serving on 0.0.0.0:8000 view at http://127.0.0.1:8000/ Using HTTP/1.1 protocol version 127.0.0.1 - - [26/Nov/2022 09:53:15] "GET / HTTP/1.1" 200 - Segmentation fault (core dumped) $
I use:
- Trac 1.5.4.dev0 (revision 17604)
- Jinja2 3.1.2
- Babel 2.11.0
- MarkupSafe 2.1.1
- Fedora 37 (both of x86_64 and aarch64)
Attachments (0)
Change History (10)
comment:1 by , 2 years ago
comment:2 by , 2 years ago
Keywords: | python3.11 added |
---|---|
Owner: | set to |
Status: | new → assigned |
Thanks for the reporting! That's pretty bad. I just tried to reproduce it and got the same. Investigating…
comment:3 by , 2 years ago
It seems that the issue is related to sqlite cursor.
$ gdb --args /dev/shm/trac-py311/bin/python3.11-dbg -m trac.admin.console /dev/shm/tracenv-py311 initenv Project sqlite:db/trac.db ... (gdb) bt #0 Py_DECREF (op=<unknown at remote 0xdddddddddddddddd>, lineno=5566, filename=0x780168 "../Objects/dictobject.c") at ../Include/object.h:521 #1 _PyObject_ClearInstanceAttributes (self=self@entry=<EagerCursor(pos=<unknown at remote 0xdddddddddddddddd>, cnx=<unknown at remote 0xdddddddddddddddd>) at remote 0x7ffff51160e0>) at ../Objects/dictobject.c:5566 #2 0x000000000052e9ad in subtype_clear (self=<EagerCursor(pos=<unknown at remote 0xdddddddddddddddd>, cnx=<unknown at remote 0xdddddddddddddddd>) at remote 0x7ffff51160e0>) at ../Objects/typeobject.c:1288 #3 0x00007ffff59d8a9c in cursor_dealloc (self=self@entry=0x7ffff51160e0) at ./Modules/_sqlite/cursor.c:184 #4 0x0000000000531149 in subtype_dealloc (self=<EagerCursor(pos=<unknown at remote 0xdddddddddddddddd>, cnx=<unknown at remote 0xdddddddddddddddd>) at remote 0x7ffff51160e0>) at ../Objects/typeobject.c:1472 #5 0x0000000000514a02 in _Py_Dealloc (op=<optimized out>) at ../Objects/object.c:2389 #6 0x000000000052dc10 in Py_DECREF (op=<optimized out>, lineno=1262, filename=0x78bd03 "../Objects/typeobject.c") at ../Include/object.h:527 #7 clear_slots (type=type@entry=0x137b720, self=self@entry=<IterableCursor at remote 0x7ffff51adea0>) at ../Objects/typeobject.c:1262 #8 0x0000000000530e9f in subtype_dealloc (self=<IterableCursor at remote 0x7ffff51adea0>) at ../Objects/typeobject.c:1428 #9 0x0000000000514a02 in _Py_Dealloc (op=<optimized out>) at ../Objects/object.c:2389 #10 0x00000000005fedb7 in Py_DECREF (op=<optimized out>, lineno=602, filename=0x752b35 "../Include/object.h") at ../Include/object.h:527 #11 Py_XDECREF (op=<optimized out>) at ../Include/object.h:602 #12 _PyFrame_Clear (frame=frame@entry=0x7ffff7fc0980) at ../Python/frame.c:131 #13 0x00000000005c233b in _PyEvalFrameClearAndPop (tstate=tstate@entry=0xb476f8 <_PyRuntime+166328>, frame=frame@entry=0x7ffff7fc0980) at ../Python/ceval.c:6400 #14 0x00000000005dc7ce in _PyEval_Vector (tstate=0xb476f8 <_PyRuntime+166328>, func=<optimized out>, locals=locals@entry=0x0, args=<optimized out>, argcount=<optimized out>, kwnames=<optimized out>) at ../Python/ceval.c:6433 #15 0x00000000004b981c in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at ../Objects/call.c:393 #16 0x00000000004b9c7d in _PyObject_FastCallDictTstate (tstate=tstate@entry=0xb476f8 <_PyRuntime+166328>, callable=callable@entry=<function at remote 0x7ffff5a0adb0>, args=args@entry=0x7fffffffd5c0, nargsf=nargsf@entry=3, kwargs=kwargs@entry=0x0) at ../Objects/call.c:141 #17 0x00000000004b9f29 in _PyObject_Call_Prepend (tstate=tstate@entry=0xb476f8 <_PyRuntime+166328>, callable=callable@entry=<function at remote 0x7ffff5a0adb0>, obj=obj@entry=<ConnectionWrapper at remote 0x7ffff5166530>, args=args@entry=('\n SELECT value FROM `system` WHERE name=%s\n ', ('initial_database_version',)), kwargs=kwargs@entry=0x0) at ../Objects/call.c:482 #18 0x0000000000537368 in slot_tp_call (self=<ConnectionWrapper at remote 0x7ffff5166530>, args=('\n SELECT value FROM `system` WHERE name=%s\n ', ('initial_database_version',)), kwds=0x0) at ../Objects/typeobject.c:7630 #19 0x00000000004b9ad6 in _PyObject_MakeTpCall (tstate=tstate@entry=0xb476f8 <_PyRuntime+166328>, callable=callable@entry=<ConnectionWrapper at remote 0x7ffff5166530>, args=args@entry=0x7ffff7fc0958, nargs=<optimized out>, keywords=keywords@entry=0x0) at ../Objects/call.c:214 #20 0x00000000004ba446 in _PyObject_VectorcallTstate (kwnames=0x0, nargsf=9223372036854775810, args=0x7ffff7fc0958, callable=<ConnectionWrapper at remote 0x7ffff5166530>, tstate=0xb476f8 <_PyRuntime+166328>) at ../Include/internal/pycore_call.h:90 #21 PyObject_Vectorcall (callable=callable@entry=<ConnectionWrapper at remote 0x7ffff5166530>, args=args@entry=0x7ffff7fc0958, nargsf=<optimized out>, kwnames=kwnames@entry=0x0) at ../Objects/call.c:299 #22 0x00000000005d758f in _PyEval_EvalFrameDefault (tstate=tstate@entry=0xb476f8 <_PyRuntime+166328>, frame=0x7ffff7fc08d8, frame@entry=0x7ffff7fc0638, throwflag=throwflag@entry=0) at ../Python/ceval.c:4772 #23 0x00000000005dc7e6 in _PyEval_EvalFrame (throwflag=0, frame=0x7ffff7fc0638, tstate=0xb476f8 <_PyRuntime+166328>) at ../Include/internal/pycore_ceval.h:73 #24 _PyEval_Vector (tstate=0xb476f8 <_PyRuntime+166328>, func=<optimized out>, locals=locals@entry=0x0, args=<optimized out>, argcount=<optimized out>, kwnames=<optimized out>) at ../Python/ceval.c:6428 #25 0x00000000004b981c in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at ../Objects/call.c:393 #26 0x00000000004bcf1a in _PyObject_VectorcallTstate (kwnames=('create', 'options', 'default_data'), nargsf=2, args=0x7ffff5540440, callable=<function at remote 0x7ffff54e41b0>, tstate=0xb476f8 <_PyRuntime+166328>) at ../Include/internal/pycore_call.h:92 #27 method_vectorcall (method=<optimized out>, args=0x7ffff5540448, nargsf=<optimized out>, kwnames=('create', 'options', 'default_data')) at ../Objects/classobject.c:59 #28 0x00000000004b93dc in _PyVectorcall_Call (tstate=tstate@entry=0xb476f8 <_PyRuntime+166328>, func=0x4bcd1d <method_vectorcall>, callable=callable@entry=<method at remote 0x7ffff5c7cb90>, tuple=tuple@entry=('/dev/shm/tracenv-py311',), kwargs=kwargs@entry={'create': True, 'options': [('project', 'name', 'Project'), ('trac', 'database', 'sqlite:db/trac.db')], 'default_data': True}) at ../Objects/call.c:257 #29 0x00000000004b973d in _PyObject_Call (tstate=0xb476f8 <_PyRuntime+166328>, callable=callable@entry=<method at remote 0x7ffff5c7cb90>, args=args@entry=('/dev/shm/tracenv-py311',), kwargs=kwargs@entry={'create': True, 'options': [('project', 'name', 'Project'), ('trac', 'database', 'sqlite:db/trac.db')], 'default_data': True}) at ../Objects/call.c:328 #30 0x00000000004b97a1 in PyObject_Call (callable=callable@entry=<method at remote 0x7ffff5c7cb90>, args=args@entry=('/dev/shm/tracenv-py311',), kwargs=kwargs@entry={'create': True, 'options': [('project', 'name', 'Project'), ('trac', 'database', 'sqlite:db/trac.db')], 'default_data': True}) at ../Objects/call.c:355 ...
comment:4 by , 2 years ago
Could you please try the following patch and feedback the result?
-
trac/db/sqlite_backend.py
diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py index b1b7782c5..321d0e844 100644
a b class PyFormatCursor(sqlite.Cursor): 52 52 try: 53 53 return function(self, *args, **kwargs) 54 54 except sqlite.DatabaseError: 55 self.c nx.rollback()55 self.connection.rollback() 56 56 raise 57 57 58 58 def execute(self, sql, args=None): … … class SQLiteConnection(ConnectionBase, ConnectionWrapper): 326 326 def cursor(self): 327 327 cursor = self.cnx.cursor((PyFormatCursor, EagerCursor)[self._eager]) 328 328 self._active_cursors[cursor] = True 329 cursor.cnx = self330 329 return IterableCursor(cursor, self.log) 331 330 332 331 def rollback(self):
comment:5 by , 2 years ago
Component: | general → database backend |
---|---|
Keywords: | sqlite added |
comment:6 by , 2 years ago
I noticed the patch in comment:4 is incorrect. Instead, please try the following patch:
-
trac/db/sqlite_backend.py
diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py index b1b7782c5..c058e6840 100644
a b min_sqlite_version = (3, 0, 0) 48 48 49 49 50 50 class PyFormatCursor(sqlite.Cursor): 51 52 __slots__ = ['cnx'] 53 51 54 def _rollback_on_error(self, function, *args, **kwargs): 52 55 try: 53 56 return function(self, *args, **kwargs)
comment:7 by , 2 years ago
Thank you for your quick response.
This patch (comment:6) seems to work well.
comment:8 by , 2 years ago
Release Notes: | modified (diff) |
---|---|
Resolution: | → fixed |
Status: | assigned → closed |
Thanks for the feedback. Confirmed that unit tests pass with Python 3.5 - 3.11. Fixed in [17605].
comment:9 by , 2 years ago
I think we should report this issue to https://github.com/python/cpython/issues, however I don't succeed to create minimal reproduction code yet.
comment:10 by , 2 years ago
Well, I found the same issue has been reported at Segmentation fault when using a subclassed sqlite3.Cursor on 3.11.x · Issue #99886 · python/cpython and fixed.
I try to create a newly trac environment,
trac-admin
also dies.