libs/posix: Fix NULL pointer in uselocale

uselocale now attempts to create a backend and a databrige.

If the attempt fails due to a missing libroot-addon-icu, uselocale
does nothing (to support applications calling uselocale during
startup to enforce the C locale).

Else, uselocale will fail with ENOMEM.

LocaleBackend::CreateBackend() has been modified to return a status_t
that indicates whether NULL is returned due to out of memory (B_NO_MEMORY)
or due to being unable to load the ICU addon (B_MISSING_LIBRARY).

Change-Id: I0f62ebde5890364c64e6694ec58d38de43ec6841
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5505
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Trung Nguyen
2022-08-03 00:16:08 +00:00
committed by waddlesplash
parent b9643e557d
commit d02c0bade7
3 changed files with 41 additions and 16 deletions
@@ -187,7 +187,7 @@ public:
virtual void Initialize(LocaleDataBridge* dataBridge) = 0;
static status_t LoadBackend();
static LocaleBackend* CreateBackend();
static status_t CreateBackend(LocaleBackend*& backendOut);
static void DestroyBackend(LocaleBackend* instance);
};
@@ -52,7 +52,7 @@ LoadFunctions()
static void
LoadBackend()
{
gGlobalLocaleBackend = LocaleBackend::CreateBackend();
LocaleBackend::CreateBackend(gGlobalLocaleBackend);
if (gGlobalLocaleBackend != NULL) {
gGlobalLocaleBackend->Initialize(&gGlobalLocaleDataBridge);
}
@@ -81,19 +81,20 @@ LocaleBackend::LoadBackend()
}
LocaleBackend*
LocaleBackend::CreateBackend()
status_t
LocaleBackend::CreateBackend(LocaleBackend*& backendOut)
{
if (sCreateInstanceFunc == NULL) {
pthread_once(&sFunctionsInitOnce, &BPrivate::Libroot::LoadFunctions);
}
if (sCreateInstanceFunc != NULL) {
LocaleBackend* backend = sCreateInstanceFunc();
return backend;
backendOut = sCreateInstanceFunc();
return backendOut != NULL ? B_OK : B_NO_MEMORY;
}
return NULL;
backendOut = NULL;
return B_MISSING_LIBRARY;
}
+33 -9
View File
@@ -53,14 +53,13 @@ duplocale(locale_t l)
return (locale_t)newObj;
}
BPrivate::ErrnoMaintainer errnoMaintainer;
LocaleBackend*& newBackend = newObj->backend;
LocaleDataBridge*& newDataBridge = newObj->databridge;
newBackend = LocaleBackend::CreateBackend();
status_t status = LocaleBackend::CreateBackend(newBackend);
if (newBackend == NULL) {
errno = ENOMEM;
errno = status;
delete newObj;
return (locale_t)0;
}
@@ -69,7 +68,7 @@ duplocale(locale_t l)
if (newDataBridge == NULL) {
errno = ENOMEM;
delete newBackend;
LocaleBackend::DestroyBackend(newBackend);
delete newObj;
return (locale_t)0;
}
@@ -164,9 +163,9 @@ newlocale(int category_mask, const char* locale, locale_t base)
}
}
if (needBackend) {
backend = LocaleBackend::CreateBackend();
status_t status = LocaleBackend::CreateBackend(backend);
if (backend == NULL) {
errno = ENOMEM;
errno = status;
if (newObject) {
delete localeObject;
}
@@ -175,7 +174,7 @@ newlocale(int category_mask, const char* locale, locale_t base)
databridge = new (std::nothrow) LocaleDataBridge(false);
if (databridge == NULL) {
errno = ENOMEM;
delete backend;
LocaleBackend::DestroyBackend(backend);
if (newObject) {
delete localeObject;
}
@@ -228,7 +227,32 @@ uselocale(locale_t newLoc)
SetCurrentLocaleInfo((LocaleBackendData*)appliedLoc);
if (appliedLoc != NULL) {
((LocaleBackendData*)appliedLoc)->databridge->ApplyToCurrentThread();
LocaleDataBridge*& databridge = ((LocaleBackendData*)appliedLoc)->databridge;
// Happens when appliedLoc represents the C locale.
if (databridge == NULL) {
LocaleBackend*& backend = ((LocaleBackendData*)appliedLoc)->backend;
status_t status = LocaleBackend::CreateBackend(backend);
if (backend == NULL) {
if (status == B_MISSING_LIBRARY) {
// This means libroot-addon-icu is not available.
// Therefore, the global locale is still the C locale
// and cannot be set to any other locale. Do nothing.
return oldLoc;
}
errno = status;
return (locale_t)0;
}
databridge = new (std::nothrow) LocaleDataBridge(false);
if (databridge == NULL) {
LocaleBackend::DestroyBackend(backend);
errno = ENOMEM;
return (locale_t)0;
}
backend->Initialize(databridge);
}
databridge->ApplyToCurrentThread();
} else {
gGlobalLocaleDataBridge.ApplyToCurrentThread();
}