Skip to content

Fix GH-17384: Reject too large number_format decimals#22435

Open
LamentXU123 wants to merge 3 commits into
php:masterfrom
LamentXU123:number_format-ValueError
Open

Fix GH-17384: Reject too large number_format decimals#22435
LamentXU123 wants to merge 3 commits into
php:masterfrom
LamentXU123:number_format-ValueError

Conversation

@LamentXU123

Copy link
Copy Markdown
Member

number_format($number, 9876543210); is now silently equals to number_format($number, 2147483647); and generates 2147483647 decimal places and eat up 2 GB memory (and exhaust almost half of them which cause a fatal error).

I only reject very large positive numbers here (as every input larger than 2147483647 is silently turned into 2147483647). Because negative ones is always returning 0 anyways and only very large positive numbers can cause to such problems.

Fixes #17384

Comment thread ext/standard/math.c Outdated
Comment on lines +1418 to +1421
if (dec > INT_MAX) {
zend_argument_value_error(2, "must be less than or equal to %d", INT_MAX);
RETURN_THROWS();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Surely, to error on truncation?

Suggested change
if (dec > INT_MAX) {
zend_argument_value_error(2, "must be less than or equal to %d", INT_MAX);
RETURN_THROWS();
}
if (dec > INT_MAX || dec < INT_MIN) {
zend_argument_value_error(2, "must be between %d and %d", INT_MIN, INT_MAX);
RETURN_THROWS();
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hmm I don't think we should reject "large" negative numbers. They works fine (see: https://3v4l.org/4uI70#v) because they always returns to 0 and doesn't awkwardly allocates a whopping 2GB memories.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think we should silently be truncating stuff, which is what is happening in the ZEND_LONG_INT_UDFL(dec) ? INT_MIN : (int)dec; code.

Also if you pass such a negative number I've got questions

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also surround in UNEXPECTED please.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Noted. It is fixed now :)

Let's now use dec_int = (int) dec; instead of dec_int = ZEND_LONG_INT_UDFL(dec) ? INT_MIN : (int)dec; then.

@LamentXU123 LamentXU123 Jun 25, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Also if you pass such a negative number I've got questions

Previous test files tests for PHP_INT_MIN to make sure it returns 0. Not sure if it is intentional by design: 4471528

But rejecting it also make sense, I won't object if people might think accepting large negative numbers while rejecting positive ones is weird. So now I change this patch to reject both (as what you've suggested).

@LamentXU123 LamentXU123 force-pushed the number_format-ValueError branch from 0ed083a to c02f291 Compare June 25, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

number_format function gives an out of memory error for bad $decimals value

2 participants