From aa93eb1614bbf151757c5a2e9a4ba50c3ca2b87d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 3 Nov 2025 16:25:39 +0100 Subject: [PATCH] Adjust stack trace parsing for newer Python --- qutebrowser/misc/crashdialog.py | 6 +-- tests/unit/misc/test_crashdialog.py | 58 +++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/qutebrowser/misc/crashdialog.py b/qutebrowser/misc/crashdialog.py index 5b940a8a3..97815105f 100644 --- a/qutebrowser/misc/crashdialog.py +++ b/qutebrowser/misc/crashdialog.py @@ -48,8 +48,8 @@ def parse_fatal_stacktrace(text): lines = [ r'(?PFatal Python error|Windows fatal exception): (?P.*)', r' *', - r'(Current )?[Tt]hread [^ ]* \(most recent call first\): *', - r' File ".*", line \d+ in (?P.*)', + r'(Current )?[Tt]hread .* \(most recent call first\): *', + r' (File ".*", line \d+ in (?P.*)|)', ] m = re.search('\n'.join(lines), text) if m is None: @@ -58,7 +58,7 @@ def parse_fatal_stacktrace(text): else: msg = m.group('msg') typ = m.group('type') - func = m.group('func') + func = m.group('func') or '' if typ == 'Windows fatal exception': msg = 'Windows ' + msg return msg, func diff --git a/tests/unit/misc/test_crashdialog.py b/tests/unit/misc/test_crashdialog.py index 49162370e..0b4501938 100644 --- a/tests/unit/misc/test_crashdialog.py +++ b/tests/unit/misc/test_crashdialog.py @@ -32,6 +32,31 @@ Thread 0x00007fa135ac7700 (most recent call first): File "", line 1 in testfunc """ +VALID_CRASH_TEXT_PY314 = """ +Fatal Python error: Segmentation fault +_ +Current thread 0x00000001fe53e140 [CrBrowserMain] (most recent call first): + File "qutebrowser/app.py", line 126 in qt_mainloop + File "qutebrowser/app.py", line 116 in run + File "qutebrowser/qutebrowser.py", line 234 in main + File "__main__.py", line 15 in +_ +Current thread's C stack trace (most recent call first): + Binary file "...", at _Py_DumpStack+0x48 [0x10227cc9c] + +""" + +VALID_CRASH_TEXT_PY314_NO_PY = """ +Fatal Python error: Segmentation fault +_ +Current thread 0x00007f0dc805cbc0 [qutebrowser] (most recent call first): + +_ +Current thread's C stack trace (most recent call first): + Binary file "/lib64/libpython3.14.so.1.0", at _Py_DumpStack+0x4c [0x7f0dc7b2127b] + +""" + WINDOWS_CRASH_TEXT = r""" Windows fatal exception: access violation _ @@ -45,13 +70,32 @@ Hello world! """ -@pytest.mark.parametrize('text, typ, func', [ - (VALID_CRASH_TEXT, 'Segmentation fault', 'testfunc'), - (VALID_CRASH_TEXT_THREAD, 'Segmentation fault', 'testfunc'), - (VALID_CRASH_TEXT_EMPTY, 'Aborted', ''), - (WINDOWS_CRASH_TEXT, 'Windows access violation', 'tabopen'), - (INVALID_CRASH_TEXT, '', ''), -]) +@pytest.mark.parametrize( + "text, typ, func", + [ + pytest.param(VALID_CRASH_TEXT, "Segmentation fault", "testfunc", id="valid"), + pytest.param( + VALID_CRASH_TEXT_THREAD, "Segmentation fault", "testfunc", id="valid-thread" + ), + pytest.param( + VALID_CRASH_TEXT_PY314, + "Segmentation fault", + "qt mainloop", + id="valid-py314", + ), + pytest.param( + VALID_CRASH_TEXT_PY314_NO_PY, + "Segmentation fault", + "", + id="valid-py314-no-py", + ), + pytest.param(VALID_CRASH_TEXT_EMPTY, "Aborted", "", id="valid-empty"), + pytest.param( + WINDOWS_CRASH_TEXT, "Windows access violation", "tabopen", id="windows" + ), + pytest.param(INVALID_CRASH_TEXT, "", "", id="invalid"), + ], +) def test_parse_fatal_stacktrace(text, typ, func): text = text.strip().replace('_', ' ') assert crashdialog.parse_fatal_stacktrace(text) == (typ, func)