String positions and indices are clamped before they reach a pointer or a count - #28
Merged
Merged
Conversation
…or a count slice with its end at or before its start computed a negative count, which resize and memcpy took as a huge size and copied past the result (#27). It now returns "", as in JavaScript; slice does not swap the way substring does. The end parameter of slice and substring, and the position of endsWith and lastIndexOf, defaulted to this.length and so took its unsigned type, though lib.d.ts declares int: a negative argument became huge, every `< 0` check was dead, and slice(1, -3) returned "bcdef". They are int now. Positions are clamped to [0, length] before they become a pointer into the string: startsWith, includes and indexOf read before the string for a negative position, and endsWith and lastIndexOf read after its terminator for one past the end. indexOf past the end returned the length for any search string; now only "" is found there, as in JavaScript. includes and lastIndexOf return "not found" for a null search string, as indexOf does (includes passed null to strstr; lastIndexOf returned the position). trim and trimEnd passed the last kept character as substring's exclusive end and dropped it (" ab ".trim() was "a"), and a string of spaces kept all but one of them. Fixes #27 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
String positions and indices are clamped before they become a pointer into the string or a byte count.
sliceoverflow (String.slice(start, end) with end < start overflows the result buffer #27): an end at or before the start gave a negative count, whichresizeandmemcpytook as a huge size.slicenow returns"", as in JavaScript. It does not swap the waysubstringdoes.indexEndofslice/substringand thepositionofendsWith/lastIndexOfdefaulted tothis.lengthand so took its unsigned type, althoughlib.d.tsdeclaresint. Every< 0check was dead, and"abcdef".slice(1, -3)returned"bcdef". They are annotatedintnow.[0, length]. Before,startsWith,includesandindexOfread before the string for a negative position, andendsWithandlastIndexOfread after the terminator for a position past the end.indexOfpast the end returned the length for any search string. Now only""is found there, as in JavaScript.includes(null)returns false. Before, it passed null tostrstr.lastIndexOf(null)returns -1. Before, it returned the position.indexOf.trim/trimEnd: they passed the last kept character assubstring's exclusive end." ab ".trim()was"a", and a string of spaces kept all but one of them.Fixes #27
The compiler half of this pass (string concatenation without
strcpy/strcat) is ASDAlexander77/TypeScriptCompiler#520. The two are independent.Test plan
tests/string_bounds.ts: each case above, checked against JavaScript's resultsmaintoo. That is being looked into separately.🤖 Generated with Claude Code