From 218604196afb8f7bc142ab94af6e9cafdf5327b2 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 11 Jan 2022 16:31:56 -0500 Subject: [PATCH] libroot: Fix ICU locale implementation of wcsxfrm. * The "size" parameter is the size of "out" not "in", and the return size_t parameter is supposed to always have the total amount of wchar_ts needed, not how many are actually used. * In the case where "outSize == 0", we set "requiredSize" and then return. Fixes crashes seen in glib2 Unicode collation routines, which are used in GTK file dialogs. Thanks to PulkoMandy for glancing at this. --- headers/private/libroot/locale/ICUCollateData.h | 2 +- headers/private/libroot/locale/ICULocaleBackend.h | 2 +- headers/private/libroot/locale/LocaleBackend.h | 2 +- src/system/libroot/add-ons/icu/ICUCollateData.cpp | 15 +++++++++------ .../libroot/add-ons/icu/ICULocaleBackend.cpp | 6 +++--- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/headers/private/libroot/locale/ICUCollateData.h b/headers/private/libroot/locale/ICUCollateData.h index fe1c8a2b04..fd481f3f71 100644 --- a/headers/private/libroot/locale/ICUCollateData.h +++ b/headers/private/libroot/locale/ICUCollateData.h @@ -33,7 +33,7 @@ public: status_t Wcscoll(const wchar_t* a, const wchar_t* b, int& out); status_t Wcsxfrm(wchar_t* out, const wchar_t* in, - size_t size, size_t& outSize); + size_t outSize, size_t& requiredSize); private: status_t _ToUnicodeString(const char* in, diff --git a/headers/private/libroot/locale/ICULocaleBackend.h b/headers/private/libroot/locale/ICULocaleBackend.h index 1d5f5f4807..93e4d9f819 100644 --- a/headers/private/libroot/locale/ICULocaleBackend.h +++ b/headers/private/libroot/locale/ICULocaleBackend.h @@ -64,7 +64,7 @@ public: virtual status_t Wcscoll(const wchar_t* a, const wchar_t* b, int& out); virtual status_t Wcsxfrm(wchar_t* out, const wchar_t* in, - size_t size, size_t& outSize); + size_t outSize, size_t& requiredSize); virtual status_t TZSet(const char* timeZoneID, const char* tz); virtual status_t Localtime(const time_t* inTime, diff --git a/headers/private/libroot/locale/LocaleBackend.h b/headers/private/libroot/locale/LocaleBackend.h index eb4fc8e8eb..38798b366b 100644 --- a/headers/private/libroot/locale/LocaleBackend.h +++ b/headers/private/libroot/locale/LocaleBackend.h @@ -147,7 +147,7 @@ public: virtual status_t Wcscoll(const wchar_t* a, const wchar_t* b, int& out) = 0; virtual status_t Wcsxfrm(wchar_t* out, const wchar_t* in, - size_t size, size_t& outSize) = 0; + size_t outSize, size_t& requiredSize) = 0; virtual status_t TZSet(const char* timeZoneID, const char* tz) = 0; diff --git a/src/system/libroot/add-ons/icu/ICUCollateData.cpp b/src/system/libroot/add-ons/icu/ICUCollateData.cpp index 4c32b11326..ce3466a880 100644 --- a/src/system/libroot/add-ons/icu/ICUCollateData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCollateData.cpp @@ -174,18 +174,18 @@ ICUCollateData::Wcscoll(const wchar_t* a, const wchar_t* b, int& result) status_t -ICUCollateData::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size, - size_t& outSize) +ICUCollateData::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t outSize, + size_t& requiredSize) { if (in == NULL) { - outSize = 0; + requiredSize = 0; return B_OK; } if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) { // handle POSIX here as the collator ICU uses for that (english) is // incompatible in too many ways - outSize = wcslcpy(out, in, size); + requiredSize = wcslcpy(out, in, outSize); for (const wchar_t* inIter = in; *inIter != 0; ++inIter) { if (*inIter > 127) return B_BAD_VALUE; @@ -194,10 +194,13 @@ ICUCollateData::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size, } UnicodeString unicodeIn = UnicodeString::fromUTF32((UChar32*)in, -1); - size_t requiredSize = fCollator->getSortKey(unicodeIn, NULL, 0); + requiredSize = fCollator->getSortKey(unicodeIn, NULL, 0); + + if (outSize == 0) + return B_OK; uint8_t* buffer = (uint8_t*)out; - outSize = fCollator->getSortKey(unicodeIn, buffer, requiredSize); + fCollator->getSortKey(unicodeIn, buffer, outSize); // convert 1-byte characters to 4-byte wide characters: for (size_t i = 0; i < outSize; ++i) diff --git a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp index a1c45b705a..5dccc60f7f 100644 --- a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp +++ b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp @@ -308,12 +308,12 @@ ICULocaleBackend::Wcscoll(const wchar_t* a, const wchar_t* b, int& result) status_t -ICULocaleBackend::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size, - size_t& outSize) +ICULocaleBackend::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t outSize, + size_t& requiredSize) { ErrnoMaintainer errnoMaintainer; - return fCollateData.Wcsxfrm(out, in, size, outSize); + return fCollateData.Wcsxfrm(out, in, outSize, requiredSize); }