diff --git a/syft/pkg/cataloger/dotnet/deps_json.go b/syft/pkg/cataloger/dotnet/deps_json.go index d61f09ce5..b0a8d2af8 100644 --- a/syft/pkg/cataloger/dotnet/deps_json.go +++ b/syft/pkg/cataloger/dotnet/deps_json.go @@ -252,8 +252,8 @@ func getLogicalDepsJSON(deps depsJSON, lm *libmanJSON) logicalDepsJSON { if !bundlingDetected && knownBundlers.Has(name) { bundlingDetected = true } - p.AnyChildClaimsDLLs = searchForDLLClaims(packageMap, p.dependencyNameVersions()...) - p.AnyChildHasDLLs = searchForDLLEvidence(packageMap, p.dependencyNameVersions()...) + p.AnyChildClaimsDLLs = searchForDLLClaims(packageMap, strset.New(), p.dependencyNameVersions()...) + p.AnyChildHasDLLs = searchForDLLEvidence(packageMap, strset.New(), p.dependencyNameVersions()...) packages[p.NameVersion] = *p } @@ -286,31 +286,35 @@ func mergeSets(s1, s2 *strset.Set) *strset.Set { type visitorFunc func(p *logicalDepsJSONPackage) bool // searchForDLLEvidence recursively searches for executables found for any of the given nameVersions and children recursively. -func searchForDLLEvidence(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool { +func searchForDLLEvidence(packageMap map[string]*logicalDepsJSONPackage, visited *strset.Set, nameVersions ...string) bool { return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool { return p.FoundDLLs(true) - }, nameVersions...) + }, visited, nameVersions...) } // searchForDLLClaims recursively searches for DLL claims in the deps.json for any of the given nameVersions and children recursively. -func searchForDLLClaims(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool { +func searchForDLLClaims(packageMap map[string]*logicalDepsJSONPackage, visited *strset.Set, nameVersions ...string) bool { return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool { return p.ClaimsDLLs(true) - }, nameVersions...) + }, visited, nameVersions...) } -func traverseDependencies(packageMap map[string]*logicalDepsJSONPackage, visitor visitorFunc, nameVersions ...string) bool { +func traverseDependencies(packageMap map[string]*logicalDepsJSONPackage, visitor visitorFunc, visited *strset.Set, nameVersions ...string) bool { if len(nameVersions) == 0 { return false } for _, nameVersion := range nameVersions { + if visited.Has(nameVersion) { + continue + } + visited.Add(nameVersion) if p, ok := packageMap[nameVersion]; ok { if visitor(p) { return true } - if traverseDependencies(packageMap, visitor, p.dependencyNameVersions()...) { + if traverseDependencies(packageMap, visitor, visited, p.dependencyNameVersions()...) { return true } } diff --git a/syft/pkg/cataloger/dotnet/deps_json_test.go b/syft/pkg/cataloger/dotnet/deps_json_test.go index 96fd34571..d8e391558 100644 --- a/syft/pkg/cataloger/dotnet/deps_json_test.go +++ b/syft/pkg/cataloger/dotnet/deps_json_test.go @@ -149,6 +149,11 @@ func TestGetLogicalDepsJSON_MergeTargets(t *testing.T) { "lib/netcoreapp3.1/Microsoft.CodeAnalysis.CSharp.dll": {}, }, }, + "Microsoft.CodeAnalysis.Common/4.0.0": { + Dependencies: map[string]string{ + "Microsoft.CodeAnalysis.CSharp": "4.0.0", + }, + }, }, }, Libraries: map[string]depsLibrary{