mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-20169 Replace uprv_malloc() / uprv_free() with MemoryPool.
This resolves the immediate problem of brittle memory management in the error handling code. An obvious future improvement would be to replace the old C style "plain struct with pointers" VariantListEntry, AttributeListEntry and ExtensionListEntry with contemporary C++ style containers that take care of ownership and memory management.
This commit is contained in:
parent
710212c495
commit
93e84caa65
1 changed files with 110 additions and 167 deletions
|
@ -31,17 +31,17 @@ typedef struct VariantListEntry {
|
|||
} VariantListEntry;
|
||||
|
||||
/* struct holding a single attribute value */
|
||||
typedef struct AttributeListEntry {
|
||||
struct AttributeListEntry : public icu::UMemory {
|
||||
const char *attribute;
|
||||
struct AttributeListEntry *next;
|
||||
} AttributeListEntry;
|
||||
};
|
||||
|
||||
/* struct holding a single extension */
|
||||
typedef struct ExtensionListEntry {
|
||||
struct ExtensionListEntry : public icu::UMemory {
|
||||
const char *key;
|
||||
const char *value;
|
||||
struct ExtensionListEntry *next;
|
||||
} ExtensionListEntry;
|
||||
};
|
||||
|
||||
#define MAXEXTLANG 3
|
||||
typedef struct ULanguageTag {
|
||||
|
@ -1066,6 +1066,10 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
|
|||
char attrBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY] = { 0 };
|
||||
int32_t attrBufLength = 0;
|
||||
|
||||
icu::MemoryPool<AttributeListEntry> attrPool;
|
||||
icu::MemoryPool<ExtensionListEntry> extPool;
|
||||
icu::MemoryPool<icu::CharString> strPool;
|
||||
|
||||
icu::LocalUEnumerationPointer keywordEnum(uloc_openKeywords(localeID, status));
|
||||
if (U_FAILURE(*status) && !hadPosix) {
|
||||
return;
|
||||
|
@ -1078,7 +1082,6 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
|
|||
ExtensionListEntry *ext;
|
||||
AttributeListEntry *firstAttr = NULL;
|
||||
AttributeListEntry *attr;
|
||||
char *attrValue;
|
||||
icu::MemoryPool<icu::CharString> extBufPool;
|
||||
const char *bcpKey=nullptr, *bcpValue=nullptr;
|
||||
UErrorCode tmpStatus = U_ZERO_ERROR;
|
||||
|
@ -1160,22 +1163,23 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
|
|||
}
|
||||
|
||||
/* create AttributeListEntry */
|
||||
attr = (AttributeListEntry*)uprv_malloc(sizeof(AttributeListEntry));
|
||||
attr = attrPool.create();
|
||||
if (attr == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
break;
|
||||
}
|
||||
attrValue = (char*)uprv_malloc(attrBufLength + 1);
|
||||
icu::CharString* attrValue =
|
||||
strPool.create(attrBuf, attrBufLength, *status);
|
||||
if (attrValue == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
break;
|
||||
}
|
||||
uprv_strcpy(attrValue, attrBuf);
|
||||
attr->attribute = attrValue;
|
||||
if (U_FAILURE(*status)) {
|
||||
break;
|
||||
}
|
||||
attr->attribute = attrValue->data();
|
||||
|
||||
if (!_addAttributeToList(&firstAttr, attr)) {
|
||||
uprv_free(attr);
|
||||
uprv_free(attrValue);
|
||||
if (strict) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
break;
|
||||
|
@ -1273,7 +1277,7 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
|
|||
}
|
||||
|
||||
/* create ExtensionListEntry */
|
||||
ext = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
|
||||
ext = extPool.create();
|
||||
if (ext == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
break;
|
||||
|
@ -1282,7 +1286,6 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
|
|||
ext->value = bcpValue;
|
||||
|
||||
if (!_addExtensionToList(&firstExt, ext, TRUE)) {
|
||||
uprv_free(ext);
|
||||
if (strict) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
break;
|
||||
|
@ -1293,16 +1296,16 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
|
|||
/* Special handling for POSIX variant - add the keywords for POSIX */
|
||||
if (hadPosix) {
|
||||
/* create ExtensionListEntry for POSIX */
|
||||
ext = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
|
||||
ext = extPool.create();
|
||||
if (ext == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
ext->key = POSIX_KEY;
|
||||
ext->value = POSIX_VALUE;
|
||||
|
||||
if (!_addExtensionToList(&firstExt, ext, TRUE)) {
|
||||
uprv_free(ext);
|
||||
// Silently ignore errors.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1331,27 +1334,6 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
|
|||
}
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
/* clean up */
|
||||
ext = firstExt;
|
||||
while (ext != NULL) {
|
||||
ExtensionListEntry *tmpExt = ext->next;
|
||||
uprv_free(ext);
|
||||
ext = tmpExt;
|
||||
}
|
||||
|
||||
attr = firstAttr;
|
||||
while (attr != NULL) {
|
||||
AttributeListEntry *tmpAttr = attr->next;
|
||||
char *pValue = (char *)attr->attribute;
|
||||
uprv_free(pValue);
|
||||
uprv_free(attr);
|
||||
attr = tmpAttr;
|
||||
}
|
||||
|
||||
if (U_FAILURE(*status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1361,7 +1343,7 @@ cleanup:
|
|||
* Note: char* buf is used for storing keywords
|
||||
*/
|
||||
static void
|
||||
_appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendTo, icu::MemoryPool<icu::CharString>& kwdBuf, UBool *posixVariant, UErrorCode *status) {
|
||||
_appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendTo, icu::MemoryPool<ExtensionListEntry>& extPool, icu::MemoryPool<icu::CharString>& kwdBuf, UBool *posixVariant, UErrorCode *status) {
|
||||
const char *pTag; /* beginning of current subtag */
|
||||
const char *pKwds; /* beginning of key-type pairs */
|
||||
UBool variantExists = *posixVariant;
|
||||
|
@ -1369,108 +1351,100 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
ExtensionListEntry *kwdFirst = NULL; /* first LDML keyword */
|
||||
ExtensionListEntry *kwd, *nextKwd;
|
||||
|
||||
AttributeListEntry *attrFirst = NULL; /* first attribute */
|
||||
AttributeListEntry *attr, *nextAttr;
|
||||
|
||||
int32_t len;
|
||||
|
||||
char attrBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
|
||||
int32_t attrBufIdx = 0;
|
||||
|
||||
/* Reset the posixVariant value */
|
||||
*posixVariant = FALSE;
|
||||
|
||||
pTag = ldmlext;
|
||||
pKwds = NULL;
|
||||
|
||||
/* Iterate through u extension attributes */
|
||||
while (*pTag) {
|
||||
/* locate next separator char */
|
||||
for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++);
|
||||
{
|
||||
AttributeListEntry *attrFirst = NULL; /* first attribute */
|
||||
AttributeListEntry *attr, *nextAttr;
|
||||
|
||||
if (ultag_isUnicodeLocaleKey(pTag, len)) {
|
||||
pKwds = pTag;
|
||||
break;
|
||||
}
|
||||
char attrBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
|
||||
int32_t attrBufIdx = 0;
|
||||
|
||||
/* add this attribute to the list */
|
||||
attr = (AttributeListEntry*)uprv_malloc(sizeof(AttributeListEntry));
|
||||
if (attr == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
icu::MemoryPool<AttributeListEntry> attrPool;
|
||||
|
||||
if (len < (int32_t)sizeof(attrBuf) - attrBufIdx) {
|
||||
uprv_memcpy(&attrBuf[attrBufIdx], pTag, len);
|
||||
attrBuf[attrBufIdx + len] = 0;
|
||||
attr->attribute = &attrBuf[attrBufIdx];
|
||||
attrBufIdx += (len + 1);
|
||||
} else {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
uprv_free(attr);
|
||||
goto cleanup;
|
||||
}
|
||||
/* Iterate through u extension attributes */
|
||||
while (*pTag) {
|
||||
/* locate next separator char */
|
||||
for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++);
|
||||
|
||||
if (!_addAttributeToList(&attrFirst, attr)) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
uprv_free(attr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* next tag */
|
||||
pTag += len;
|
||||
if (*pTag) {
|
||||
/* next to the separator */
|
||||
pTag++;
|
||||
}
|
||||
}
|
||||
|
||||
if (attrFirst) {
|
||||
/* emit attributes as an LDML keyword, e.g. attribute=attr1-attr2 */
|
||||
|
||||
kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
|
||||
if (kwd == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
icu::CharString* value = kwdBuf.create();
|
||||
if (value == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* attribute subtags sorted in alphabetical order as type */
|
||||
attr = attrFirst;
|
||||
while (attr != NULL) {
|
||||
nextAttr = attr->next;
|
||||
if (attr != attrFirst) {
|
||||
value->append('-', *status);
|
||||
if (ultag_isUnicodeLocaleKey(pTag, len)) {
|
||||
pKwds = pTag;
|
||||
break;
|
||||
}
|
||||
|
||||
/* add this attribute to the list */
|
||||
attr = attrPool.create();
|
||||
if (attr == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (len < (int32_t)sizeof(attrBuf) - attrBufIdx) {
|
||||
uprv_memcpy(&attrBuf[attrBufIdx], pTag, len);
|
||||
attrBuf[attrBufIdx + len] = 0;
|
||||
attr->attribute = &attrBuf[attrBufIdx];
|
||||
attrBufIdx += (len + 1);
|
||||
} else {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_addAttributeToList(&attrFirst, attr)) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
/* next tag */
|
||||
pTag += len;
|
||||
if (*pTag) {
|
||||
/* next to the separator */
|
||||
pTag++;
|
||||
}
|
||||
value->append(attr->attribute, *status);
|
||||
attr = nextAttr;
|
||||
}
|
||||
if (U_FAILURE(*status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
kwd->key = LOCALE_ATTRIBUTE_KEY;
|
||||
kwd->value = value->data();
|
||||
if (attrFirst) {
|
||||
/* emit attributes as an LDML keyword, e.g. attribute=attr1-attr2 */
|
||||
|
||||
if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
uprv_free(kwd);
|
||||
goto cleanup;
|
||||
}
|
||||
kwd = extPool.create();
|
||||
if (kwd == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
/* once keyword entry is created, delete the attribute list */
|
||||
attr = attrFirst;
|
||||
while (attr != NULL) {
|
||||
nextAttr = attr->next;
|
||||
uprv_free(attr);
|
||||
attr = nextAttr;
|
||||
icu::CharString* value = kwdBuf.create();
|
||||
if (value == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
/* attribute subtags sorted in alphabetical order as type */
|
||||
attr = attrFirst;
|
||||
while (attr != NULL) {
|
||||
nextAttr = attr->next;
|
||||
if (attr != attrFirst) {
|
||||
value->append('-', *status);
|
||||
}
|
||||
value->append(attr->attribute, *status);
|
||||
attr = nextAttr;
|
||||
}
|
||||
if (U_FAILURE(*status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
kwd->key = LOCALE_ATTRIBUTE_KEY;
|
||||
kwd->value = value->data();
|
||||
|
||||
if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
attrFirst = NULL;
|
||||
}
|
||||
|
||||
if (pKwds) {
|
||||
|
@ -1534,7 +1508,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
if (bcpKeyLen >= (int32_t)sizeof(bcpKeyBuf)) {
|
||||
/* the BCP key is invalid */
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
|
||||
uprv_strncpy(bcpKeyBuf, pBcpKey, bcpKeyLen);
|
||||
|
@ -1544,7 +1518,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
pKey = uloc_toLegacyKey(bcpKeyBuf);
|
||||
if (pKey == NULL) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
if (pKey == bcpKeyBuf) {
|
||||
/*
|
||||
|
@ -1555,10 +1529,10 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
icu::CharString* key = kwdBuf.create(bcpKeyBuf, bcpKeyLen, *status);
|
||||
if (key == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
if (U_FAILURE(*status)) {
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
pKey = key->data();
|
||||
}
|
||||
|
@ -1568,7 +1542,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
if (bcpTypeLen >= (int32_t)sizeof(bcpTypeBuf)) {
|
||||
/* the BCP type is too long */
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
|
||||
uprv_strncpy(bcpTypeBuf, pBcpType, bcpTypeLen);
|
||||
|
@ -1578,7 +1552,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
pType = uloc_toLegacyType(pKey, bcpTypeBuf);
|
||||
if (pType == NULL) {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
if (pType == bcpTypeBuf) {
|
||||
/*
|
||||
|
@ -1590,10 +1564,10 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
icu::CharString* type = kwdBuf.create(bcpTypeBuf, bcpTypeLen, *status);
|
||||
if (type == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
if (U_FAILURE(*status)) {
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
pType = type->data();
|
||||
}
|
||||
|
@ -1608,10 +1582,10 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
*posixVariant = TRUE;
|
||||
} else {
|
||||
/* create an ExtensionListEntry for this keyword */
|
||||
kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
|
||||
kwd = extPool.create();
|
||||
if (kwd == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
goto cleanup;
|
||||
return;
|
||||
}
|
||||
|
||||
kwd->key = pKey;
|
||||
|
@ -1620,7 +1594,6 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
|
||||
// duplicate keyword is allowed, Only the first
|
||||
// is honored.
|
||||
uprv_free(kwd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1638,23 +1611,6 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
_addExtensionToList(appendTo, kwd, FALSE);
|
||||
kwd = nextKwd;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
attr = attrFirst;
|
||||
while (attr != NULL) {
|
||||
nextAttr = attr->next;
|
||||
uprv_free(attr);
|
||||
attr = nextAttr;
|
||||
}
|
||||
|
||||
kwd = kwdFirst;
|
||||
while (kwd != NULL) {
|
||||
nextKwd = kwd->next;
|
||||
uprv_free(kwd);
|
||||
kwd = nextKwd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1665,6 +1621,7 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
|
|||
ExtensionListEntry *kwdFirst = NULL;
|
||||
ExtensionListEntry *kwd;
|
||||
const char *key, *type;
|
||||
icu::MemoryPool<ExtensionListEntry> extPool;
|
||||
icu::MemoryPool<icu::CharString> kwdBuf;
|
||||
UBool posixVariant = FALSE;
|
||||
|
||||
|
@ -1684,12 +1641,12 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
|
|||
key = ultag_getExtensionKey(langtag, i);
|
||||
type = ultag_getExtensionValue(langtag, i);
|
||||
if (*key == LDMLEXT) {
|
||||
_appendLDMLExtensionAsKeywords(type, &kwdFirst, kwdBuf, &posixVariant, status);
|
||||
_appendLDMLExtensionAsKeywords(type, &kwdFirst, extPool, kwdBuf, &posixVariant, status);
|
||||
if (U_FAILURE(*status)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
|
||||
kwd = extPool.create();
|
||||
if (kwd == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
break;
|
||||
|
@ -1697,7 +1654,6 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
|
|||
kwd->key = key;
|
||||
kwd->value = type;
|
||||
if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
|
||||
uprv_free(kwd);
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
@ -1708,14 +1664,13 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
|
|||
type = ultag_getPrivateUse(langtag);
|
||||
if ((int32_t)uprv_strlen(type) > 0) {
|
||||
/* add private use as a keyword */
|
||||
kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
|
||||
kwd = extPool.create();
|
||||
if (kwd == NULL) {
|
||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||
} else {
|
||||
kwd->key = PRIVATEUSE_KEY;
|
||||
kwd->value = type;
|
||||
if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
|
||||
uprv_free(kwd);
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -1753,18 +1708,6 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
|
|||
kwd = kwd->next;
|
||||
} while (kwd);
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
kwd = kwdFirst;
|
||||
while (kwd != NULL) {
|
||||
ExtensionListEntry *tmpKwd = kwd->next;
|
||||
uprv_free(kwd);
|
||||
kwd = tmpKwd;
|
||||
}
|
||||
|
||||
if (U_FAILURE(*status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Add table
Reference in a new issue