Zend: Add zend_try_get_double - #23398
Conversation
|
that s a nice addition ! |
| ZEND_ASSERT(Z_TYPE(dst) == IS_DOUBLE); | ||
| return Z_DVAL(dst); | ||
| } | ||
| case IS_UNDEF: |
There was a problem hiding this comment.
We don't check this for zval_get_double, and I don't think we should do this here either. If you hand an UNDEF zval there are bigger issues at hand that need to be investigated.
There was a problem hiding this comment.
I manually add this case :| But this makes debug easier so sure.
There was a problem hiding this comment.
It seems the reason we do this in the other ones is for VM optimizations (which probably would be good to add a comment using the commit description as to why IS_UNDEF is checked there)
There was a problem hiding this comment.
I will also add a comment in code to make it clear.
There was a problem hiding this comment.
We shouldn't be reading an uninitialized typed property, that's a bug in the calling code.
There was a problem hiding this comment.
Okay I take some hour to learn this stuff. AFAIK it is reasonable to remove IS_UNDEF. I don't know anything about VM optimizations, but I can tell that this:
case IS_UNDEF:
*failed = true;
return 0.0;Is completely the wrong semantic. IS_UNDEF should not be considered as 0.0. This
a. makes debugging harder cuz this is hiding the bug and makes the code base even more unpredictable.
b. makes no sense because IS_UNDEF isn't any value and shouldn't be considered as 0 anyways.
Instead if we remove this logic, this falls into
default:
ZEND_UNREACHABLE();That immediately catch the bug. And is more nicer semantically because trying to turn it into a double value is indeed unreachable behavior.
I know we have *failed = true. But IMO this is more like indicating a error when turning the value. I think if you are trying to get a double from an UNDEF type, the problem is way more serious than that and errors need to be thrown here.
Also the bug you've mentioned make sense too. This isn't correct logic anyways.
| } | ||
| /* }}} */ | ||
|
|
||
| static zend_never_inline double ZEND_FASTCALL zval_try_get_double_func(const zval *op, bool *failed) /* {{{ */ |
There was a problem hiding this comment.
Why never inline? Given this is called only from zval_try_get_double(), which cannot be inlined in other compilation units, this should very much be inlined.
| *failed = false; | ||
| return Z_DVAL_P(op); | ||
| } | ||
| return zval_try_get_double_func(op, failed); |
There was a problem hiding this comment.
This pattern doesn't really make sense unless you move this function to the .h file so it can be inlined.
In that case, the zend_never_inline on zval_try_get_double_func() would make a bit more sense.
|
I'd also ask why this is tested in zend_test instead of on actual extensions. |
Ah. Because I have yet to write a actual bug fix that use this function. So I only write test in zend_test as a new feature. |
|
IMO we should not introduce functions that aren't made use of. If this is merged and branched into 8.6, we'll fix on an implementation we have no real proof is correct, and after that point changing it becomes a BC break for extensions. |
|
Okay I add an actual fix in GD to use this internal function. So we might need reviews from David. |
2f9013f to
cbf5e37
Compare
| @@ -0,0 +1,99 @@ | |||
| --TEST-- | |||
There was a problem hiding this comment.
I am not convinced gd is necessarily the best experiment terrain for this. e.g. standard pack() seems a better candidate.
0d5e68e to
c2ac548
Compare
|
pack() now throws a TypeError when a value for the f, g, G, d, e, or E format code cannot be converted to float, instead of silently coercing it. I guess this is a better way to use zend_try_get_double? |
|
seems better but @iluuu1994 is right please address his comment. |
| @@ -0,0 +1,113 @@ | |||
| --TEST-- | |||
There was a problem hiding this comment.
it surely deserves better coverage.
|
I've already Ilija's comment. Added more tests, I even test it's behavior in gmp :) |
|
The declaration is still never inlined (zend_operators.h). |
devnexen
left a comment
There was a problem hiding this comment.
except the nit, looking good but please wait another approval.
|
I would agree to remove that. It's meaningless because |
| default: ZEND_UNREACHABLE(); | ||
| } | ||
| } | ||
| /* }}} */ |
There was a problem hiding this comment.
Please also avoid vim folding on new functions
|
I may have approved a bit fast after all.. |
| double d; | ||
| float v; | ||
| if (!php_pack_try_get_double(&argv[currentarg], currentarg + 2, &d)) { | ||
| zend_string_release(output); |
There was a problem hiding this comment.
seems this cleanup is repetitive
|
|
||
| *result = zval_try_get_double(value, &failed); | ||
| if (UNEXPECTED(failed)) { | ||
| if (!EG(exception)) { |
There was a problem hiding this comment.
you may need to update php_pack too ?
|
Done. I also add more tests on error handling. |
|
Okay. I am not familiar with the standard |
| return 0.0; | ||
| } | ||
| } | ||
| return type == IS_LONG ? (double) lval : dval; |
There was a problem hiding this comment.
if (type == IS_DOUBLE) {
return dval;
}
if (UNEXPECTED(lval == 0)) {
return zend_strtod(Z_STRVAL_P(op), NULL);
}
return (double) lval;There was a problem hiding this comment.
Makes sense to preserve "-0" here ig.
| return 0.0; | ||
| } | ||
| } | ||
| if (type == IS_DOUBLE) { |
There was a problem hiding this comment.
I realise ... this ... from 1100 to 1106 should be above the trailing data check above wdyt ?
| . Added zend_string_ends_with() and related variants. | ||
| . Added trait support for internal classes. | ||
| . Added do_php_cli(). | ||
| . Added zval_try_get_double(), which converts a defined zval to a double and |
There was a problem hiding this comment.
in the end, it should probably be reviewed.
Girgias
left a comment
There was a problem hiding this comment.
Can the changes to pack be split out from the PR? I'd rather have the API available for 8.6+ then the pack changes.
552b1ee to
278a069
Compare
|
Okay I split the changes to pack out to #23590 |
|
Thank you all! Very much appreciated. |
See php/php-tasks#32. Given now we have corresponding
tryfunctions to almost everyzval_get_TYPEfunctions except double, it is reasonable to addzend_try_get_double. A quick search shows that there are 62 occasions ofzend_get_doublein the code base.A real-world bug example is in #23384 (comment)_
cc @Girgias
I almost copy-paste the implementation of
zend_try_get_longfor this function.