Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICU-20036 CurrencyPluralInfo class improve handling of OOM errors #17

Merged
merged 8 commits into from
Aug 6, 2018

Conversation

jefgen
Copy link
Member

@jefgen jefgen commented Jul 20, 2018

Not all code paths that allocate memory check/handle OOM errors in the CurrencyPluralInfo class.
Use an internal error code (fInternalStatus) to better report errors during clone and copy construction.

srl295
srl295 previously approved these changes Jul 21, 2018
axelandrejs
axelandrejs previously approved these changes Jul 21, 2018
@jefgen jefgen dismissed stale reviews from axelandrejs and srl295 via 03445f0 July 26, 2018 22:13
…ets fPluralRules and fLocale to nullptr in the assignment operator in order to prevent possible double deletes in the failure case. Also use LocalPointer in a few more cases in order to clean things up somewhat.
void
CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
delete fLocale;
fLocale = loc.clone();
if (fLocale) {
Copy link
Member

@sffc sffc Aug 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some methods, like operator=, you delete without checking first, but here you first check if the pointer is not nullptr before calling delete. Personally I like the first style better, but at a minimum you should probably be consistent in your style. #Resolved

Copy link
Member Author

@jefgen jefgen Aug 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Shane. I was trying to mimic the style within each function (if it checked for nullptr, then I would too. If it didn't then I didn't).
However, since I'm already making a bunch of changes it would probably be better to be consistent.
Since calling delete on nullptr is safe, it seems like it would be cleaner to omit the checks.


In reply to: 207376490 [](ancestors = 207376490)

UErrorCode ec = U_ZERO_ERROR;
UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
UResourceBundle *numElements = ures_getByKeyWithFallback(rb, gNumberElementsTag, NULL, &ec);
UResourceBundle *rb = ures_open(nullptr, loc.getName(), &ec);
Copy link
Member

@sffc sffc Aug 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: change this to LocalUResourceBundlePointer. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Shane, that would likely be a good idea. :)


In reply to: 207378377 [](ancestors = 207378377)

jefgen added 2 commits August 2, 2018 18:22
…order to simply the code and not need manual deletes.
sffc
sffc previously approved these changes Aug 3, 2018
Copy link
Member

@sffc sffc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, with some additional optional suggestions.

rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
LocalUResourceBundlePointer rb(ures_open(nullptr, loc.getName(), &ec));
LocalUResourceBundlePointer numElements(ures_getByKeyWithFallback(rb.getAlias(), gNumberElementsTag, nullptr, &ec));
LocalUResourceBundlePointer numSystemScript(ures_getByKeyWithFallback(numElements.getAlias(), ns->getName(), nullptr, &ec));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine, but I think it should still be safe to use the third argument of ures_getByKeyWithFallback rather than making a new LocalUResourceBundlePointer for every level in the resource bundle tree.

Copy link
Member Author

@jefgen jefgen Aug 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that too, but then I was wondering who would call close on the ResourceBundle? (and in the correct order).
IIUC, calling orphan() doesn't call the close function, and if you call getAlias(), then the original bundle might be overwritten before the adoptInstead() can call close.

Ex:
rb.adoptInstead(ures_getByKeyWithFallback(numElements.getAlias(), ns->getName(), rb.orphan(), &ec));

rb.adoptInstead(ures_getByKeyWithFallback(numElements.getAlias(), ns->getName(), rb.getAlias(), &ec));


In reply to: 207658933 [](ancestors = 207658933)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant was, I think it is safe to do,

LocalUResourceBundlePointer rb(ures_open(...));
ures_getByKeyWithFallback(rb.getAlias(), "...", rb.getAlias(), &ec);
ures_getByKeyWithFallback(rb.getAlias(), "...", rb.getAlias(), &ec);
ures_getByKeyWithFallback(rb.getAlias(), "...", rb.getAlias(), &ec);

Example of a place in ICU code that uses this pattern already:

LocalUResourceBundlePointer rb(ures_open(NULL, localeID, &status));

I'm double-checking with Markus that this is safe.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After studying uresbund.cpp, I can't find any code paths in ures_getByKeyWithFallback and related functions that obviously return a different object than the one you passed via the fillIn parameter. Markus didn't have an answer. The documentation also does not provide any clues.

There is one thing that we can assume, and it's that when you pass a fillIn parameter to ures_getByKeyWithFallback, that you are passing ownership to that function, because most call sites, including the one you are refactoring, overwrite the original rb pointer with the return value. In most cases, ures_getByKeyWithFallback hands ownership of fillIn right back again by returning the same pointer; the question which I can't give a 100% certain answer to is whether fillIn is always the return value when it is non-null.

What I can see by looking at the code is that you should be able to expect better performance by using the fillIn, because without the fillIn, you add extra mallocs.

I think the pattern I posted above is probably fine, since I can find other places in ICU code that use it, but if you are hesitant, then I think the following pattern is also definitely safe:

LocalUResourceBundlePointer rb(ures_open(...));
rb.adoptInstead(ures_getByKeyWithFallback(rb.getAlias(), "...", rb.orphan(), &ec));
rb.adoptInstead(ures_getByKeyWithFallback(rb.getAlias(), "...", rb.orphan(), &ec));
rb.adoptInstead(ures_getByKeyWithFallback(rb.getAlias(), "...", rb.orphan(), &ec));

rb.getAlias() gets called first, then rb.orphan(), then ures_getByKeyWithFallback does its stuff, then you save the result back into rb.

Copy link
Member Author

@jefgen jefgen Aug 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Shane.
My hesitation about using that exact pattern was more about the question of "who calls the ures_close" once the code is done with the Resource Bundle, in order to ensure that there are no leaks. I was thinking that when you pass the fillIn it might not close.

However, from taking a close look at the code, it looks like it will automatically call the appropriate close methods if the fillIn argument is not NULL.
Inside the init_resb_result function:

    if(resB == NULL) {
        // .... omitted...
    } else {
        if(resB->fData != NULL) {
            entryClose(resB->fData);
        }
        if(resB->fVersion != NULL) {
            uprv_free(resB->fVersion);
        }
        // .... omitted...
    }

So, yes I would agree that it is safe in terms of not leaking when you use this pattern.

In terms of the pattern below, I think that even if getByKeyWithFallback did allocate a new object, it would still modify the incoming argument/parameter fillIn.

Pattern:

LocalUResourceBundlePointer rb(ures_open(...));
ures_getByKeyWithFallback(rb.getAlias(), "...", rb.getAlias(), &ec);

ICU Code:

U_CAPI UResourceBundle* U_EXPORT2 
ures_getByKeyWithFallback(const UResourceBundle *resB, 
                          const char* inKey, 
                          UResourceBundle *fillIn, 
                          UErrorCode *status) {
      // .....

                fillIn = init_resb_result(&(dataEntry->fData), res, inKey, -1, dataEntry, resB, 0, fillIn, status);
            } else {
                *status = U_MISSING_RESOURCE_ERROR;
            }
        } else {
            fillIn = init_resb_result(&(resB->fResData), res, key, -1, resB->fData, resB, 0, fillIn, status);
        }

So the rb object might be pointing at a new object after the call if this occurred. But that still would be safe as the close would be called when the LocalUResourceBundlePointer object goes out of scope.

fPluralRules = nullptr;
}
delete fPluralRules;
fPluralRules = nullptr;
Copy link
Member

@sffc sffc Aug 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: this assignment fPluralRules = nullptr; is redundant with the following line that just reassigns it. Feel free to leave as-is if you think it increases readability. #Resolved

Copy link
Member Author

@jefgen jefgen Aug 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Shane. I will push another commit that address this, but I think I will leave the other LocalUResourceBundlePointers for now. #Resolved

@sffc
Copy link
Member

sffc commented Aug 6, 2018

LGTM; there are a lot of commits here so I suggest a squash-merge, but you can do a merge commit if you want to preserve the history.

@jefgen jefgen merged commit e878d9d into unicode-org:master Aug 6, 2018
@jefgen jefgen deleted the jefgen/20036 branch August 6, 2018 20:22
@jefgen
Copy link
Member Author

jefgen commented Aug 6, 2018

Thank you for the detailed review Shane!
I did a squash-merge and consolidated some of the commit messages into the single commit message on the squashed commit.

sffc referenced this pull request in sffc/icu Sep 26, 2018
ICU-20036 CurrencyPluralInfo class doesn't always check/handle OOM errors.

Changes include:
- Using LocalPointer instead of raw new/delete, in order to make the code cleaner.
- Using nullptr instead of NULL.
- Inspired by Andy's review feedback PluralRules changes, this change sets fPluralRules and fLocale to nullptr in the assignment operator in order to prevent possible double deletes in the failure case.
- More consistent about not checking for nullptr when calling delete.
- Using LocalUResourceBundlePointer in order to simply the code and not need manual deletes.
- Reduce memory usage by using the same LocalUResourceBundle with .getAlias() instead of allocating new ones.
sffc referenced this pull request in sffc/icu Sep 26, 2018
ICU-20036 CurrencyPluralInfo class doesn't always check/handle OOM errors.

Changes include:
- Using LocalPointer instead of raw new/delete, in order to make the code cleaner.
- Using nullptr instead of NULL.
- Inspired by Andy's review feedback PluralRules changes, this change sets fPluralRules and fLocale to nullptr in the assignment operator in order to prevent possible double deletes in the failure case.
- More consistent about not checking for nullptr when calling delete.
- Using LocalUResourceBundlePointer in order to simply the code and not need manual deletes.
- Reduce memory usage by using the same LocalUResourceBundle with .getAlias() instead of allocating new ones.
sffc referenced this pull request in sffc/icu Sep 27, 2018
ICU-20036 CurrencyPluralInfo class doesn't always check/handle OOM errors.

Changes include:
- Using LocalPointer instead of raw new/delete, in order to make the code cleaner.
- Using nullptr instead of NULL.
- Inspired by Andy's review feedback PluralRules changes, this change sets fPluralRules and fLocale to nullptr in the assignment operator in order to prevent possible double deletes in the failure case.
- More consistent about not checking for nullptr when calling delete.
- Using LocalUResourceBundlePointer in order to simply the code and not need manual deletes.
- Reduce memory usage by using the same LocalUResourceBundle with .getAlias() instead of allocating new ones.
sffc referenced this pull request in sffc/icu Sep 27, 2018
ICU-20036 CurrencyPluralInfo class doesn't always check/handle OOM errors.

Changes include:
- Using LocalPointer instead of raw new/delete, in order to make the code cleaner.
- Using nullptr instead of NULL.
- Inspired by Andy's review feedback PluralRules changes, this change sets fPluralRules and fLocale to nullptr in the assignment operator in order to prevent possible double deletes in the failure case.
- More consistent about not checking for nullptr when calling delete.
- Using LocalUResourceBundlePointer in order to simply the code and not need manual deletes.
- Reduce memory usage by using the same LocalUResourceBundle with .getAlias() instead of allocating new ones.
sffc referenced this pull request in sffc/icu Sep 27, 2018
ICU-20036 CurrencyPluralInfo class doesn't always check/handle OOM errors.

Changes include:
- Using LocalPointer instead of raw new/delete, in order to make the code cleaner.
- Using nullptr instead of NULL.
- Inspired by Andy's review feedback PluralRules changes, this change sets fPluralRules and fLocale to nullptr in the assignment operator in order to prevent possible double deletes in the failure case.
- More consistent about not checking for nullptr when calling delete.
- Using LocalUResourceBundlePointer in order to simply the code and not need manual deletes.
- Reduce memory usage by using the same LocalUResourceBundle with .getAlias() instead of allocating new ones.
sffc referenced this pull request in sffc/icu Sep 27, 2018
ICU-20036 CurrencyPluralInfo class doesn't always check/handle OOM errors.

Changes include:
- Using LocalPointer instead of raw new/delete, in order to make the code cleaner.
- Using nullptr instead of NULL.
- Inspired by Andy's review feedback PluralRules changes, this change sets fPluralRules and fLocale to nullptr in the assignment operator in order to prevent possible double deletes in the failure case.
- More consistent about not checking for nullptr when calling delete.
- Using LocalUResourceBundlePointer in order to simply the code and not need manual deletes.
- Reduce memory usage by using the same LocalUResourceBundle with .getAlias() instead of allocating new ones.
hugovdm pushed a commit to hugovdm/icu that referenced this pull request Feb 25, 2020
ICU-20568 Fix ldml2icu convertUnit rules and update units.txt
hugovdm added a commit to hugovdm/icu that referenced this pull request Mar 26, 2020
hugovdm added a commit to hugovdm/icu that referenced this pull request Jul 21, 2020
Export addSingleFactorConstant in header file
ctrlaltf24 pushed a commit to FaithLife-Community/icu that referenced this pull request Oct 23, 2024
…unicode-org#17)

This change converts the Nuget build pipeline configuration from the ADO "classic" configuration into a YML/YAML file, which can be checked in to the repository.

Previously the Nuget build pipeline configuration only existed on MSCodeHub, meaning that nobody else could make any changes to it. This meant that in order to (for example) add support for a new platform to the Nuget package, changes would need to be done manually by someone on our team to the ADO pipeline setup within MSCodeHub.
With this change, anyone can create a PR to propose changes to add support for a new platform, etc. to the Nuget package pipeline.

This change also fixes the casing on the Nuget name to be "Microsoft.ICU.ICU4C.Runtime".

Changes in this commit:
* Only add the alpha+buildnum to the Nuget package if prerelease is passed to the script.
* Fix the casing on the package name.
* Change the wording in the nuspec slightly.
* Add YAML build file for Nuget package.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants