Skip to content

Commit

Permalink
Fixed a Potential Stack Overflow Error in findProductRef (#1146)
Browse files Browse the repository at this point in the history
* * Fixed the potential stack overflow error for the function `findProductRef` in `pkg/ingestor/parser/csaf/parser_csaf.go`
* Included unit tests for `findProductRef`
* Used a visted map to solve the stack overflow, and didn't use Dynamic Programing because there was no need to go over the nodes again

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Fixed fmt error

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Removed flag for stack overflow

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

---------

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>
  • Loading branch information
nathannaveen committed Aug 17, 2023
1 parent 30e2a71 commit be3da8d
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
18 changes: 17 additions & 1 deletion pkg/ingestor/parser/csaf/parser_csaf.go
Expand Up @@ -58,6 +58,13 @@ type csafParser struct {
csaf *csaf.CSAF
}

type visitedProductRef struct {
productName string
productID string
name string
category string
}

func NewCsafParser() common.DocumentParser {
return &csafParser{
identifierStrings: &common.IdentifierStrings{},
Expand Down Expand Up @@ -101,14 +108,23 @@ func findPurl(ctx context.Context, tree csaf.ProductBranch, product_ref string)
}

func findProductRef(ctx context.Context, tree csaf.ProductBranch, product_id string) *string {
return findProductRefSearch(ctx, tree, product_id, make(map[visitedProductRef]bool))
}

func findProductRefSearch(ctx context.Context, tree csaf.ProductBranch, product_id string, visited map[visitedProductRef]bool) *string {
if visited[visitedProductRef{tree.Product.Name, tree.Product.ID, tree.Name, tree.Category}] {
return nil
}
visited[visitedProductRef{tree.Product.Name, tree.Product.ID, tree.Name, tree.Category}] = true

for _, r := range tree.Relationships {
if r.FullProductName.ID == product_id {
return &r.ProductRef
}
}

for _, b := range tree.Branches {
pref := findProductRef(ctx, b, product_id)
pref := findProductRefSearch(ctx, b, product_id, visited)
if pref != nil {
return pref
}
Expand Down
86 changes: 86 additions & 0 deletions pkg/ingestor/parser/csaf/parser_csaf_test.go
Expand Up @@ -17,8 +17,11 @@ package csaf

import (
"context"
"reflect"
"testing"

"github.com/openvex/go-vex/pkg/csaf"

"github.com/google/go-cmp/cmp"
"github.com/guacsec/guac/internal/testing/testdata"
"github.com/guacsec/guac/pkg/assembler"
Expand Down Expand Up @@ -69,3 +72,86 @@ func Test_csafParser(t *testing.T) {
})
}
}

func Test_findProductRef(t *testing.T) {
defaultTestTree := csaf.ProductBranch{
Name: "node1",
Branches: []csaf.ProductBranch{
{
Name: "node2",
Relationships: []csaf.Relationship{
{
FullProductName: csaf.Product{
ID: "relationshipProductID2",
},
ProductRef: "relationshipProductRef2",
},
},
},
},
}
defaultReturnProductRef := &defaultTestTree.Branches[0].Relationships[0].ProductRef

// creating the tree outside the test loop and then making the child point back to the parent because
// the child can only point back to the parent if the tree is already created
// The child is pointing back to the parent outside the loop so that this test doesn't need a stackoverflow flag
stackoverflowTestTree := csaf.ProductBranch{
Name: "node1",
Product: csaf.Product{
Name: "productName1",
ID: "productID1",
},
Category: "category1",

Branches: []csaf.ProductBranch{
{ // create a child branch which will then point back to the parent branch
Name: "node2",
Product: csaf.Product{
Name: "productName2",
ID: "productID2",
},
Category: "category2",
},
},
}

// The child branch is pointing back to the parent branch to create a loop
stackoverflowTestTree.Branches[0].Branches = append(stackoverflowTestTree.Branches[0].Branches, stackoverflowTestTree)

type args struct {
ctx context.Context
tree csaf.ProductBranch
product_id string
}
tests := []struct {
name string
args args
want *string
}{
{
name: "default",
args: args{
ctx: context.Background(),
tree: defaultTestTree,
product_id: defaultTestTree.Branches[0].Relationships[0].FullProductName.ID,
},
want: defaultReturnProductRef,
},
{
name: "can stack overflow",
args: args{
ctx: context.Background(),
tree: stackoverflowTestTree,
product_id: "not equal to any tree nodes",
},
want: nil,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if got := findProductRef(test.args.ctx, test.args.tree, test.args.product_id); !reflect.DeepEqual(got, test.want) {
t.Errorf("findProductRef() = %v, want %v", got, test.want)
}
})
}
}

0 comments on commit be3da8d

Please sign in to comment.