-
Notifications
You must be signed in to change notification settings - Fork 686
Fix for toFixed method #1994
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
Fix for toFixed method #1994
Conversation
| { | ||
| ecma_double_to_ascii (val, buffer_p, &char_cnt); | ||
| if (num_of_digits < 22) | ||
| { |
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.
Why 22? Please do not use magic number.
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 magic number comes from here
https://github.com/jerryscript-project/jerryscript/blob/master/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c#L593
But I'm going to define a variable for 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.
Great, thanks. Could you define that magic number 21 somewhere where both files reach it (and you can replace the condition to <= 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.
Of course. :)
daeac38 to
7881cc3
Compare
jerry-core/ecma/base/ecma-globals.h
Outdated
|
|
||
| /** | ||
| * Maximum number of digits in string representation of ecma-number exponent part | ||
| */ |
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 we introduce such a constant then it should be used throughout the codebase. I've grepped for 21 under jerry-core/ecma and found other occurrences:
ecma-builtin-number-prototype.c:
L585 (ecma_builtin_number_prototype_object_to_fixed)
L727 (ecma_builtin_number_prototype_object_to_exponential)
L915 (ecma_builtin_number_prototype_object_to_precision)
ecma-helpers-conversion.c:
L1134-1138 (ecma_number_to_utf8_string)
L1146-1150 (ecma_number_to_utf8_string)
It should be thoroughly checked of course whether these 21s are the same 21 that we try to replace. But if they are, the new macro should be used in place of them.
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.
After some discussion https://www.ecma-international.org/ecma-262/5.1/#sec-15.7.4.5 does not provide precise explanation about these 'magic numbers', so we can keep them instead of defining a new macro for them.
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.
@rerobika For the sake of clarity: so, none of the above 5 instances of the numeric literal 21 have any connection with the "maximum number of digits in string representation of ecma-number exponent part" concept? But the functions already touched in the current patch (ecma_double_to_binary_floating_point and ecma_builtin_number_prototype_object_to_fixed) do use this concept? Seems strange to me.
OK, just checked ES5.1 15.7.4.5 (Number.prototype.toFixed) step 7 (currently touched). No explanation there either. So, the patch, as is now, introduces a new macro and inconsistently uses it in the code base. I start to get the feeling that we don't need this macro at all. Magic constants in the code are evil for sure, but such inconsistencies are even worse, IMHO.
(BTW, it seems to me that the current macro name + docstring are misleading. There is no way that we have 21 digits in the exponent. In double precision floating point, exponent is 11 bits, which is 4 base-10 digits at most.)
Summary: I think we should revert to NOT introducing a new macro and NOT touching other parts of the code base but where the bug is fixed.
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.
Yeah, it seems like a better idea.
7881cc3 to
9b79d5f
Compare
|
@akosthekiss I've updated this PR, please review. |
| } | ||
| else | ||
| { | ||
| /** NOTE: In this case no further conversations are required, execution will continue by 'toString' method */ |
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 think that a more precise cross reference would help a lot here. It took me quite some time to dig out from the code why toString will be called later on in this case. It's because this ecma_double_to_binary_floating_point seems to be called (transitively) from ecma_builtin_number_prototype_object_to_fixed only in step 6., and in step 7., the exponent (here: *exp_p) is checked whether its larger than 21. (And if it's larger, then the value returned and the buffer written by this function are discarded, and ecma_builtin_number_prototype_object_to_string is called instead. So, I think it's definitely worth noting here that the number 21 above is to be kept in sync with the number 21 in ecma_builtin_number_prototype_object_to_fixed step 7.
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'll give more detailed information about this cross reference to make this code easier to understand.
| else | ||
| { | ||
| ecma_double_to_ascii (val, buffer_p, &char_cnt); | ||
| if (num_of_digits <= 21) |
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 think we can use the else if chain here, too. I.e.,
if (fabs (integer_part) < EPSILON)
else if (integer_part < 10e16)
else if (num_of_digits <= 21)
else(instead of nesting an if/else in the final else).
BTW, now that we have num_of_digits in this function, do we need integer_part < 10e16 in the second if or can we have num_of_digits <= 16? Integer comparisons should be faster than FP, in general.
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.
That's a good idea.
|
Patch is fixed and I've added more precise description. |
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| assert(parseFloat(Number.MAX_VALUE).toFixed(5) == 1.7976931348623157e+308); |
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.
Hardcoding the numeric constant into the test may not be the best approach. Couldn't we check with assert(parseFloat(Number.MAX_VALUE).toFixed(5) == parseFloat(Number.MAX_VALUE).toString());? Seems to be a more maintainable approach to me.
| { | ||
| ecma_double_to_ascii (val, buffer_p, &char_cnt); | ||
| /** | ||
| * According to ECMA-262 v5, 15.7.4.5 7th step: if x ≥ 10^21, then execution will continue by |
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.
We shouldn't use non-ASCII characters in comments (or anywhere in the sources, actually). ≥ is U+2265. I think, >= would work just as well.
| else | ||
| { | ||
| ecma_double_to_ascii (val, buffer_p, &char_cnt); | ||
| /** |
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 is not (should not be) a doxygen comment. Just use simple /*. (/** is for documenting functions, arguments, structs, fields, macros, etc. Not for commenting code inside a functions.)
| * method 7th step. | ||
| */ | ||
| *exp_p = num_of_digits; | ||
| return (lit_utf8_size_t) char_cnt; |
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.
Is this a bit convoluted way of saying return 0;?
|
I can agree with your suggestions above. According to them I've updated this PR. |
akosthekiss
left a comment
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.
LGTM (it would be nice to have the wording of the comment text fixed before merging, though)
| /* According to ECMA-262 v5, 15.7.4.5 7th step: if x >= 10^21, then execution will continue by | ||
| * ToString(x) so in this case no further conversations are required. Number 21 in the else if condition | ||
| * above must be kept in sync with the number 21 in ecma_builtin_number_prototype_object_to_fixed | ||
| * method 7th step. */ |
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.
minor text improvement suggestions:
- "ECMA-262 v5, 15.7.4.5 7th step" -> "ECMA-262 v5, 15.7.4.5, step 7"
- "continue by" -> "continue with"
- "conversations" -> "conversions"
- "ecma_builtin_number_prototype_object_to_fixed method 7th step." -> "function ecma_builtin_number_prototype_object_to_fixed, step 7."
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.
Thanks for your suggestions. I've applied them!
|
still LGTM |
This patch fixes this bug which caused corrupted stack by preventing unnecessary double to ascii conversion even if the convertible number of digits is higher than allowed. In addition, improved ecma_double_to_binary_floating_point function by removing a needless buffer. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
| else | ||
| { | ||
| ecma_double_to_ascii (val, buffer_p, &char_cnt); | ||
| /* According to ECMA-262 v5, 15.7.4.5, step 7: if x >= 10^21, then execution will continue with |
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.
wrong indentation
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.
Fixed!
LaszloLango
left a comment
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.
LGTM
This patch fixes this bug which caused corrupted stack by preventing unnecessary double to ascii conversion even if
the convertable number of digits is higher than allowed.
In addition, improved ecma_double_to_binary_floating_point function by removing a needless buffer.
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu