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; virtual void Initialize(LocaleDataBridge* dataBridge) = 0;
static status_t LoadBackend(); static status_t LoadBackend();
static LocaleBackend* CreateBackend(); static status_t CreateBackend(LocaleBackend*& backendOut);
static void DestroyBackend(LocaleBackend* instance); static void DestroyBackend(LocaleBackend* instance);
}; };
@@ -52,7 +52,7 @@ LoadFunctions()
static void static void
LoadBackend() LoadBackend()
{ {
gGlobalLocaleBackend = LocaleBackend::CreateBackend(); LocaleBackend::CreateBackend(gGlobalLocaleBackend);
if (gGlobalLocaleBackend != NULL) { if (gGlobalLocaleBackend != NULL) {
gGlobalLocaleBackend->Initialize(&gGlobalLocaleDataBridge); gGlobalLocaleBackend->Initialize(&gGlobalLocaleDataBridge);
} }
@@ -81,19 +81,20 @@ LocaleBackend::LoadBackend()
} }
LocaleBackend* status_t
LocaleBackend::CreateBackend() LocaleBackend::CreateBackend(LocaleBackend*& backendOut)
{ {
if (sCreateInstanceFunc == NULL) { if (sCreateInstanceFunc == NULL) {
pthread_once(&sFunctionsInitOnce, &BPrivate::Libroot::LoadFunctions); pthread_once(&sFunctionsInitOnce, &BPrivate::Libroot::LoadFunctions);
} }
if (sCreateInstanceFunc != NULL) { if (sCreateInstanceFunc != NULL) {
LocaleBackend* backend = sCreateInstanceFunc(); backendOut = sCreateInstanceFunc();
return backend; 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; return (locale_t)newObj;
} }
BPrivate::ErrnoMaintainer errnoMaintainer;
LocaleBackend*& newBackend = newObj->backend; LocaleBackend*& newBackend = newObj->backend;
LocaleDataBridge*& newDataBridge = newObj->databridge; LocaleDataBridge*& newDataBridge = newObj->databridge;
newBackend = LocaleBackend::CreateBackend();
status_t status = LocaleBackend::CreateBackend(newBackend);
if (newBackend == NULL) { if (newBackend == NULL) {
errno = ENOMEM; errno = status;
delete newObj; delete newObj;
return (locale_t)0; return (locale_t)0;
} }
@@ -69,7 +68,7 @@ duplocale(locale_t l)
if (newDataBridge == NULL) { if (newDataBridge == NULL) {
errno = ENOMEM; errno = ENOMEM;
delete newBackend; LocaleBackend::DestroyBackend(newBackend);
delete newObj; delete newObj;
return (locale_t)0; return (locale_t)0;
} }
@@ -164,9 +163,9 @@ newlocale(int category_mask, const char* locale, locale_t base)
} }
} }
if (needBackend) { if (needBackend) {
backend = LocaleBackend::CreateBackend(); status_t status = LocaleBackend::CreateBackend(backend);
if (backend == NULL) { if (backend == NULL) {
errno = ENOMEM; errno = status;
if (newObject) { if (newObject) {
delete localeObject; delete localeObject;
} }
@@ -175,7 +174,7 @@ newlocale(int category_mask, const char* locale, locale_t base)
databridge = new (std::nothrow) LocaleDataBridge(false); databridge = new (std::nothrow) LocaleDataBridge(false);
if (databridge == NULL) { if (databridge == NULL) {
errno = ENOMEM; errno = ENOMEM;
delete backend; LocaleBackend::DestroyBackend(backend);
if (newObject) { if (newObject) {
delete localeObject; delete localeObject;
} }
@@ -228,7 +227,32 @@ uselocale(locale_t newLoc)
SetCurrentLocaleInfo((LocaleBackendData*)appliedLoc); SetCurrentLocaleInfo((LocaleBackendData*)appliedLoc);
if (appliedLoc != NULL) { 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 { } else {
gGlobalLocaleDataBridge.ApplyToCurrentThread(); gGlobalLocaleDataBridge.ApplyToCurrentThread();
} }