Skip to content

Conversation

@rerobika
Copy link
Member

@rerobika rerobika commented Sep 4, 2017

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

{
ecma_double_to_ascii (val, buffer_p, &char_cnt);
if (num_of_digits < 22)
{
Copy link
Contributor

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@robertsipka robertsipka Sep 5, 2017

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) ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Of course. :)

@rerobika rerobika changed the title Fix for issue #1993 Fix for toFixed method Sep 5, 2017
@rerobika rerobika force-pushed the issue_1993 branch 2 times, most recently from daeac38 to 7881cc3 Compare September 8, 2017 14:18

/**
* Maximum number of digits in string representation of ecma-number exponent part
*/
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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.

@rerobika
Copy link
Member Author

@akosthekiss I've updated this PR, please review.

}
else
{
/** NOTE: In this case no further conversations are required, execution will continue by 'toString' method */
Copy link
Member

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.

Copy link
Member Author

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)
Copy link
Member

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.

Copy link
Member Author

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.

@rerobika
Copy link
Member Author

rerobika commented Nov 6, 2017

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);
Copy link
Member

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
Copy link
Member

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);
/**
Copy link
Member

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;
Copy link
Member

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;?

@rerobika
Copy link
Member Author

rerobika commented Nov 8, 2017

I can agree with your suggestions above. According to them I've updated this PR.

Copy link
Member

@akosthekiss akosthekiss left a 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. */
Copy link
Member

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."

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 for your suggestions. I've applied them!

@akosthekiss
Copy link
Member

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
Copy link
Contributor

Choose a reason for hiding this comment

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

wrong indentation

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed!

Copy link
Contributor

@LaszloLango LaszloLango left a comment

Choose a reason for hiding this comment

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

LGTM

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