Skip to content

Commit 9347366

Browse files
authored
Fix out of bounds panic when tsconfig "files" contains duplicates (#1675)
1 parent e8a0920 commit 9347366

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

internal/tsoptions/parsedcommandline.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type ParsedCommandLine struct {
3737
resolvedProjectReferencePaths []string
3838
resolvedProjectReferencePathsOnce sync.Once
3939

40+
literalFileNamesLen int
4041
fileNamesByPath map[tspath.Path]string // maps file names to their paths, used for quick lookups
4142
fileNamesByPathOnce sync.Once
4243
}
@@ -217,7 +218,7 @@ func (p *ParsedCommandLine) WildcardDirectories() map[string]bool {
217218
// Normalized file names explicitly specified in `files`
218219
func (p *ParsedCommandLine) LiteralFileNames() []string {
219220
if p != nil && p.ConfigFile != nil {
220-
return p.FileNames()[0:len(p.ConfigFile.configFileSpecs.validatedFilesSpec)]
221+
return p.FileNames()[0:p.literalFileNamesLen]
221222
}
222223
return nil
223224
}
@@ -349,13 +350,14 @@ func (p *ParsedCommandLine) GetMatchedIncludeSpec(fileName string) (string, bool
349350

350351
func (p *ParsedCommandLine) ReloadFileNamesOfParsedCommandLine(fs vfs.FS) *ParsedCommandLine {
351352
parsedConfig := *p.ParsedConfig
352-
parsedConfig.FileNames = getFileNamesFromConfigSpecs(
353+
fileNames, literalFileNamesLen := getFileNamesFromConfigSpecs(
353354
*p.ConfigFile.configFileSpecs,
354355
p.GetCurrentDirectory(),
355356
p.CompilerOptions(),
356357
fs,
357358
p.extraFileExtensions,
358359
)
360+
parsedConfig.FileNames = fileNames
359361
parsedCommandLine := ParsedCommandLine{
360362
ParsedConfig: &parsedConfig,
361363
ConfigFile: p.ConfigFile,
@@ -365,6 +367,7 @@ func (p *ParsedCommandLine) ReloadFileNamesOfParsedCommandLine(fs vfs.FS) *Parse
365367
comparePathsOptions: p.comparePathsOptions,
366368
wildcardDirectories: p.wildcardDirectories,
367369
extraFileExtensions: p.extraFileExtensions,
370+
literalFileNamesLen: literalFileNamesLen,
368371
}
369372
return &parsedCommandLine
370373
}

internal/tsoptions/parsedcommandline_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,28 @@ func TestParsedCommandLine(t *testing.T) {
111111
"/dev/b.ts",
112112
})
113113
})
114+
115+
t.Run("duplicates", func(t *testing.T) {
116+
t.Parallel()
117+
parsedCommandLine := tsoptionstest.GetParsedCommandLine(
118+
t,
119+
`{
120+
"files": [
121+
"a.ts",
122+
"a.ts",
123+
"b.ts",
124+
]
125+
}`,
126+
files,
127+
"/dev",
128+
/*useCaseSensitiveFileNames*/ true,
129+
)
130+
131+
assert.DeepEqual(t, parsedCommandLine.LiteralFileNames(), []string{
132+
"/dev/a.ts",
133+
"/dev/b.ts",
134+
})
135+
})
114136
})
115137

116138
t.Run("with literal include list", func(t *testing.T) {

internal/tsoptions/tsconfigparsing.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,9 +1269,9 @@ func parseJsonConfigFileContentWorker(
12691269
sourceFile.configFileSpecs = &configFileSpecs
12701270
}
12711271

1272-
getFileNames := func(basePath string) []string {
1272+
getFileNames := func(basePath string) ([]string, int) {
12731273
parsedConfigOptions := parsedConfig.options
1274-
fileNames := getFileNamesFromConfigSpecs(configFileSpecs, basePath, parsedConfigOptions, host.FS(), extraFileExtensions)
1274+
fileNames, literalFileNamesLen := getFileNamesFromConfigSpecs(configFileSpecs, basePath, parsedConfigOptions, host.FS(), extraFileExtensions)
12751275
if shouldReportNoInputFiles(fileNames, canJsonReportNoInputFiles(rawConfig), resolutionStack) {
12761276
includeSpecs := configFileSpecs.includeSpecs
12771277
excludeSpecs := configFileSpecs.excludeSpecs
@@ -1283,7 +1283,7 @@ func parseJsonConfigFileContentWorker(
12831283
}
12841284
errors = append(errors, ast.NewCompilerDiagnostic(diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, configFileName, core.Must(core.StringifyJson(includeSpecs, "", "")), core.Must(core.StringifyJson(excludeSpecs, "", ""))))
12851285
}
1286-
return fileNames
1286+
return fileNames, literalFileNamesLen
12871287
}
12881288

12891289
getProjectReferences := func(basePath string) []*core.ProjectReference {
@@ -1310,12 +1310,13 @@ func parseJsonConfigFileContentWorker(
13101310
return projectReferences
13111311
}
13121312

1313+
fileNames, literalFileNamesLen := getFileNames(basePathForFileNames)
13131314
return &ParsedCommandLine{
13141315
ParsedConfig: &core.ParsedOptions{
13151316
CompilerOptions: parsedConfig.options,
13161317
TypeAcquisition: parsedConfig.typeAcquisition,
13171318
// WatchOptions: nil,
1318-
FileNames: getFileNames(basePathForFileNames),
1319+
FileNames: fileNames,
13191320
ProjectReferences: getProjectReferences(basePathForFileNames),
13201321
},
13211322
ConfigFile: sourceFile,
@@ -1327,6 +1328,7 @@ func parseJsonConfigFileContentWorker(
13271328
UseCaseSensitiveFileNames: host.FS().UseCaseSensitiveFileNames(),
13281329
CurrentDirectory: basePathForFileNames,
13291330
},
1331+
literalFileNamesLen: literalFileNamesLen,
13301332
}
13311333
}
13321334

@@ -1608,7 +1610,7 @@ func getFileNamesFromConfigSpecs(
16081610
options *core.CompilerOptions,
16091611
host vfs.FS,
16101612
extraFileExtensions []FileExtensionInfo,
1611-
) []string {
1613+
) ([]string, int) {
16121614
extraFileExtensions = []FileExtensionInfo{}
16131615
basePath = tspath.NormalizePath(basePath)
16141616
keyMappper := func(value string) string { return tspath.GetCanonicalFileName(value, host.UseCaseSensitiveFileNames()) }
@@ -1696,7 +1698,7 @@ func getFileNamesFromConfigSpecs(
16961698
for file := range wildCardJsonFileMap.Values() {
16971699
files = append(files, file)
16981700
}
1699-
return files
1701+
return files, literalFileMap.Size()
17001702
}
17011703

17021704
func GetSupportedExtensions(compilerOptions *core.CompilerOptions, extraFileExtensions []FileExtensionInfo) [][]string {

0 commit comments

Comments
 (0)