Skip to content

TryReadResponseFile masks nested response file resolution failures #2324

Open
@tannergooding

Description

@tannergooding

TryReadResponseFile is implemented here:

internal static bool TryReadResponseFile(
string filePath,
out IReadOnlyList<string>? newTokens,
out string? error)
{
try
{
newTokens = ExpandResponseFile(filePath).ToArray();
error = null;
return true;
}
catch (FileNotFoundException)
{
error = LocalizationResources.ResponseFileNotFound(filePath);
}
catch (IOException e)
{
error = LocalizationResources.ErrorReadingResponseFile(filePath, e);
}
newTokens = null;
return false;
static IEnumerable<string> ExpandResponseFile(string filePath)
{
var lines = File.ReadAllLines(filePath);
for (var i = 0; i < lines.Length; i++)
{
var line = lines[i];
foreach (var p in SplitLine(line))
{
if (p.GetReplaceableTokenValue() is { } path)
{
foreach (var q in ExpandResponseFile(path))
{
yield return q;
}
}
else
{
yield return p;
}
}
}
}

It is effectively just calling ExpandResponseFile in a try/catch, which itself will recursively call ExpandResponseFile not in a try/catch.

What this means is that the top-most response file can succeed in resolution, but a nested response file might fail, which will in then report that the top most file was the point of failure.


Imagine you have:

WorkingDirectory
    ChildDir
        File1.rsp
    OtherDir
        File2.rsp

You then call Program @ChildDir/File1.rsp where File1.rsp itself contains @../OtherDir/File2.rsp.

You will get a failure of Response file not found 'ChildDir/File1.rsp, even though that file was found and it was ../OtherDir/File2.rsp which could not be resolved.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions