summaryrefslogtreecommitdiff
path: root/sal
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2020-11-20 18:26:43 +0100
committerStephan Bergmann <sbergman@redhat.com>2020-11-21 13:32:21 +0100
commit142e8ccd3aa14a347f44bd09fa1020b097298140 (patch)
tree6fd02f6b694460539020844991ad248bacd1b0d8 /sal
parent01baeab99890e5650b3dabc15f8d900490a5a133 (diff)
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 <sbergman@redhat.com>
Diffstat (limited to 'sal')
-rw-r--r--sal/CppunitTest_sal_rtl.mk1
-rw-r--r--sal/qa/rtl/strings/test_strings_defaultstringview.cxx118
-rw-r--r--sal/rtl/strtmpl.cxx10
-rw-r--r--sal/rtl/ustring.cxx27
4 files changed, 143 insertions, 13 deletions
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,