Fix segfaults with String and ByteVector nullptr arguments (#1247) (#1248)

This commit is contained in:
Urs Fleisch 2024-11-02 06:39:21 +01:00 committed by GitHub
parent e3de03501f
commit 5b6f9ef848
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 206 additions and 19 deletions

View File

@ -158,7 +158,7 @@ ByteVector fromNumber(T value, bool mostSignificantByteFirst)
template <typename TFloat, typename TInt, Utils::ByteOrder ENDIAN>
TFloat toFloat(const ByteVector &v, size_t offset)
{
if(offset > v.size() - sizeof(TInt)) {
if(offset + sizeof(TInt) > v.size()) {
debug("toFloat() - offset is out of range. Returning 0.");
return 0.0;
}
@ -195,7 +195,7 @@ long double toFloat80(const ByteVector &v, size_t offset)
{
using std::swap;
if(offset > v.size() - 10) {
if(offset + 10 > v.size()) {
debug("toFloat80() - offset is out of range. Returning 0.");
return 0.0;
}
@ -360,7 +360,7 @@ ByteVector::ByteVector(const char *data, unsigned int length) :
}
ByteVector::ByteVector(const char *data) :
d(std::make_unique<ByteVectorPrivate>(data, static_cast<unsigned int>(::strlen(data))))
d(std::make_unique<ByteVectorPrivate>(data, data ? static_cast<unsigned int>(::strlen(data)) : 0))
{
}
@ -767,6 +767,9 @@ bool ByteVector::operator!=(const ByteVector &v) const
bool ByteVector::operator==(const char *s) const
{
if(!s)
return isEmpty();
if(size() != ::strlen(s))
return false;

View File

@ -195,23 +195,27 @@ String::String(const wchar_t *s) :
String::String(const wchar_t *s, Type t) :
d(std::make_shared<StringPrivate>())
{
if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
copyFromUTF16(d->data, s, ::wcslen(s), t);
}
else {
debug("String::String() -- const wchar_t * should not contain Latin1 or UTF-8.");
if(s) {
if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
copyFromUTF16(d->data, s, ::wcslen(s), t);
}
else {
debug("String::String() -- const wchar_t * should not contain Latin1 or UTF-8.");
}
}
}
String::String(const char *s, Type t) :
d(std::make_shared<StringPrivate>())
{
if(t == Latin1)
copyFromLatin1(d->data, s, ::strlen(s));
else if(t == String::UTF8)
copyFromUTF8(d->data, s, ::strlen(s));
else {
debug("String::String() -- const char * should not contain UTF16.");
if(s) {
if(t == Latin1)
copyFromLatin1(d->data, s, ::strlen(s));
else if(t == String::UTF8)
copyFromUTF8(d->data, s, ::strlen(s));
else {
debug("String::String() -- const char * should not contain UTF16.");
}
}
}
@ -546,6 +550,10 @@ bool String::operator!=(const String &s) const
bool String::operator==(const char *s) const
{
if(!s) {
return isEmpty();
}
const wchar_t *p = toCWString();
while(*p != L'\0' || *s != '\0') {
@ -562,6 +570,10 @@ bool String::operator!=(const char *s) const
bool String::operator==(const wchar_t *s) const
{
if(!s) {
return isEmpty();
}
return d->data == s;
}
@ -580,18 +592,22 @@ String &String::operator+=(const String &s)
String &String::operator+=(const wchar_t *s)
{
detach();
if(s) {
detach();
d->data += s;
d->data += s;
}
return *this;
}
String &String::operator+=(const char *s)
{
detach();
if(s) {
detach();
for(int i = 0; s[i] != 0; i++)
d->data += static_cast<unsigned char>(s[i]);
for(int i = 0; s[i] != 0; i++)
d->data += static_cast<unsigned char>(s[i]);
}
return *this;
}

View File

@ -23,6 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <cstring>
#define _USE_MATH_DEFINES
#include <cmath>
@ -53,6 +54,7 @@ class TestByteVector : public CppUnit::TestFixture
CPPUNIT_TEST(testAppend1);
CPPUNIT_TEST(testAppend2);
CPPUNIT_TEST(testBase64);
CPPUNIT_TEST(testEmpty);
CPPUNIT_TEST_SUITE_END();
public:
@ -612,6 +614,94 @@ public:
}
void testEmpty()
{
const ByteVector empty;
const ByteVector notEmpty("A");
ByteVector mutEmpty;
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(""));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector("", 0));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(0U));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(empty, 0, 0));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(notEmpty, 1, 0));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(static_cast<const char *>(nullptr), 0));
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData("", 0), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData(""), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData(nullptr, 0), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData(nullptr), empty);
CPPUNIT_ASSERT(!empty.data());
CPPUNIT_ASSERT(!mutEmpty.data());
CPPUNIT_ASSERT_EQUAL(empty.mid(0), empty);
CPPUNIT_ASSERT_EQUAL(empty.at(0), '\0');
// Note that the behavior of ByteVector::find() with an empty pattern is
// not consistent with String::find() and std::string::find().
CPPUNIT_ASSERT_EQUAL(empty.find(mutEmpty), -1);
CPPUNIT_ASSERT_EQUAL(empty.find(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.find(empty), -1);
CPPUNIT_ASSERT_EQUAL(empty.find('\0'), -1);
CPPUNIT_ASSERT_EQUAL(empty.rfind(mutEmpty), -1);
CPPUNIT_ASSERT_EQUAL(empty.rfind(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.rfind(empty), -1);
CPPUNIT_ASSERT_EQUAL(empty.containsAt(mutEmpty, 0), false);
CPPUNIT_ASSERT_EQUAL(empty.startsWith(mutEmpty), false);
CPPUNIT_ASSERT_EQUAL(empty.startsWith(notEmpty), false);
CPPUNIT_ASSERT_EQUAL(notEmpty.startsWith(empty), false);
CPPUNIT_ASSERT_EQUAL(empty.endsWith(mutEmpty), false);
CPPUNIT_ASSERT_EQUAL(empty.endsWithPartialMatch(mutEmpty), -1);
CPPUNIT_ASSERT_EQUAL(mutEmpty.replace('a', 'b'), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.replace("abc", ""), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(empty), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(notEmpty), notEmpty);
mutEmpty.clear();
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(ByteVector(notEmpty).append(empty), notEmpty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append('A'), notEmpty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.resize(0), empty);
CPPUNIT_ASSERT_EQUAL(empty.size(), 0U);
CPPUNIT_ASSERT(empty.begin() == empty.end());
CPPUNIT_ASSERT(empty.cbegin() == empty.cend());
CPPUNIT_ASSERT(empty.rbegin() == empty.rend());
CPPUNIT_ASSERT(mutEmpty.begin() == mutEmpty.end());
CPPUNIT_ASSERT(mutEmpty.rbegin() == mutEmpty.rend());
CPPUNIT_ASSERT(empty.isEmpty());
CPPUNIT_ASSERT_EQUAL(empty.toUInt(), 0U);
CPPUNIT_ASSERT_EQUAL(empty.toUInt(0, true), 0U);
CPPUNIT_ASSERT_EQUAL(empty.toUInt(0, 0, true), 0U);
CPPUNIT_ASSERT_EQUAL(empty.toShort(), static_cast<short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toShort(0, true), static_cast<short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toUShort(), static_cast<unsigned short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toUShort(0, true), static_cast<unsigned short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toLongLong(), 0LL);
CPPUNIT_ASSERT_EQUAL(empty.toLongLong(0, true), 0LL);
CPPUNIT_ASSERT_EQUAL(empty.toULongLong(), 0ULL);
CPPUNIT_ASSERT_EQUAL(empty.toULongLong(0, true), 0ULL);
CPPUNIT_ASSERT_EQUAL(empty.toFloat32LE(0), 0.f);
CPPUNIT_ASSERT_EQUAL(empty.toFloat32BE(0), 0.f);
CPPUNIT_ASSERT_EQUAL(empty.toFloat64LE(0), 0.);
CPPUNIT_ASSERT_EQUAL(empty.toFloat64BE(0), 0.);
CPPUNIT_ASSERT_EQUAL(empty.toFloat80LE(0), 0.l);
CPPUNIT_ASSERT_EQUAL(empty.toFloat80BE(0), 0.l);
CPPUNIT_ASSERT(empty == mutEmpty);
CPPUNIT_ASSERT(empty != notEmpty);
CPPUNIT_ASSERT(empty == "");
CPPUNIT_ASSERT(empty != " ");
CPPUNIT_ASSERT(empty == static_cast<const char *>(nullptr));
CPPUNIT_ASSERT(!(empty != static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT(empty < notEmpty);
CPPUNIT_ASSERT(!(empty > notEmpty));
CPPUNIT_ASSERT_EQUAL(empty + mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty + notEmpty, notEmpty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = static_cast<const char *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = notEmpty, notEmpty);
ByteVector tmp;
mutEmpty.swap(tmp);
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty.toHex(), empty);
CPPUNIT_ASSERT_EQUAL(empty.toBase64(), empty);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVector);

View File

@ -23,9 +23,12 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <string>
#include <cstring>
#include "tstring.h"
#include "tstringlist.h"
#include "tbytevector.h"
#include "tutils.h"
#include <cppunit/extensions/HelperMacros.h>
@ -54,6 +57,7 @@ class TestString : public CppUnit::TestFixture
CPPUNIT_TEST(testEncodeNonBMP);
CPPUNIT_TEST(testIterator);
CPPUNIT_TEST(testInvalidUTF8);
CPPUNIT_TEST(testEmpty);
CPPUNIT_TEST_SUITE_END();
public:
@ -370,6 +374,80 @@ public:
CPPUNIT_ASSERT(String(ByteVector("\xED\xB0\x80\xED\xA0\x80"), String::UTF8).isEmpty());
}
void testEmpty()
{
const String empty;
const String notEmpty("A");
String mutEmpty;
CPPUNIT_ASSERT_EQUAL(empty, String(""));
CPPUNIT_ASSERT_EQUAL(empty, String(std::wstring()));
CPPUNIT_ASSERT_EQUAL(empty, String(static_cast<const wchar_t *>(nullptr)));
CPPUNIT_ASSERT(empty != String('\0'));
CPPUNIT_ASSERT_EQUAL(empty, String(L'\0'));
CPPUNIT_ASSERT_EQUAL(empty, String(static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT_EQUAL(empty, String(ByteVector()));
CPPUNIT_ASSERT_EQUAL(empty.to8Bit(), std::string());
CPPUNIT_ASSERT_EQUAL(empty.toWString(), std::wstring());
CPPUNIT_ASSERT_EQUAL(::strlen(empty.toCString()), (size_t)0);
CPPUNIT_ASSERT_EQUAL(::wcslen(empty.toCWString()), (size_t)0);
CPPUNIT_ASSERT(empty.begin() == empty.end());
CPPUNIT_ASSERT(empty.cbegin() == empty.cend());
CPPUNIT_ASSERT(mutEmpty.begin() == mutEmpty.end());
CPPUNIT_ASSERT_EQUAL(empty.find(mutEmpty), 0);
CPPUNIT_ASSERT_EQUAL(empty.find(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.find(empty), 0);
CPPUNIT_ASSERT_EQUAL(empty.rfind(mutEmpty), 0);
CPPUNIT_ASSERT_EQUAL(empty.rfind(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.rfind(empty), 1);
CPPUNIT_ASSERT_EQUAL(empty.split(), StringList(empty));
CPPUNIT_ASSERT_EQUAL(empty.startsWith(mutEmpty), true);
CPPUNIT_ASSERT_EQUAL(empty.startsWith(notEmpty), false);
CPPUNIT_ASSERT_EQUAL(notEmpty.startsWith(empty), true);
CPPUNIT_ASSERT_EQUAL(empty.substr(0), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(empty), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(notEmpty), notEmpty);
mutEmpty.clear();
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(String(notEmpty).append(empty), notEmpty);
CPPUNIT_ASSERT_EQUAL(empty.upper(), empty);
CPPUNIT_ASSERT_EQUAL(empty.size(), 0U);
CPPUNIT_ASSERT_EQUAL(empty.length(), 0U);
CPPUNIT_ASSERT_EQUAL(empty.isEmpty(), true);
CPPUNIT_ASSERT_EQUAL(empty.data(String::Latin1), ByteVector());
CPPUNIT_ASSERT_EQUAL(empty.data(String::UTF16LE), ByteVector());
bool ok;
empty.toInt(&ok);
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(empty.stripWhiteSpace(), empty);
CPPUNIT_ASSERT_EQUAL(empty.isLatin1(), true);
CPPUNIT_ASSERT_EQUAL(empty.isAscii(), true);
CPPUNIT_ASSERT(empty == mutEmpty);
CPPUNIT_ASSERT(empty != notEmpty);
CPPUNIT_ASSERT(empty == "");
CPPUNIT_ASSERT(empty != " ");
CPPUNIT_ASSERT(empty == L"");
CPPUNIT_ASSERT(empty != L" ");
CPPUNIT_ASSERT(empty == static_cast<const char *>(nullptr));
CPPUNIT_ASSERT(!(empty != static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT(empty == static_cast<const wchar_t *>(nullptr));
CPPUNIT_ASSERT(!(empty != static_cast<const wchar_t *>(nullptr)));
CPPUNIT_ASSERT_EQUAL(mutEmpty += empty, empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty += notEmpty, notEmpty);
mutEmpty.clear();
CPPUNIT_ASSERT_EQUAL(mutEmpty += static_cast<const char *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty += static_cast<const wchar_t *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = static_cast<const char *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = static_cast<const wchar_t *>(nullptr), empty);
String tmp;
mutEmpty.swap(tmp);
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty < notEmpty, true);
CPPUNIT_ASSERT_EQUAL(empty + mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty + notEmpty, notEmpty);
CPPUNIT_ASSERT_EQUAL(empty + static_cast<const char *>(nullptr), empty);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestString);