GSoC 25: BASIC IDE - Object Browser - Async IDE Launch and Solving UI Crash [WEEK 12 - 13]
Devansh Varshney
varshney.devansh614 at gmail.com
Fri Aug 29 10:51:20 UTC 2025
Hi everyone,
Following up on our Week 11 report, this update focuses on the primary
goal for
the past two weeks: investigating and fixing the "Ghost Parent" UI crash.
After a deep and complex investigation, we may have found the root cause
and
have implemented a solution which needs feedback and testing. The bug
seems to
a multi-layered problem involving a UI deadlock, a memory-safety
issue, and a loss of application context post fixing it(I will tell
below).
*Asynchronously launch IDE:*
https://gerrit.libreoffice.org/c/core/+/189922
Just now the CI is passing which I anticipated. But, I need feedback and
testing
from community members and also is this approach even better or not? As
of now
to me it seems to be solving the situation and we also noticed a past
patch
trying to fix a similar UI situation with "Choose Macros UI" by hiding it
-
*m_xDialog->hide(); // tdf#126828 dismiss dialog before opening new
window*
To my understanding there were historically some problems with how IDE
was launched.
And what I have also understood is that the BASIC IDE can have only one
single
instance throughout the entire application's lifetime which means it is a
Singleton.
Which means that the BASIC IDE is not like a normal document. We can open
many
Writer documents at once, but we can only have one BASIC IDE window open
at a time.
*in file basctl/source/basicide/iderdll.cxx - `Shell* GetShell ()`*
---------------------------------------------------------------------------
* Chapter 1: The Initial Symptom - The "Ghost Window"*
The journey began with a UI freeze. When clicking the "Edit" button in the
"Tools > Macros > Edit" dialog without a document open. The IDE was
launching
but the parent "BASIC Macros" dialog would remain on screen as a
non-functional "ghost". Clicking this ghost window would crash the
application.
Our initial finding was that this was caused by a synchronous deadlock.
The code("Choose Macro") was telling the UI thread to "launch the IDE
and wait", which blocked the thread from doing its other job: closing
this window.
Flowchart 1: The Synchronous Deadlock
[UI Thread]
|
v
[User clicks "Edit" -> Synchronous "Launch IDE" command]
|
+------> [This call BLOCKS the entire UI thread...]
|
[Thread is FROZEN, cannot process "close dialog" event]
|
v
+------------------------+
| GHOST WINDOW ON SCREEN |
+------------------------+
* Chapter 2: The Mystery of the "New" Button*
A key clue was that clicking the "New" button worked fine, even though its
code also used a synchronous launch. We investigated and found that the
"New" button first calls a function, CreateMacro().
This function does a lot of background work, like loading libraries and
modifying the document model. This work accidentally? processed the
pending
UI events, preventing the deadlock? This is what I was able to understand
from the code as with "Edit" the IDE was launching immediately but with
this
delaying of operations with "New Button" gave it enough time to process
the UI?
So, I am looking for feedback specially how this is going to impact as I
not only
have made changes for Fixing the "Edit Button" but also for the "New
Button"
since both of the codes were similar in how the IDE should be launched.
The code related to these are in file basctl/source/basicide/macrodlg.cxx
-
*IMPL_LINK*(MacroChooser, ButtonHdl, weld::Button&, rButton, void)
inside this clause -
*else if (&rButton == m_xEditButton.get() || &rButton == m_xDelButton.get()
|| &rButton == m_xNewButton.get())*
*Chapter 3: The First Fix & A Deeper Bug - Memory Corruption*
The obvious fix for this situation was to make the launch *asynchronous*
("do it later"). This solved the UI freeze, but the CI build started
failing with crashes in other parts of the application which was in `sw`
*`cppunit test CppunitTest_sw_a11y failed`*
This seems like a classic sign of a `use-after-free memory` bug. The new
async
handler was a member of the dialog object. The dialog would schedule the
handler to run later and then immediately close itself. By the time the
handler ran, the dialog object was destroyed, and its `this` pointer was
invalid, causing memory corruption in the CI? Again how I understand
these events.
* Chapter 4: The Second Fix & The Final Bug - The Broken UI*
To fix the memory corruption, we made the handler `static` as suggested
by the CI error "this member function can be declared static
[loplugin:staticmethods]"
A static function is independent and doesn't have a `this` pointer, so it
can run
safely after the dialog is destroyed. This fixed the CI crashes.
However, this introduced the final problem: the IDE would launch with a
broken/default? UI with text written in the IDE "Copyright 2012-2017
Jean-Pierre LEDURE"
The UI didn't know which macro to open.
The static handler, while safe, had lost the UI "context".
Which again brings us back to our WEEK 4 mail main highlight "CONTEXT"
> UNO Services and Memes - Why Context Comes First
Flowchart 2: The Flawed Asynchronous Fix
[Dialog] [Event Queue]
|
+---- "Launch IDE" message ----> (Message is queued)
| (with no context)
|
[Dialog is destroyed]
|
v
(Later...) [Static handler runs]
|
v
[Launches a generic IDE]
|
v
+--------------------+
| BROKEN/DEFAULT? UI |
+--------------------+
*Chapter 5: The Definitive Solution - Finding the Context*
The final challenge was to launch asynchronously and safely, without
losing
the context. The solution was a two-step process within the static
handler,
especially for the "no document" case:
1. Launch: First, tell the main application to launch the IDE. This
creates the IDE window and its core object, the `basctl::Shell`.
2. Find & Command: After the IDE appears, we use a global function we
discovered, `basctl::GetShell()`, to get a pointer to the newly
created IDE's shell. Now that we have the IDE's specific context, we
can send it the final command telling it which macro to edit.
Flowchart 3: The Correct? Asynchronous Solution
[Dialog] [Event Queue]
|
+---- "Launch IDE" message ----> (Message is queued)
| (with macro info)
|
[Dialog is destroyed]
|
v
(Later...) [Static handler runs]
|
v
1. [Launches a generic IDE]
|
v
2. [Finds new IDE via
GetShell()]
|
v
3. [Sends it the macro info]
|
v
+---------------------+
| IDE LOADS CORRECTLY |
+---------------------+
Now regarding the Object Browser I am able to split the code logically but
it is all still in the same one patch for search and navigation buttons.
Based on my mentors feedback the search UI as been improved as of now I am
now we are having grouped search results with a 350ms search delay and
now
trying to fix the grouped search expansion bug and there are still some
refinements needs to be done for the navigation buttons the vision I had
for
the Navigation Buttons is like how git works making an image of time
instance
so they would work exactly like what user selected in the UI and being
able to
go backward and forward what they did.
I also made a mistake this week while trying to having a discussion over
the
async IDE launch patch I unecessarly sent a really long reply which I made
overly
detailed & refined with an LLM and which isn't how professional 2 way
communication
works. Which is not going to happen again :)
Now given the timelines my mentors specially Jonathan suggested for this
project's
extension and here is what years of experience make a difference while I
was
maybe in overconfidence? estimated that I would be able to resolve all
these
situations of bugs and be able to break this patch in multiple
chronological patches.
Which I am still far away since this August from the mid I kept dealing
with this libreoffice post mouseEvent crash which wasn't caused by the
Object Browser
rather this new time consuming process exposed this pre-existing problem?
So, while solving and investigating this puzzle was interesting, on the
other hand I
kinda lost the time which was crucial for at least getting the Object
Browser complete.
Hence, his vision and experience has now made things possible to achieve
and we have
extended this project.
A major chunk of this project which is Auto Code Suggestion is still
remaining and
can be thought as the remaining 35% of this project which has to be done
quickly.
https://gerrit.libreoffice.org/c/core/+/186822
I have also attached the Images related to this week's work and a text
file.
Images:
*BASIC IDE launch without STATIC ASYNC handler*
<https://bugs.documentfoundation.org/attachment.cgi?id=202573> -
https://bug-attachments.documentfoundation.org/attachment.cgi?id=202573
*BASIC IDE launch with STATIC ASYNC handler*
<https://bugs.documentfoundation.org/attachment.cgi?id=202574> -
https://bug-attachments.documentfoundation.org/attachment.cgi?id=202574
*post patch 32 grouped search*
https://bug-attachments.documentfoundation.org/attachment.cgi?id=202575
https://bug-attachments.documentfoundation.org/attachment.cgi?id=202576
*Previous Updates:*
Week 1:
https://lists.freedesktop.org/archives/libreoffice/2025-May/093264.html
Weeks 2-3:
https://lists.freedesktop.org/archives/libreoffice/2025-June/093362.html
Week 4:
https://lists.freedesktop.org/archives/libreoffice/2025-June/093392.html
Week 5:
https://lists.freedesktop.org/archives/libreoffice/2025-June/093443.html
Week 6:
https://lists.freedesktop.org/archives/libreoffice/2025-July/093493.html
Week 7:
https://lists.freedesktop.org/archives/libreoffice/2025-July/093527.html
Week 8:
https://lists.freedesktop.org/archives/libreoffice/2025-July/093572.html
Week 9-10:
https://lists.freedesktop.org/archives/libreoffice/2025-August/093662.html
Week 11:
https://lists.freedesktop.org/archives/libreoffice/2025-August/093694.html
If there is any mistake or something I missed in my understanding do let me
know :)
--
*Regards,*
*Devansh*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/libreoffice/attachments/20250829/fd604b42/attachment.htm>
-------------- next part --------------
GSoC 25: BASIC IDE - Object Browser - Async IDE Launch and Solving UI Crash [WEEK 12 - 13]
Hi everyone,
Following up on our Week 11 report, this update focuses on the primary goal for
the past two weeks: investigating and fixing the "Ghost Parent" UI crash.
After a deep and complex investigation, we may have found the root cause and
have implemented a solution which needs feedback and testing. The bug seems to
a multi-layered problem involving a UI deadlock, a memory-safety
issue, and a loss of application context post fixing it(I will tell below).
Asynchronously launch IDE: https://gerrit.libreoffice.org/c/core/+/189922
Just now the CI is passing which I anticipated. But, I need feedback and testing
from community members and also is this approach even better or not? As of now
to me it seems to be solving the situation and we also noticed a past patch
trying to fix a similar UI situation with "Choose Macros UI" by hiding it -
m_xDialog->hide(); // tdf#126828 dismiss dialog before opening new window
To my understanding there were historically some problems with how IDE was launched.
And what I have also understood is that the BASIC IDE can have only one single
instance throughout the entire application's lifetime which means it is a Singleton.
Which means that the BASIC IDE is not like a normal document. We can open many
Writer documents at once, but we can only have one BASIC IDE window open at a time.
in file basctl/source/basicide/iderdll.cxx - `Shell* GetShell ()`
---------------------------------------------------------------------------
Chapter 1: The Initial Symptom - The "Ghost Window"
The journey began with a UI freeze. When clicking the "Edit" button in the
"Tools > Macros > Edit" dialog without a document open. The IDE was launching
but the parent "BASIC Macros" dialog would remain on screen as a
non-functional "ghost". Clicking this ghost window would crash the application.
Our initial finding was that this was caused by a synchronous deadlock.
The code("Choose Macro") was telling the UI thread to "launch the IDE
and wait", which blocked the thread from doing its other job: closing this window.
Flowchart 1: The Synchronous Deadlock
[UI Thread]
|
v
[User clicks "Edit" -> Synchronous "Launch IDE" command]
|
+------> [This call BLOCKS the entire UI thread...]
|
[Thread is FROZEN, cannot process "close dialog" event]
|
v
+------------------------+
| GHOST WINDOW ON SCREEN |
+------------------------+
Chapter 2: The Mystery of the "New" Button
A key clue was that clicking the "New" button worked fine, even though its
code also used a synchronous launch. We investigated and found that the
"New" button first calls a function, CreateMacro().
This function does a lot of background work, like loading libraries and
modifying the document model. This work accidentally? processed the pending
UI events, preventing the deadlock? This is what I was able to understand
from the code as with "Edit" the IDE was launching immediately but with this
delyaing of operations with "New Button" gave it enough time to process the UI?
So, I am looking for feedback specially how this is going to impact as I not only
have made changes for Fixing the "Edit Button" but also for the "New Button"
since both of the codes were similar in how the IDE should be launched.
The code related to these are in file basctl/source/basicide/macrodlg.cxx -
IMPL_LINK(MacroChooser, ButtonHdl, weld::Button&, rButton, void)
inside this clause -
else if (&rButton == m_xEditButton.get() || &rButton == m_xDelButton.get() || &rButton == m_xNewButton.get())
Chapter 3: The First Fix & A Deeper Bug - Memory Corruption
The obvious fix for this situation was to make the launch asynchronous
("do it later"). This solved the UI freeze, but the CI build started
failing with crashes in other parts of the application which was in `sw`
`cppunit test CppunitTest_sw_a11y failed`
This seems like a classic sign of a `use-after-free memory` bug. The new async
handler was a member of the dialog object. The dialog would schedule the
handler to run later and then immediately close itself. By the time the
handler ran, the dialog object was destroyed, and its this pointer was
invalid, causing memory corruption in the CI? Again how I understand these events.
Chapter 4: The Second Fix & The Final Bug - The Broken UI
To fix the memory corruption, we made the handler `static` as suggested
by the CI error "this member function can be declared static [loplugin:staticmethods]"
A static function is independent and doesn't have a `this` pointer, so it can run
safely after the dialog is destroyed. This fixed the CI crashes.
However, this introduced the final problem: the IDE would launch with a
broken/default? UI with text written in the IDE "Copyright 2012-2017 Jean-Pierre LEDURE"
The UI didn't know which macro to open.
The static handler, while safe, had lost the UI "context".
Which again brings us back to our WEEK 4 mail main highlight "CONTEXT"
> UNO Services and Memes - Why Context Comes First
Flowchart 2: The Flawed Asynchronous Fix
[Dialog] [Event Queue]
|
+---- "Launch IDE" message ----> (Message is queued)
| (with no context)
|
[Dialog is destroyed]
|
v
(Later...) [Static handler runs]
|
v
[Launches a generic IDE]
|
v
+--------------------+
| BROKEN/DEFAULT? UI |
+--------------------+
Chapter 5: The Definitive Solution - Finding the Context
The final challenge was to launch asynchronously and safely, without losing
the context. The solution was a two-step process within the static handler,
especially for the "no document" case:
1. Launch: First, tell the main application to launch the IDE. This
creates the IDE window and its core object, the `basctl::Shell`.
2. Find & Command: After the IDE appears, we use a global function we
discovered, `basctl::GetShell()`, to get a pointer to the newly
created IDE's shell. Now that we have the IDE's specific context, we
can send it the final command telling it which macro to edit.
Flowchart 3: The Correct? Asynchronous Solution
[Dialog] [Event Queue]
|
+---- "Launch IDE" message ----> (Message is queued)
| (with macro info)
|
[Dialog is destroyed]
|
v
(Later...) [Static handler runs]
|
v
1. [Launches a generic IDE]
|
v
2. [Finds new IDE via GetShell()]
|
v
3. [Sends it the macro info]
|
v
+---------------------+
| IDE LOADS CORRECTLY |
+---------------------+
Now regarding the Object Browser I am able to split the code logically but
it is all still in the same one patch for search and navigation buttons.
Based on my mentors feedback the search UI as been improved as of now I am
now we are having grouped search results with a 350ms search delay and now
trying to fix the grouped search expansion bug and there are still some
refinements needs to be done for the navigation buttons the vision I had for
the Navigation Buttons is like how git works making an image of time instance
so they would work exactly like what user selected in the UI and being able to
go backward and forward what they did.
I also made a mistake this week while trying to having a discussion over the
async IDE launch patch I unecessarly sent a really long reply which I made
detailed & refined with an LLM and which isn't how professional 2 way communication
works. Which is not going to happen again :)
Now given the timelines my mentors specially Jonathan suggested for this project's
extension and here is what years of experience make a difference while I was
maybe in overconfidence? estimated that I would be able to resolve all these
situations of bugs and be able to break this patch in multiple chronological patches.
Which I am still far away since this August from the mid I kept dealing
with this libreoffice post mouseEvent crash which wasn't caused by the Object Browser
rather this new time consuming process exposed this pre-existing problem?
So, while solving and investigating this puzzle was interesting, on the other hand I
kinda lost the time which was crucial for at least getting the Object Browser complete.
Hence, his vision and experience has now made things possible to achieve and we have
extended this project.
A major chunk of this project which is Auto Code Suggestion is still remaining and
can be thought as the remaining 35% of this project which has to be done quickly.
https://gerrit.libreoffice.org/c/core/+/186822
I have also attached the Images related to this week's work and a text file.
Images:
BASIC IDE launch without STATIC ASYNC handler - https://bug-attachments.documentfoundation.org/attachment.cgi?id=202573
BASIC IDE launch with STATIC ASYNC handler - https://bug-attachments.documentfoundation.org/attachment.cgi?id=202574
post patch 32 grouped search
https://bug-attachments.documentfoundation.org/attachment.cgi?id=202575
https://bug-attachments.documentfoundation.org/attachment.cgi?id=202576
Previous Updates:
Week 1: https://lists.freedesktop.org/archives/libreoffice/2025-May/093264.html
Weeks 2-3: https://lists.freedesktop.org/archives/libreoffice/2025-June/093362.html
Week 4: https://lists.freedesktop.org/archives/libreoffice/2025-June/093392.html
Week 5: https://lists.freedesktop.org/archives/libreoffice/2025-June/093443.html
Week 6: https://lists.freedesktop.org/archives/libreoffice/2025-July/093493.html
Week 7: https://lists.freedesktop.org/archives/libreoffice/2025-July/093527.html
Week 8: https://lists.freedesktop.org/archives/libreoffice/2025-July/093572.html
Week 9-10: https://lists.freedesktop.org/archives/libreoffice/2025-August/093662.html
Week 11: https://lists.freedesktop.org/archives/libreoffice/2025-August/093694.html
If there is any mistake or something I missed in my understanding do let me know :)
More information about the LibreOffice
mailing list