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