Skip to content

Commit

Permalink
Avoid stack overflow error for root_package (guacsec#404)
Browse files Browse the repository at this point in the history
* Remove stack overflow error

I realized that there could be a stack overflow error in `getCompHelper()` from the file `pkg/components/root_package/root_package.go`.  The reason for this being that there is a recusive call to `getCompHelper()`. Because of this I edited `getCompHelper()` and wrote a test. After figuring out that there was a stack overflow error I created a `vistited` map to solve the issue.

I edited `getCompHelper()` to make it easier for me to test whether there would be a stack overflow error.

``` go
func getCompHelper(ctx context.Context, client graphdb.Client, parentPurl string, dependencies []interface{}, visited map[int64]bool) ([]*PackageComponent, error) {
	//dependencies, err := graphdb.ReadQuery(client, "MATCH (p:Package) WHERE p.purl = $rootPurl WITH p MATCH (p)-[:DependsOn]->(p2:Package) return p2",
	//	map[string]any{"rootPurl": parentPurl})
	//if err != nil {
	//	return nil, err
	//}
	depPackages := []*PackageComponent{}
	for _, dep := range dependencies {
		foundDep, ok := dep.(dbtype.Node)
		if !ok {
			return nil, errors.New("failed to cast to node type")
		}
		if _, ok := visited[foundDep.Id]; ok {
			continue
		}
		visited[foundDep.Id] = true
		foundDepPack := assembler.PackageNode{}
		foundDepPack.Purl, ok = foundDep.Props["purl"].(string)
		if !ok {
			return nil, errors.New("failed to cast purl property to string type")
		}
		deps, err := getCompHelper(ctx, client, foundDepPack.Purl, dependencies, visited)
		if err != nil {
			return nil, err
		}
		depPackages = append(depPackages, &PackageComponent{
			Package:     foundDepPack,
			DepPackages: deps,
		})
	}
	return depPackages, nil
}
```

``` go
func TestGetCompHelperForStackOverflow(t *testing.T) {
	ctx := context.Background()
	ctrl := gomock.NewController(t)
	driver := mocks.NewMockDriver(ctrl)
	client := driver
	parentPurl := "testPurl"
	dependencies := []interface{}{}
	// create a circular dependency to cause stack overflow
	for i := 0; i < 10000; i++ {
		dependencies = append(dependencies, dbtype.Node{
			Id:     int64(i),
			Labels: []string{"Package"},
			Props:  map[string]interface{}{"purl": parentPurl},
		})
	}

	_, err := getCompHelper(ctx, client, parentPurl, dependencies, map[int]bool{})
	if err != nil {
		t.Error(err)
	}
}
```

Signed-off-by: nathannaveen <[email protected]>

* Updated based on code reivew

Signed-off-by: nathannaveen <[email protected]>

---------

Signed-off-by: nathannaveen <[email protected]>
  • Loading branch information
nathannaveen authored Mar 3, 2023
1 parent 8fe8ce7 commit 1ad4a4d
Showing 1 changed file with 9 additions and 3 deletions.
12 changes: 9 additions & 3 deletions pkg/certifier/components/root_package/root_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ func (q *packageQuery) GetComponents(ctx context.Context, compChan chan<- interf
if !ok {
return errors.New("failed to cast to node type")
}
visited := map[int64]bool{foundNode.Id: true}
rootPackage := assembler.PackageNode{}
rootPackage.Purl, ok = foundNode.Props["purl"].(string)
if !ok {
return errors.New("failed to cast purl property to string type")
}
deps, err := getCompHelper(ctx, q.client, rootPackage.Purl)
deps, err := getCompHelper(ctx, q.client, rootPackage.Purl, visited)
if err != nil {
return err
}
Expand All @@ -76,7 +77,7 @@ func (q *packageQuery) GetComponents(ctx context.Context, compChan chan<- interf
return nil
}

func getCompHelper(ctx context.Context, client graphdb.Client, parentPurl string) ([]*PackageComponent, error) {
func getCompHelper(ctx context.Context, client graphdb.Client, parentPurl string, visited map[int64]bool) ([]*PackageComponent, error) {
dependencies, err := graphdb.ReadQuery(client, "MATCH (p:Package) WHERE p.purl = $rootPurl WITH p MATCH (p)-[:DependsOn]->(p2:Package) return p2",
map[string]any{"rootPurl": parentPurl})
if err != nil {
Expand All @@ -88,12 +89,17 @@ func getCompHelper(ctx context.Context, client graphdb.Client, parentPurl string
if !ok {
return nil, errors.New("failed to cast to node type")
}
if visited[foundDep.Id] {
continue
}
visited[foundDep.Id] = true

foundDepPack := assembler.PackageNode{}
foundDepPack.Purl, ok = foundDep.Props["purl"].(string)
if !ok {
return nil, errors.New("failed to cast purl property to string type")
}
deps, err := getCompHelper(ctx, client, foundDepPack.Purl)
deps, err := getCompHelper(ctx, client, foundDepPack.Purl, visited)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 1ad4a4d

Please sign in to comment.