-
Notifications
You must be signed in to change notification settings - Fork 7.7k
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
Fixed #74063 - NumberFormatter did not work properly when restored from session. #2378
Conversation
fba6e74
to
b45a3dc
Compare
b45a3dc
to
5176ccc
Compare
ext/intl/formatter/formatter_main.c
Outdated
} | ||
|
||
/* Create an ICU number formatter. */ | ||
FORMATTER_OBJECT(nfo) = unum_open(style, spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(nfo)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if this fails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same call we have in numfmt_ctor
and I guess in case if this call will fail, wrong number formatter object will be handled by FORMATTER_METHOD_FETCH_OBJECT
macro
ext/intl/formatter/formatter_main.c
Outdated
} | ||
|
||
/* Create an ICU number formatter. */ | ||
FORMATTER_OBJECT(nfo) = unum_open(style, spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(nfo)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If pattern is not set or is not a string, this will be called with null pattern and probably will crash. Also, style may not be initialized when calling it. Also, I don't think default locale should be used when unserializing - this may lead to a situation where same object ins unserialized in different ways, leading to very hard to reproduce bugs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smalyshev case when pattern is null covered with test provided, it works ok.
About style - agree, it's better at least to initialize it with 0
And good catch about default locate, thanks! I will fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smalyshev just fixed it, thanks!
709df96
to
ef8201c
Compare
ext/intl/formatter/formatter_main.c
Outdated
if (z_locale && Z_TYPE_P(z_locale) == IS_STRING) { | ||
str = zval_get_string(z_locale); | ||
locale = ZSTR_VAL(str); | ||
zend_string_release(str); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This releases the string to which locale
still points (and is used later).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nikic thanks for the review! just fixed all the issues.
ext/intl/formatter/formatter_main.c
Outdated
str = zval_get_string(z_pattern); | ||
pattern = ZSTR_VAL(str); | ||
pattern_len = ZSTR_LEN(str); | ||
zend_string_release(str); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, this also releases a string that may later be used. Instead you should simply keep the whole zend_string and release it at the end.
ext/intl/formatter/formatter_main.c
Outdated
|
||
if(spattern) { | ||
efree(spattern); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something went wrong with the indentation here, looks like mix of tabs and spaces.
@andrewnester I see commits yesterday, status please ? |
@krakjoe sorry, changes requested by @nikic fixed, mentioned it here #2378 (comment) |
ext/intl/formatter/formatter_main.c
Outdated
|
||
z_locale = zend_read_property(Z_OBJCE_P(return_value), return_value, "locale", sizeof("locale") - 1, 0, &rv); | ||
if (z_locale != NULL) { | ||
zstr_locale = zval_get_string(z_locale); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's unserialized data, there's no guarantee z_locale is a string. It should be checked, and wakeup should fail if it's not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't assume that z_locale is a string: It does a string cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, well, I'm not sure it's the right thing to do anyway - what if it's an object? It's probably not safe to call __toString here... - but it's better then. For long conversion, it may be ok, not sure... I'd not risk it anyway and refuse to deal with broken data, we had enough problem with it lately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @smalyshev - it would be better to check for types and fail waking up in case of wrong data
ext/intl/formatter/formatter_main.c
Outdated
*/ | ||
PHP_METHOD( NumberFormatter, __wakeup ) | ||
{ | ||
const char* locale = intl_locale_get_default(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still uses default locale if serialization data do not contain locale value. Instead, it should fail.
ext/intl/formatter/formatter_main.c
Outdated
|
||
z_style = zend_read_property(Z_OBJCE_P(return_value), return_value, "style", sizeof("style") - 1, 0, &rv); | ||
if (z_style != NULL) { | ||
style = zval_get_long(z_style); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, should not assume it's long.
ext/intl/formatter/formatter_main.c
Outdated
|
||
z_pattern = zend_read_property(Z_OBJCE_P(return_value), return_value, "pattern", sizeof("pattern") - 1, 0, &rv); | ||
if (z_pattern != NULL) { | ||
zstr_pattern = zval_get_string(z_pattern); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, should not assume it's string.
|
||
/* Convert pattern (if specified) to UTF-16. */ | ||
if(pattern && pattern_len) { | ||
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error code not checked here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smalyshev thanks! just made changes you requested.
My main question here would be what our current stance on serialization of internal classes is in general. This particular PR uses an approach I haven't seen anywhere, which is to actually mirror the internal object state with exposed properties. The two approaches that are used elsewhere are a) using a I'm wondering if it might make sense to add a |
I remember seeing this in other classes too, though don't remember the examples right now. In general, (un)serializing internal classes is a problem because not all classes have exportable - and, more importantly, importable - state. I think it makes a lot of sense to have centralized approach to this, and discussing it on internals and probably making the RFC looks like the right way to go here. |
@nikic @smalyshev just to let you know I took this approach from this https://github.com/php/php-src/blob/master/Zend/zend_exceptions.c#L314 |
@nikic @smalyshev so what's the conclusion finally on this one? |
@andrewnester it would seem there is some dissent from core maintainers about the suitability of this approach, and in addition, some suggestions for other solutions to the problem being solved here. Since an RFC has been suggested, and since a discussion with the wider community would appear to be necessary, I would suggest at this point that you start an internals discussion with a view to creating an RFC, and possibly adopting a different approach. Please link to any discussion here for future reference. |
@krakjoe thanks! I just started discussion here http://news.php.net/php.internals/98706 |
@krakjoe I tried to start discussion on internals but doesn't look like it's going to happen |
What I'm going to do is close this PR. What I suggest you do is open a new PR with a new approach, if we (those people that get involved in pull request discussions) find the approach to be acceptable, we may be able to skip the RFC, or it may just be a formality ... either way it would appear that this approach is dead in the water, and a fresh approach is needed. I'm hoping we can skip an RFC if the approach is okay, personally. Sorry about the amount of time this is taking ... |
Bug fix for https://bugs.php.net/bug.php?id=74063