include/rtl/ustring.h                                 |   16 +-
 sal/CppunitTest_sal_rtl.mk                            |    1 
 sal/qa/rtl/strings/test_strings_defaultstringview.cxx |  118 ++++++++++++++++++
 sal/rtl/strtmpl.cxx                                   |   10 +
 sal/rtl/ustring.cxx                                   |   27 ++--
 5 files changed, 151 insertions(+), 21 deletions(-)

New commits:
commit 142e8ccd3aa14a347f44bd09fa1020b097298140
Author:     Stephan Bergmann <sberg...@redhat.com>
AuthorDate: Fri Nov 20 18:26:43 2020 +0100
Commit:     Stephan Bergmann <sberg...@redhat.com>
CommitDate: Sat Nov 21 13:32:21 2020 +0100

    Relax non-null requirement for some rtl_uString_* functions
    
    ...that take a pointer and a length, and where it should be OK that the 
pointer
    is null if the length is zero.  Those rtl_uString_* functions are targets of
    OUString member functions that take std::[u16]string_view arguments, and
    19926ed35ebb623fc896942b1f232b83edf1fc1e "loplugin:stringview: Flag empty 
string
    converted to string view" (which changed some call sites to pass in default-
    constructed std::[u16]string_view, for which data() returns null) revealed 
that
    those rtl_uString_* functions were not prepared for such input.
    
    (The guardings of memcpy are necessary because memcpy still requires its 
pointer
    arguments to be non-null, even if the corresponding length is zero.)
    
    The new sal/qa/rtl/strings/test_strings_defaultstringview.cxx systematically
    tests all O[U]String[Buffer] member functions taking std::[u16]string_view
    arguments.  It revealed one further issue in
    IMPL_RTL_STRNAME(compare_WithLength), where UBSan reported a
    nullptr-with-nonzero-offset
    
    > sal/rtl/strtmpl.cxx:149:9: runtime error: applying non-zero offset 
18446744073709551614 to null pointer
    
    Also, rtl_uString_newReplaceFirstUtf16LUtf16L was found to lack a check for 
its
    `from` argument to be non-null.
    
    Change-Id: I6a7a712570f7d1e8d52097208c8a43a5a24797af
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/106295
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <sberg...@redhat.com>

diff --git a/include/rtl/ustring.h b/include/rtl/ustring.h
index abd33bb77f15..9e61df974618 100644
--- a/include/rtl/ustring.h
+++ b/include/rtl/ustring.h
@@ -1495,8 +1495,8 @@ SAL_DLLPUBLIC void SAL_CALL rtl_uString_newConcatAsciiL(
 
     @param left a valid string.
 
-    @param right must not be null and must point to memory of at least
-    \p rightLength UTF-16 code units
+    @param right must point to memory of at least \p rightLength UTF-16 code 
units; may be null if
+    \p rigthLength is zero
 
     @param rightLength the length of the \p right string; must be non-negative
 
@@ -1763,13 +1763,13 @@ SAL_DLLPUBLIC void SAL_CALL 
rtl_uString_newReplaceFirstUtf16LAsciiL(
 
     @param str  pointer to the original string; must not be null
 
-    @param from  pointer to the substring to be replaced; must not be null and
-    must point to memory of at least \p fromLength UTF-16 code units
+    @param from  pointer to the substring to be replaced; must point to memory 
of at least
+    \p fromLength UTF-16 code units; may be null if \p toLength is zero
 
     @param fromLength  the length of the \p from substring; must be 
non-negative
 
-    @param to  pointer to the substring to be replaced; must not be null and
-    must point to memory of at least \p toLength UTF-16 code units
+    @param to  pointer to the substring to be replaced; must point to memory 
of at least \p toLength
+    UTF-16 code units; may be null if \p toLength is zero
 
     @param toLength  the length of the \p to substring; must be non-negative
 
@@ -1927,8 +1927,8 @@ SAL_DLLPUBLIC void SAL_CALL 
rtl_uString_newReplaceAllAsciiLAsciiL(
 
     @param fromLength  the length of the \p from substring; must be 
non-negative
 
-    @param to  pointer to the substring to be replaced; must not be null and
-    must point to memory of at least \p toLength UTF-16 code units
+    @param to  pointer to the substring to be replaced; must point to memory 
of at least \p toLength
+    UTF-16 code units; may be null if \p toLength is zero
 
     @param toLength  the length of the \p to substring; must be non-negative
 
diff --git a/sal/CppunitTest_sal_rtl.mk b/sal/CppunitTest_sal_rtl.mk
index f559202c54d5..02b6c94e3d1b 100644
--- a/sal/CppunitTest_sal_rtl.mk
+++ b/sal/CppunitTest_sal_rtl.mk
@@ -31,6 +31,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,sal_rtl,\
        sal/qa/rtl/ref/rtl_ref \
        sal/qa/rtl/strings/nonconstarray \
        sal/qa/rtl/strings/test_strings_replace \
+       sal/qa/rtl/strings/test_strings_defaultstringview \
        sal/qa/rtl/strings/test_ostring \
        sal/qa/rtl/strings/test_ostring_concat \
        sal/qa/rtl/strings/test_ostring_stringliterals \
diff --git a/sal/qa/rtl/strings/test_strings_defaultstringview.cxx 
b/sal/qa/rtl/strings/test_strings_defaultstringview.cxx
new file mode 100644
index 000000000000..a188886e5d49
--- /dev/null
+++ b/sal/qa/rtl/strings/test_strings_defaultstringview.cxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <rtl/string.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+
+namespace
+{
+class Test : public CppUnit::TestFixture
+{
+    void string() { CPPUNIT_ASSERT_EQUAL(OString(), 
OString(std::string_view())); }
+
+    void stringbuffer()
+    {
+        // No functions related to OStringBuffer that take a std::string_view 
or std::u16string_view
+        // argument.
+    }
+
+    void ustring()
+    {
+        CPPUNIT_ASSERT_EQUAL(OUString(), OUString(std::u16string_view()));
+        OUString s1("foo");
+        s1 = std::u16string_view();
+        CPPUNIT_ASSERT_EQUAL(OUString(), s1);
+        OUString s2("foo");
+        s2 += std::u16string_view();
+        CPPUNIT_ASSERT_EQUAL(OUString("foo"), s2);
+        CPPUNIT_ASSERT_GREATER(sal_Int32(0),
+                               
OUString("foo").reverseCompareTo(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(false, 
OUString("foo").equalsIgnoreAsciiCase(std::u16string_view()));
+        CPPUNIT_ASSERT_GREATER(sal_Int32(0),
+                               
OUString("foo").compareToIgnoreAsciiCase(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(true, 
OUString("foo").match(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(true, 
OUString("foo").matchIgnoreAsciiCase(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(true, 
OUString("foo").startsWith(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(true,
+                             
OUString("foo").startsWithIgnoreAsciiCase(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(true, 
OUString("foo").endsWith(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(true, 
OUString("foo").endsWithIgnoreAsciiCase(std::u16string_view()));
+        OUString const foo("foo"); // avoid loplugin:stringconstant
+        CPPUNIT_ASSERT_EQUAL(false, foo == std::u16string_view());
+        CPPUNIT_ASSERT_EQUAL(true, foo != std::u16string_view());
+        CPPUNIT_ASSERT_EQUAL(false, OUString("foo") < std::u16string_view());
+        CPPUNIT_ASSERT_EQUAL(false, OUString("foo") <= std::u16string_view());
+        CPPUNIT_ASSERT_EQUAL(true, OUString("foo") > std::u16string_view());
+        CPPUNIT_ASSERT_EQUAL(true, OUString("foo") >= std::u16string_view());
+        CPPUNIT_ASSERT_EQUAL(false, std::u16string_view() == foo);
+        CPPUNIT_ASSERT_EQUAL(true, std::u16string_view() != foo);
+        CPPUNIT_ASSERT_EQUAL(true, std::u16string_view() < OUString("foo"));
+        CPPUNIT_ASSERT_EQUAL(true, std::u16string_view() <= OUString("foo"));
+        CPPUNIT_ASSERT_EQUAL(false, std::u16string_view() > OUString("foo"));
+        CPPUNIT_ASSERT_EQUAL(false, std::u16string_view() >= OUString("foo"));
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), 
OUString("foo").indexOf(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), 
OUString("foo").lastIndexOf(std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), 
OUString("foo").lastIndexOf(std::u16string_view(), 3));
+        CPPUNIT_ASSERT_EQUAL(
+            OUString("foobarfoo"),
+            OUString("foobarfoo").replaceFirst(std::u16string_view(), 
std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(
+            OUString("barfoo"),
+            OUString("foobarfoo").replaceFirst(std::u16string_view(u"foo"), 
std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(
+            OUString("foobarfoo"),
+            OUString("foobarfoo").replaceFirst(std::u16string_view(), 
std::u16string_view(u"baz")));
+        CPPUNIT_ASSERT_EQUAL(OUString("barfoo"),
+                             OUString("foobarfoo").replaceFirst("foo", 
std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(OUString("foobarfoo"),
+                             
OUString("foobarfoo").replaceFirst(std::u16string_view(), "baz"));
+        CPPUNIT_ASSERT_EQUAL(
+            OUString("foobarfoo"),
+            OUString("foobarfoo").replaceAll(std::u16string_view(), 
std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(
+            OUString("bar"),
+            OUString("foobarfoo").replaceAll(std::u16string_view(u"foo"), 
std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(
+            OUString("foobarfoo"),
+            OUString("foobarfoo").replaceAll(std::u16string_view(), 
std::u16string_view(u"baz")));
+        CPPUNIT_ASSERT_EQUAL(OUString("bar"),
+                             OUString("foobarfoo").replaceAll("foo", 
std::u16string_view()));
+        CPPUNIT_ASSERT_EQUAL(OUString("foobarfoo"),
+                             
OUString("foobarfoo").replaceAll(std::u16string_view(), "baz"));
+        CPPUNIT_ASSERT_EQUAL(OUString(), 
OUString::createFromAscii(std::string_view()));
+    }
+
+    void ustringbuffer()
+    {
+        OUStringBuffer b("foo");
+        b.append(std::u16string_view());
+        CPPUNIT_ASSERT_EQUAL(OUString("foo"), b.toString());
+    }
+
+    CPPUNIT_TEST_SUITE(Test);
+    CPPUNIT_TEST(string);
+    CPPUNIT_TEST(stringbuffer);
+    CPPUNIT_TEST(ustring);
+    CPPUNIT_TEST(ustringbuffer);
+    CPPUNIT_TEST_SUITE_END();
+};
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Test);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sal/rtl/strtmpl.cxx b/sal/rtl/strtmpl.cxx
index 8ff170767b18..082dcd7d3913 100644
--- a/sal/rtl/strtmpl.cxx
+++ b/sal/rtl/strtmpl.cxx
@@ -145,9 +145,13 @@ sal_Int32 SAL_CALL IMPL_RTL_STRNAME( compare_WithLength )( 
const IMPL_RTL_STRCOD
         sal_Int32 nRet = nStr1Len - nStr2Len;
         int nCount = (nRet <= 0) ? nStr1Len : nStr2Len;
 
-        --pStr1;
-        --pStr2;
-        while( (--nCount >= 0) && (*++pStr1 == *++pStr2) ) ;
+        while( --nCount >= 0 ) {
+            if (*pStr1 != *pStr2) {
+                break;
+            }
+            ++pStr1;
+            ++pStr2;
+        }
 
         if( nCount >= 0 )
             nRet = static_cast<sal_Int32>(IMPL_RTL_USTRCODE( *pStr1 ))
diff --git a/sal/rtl/ustring.cxx b/sal/rtl/ustring.cxx
index 7b6687f74bd5..f84e3e1bd2d4 100644
--- a/sal/rtl/ustring.cxx
+++ b/sal/rtl/ustring.cxx
@@ -636,7 +636,7 @@ void rtl_uString_newConcatUtf16L(
 {
     assert(newString != nullptr);
     assert(left != nullptr);
-    assert(right != nullptr);
+    assert(right != nullptr || rightLength == 0);
     assert(rightLength >= 0);
     if (left->length > std::numeric_limits<sal_Int32>::max() - rightLength) {
 #if !defined(__COVERITY__)
@@ -650,9 +650,11 @@ void rtl_uString_newConcatUtf16L(
     sal_Int32 n = left->length + rightLength;
     rtl_uString_assign(newString, left);
     rtl_uString_ensureCapacity(newString, n);
-    memcpy(
-        (*newString)->buffer + (*newString)->length, right,
-        rightLength * sizeof (sal_Unicode));
+    if (rightLength != 0) {
+        memcpy(
+            (*newString)->buffer + (*newString)->length, right,
+            rightLength * sizeof (sal_Unicode));
+    }
     (*newString)->buffer[n] = 0;
     (*newString)->length = n;
 }
@@ -1316,7 +1318,7 @@ void rtl_uString_newReplaceFirstAsciiLUtf16L(
     assert(index != nullptr);
     assert(*index >= 0 && *index <= str->length);
     assert(fromLength >= 0);
-    assert(to != nullptr);
+    assert(to != nullptr || toLength == 0);
     assert(toLength >= 0);
     sal_Int32 i = rtl_ustr_indexOfAscii_WithLength(
         str->buffer + *index, str->length - *index, from, fromLength);
@@ -1338,8 +1340,10 @@ void rtl_uString_newReplaceFirstAsciiLUtf16L(
                 assert(i >= 0 && i < str->length);
                 memcpy(
                     (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
-                memcpy(
-                    (*newStr)->buffer + i, to, toLength * sizeof 
(sal_Unicode));
+                if (toLength != 0) {
+                    memcpy(
+                        (*newStr)->buffer + i, to, toLength * sizeof 
(sal_Unicode));
+                }
                 memcpy(
                     (*newStr)->buffer + i + toLength,
                     str->buffer + i + fromLength,
@@ -1405,8 +1409,9 @@ void rtl_uString_newReplaceFirstUtf16LUtf16L(
     assert(str != nullptr);
     assert(index != nullptr);
     assert(*index >= 0 && *index <= str->length);
+    assert(from != nullptr || fromLength == 0);
     assert(fromLength >= 0);
-    assert(to != nullptr);
+    assert(to != nullptr || toLength == 0);
     assert(toLength >= 0);
     sal_Int32 i = rtl_ustr_indexOfStr_WithLength(
         str->buffer + *index, str->length - *index, from, fromLength);
@@ -1428,8 +1433,10 @@ void rtl_uString_newReplaceFirstUtf16LUtf16L(
                 assert(i >= 0 && i < str->length);
                 memcpy(
                     (*newStr)->buffer, str->buffer, i * sizeof (sal_Unicode));
-                memcpy(
-                    (*newStr)->buffer + i, to, toLength * sizeof 
(sal_Unicode));
+                if (toLength != 0) {
+                    memcpy(
+                        (*newStr)->buffer + i, to, toLength * sizeof 
(sal_Unicode));
+                }
                 memcpy(
                     (*newStr)->buffer + i + toLength,
                     str->buffer + i + fromLength,
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to