Fix String.prototype.repeat with a large count on an empty string - #1741
Merged
bnoordhuis merged 2 commits intoSep 24, 2026
Merged
Conversation
Step 4 of String.prototype.repeat throws a RangeError only when the count is negative or +Infinity. We threw for any count above 2^31-1, so "".repeat(Number.MAX_SAFE_INTEGER) raised a RangeError where the spec asks for the empty String. The range check ran before the len == 0 short circuit, and JS_ToInt64Sat saturates +Infinity and a large finite count to the same value, so the two could not be told apart. Do the ToIntegerOrInfinity conversion in a double instead: reject a negative or infinite count, then return early for an empty receiver, and only after that reject a count that would overflow JS_STRING_LEN_MAX. A large finite count on a non-empty string still throws, now as "invalid string length".
bnoordhuis
reviewed
Sep 22, 2026
bnoordhuis
left a comment
Contributor
There was a problem hiding this comment.
While the change is functionally correct, it makes the error message for large repeat counts worse: invalid string length instead of invalid repeat count
Can you change it to something like string too long?
A finite count that makes the result exceed JS_STRING_LEN_MAX now throws RangeError: string too long, which says more than "invalid string length". A negative or infinite count still throws "invalid repeat count".
Contributor
Author
|
Changed it to |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1735.
Step 4 of
String.prototype.repeatthrows a RangeError only when the count isnegative or
+Infinity; step 6 then producesncopies of the receiver. For anempty receiver that is the empty String for any finite
n, however large, andno allocation is needed. We threw for any count above
2^31-1, so"".repeat(Number.MAX_SAFE_INTEGER)raisedRangeError: invalid repeat countwhere V8, JSC, SpiderMonkey and GraalJS all return
"".Two things stood in the way of just moving the check. The range check ran before
the
len == 0 || n == 1short circuit, andJS_ToInt64Satsaturates, so+Infinityand a large finite count both arrive asINT64_MAXand cannot betold apart, yet
"".repeat(Infinity)must still throw while"".repeat(2**53-1)must not.So the conversion is now done in a double, which follows ToIntegerOrInfinity
directly: NaN maps to zero, everything else truncates toward zero, and a
negative or infinite count is rejected. The empty-receiver and
n == 1earlyreturn comes next, and the
JS_STRING_LEN_MAXcheck last, on a value that isknown to be finite and non-negative. A large finite count on a non-empty string
still throws, now as
string too long. Working in a double also sidesteps theval * lenoverflow that lifting the2^31-1bound would otherwise introduce.Behavior change, empty receiver only:
"".repeat(Number.MAX_SAFE_INTEGER)"""".repeat(2147483648)"""".repeat(1e300)""Everything else is unchanged except the message on
"ab".repeat(2**53-1)andfriends, which goes from
invalid repeat counttostring too long. Itis still a RangeError.
Validation
The first three items were run on the original commit. After the message change
in 5cf8f60,
make teston Linux (WSL), gcc: 0/117 errors, 9 excluded, andtests/bug1735.jspasses with its new message assertions.make teston macOS/arm64, clang, Release: 0/117 errors, 9 excluded. The newtests/bug1735.jsfails on master at the"".repeat(Number.MAX_SAFE_INTEGER)assertion and passes with the fix.
run-test262 -m -c test262.conf test262/test/built-ins/String: 0/1223 errorsbefore and after, so nothing in the String suite regressed. Worth noting that
test262 does not cover a large finite count on an empty receiver, which is why
this went unnoticed.
-Infinity,+Infinity, NaN,undefined,-0,0,0.9,1,2.7, a large finitecount on both an empty and a non-empty receiver, and the
JS_STRING_LEN_MAXboundary (
"a".repeat(1073741823)succeeds,1073741824throws). Alsoconfirmed the receiver is still coerced with ToString before the count is
coerced, and that a Symbol or BigInt count still throws a TypeError.