ICU-20568 Improve MacroProps error handling.

In particular: actually handle Usage memory allocation errors.
Also: correct Scale's error condition.
This commit is contained in:
Hugo van der Merwe 2020-09-11 00:03:31 +02:00
parent 7888b23e87
commit 5ed09dc9b8
3 changed files with 44 additions and 17 deletions

View file

@ -1547,7 +1547,7 @@ bool GeneratorHelpers::perUnit(const MacroProps& macros, UnicodeString& sb, UErr
}
bool GeneratorHelpers::usage(const MacroProps& macros, UnicodeString& sb, UErrorCode& /* status */) {
if (macros.usage.fLength > 0) {
if (macros.usage.isSet()) {
sb.append(u"usage/", -1);
sb.append(UnicodeString(macros.usage.fUsage, -1, US_INV));
return true;

View file

@ -28,21 +28,33 @@ using icu::StringSegment;
using icu::units::ConversionRates;
// Copy constructor
Usage::Usage(const Usage &other) : fUsage(nullptr), fLength(other.fLength), fError(other.fError) {
if (other.fUsage != nullptr) {
fUsage = (char *)uprv_malloc(fLength + 1);
uprv_strncpy(fUsage, other.fUsage, fLength + 1);
}
Usage::Usage(const Usage &other) : Usage() {
this->operator=(other);
}
// Copy assignment operator
Usage &Usage::operator=(const Usage &other) {
fLength = other.fLength;
if (other.fUsage != nullptr) {
fUsage = (char *)uprv_malloc(fLength + 1);
uprv_strncpy(fUsage, other.fUsage, fLength + 1);
}
fLength = 0;
fError = other.fError;
if (fUsage != nullptr) {
uprv_free(fUsage);
fUsage = nullptr;
}
if (other.fUsage == nullptr) {
return *this;
}
if (U_FAILURE(other.fError)) {
// We don't bother trying to allocating memory if we're in any case busy
// copying an errored Usage.
return *this;
}
fUsage = (char *)uprv_malloc(other.fLength + 1);
if (fUsage == nullptr) {
fError = U_MEMORY_ALLOCATION_ERROR;
return *this;
}
fLength = other.fLength;
uprv_strncpy(fUsage, other.fUsage, fLength + 1);
return *this;
}
@ -82,6 +94,11 @@ void Usage::set(StringPiece value) {
}
fLength = value.length();
fUsage = (char *)uprv_malloc(fLength + 1);
if (fUsage == nullptr) {
fLength = 0;
fError = U_MEMORY_ALLOCATION_ERROR;
return;
}
uprv_strncpy(fUsage, value.data(), fLength);
fUsage[fLength] = 0;
}

View file

@ -1094,7 +1094,7 @@ class U_I18N_API Scale : public UMemory {
}
UBool copyErrorTo(UErrorCode &status) const {
if (fError != U_ZERO_ERROR) {
if (U_FAILURE(fError)) {
status = fError;
return true;
}
@ -1154,13 +1154,15 @@ class U_I18N_API Usage : public UMemory {
int16_t length() const { return fLength; }
/** @internal
* Makes a copy of value.
* Makes a copy of value. Set to "" to unset.
*/
void set(StringPiece value);
/** @internal */
bool isSet() const { return fLength > 0; }
#endif // U_HIDE_INTERNAL_API
private:
char *fUsage;
int16_t fLength;
@ -1168,16 +1170,24 @@ class U_I18N_API Usage : public UMemory {
Usage() : fUsage(nullptr), fLength(0), fError(U_ZERO_ERROR) {}
/** @internal */
UBool copyErrorTo(UErrorCode &status) const {
if (U_FAILURE(fError)) {
status = fError;
return true;
}
return false;
}
// Allow NumberFormatterImpl to access fUsage.
friend class impl::NumberFormatterImpl;
// Allow skeleton generation code to access private members.
friend class impl::GeneratorHelpers;
// Allow MacroProps/MicroProps to initialize empty instances.
// Allow MacroProps/MicroProps to initialize empty instances and to call
// copyErrorTo().
friend struct impl::MacroProps;
#endif // U_HIDE_INTERNAL_API
};
// Do not enclose entire SymbolsWrapper with #ifndef U_HIDE_INTERNAL_API, needed for a protected field
@ -1487,7 +1497,7 @@ struct U_I18N_API MacroProps : public UMemory {
bool copyErrorTo(UErrorCode &status) const {
return notation.copyErrorTo(status) || precision.copyErrorTo(status) ||
padder.copyErrorTo(status) || integerWidth.copyErrorTo(status) ||
symbols.copyErrorTo(status) || scale.copyErrorTo(status);
symbols.copyErrorTo(status) || scale.copyErrorTo(status) || usage.copyErrorTo(status);
}
};