sw/qa/uibase/shells/data/tracked-change-in-unused-first-page-header.docx 
|binary
 sw/qa/uibase/shells/shells.cxx                                           |   
29 ++++++++++
 sw/source/uibase/uno/loktxdoc.cxx                                        |    
4 +
 3 files changed, 33 insertions(+)

New commits:
commit 3ac3d45fa0350af9b5b0b4af56c04fcdc2292923
Author:     Mike Kaganski <[email protected]>
AuthorDate: Mon Mar 2 17:43:24 2026 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Mon Mar 2 19:26:55 2026 +0100

    LOK Extract API: avoid crash on orphaned redlines
    
    The test document contains tracked changes in the header of the first
    page, but the import creates a page style without a separate first page
    header, so that header is not actually used in the document. The tracked
    changes are not removed from the document (they are kept in document
    nodes, as well as the now-unused header). The redlines are visible in
    the UI (Manage Changes dialog shows four changes: two for the shared
    header, and two for orphaned header; clicking the orphaned elements does
    not navigate to them). Interesting, that save-and-reload gets rid of the
    redlines.
    
    The problem used to be, that "ExtractDocumentStructure" command crashed,
    when tried to dereference orphaned redline's XText (its parent XText was
    empty, defined by sw::CreateParentXText).
    
    It is unclear to me, what is the correct behavior here:
    - Maybe we should preserve the separate first header (and its redlines);
    - Maybe we should drop the unused nodes (header and its redlines);
    - Maybe we just need to handle the orphaned redlines without a crash.
    
    Here I implemented the last option.
    
    Change-Id: Ibddc5d73e440e14b288021717193530a1e26bee1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200825
    Reviewed-by: Mike Kaganski <[email protected]>
    Tested-by: Jenkins

diff --git 
a/sw/qa/uibase/shells/data/tracked-change-in-unused-first-page-header.docx 
b/sw/qa/uibase/shells/data/tracked-change-in-unused-first-page-header.docx
new file mode 100644
index 000000000000..fd3171c46be4
Binary files /dev/null and 
b/sw/qa/uibase/shells/data/tracked-change-in-unused-first-page-header.docx 
differ
diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 5855d4570306..ec57b28b9d6c 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -1030,6 +1030,35 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testDocumentStructureExtractRedlines)
     CPPUNIT_ASSERT(bool(it == docStructure.end()));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testDocumentStructureExtractRedlines_UnusedFirstPageHeader)
+{
+    // The document contains tracked changes in the header of the first page, 
but the import code
+    // eventually creates a page style without a separate first page header, 
so that header is not
+    // actually used in the document. The tracked changes are not removed from 
the document (they
+    // are kept in document nodes, as well as the nodes of the now-unused 
header). Interesting,
+    // that save-and-reload gets rid of the redlines.
+    //
+    // The problem used to be, that collecting redlines for the 
"ExtractDocumentStructure" command
+    // crashed, when tried to dereference orphaned redline's XText 
unconditionally (its parent
+    // XText was empty, defined by sw::CreateParentXText).
+    //
+    // It is unclear to me, what is the correct behavior here:
+    // - Maybe we should preserve the separate first header (and its redlines);
+    // - Maybe we should make sure to drop the unused nodes (header and its 
redlines);
+    // - Maybe we just need to handle the orphaned redlines without a crash.
+    //
+    // Here I only check that the document doesn't crash (no test of count of 
redlines, nor their
+    // properties).
+
+    createSwDoc("tracked-change-in-unused-first-page-header.docx");
+
+    tools::JsonWriter aJsonWriter;
+    // Before the fix, this crashed:
+    getSwTextDoc()->getCommandValues(aJsonWriter,
+                                     
".uno:ExtractDocumentStructure?filter=trackchanges");
+    aJsonWriter.finishAndGetAsOString(); // writer must be finished
+}
+
 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testDocumentStructureExtractRedlines_textBeforeAfter)
 {
     // The document here has a series of insert/delete/format changes having 
different times.
diff --git a/sw/source/uibase/uno/loktxdoc.cxx 
b/sw/source/uibase/uno/loktxdoc.cxx
index 5fa3ad62fff9..dfbd052b81c9 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -1014,8 +1014,12 @@ void GetDocStructureTrackChanges(tools::JsonWriter& 
rJsonWriter, SwDocShell* pDo
             HideNewerShowOlder 
prepare(pSwXRedline->GetRedline()->GetTimeStamp(), rTable);
             auto xStart = pSwXRedline->getPropertyValue(UNO_NAME_REDLINE_START)
                               .query<css::text::XTextRange>();
+            if (xStart && !xStart->getText())
+                xStart.clear();
             auto xEnd = pSwXRedline->getPropertyValue(UNO_NAME_REDLINE_END)
                             .query<css::text::XTextRange>();
+            if (xEnd && !xEnd->getText())
+                xEnd.clear();
             if (xStart)
             {
                 auto xCursor = 
xStart->getText()->createTextCursorByRange(xStart);

Reply via email to