mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
C#: Guard against cyclic inclusions in project files
This commit is contained in:
@@ -1020,5 +1020,27 @@ namespace Semmle.Extraction.Tests
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 0, 4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestCyclicDirsProj()
|
||||
{
|
||||
Actions.FileExists["dirs.proj"] = true;
|
||||
Actions.GetEnvironmentVariable["TRAP_FOLDER"] = null;
|
||||
Actions.GetEnvironmentVariable["SOURCE_ARCHIVE"] = null;
|
||||
Actions.FileExists["csharp.log"] = false;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "dirs.proj";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
|
||||
var dirsproj1 = new XmlDocument();
|
||||
dirsproj1.LoadXml(@"<Project DefaultTargets=""Build"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""3.5"">
|
||||
<ItemGroup>
|
||||
<ProjectFiles Include=""dirs.proj"" />
|
||||
</ItemGroup>
|
||||
</Project>");
|
||||
Actions.LoadXml["dirs.proj"] = dirsproj1;
|
||||
|
||||
var autobuilder = CreateAutoBuilder("csharp", false);
|
||||
TestAutobuilderScript(autobuilder, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ namespace Semmle.Autobuild
|
||||
|
||||
public Version ToolsVersion { get; private set; }
|
||||
|
||||
readonly List<Project> includedProjects = new List<Project>();
|
||||
public override IEnumerable<IProjectOrSolution> IncludedProjects =>
|
||||
includedProjects.Concat(includedProjects.SelectMany(s => s.IncludedProjects));
|
||||
readonly Lazy<List<Project>> includedProjectsLazy;
|
||||
public override IEnumerable<IProjectOrSolution> IncludedProjects => includedProjectsLazy.Value;
|
||||
|
||||
public Project(Autobuilder builder, string path) : base(builder, path)
|
||||
{
|
||||
ToolsVersion = new Version();
|
||||
includedProjectsLazy = new Lazy<List<Project>>(() => new List<Project>());
|
||||
|
||||
if (!builder.Actions.FileExists(FullPath))
|
||||
return;
|
||||
@@ -69,17 +69,22 @@ namespace Semmle.Autobuild
|
||||
}
|
||||
}
|
||||
|
||||
// The documentation on `.proj` files is very limited, but it appears that both
|
||||
// `<ProjectFile Include="X"/>` and `<ProjectFiles Include="X"/>` is valid
|
||||
var mgr = new XmlNamespaceManager(projFile.NameTable);
|
||||
mgr.AddNamespace("msbuild", "http://schemas.microsoft.com/developer/msbuild/2003");
|
||||
var projectFileIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFile/@Include", mgr).OfType<XmlNode>();
|
||||
var projectFilesIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFiles/@Include", mgr).OfType<XmlNode>();
|
||||
foreach (var include in projectFileIncludes.Concat(projectFilesIncludes))
|
||||
includedProjectsLazy = new Lazy<List<Project>>(() =>
|
||||
{
|
||||
var includePath = builder.Actions.IsWindows() ? include.Value : include.Value.Replace("\\", "/");
|
||||
includedProjects.Add(new Project(builder, builder.Actions.PathCombine(Path.GetDirectoryName(this.FullPath), includePath)));
|
||||
}
|
||||
var ret = new List<Project>();
|
||||
// The documentation on `.proj` files is very limited, but it appears that both
|
||||
// `<ProjectFile Include="X"/>` and `<ProjectFiles Include="X"/>` is valid
|
||||
var mgr = new XmlNamespaceManager(projFile.NameTable);
|
||||
mgr.AddNamespace("msbuild", "http://schemas.microsoft.com/developer/msbuild/2003");
|
||||
var projectFileIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFile/@Include", mgr).OfType<XmlNode>();
|
||||
var projectFilesIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFiles/@Include", mgr).OfType<XmlNode>();
|
||||
foreach (var include in projectFileIncludes.Concat(projectFilesIncludes))
|
||||
{
|
||||
var includePath = builder.Actions.IsWindows() ? include.Value : include.Value.Replace("\\", "/");
|
||||
ret.Add(new Project(builder, builder.Actions.PathCombine(Path.GetDirectoryName(this.FullPath), includePath)));
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Semmle.Autobuild
|
||||
string FullPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of other projects included by this file.
|
||||
/// Gets a list of other projects directly included by this file.
|
||||
/// </summary>
|
||||
IEnumerable<IProjectOrSolution> IncludedProjects { get; }
|
||||
}
|
||||
@@ -39,8 +39,16 @@ namespace Semmle.Autobuild
|
||||
/// <summary>
|
||||
/// Holds if this file includes a project with code from language <paramref name="l"/>.
|
||||
/// </summary>
|
||||
public static bool HasLanguage(this IProjectOrSolution p, Language l) =>
|
||||
l.ProjectFileHasThisLanguage(p.FullPath) ||
|
||||
p.IncludedProjects.Any(p0 => l.ProjectFileHasThisLanguage(p0.FullPath));
|
||||
public static bool HasLanguage(this IProjectOrSolution p, Language l)
|
||||
{
|
||||
bool HasLanguage(IProjectOrSolution p0, HashSet<string> seen)
|
||||
{
|
||||
if (seen.Contains(p0.FullPath))
|
||||
return false;
|
||||
seen.Add(p0.FullPath); // guard against cyclic includes
|
||||
return l.ProjectFileHasThisLanguage(p0.FullPath) || p0.IncludedProjects.Any(p1 => HasLanguage(p1, seen));
|
||||
}
|
||||
return HasLanguage(p, new HashSet<string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user