TokenReader subrange bounds enforced inconsistently: peekToken/peekPreviousTokenKind/backtrackToMarker ignore embedded window
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 72/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- typescript
- Área
- compilers
Línea de trabajo
Empieza en tsdoc/src/parser/TokenReader.ts comparando peekToken(), peekPreviousTokenKind() y backtrackToMarker() con los métodos hermanos protegidos. Revisa el comportamiento del lector embebido y los puntos de llamada de NodeParser mencionados en el issue. Se considera terminado cuando los tres métodos respetan la ventana [_readerStartIndex, _readerEndIndex) y el comportamiento elegido para el final de la entrada está cubierto por pruebas.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
TokenReader respects its embedded subrange (_readerStartIndex/_readerEndIndex) in peekTokenKind()/peekTokenAfterKind()/peekTokenAfterAfterKind(), but three sibling methods ignore those bounds: peekToken() has no end guard at all, and peekPreviousTokenKind() / backtrackToMarker() compare against 0 / allow rewinding before the subrange start. This leaks outer tokens into embedded parses and can return undefined where Token is promised.
Location
- File:
tsdoc/src/parser/TokenReader.ts - Class:
TokenReader - Methods:
peekToken(): Token—return this.tokens[this._currentIndex];with no_readerEndIndexcheckpeekPreviousTokenKind()—if (this._currentIndex === 0)instead of=== this._readerStartIndexbacktrackToMarker(marker)— checksmarker > this._currentIndexbut notmarker < this._readerStartIndex
Contrast with the guarded siblings in the same file:
public peekTokenKind(): TokenKind {
if (this._currentIndex >= this._readerEndIndex) {
return TokenKind.EndOfInput;
}
...
}
Problem
peekToken()past end returnsundefined: return type claimsToken, but past_readerEndIndexthe index expression yieldsundefined. Callers doingpeekToken().range/peekToken().kindthen throwTypeError: Cannot read properties of undefinedinstead of getting a cleanEndOfInputsignal. Current internal hot paths inNodeParser.tshappen to callpeekTokenKind()first (e.g. block/inline tagbadCharacterpaths), which masks the hole, but the public API contract is broken for any external consumer or future internal use.peekPreviousTokenKind()leaks across embedded start: for an embedded reader starting at index N>0, calling it at the embedded start returnstokens[N-1].kind(outer context) instead ofEndOfInput.NodeParser._parseBlockTagand_parseFencedCodeswitch on this to decide start-of-input behavior (AtSignInWord,CodeFenceOpeningIndent); an embedded@or fence at the subrange start can therefore be misclassified using the token before the subrange.backtrackToMarker()can rewind before subrange start: nothing preventsmarker < _readerStartIndex, letting a laterreadToken()consume outer tokens that the embedded reader was explicitly scoped to exclude.
Trigger / Reproduction
Based on static analysis (no execution performed):
- Construct
new TokenReader(parserContext, embeddedSequence)whereembeddedSequence.startIndex > 0, advance to the embedded start, and callpeekPreviousTokenKind()— returns the outer predecessor kind instead ofEndOfInput. - Call
peekToken()when_currentIndex === _readerEndIndex— returnsundefinedinstead of signaling end (comparepeekTokenKind()returningEndOfInputin the same state). - Call
backtrackToMarker(outerMarker)withouterMarker < _readerStartIndexon an embedded reader — accepted, subsequent reads escape the subrange.
Note: this is a static-analysis finding; I did not execute a parser fixture.
Expected Behavior
All TokenReader accessors/mutators should honor the same [ _readerStartIndex, _readerEndIndex ) window: peekToken() should signal end (or throw a clear parser-bug error like readToken() does) instead of returning undefined; peekPreviousTokenKind() should return EndOfInput at the subrange start; backtrackToMarker() should reject markers below the subrange start.
Actual Behavior
Subrange bounds are enforced inconsistently, so embedded parses can observe outer tokens and end-of-input handling differs by method.
Impact
- Potential spurious
AtSignInWord/ fence-indent errors for embedded constructs starting at a subrange boundary. undefined-tokenTypeErrors for API consumers usingpeekToken()at end, bypassing the cleanEndOfInputprotocol every sibling method follows.
Suggested Direction
- Mirror the existing
peekTokenKind()guard inpeekToken()(return theEndOfInputtoken or throw a parser-bug error — maintainer's choice, but document it), change thepeekPreviousTokenKind()zero-check to_readerStartIndex, and add amarker < _readerStartIndexrejection inbacktrackToMarker(). No grammar changes needed.
Evidence
- Source via API:
tsdoc/src/parser/TokenReader.tsshows guardedpeekTokenKind/peekTokenAfterKind/peekTokenAfterAfterKindvs unguardedpeekToken/peekPreviousTokenKind/backtrackToMarker;tsdoc/src/parser/NodeParser.tsshowspeekPreviousTokenKindgatingAtSignInWord/CodeFenceOpeningIndentand embeddedTokenReaderconstruction for scoped parses. - Duplicate check: issue search for
peekToken TokenReader boundsreturnstotal_count: 0, and open issues contain no TokenReader-boundary report — no apparent duplicate. This is a non-security correctness finding, so Microsoft's private-security-disclosure requirement does not apply.
Classification
- FACT: three
TokenReadermethods ignore the subrange window that three sibling methods enforce (verified in source via API). - INFERENCE: embedded parses can observe out-of-range tokens; end-of-input
peekToken()yieldsundefined. - HYPOTHESIS: aligning all methods on the same window fixes the misclassification/TypeError risk with no grammar change.
- Lenguaje dominante
- TypeScript
- Estrellas
- 5k
- Forks
- 162
- Merge medio
- 2 d 4 h
- PR fusionados (30 d)
- 12
Preparar el entorno
Aún no hemos revisado los archivos de configuración de este proyecto. Empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de microsoft/tsdoc
-
Dificultad 3/5 1-2 días Aptitud para principiantes 35/100
microsoft/tsdoc#470 · 2 comentarios · 6 reacciones ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 25/100
microsoft/tsdoc#450 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
microsoft/tsdoc#442 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 42/100
microsoft/tsdoc#440 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de microsoft/tsdoc
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 78/100
lichess-org/api#678 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
PostHog/posthog.com#20628 ·
Los mantenedores suelen responder en 1 día
-
bug status:Needs Triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
jupyterlab/jupyterlab#19964 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
agentscope-ai/QwenPaw#8064 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
area: notebooks-jupyter bug theme: new notebook frontend
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
posit-dev/positron#16347 · 1 comentario ·
Los mantenedores suelen responder en 1 día