This is an automated email from the ASF dual-hosted git repository.

ardovm pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 8604ca21f9283f811f592bd95847a6002173ce6e
Author: Peter Kovacs <[email protected]>
AuthorDate: Sat Aug 1 12:53:44 2026 +0200

    sw: ww8: validate PLCF length
    
    Add an inline WW8PLCF::IsValidLength() predicate and call it at the
    entry of both WW8PLCF::ReadPLCF and the WW8PLCFspecial constructor.
    
    Add GoogleTest_sw_ww8plcf covering the boundary values.
    
    Thanks to Yukihiro Nakamura ([email protected])
    
    Co-authored-by: Yukihiro Nakamura ([email protected])
    Co-Authored-By: Claude Opus 5 <[email protected]>
---
 main/sw/{Module_sw.mk => GoogleTest_sw_ww8plcf.mk} | 42 ++++++------
 main/sw/Module_sw.mk                               |  1 +
 main/sw/source/filter/ww8/qa/ww8plcf_test.cxx      | 78 ++++++++++++++++++++++
 main/sw/source/filter/ww8/ww8scan.cxx              | 15 +++++
 main/sw/source/filter/ww8/ww8scan.hxx              |  3 +
 5 files changed, 116 insertions(+), 23 deletions(-)

diff --git a/main/sw/Module_sw.mk b/main/sw/GoogleTest_sw_ww8plcf.mk
similarity index 59%
copy from main/sw/Module_sw.mk
copy to main/sw/GoogleTest_sw_ww8plcf.mk
index 5465500bca..5ffedcc35a 100644
--- a/main/sw/Module_sw.mk
+++ b/main/sw/GoogleTest_sw_ww8plcf.mk
@@ -20,34 +20,30 @@
 #**************************************************************
 
 
+$(eval $(call gb_GoogleTest_GoogleTest,sw_ww8plcf))
 
-$(eval $(call gb_Module_Module,sw))
-
-$(eval $(call gb_Module_add_targets,sw,\
-       AllLangResTarget_sw \
-       Library_msword \
-       Library_sw \
-       Library_swd \
-       Library_swui \
-       Library_vbaswobj \
-       Package_misc \
-       Package_uiconfig \
-       Package_xml \
+$(eval $(call gb_GoogleTest_add_exception_objects,sw_ww8plcf, \
+       sw/source/filter/ww8/qa/ww8plcf_test \
 ))
 
-
-ifeq ($(ENABLE_UNIT_TESTS),YES)
-$(eval $(call gb_Module_add_check_targets,sw,\
-       GoogleTest_sw_bigpointerarray \
+# WW8PLCF::IsValidLength is inline and references only compile-time constants,
+# so the test compiles against the ww8 filter headers without linking msword.
+$(eval $(call gb_GoogleTest_add_linked_libs,sw_ww8plcf, \
+    sal \
+    stl \
+    sw \
+    tl \
+    $(gb_STDLIBS) \
 ))
-endif
-
 
-ifneq ($(OOO_JUNIT_JAR),)
-$(eval $(call gb_Module_add_subsequentcheck_targets,sw,\
-       JunitTest_sw_complex \
-       JunitTest_sw_unoapi \
+$(eval $(call gb_GoogleTest_set_include,sw_ww8plcf,\
+       $$(INCLUDE) \
+       -I$(SRCDIR)/sw/inc \
+       -I$(SRCDIR)/sw/inc/pch \
+       -I$(SRCDIR)/sw/source/filter/inc \
+       -I$(SRCDIR)/sw/source/filter/ww8 \
+       -I$(OUTDIR)/inc/offuh \
+       -I$(OUTDIR)/inc \
 ))
-endif
 
 # vim: set noet sw=4 ts=4:
diff --git a/main/sw/Module_sw.mk b/main/sw/Module_sw.mk
index 5465500bca..eda7a25d88 100644
--- a/main/sw/Module_sw.mk
+++ b/main/sw/Module_sw.mk
@@ -39,6 +39,7 @@ $(eval $(call gb_Module_add_targets,sw,\
 ifeq ($(ENABLE_UNIT_TESTS),YES)
 $(eval $(call gb_Module_add_check_targets,sw,\
        GoogleTest_sw_bigpointerarray \
+       GoogleTest_sw_ww8plcf \
 ))
 endif
 
diff --git a/main/sw/source/filter/ww8/qa/ww8plcf_test.cxx 
b/main/sw/source/filter/ww8/qa/ww8plcf_test.cxx
new file mode 100644
index 0000000000..c20a795e1a
--- /dev/null
+++ b/main/sw/source/filter/ww8/qa/ww8plcf_test.cxx
@@ -0,0 +1,78 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+// Regression test for WW8PLCF::IsValidLength, the length guard shared by
+// WW8PLCF::ReadPLCF and the WW8PLCFspecial constructor (ww8scan.cxx).
+
+#include "gtest/gtest.h"
+
+#include "ww8scan.hxx"     // WW8PLCF::IsValidLength (inline, no filter link)
+#include "ww8struc.hxx"    // WW8_CP_MAX
+#include <sal/types.h>
+
+// Non-positive count must be rejected.
+TEST(WW8Plcf, IsValidLengthRejectsNegativeAndZero)
+{
+    EXPECT_FALSE( WW8PLCF::IsValidLength( -1 ) );          // 0xFFFFFFFF 
narrowed
+    EXPECT_FALSE( WW8PLCF::IsValidLength( 0 ) );
+    EXPECT_FALSE( WW8PLCF::IsValidLength( -64 ) );
+    EXPECT_FALSE( WW8PLCF::IsValidLength( SAL_MIN_INT32 ) );
+}
+
+// Lengths close to the maximum must be rejected too
+TEST(WW8Plcf, IsValidLengthRejectsOverflowingUpperRange)
+{
+    EXPECT_FALSE( WW8PLCF::IsValidLength( WW8_CP_MAX ) );
+    EXPECT_FALSE( WW8PLCF::IsValidLength( WW8_CP_MAX - 1 ) );
+    EXPECT_FALSE( WW8PLCF::IsValidLength( WW8_CP_MAX - 3 ) );
+}
+
+// Genuine lengths are accepted
+TEST(WW8Plcf, IsValidLengthAcceptsBenignLengths)
+{
+    EXPECT_TRUE( WW8PLCF::IsValidLength( 1 ) );
+    EXPECT_TRUE( WW8PLCF::IsValidLength( 12 ) );
+    EXPECT_TRUE( WW8PLCF::IsValidLength( 64 ) );
+    EXPECT_TRUE( WW8PLCF::IsValidLength( WW8_CP_MAX - 4 ) );   // largest 
accepted
+}
+
+// For every accepted length, the element count both readers allocate is
+// large enough to hold the nPLCF bytes the subsequent Read copies in.
+TEST(WW8Plcf, AcceptedLengthSizesBufferToHoldRead)
+{
+    const sal_Int32 aLens[] = { 1, 3, 4, 5, 12, 64, 4096, WW8_CP_MAX - 4 };
+    for ( size_t i = 0; i < sizeof(aLens) / sizeof(aLens[0]); ++i )
+    {
+        const sal_Int32 nPLCF = aLens[i];
+        ASSERT_TRUE( WW8PLCF::IsValidLength( nPLCF ) );
+        // Done in 64-bit to model the allocation without itself overflowing.
+        const sal_Int64 nElems         = ( static_cast<sal_Int64>(nPLCF) + 3 ) 
/ 4;
+        const sal_Int64 nCapacityBytes = nElems * 4;   // sizeof(WW8_CP) == 4
+        EXPECT_GT( nElems, 0 );
+        EXPECT_GE( nCapacityBytes, static_cast<sal_Int64>(nPLCF) );
+    }
+}
+
+int main( int argc, char** argv )
+{
+    ::testing::InitGoogleTest( &argc, argv );
+    return RUN_ALL_TESTS();
+}
diff --git a/main/sw/source/filter/ww8/ww8scan.cxx 
b/main/sw/source/filter/ww8/ww8scan.cxx
index 250ca6f65b..40667c826d 100644
--- a/main/sw/source/filter/ww8/ww8scan.cxx
+++ b/main/sw/source/filter/ww8/ww8scan.cxx
@@ -2208,6 +2208,15 @@ WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, long 
nFilePos, long nPLCF,
     long nStruct, long nStartPos)
     : nIdx(0), nStru(nStruct)
 {
+    if (!WW8PLCF::IsValidLength(static_cast<sal_Int32>(nPLCF)))
+    {
+        nIMax = 0;
+        pPLCF_PosArray = new sal_Int32[1];
+        pPLCF_PosArray[0] = WW8_CP_MAX;
+        pPLCF_Contents = 0;
+        return;
+    }
+
     nIMax = ( nPLCF - 4 ) / ( 4 + nStruct );
     // Pointer auf Pos- u. Struct-Array
     pPLCF_PosArray = new sal_Int32[ ( nPLCF + 3 ) / 4 ];
@@ -2382,6 +2391,12 @@ void WW8PLCF::ReadPLCF( SvStream* pSt, WW8_FC nFilePos, 
sal_Int32 nPLCF )
 {
     bool failure = false;
 
+    if (!IsValidLength(nPLCF))
+    {
+        MakeFailedPLCF();
+        return;
+    }
+
     // Pointer auf Pos-Array
     pPLCF_PosArray = new WW8_CP[ ( nPLCF + 3 ) / 4 ];
 
diff --git a/main/sw/source/filter/ww8/ww8scan.hxx 
b/main/sw/source/filter/ww8/ww8scan.hxx
index 72f154623a..19eff0af3f 100644
--- a/main/sw/source/filter/ww8/ww8scan.hxx
+++ b/main/sw/source/filter/ww8/ww8scan.hxx
@@ -291,6 +291,9 @@ private:
 
     void MakeFailedPLCF();
 public:
+    static bool IsValidLength( sal_Int32 nPLCF )
+    { return nPLCF >= 1 && nPLCF <= ( WW8_CP_MAX - 4 ); }
+
     WW8PLCF( SvStream* pSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct,
         WW8_CP nStartPos = -1 );
 

Reply via email to