https://bugs.documentfoundation.org/show_bug.cgi?id=173208
Bug ID: 173208
Summary: LO hangs at GUI startup when RecoveryInfo/Crashed=true
triggers SynchronousDispatch while a pyuno extension
OnStartApp handler calls Desktop.getCurrentComponent()
(Solar Mutex deadlock)
Product: LibreOffice
Version: 26.2.5.2 release
Hardware: x86-64 (AMD64)
OS: Linux (All)
Status: UNCONFIRMED
Severity: normal
Priority: medium
Component: framework
Assignee: [email protected]
Reporter: [email protected]
LibreOffice hangs indefinitely at GUI startup — no window ever appears, both
oosplash
and soffice.bin remain in kernel wait states — when both of the following are
true:
(a) RecoveryInfo/Crashed=true is present in the user's
~/.config/libreoffice/4/user/registrymodifications.xcu (typical after any
previous
crash, including headless --convert-to crashes such as bug 173205, or a
SIGKILL
on a running GUI instance), AND
(b) A pyuno extension whose OnStartApp handler eventually calls
Desktop.getCurrentComponent() on a background thread is installed. Nelson
MCP 0.12.1
is a concrete reproducer that hits this reliably; the OnStartApp path is
documented
in its upstream tracker.
Neither condition alone is enough. Removing Crashed=true (setting it to false)
makes the
next launch succeed within ~1 s. Removing the extension also breaks the cycle.
Steps to Reproduce:
1. Install a pyuno extension whose OnStartApp handler calls
Desktop.getCurrentComponent()
on a background thread. Nelson MCP 0.12.1 (nelson-0.12.1.oxt) is one such
extension.
2. Cause any LibreOffice crash that leaves RecoveryInfo/Crashed=true in the
user profile.
Reliable path: run
soffice --headless --norestore --convert-to ods --outdir out
<bug-173205-file.ods>
and let it SIGABRT (see bug 173205). Alternatively, kill a running GUI
soffice.bin
with SIGKILL.
3. Start LO GUI:
soffice --writer any-file.doc
or double-click any document in the file manager.
Actual Results:
oosplash and soffice.bin are spawned. Both processes remain in kernel wait
states
forever. No window ever appears.
oosplash -> wchan = anon_pipe_read (waiting on splash-pipe
signal)
soffice.bin main -> wchan = futex_do_wait (inside
Application::Execute)
soffice.bin py×2 -> wchan = futex_do_wait (blocked at
SolarMutex::doAcquire)
The pair remains hung until killed by the user.
Expected Results:
The Writer/Calc window opens normally, or the Recovery dialog appears if
Recovery has
work to do.
Additional Information:
Live backtrace of the hung soffice.bin process captured with
sudo gdb -batch -ex 'set pagination off' -ex 'thread apply all bt 30' -p
<PID>
after the pair had been hung for 18 minutes. Full 12-thread backtrace is
attached
(08-sudo-gdb-full-bt.txt). The relevant frames are as follows.
Main thread (Thread 1) — holds the Solar Mutex, waits on a framework mutex:
#0 __lll_lock_wait libc.so.6
#1 pthread_mutex_lock@@GLIBC_2.2.5 libc.so.6
#2 ??? libmergedlo.so + 0x3539e3
#3 ??? libmergedlo.so + 0x2d3668
...
#12 comphelper::SynchronousDispatch::dispatch() libmergedlo.so
#13 ??? libmergedlo.so (document
open pipeline)
...
#18 SalUserEventList::DispatchUserEvents(bool) libmergedlo.so
#19 QtInstance::ImplYield(bool, bool) libvclplug_qt6lo.so
#20 QtInstance::DoYield(bool, bool) libvclplug_qt6lo.so
#21 Application::Yield() libmergedlo.so
#22 Application::Execute() libmergedlo.so
#23 ImplSVMain() libmergedlo.so
#24 soffice_main() libmergedlo.so
Two Python worker threads (Thread 6 and Thread 7, spawned by the extension's
OnStartApp
bootstrap) — blocked at SolarMutex::doAcquire:
#0 __lll_lock_wait libc.so.6
#1 pthread_mutex_lock@@GLIBC_2.2.5 libc.so.6
#2 osl_acquireMutex libuno_sal.so.3
#3 comphelper::SolarMutex::doAcquire libmergedlo.so ← blocked
#4 ??? libmergedlo.so + 0x3251f53
#5 framework::Desktop::getActiveFrame() libmergedlo.so
#6 framework::Desktop::getCurrentFrame() libmergedlo.so
#7 framework::Desktop::getCurrentComponent() libmergedlo.so
#8-11 ??? libgcc3_uno.so,
libreflectionlo.so
#12 ??? libinvocationlo.so
#13 ??? libpyuno.so
#14 _PyObject_MakeTpCall libpython3.13.so
#15 _PyEval_EvalFrameDefault libpython3.13.so
...
Cycle:
* Main thread is in comphelper::SynchronousDispatch::dispatch(), reached from
Application::Execute -> Yield -> DispatchUserEvents. This is the
document-open path
that Recovery drives at startup when RecoveryInfo/Crashed=true.
* Main thread holds the Solar Mutex (unsurprising during GUI startup) and
waits on
an internal framework mutex whose release requires a UNO callback to
complete.
* The UNO callback is coming from the extension's pyuno background thread;
that
thread is blocked at SolarMutex::doAcquire, which is held by the main
thread.
Falsification: reproduced on an isolated -env:UserInstallation profile without
any
pyuno extension installed. Six combinations of user profile state were tested
(Crashed x zombie RecoveryList/replace with empty TempURL x backup lock x
0-byte
backup .ods_0.ods). The Recovery dialog appeared within ~5 s in every
combination.
No hang. The extension's OnStartApp Desktop-API call is essential; the LO
Recovery
flow alone is not sufficient.
Suggested fixes (either one breaks the cycle):
(1) Recovery-triggered SynchronousDispatch in Application::Execute should not
hold
framework locks that must be released via UNO callbacks. This would let
extension OnStartApp handlers acquire the Solar Mutex concurrently.
(2) Extension OnStartApp handlers should be invoked after
Application::Execute has
yielded to idle at least once, so that startup framework locks are
released
before any pyuno-driven UNO calls run.
Related defect in the same profile-write path (may be a separate ticket at the
triager's preference): headless soffice run with
soffice -env:UserInstallation=file:///path/to/agent-profile --headless \
--convert-to <fmt> <file>
writes RecoveryInfo/Crashed=true and RecoveryList entries to the user's regular
profile (~/.config/libreoffice/4/user/registrymodifications.xcu) instead of the
agent
profile passed via -env:UserInstallation, when the process is killed by a
signal
(SIGABRT or SIGKILL). This violates the documented isolation of
-env:UserInstallation
and is the source of the Crashed=true state that later triggers the deadlock
above.
Environment:
LibreOffice 26.2.5.2 (openSUSE Tumbleweed distro build; upstream TDF 26.2.5)
VCL plugin: Qt6
Desktop: KDE Plasma 6, Wayland session
Python: 3.13
OS: openSUSE Tumbleweed, Linux 7.1.8-1-default
Reproducing extension: Nelson MCP 0.12.1 (nelson-0.12.1.oxt). Upstream Nelson
issue
tracking the extension-side fix:
https://github.com/quazardous/nelson-mcp/issues/37
--
You are receiving this mail because:
You are the assignee for the bug.