From bbff7574f59adf2bb0acec52a50dbed05cd9fad3 Mon Sep 17 00:00:00 2001 From: Alvaro Viebrantz Date: Tue, 18 Oct 2022 16:22:44 -0400 Subject: [PATCH 1/2] fix(bigquery): avoid stack overflow on query parameter with recursive types --- bigquery/params.go | 7 +++++++ bigquery/params_test.go | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/bigquery/params.go b/bigquery/params.go index 5cafbf85f06..cffe6c1b9f8 100644 --- a/bigquery/params.go +++ b/bigquery/params.go @@ -21,6 +21,7 @@ import ( "math/big" "reflect" "regexp" + "strings" "time" "cloud.google.com/go/civil" @@ -380,6 +381,12 @@ func paramType(t reflect.Type, v reflect.Value) (*bq.QueryParameterType, error) return nil, err } for _, f := range fields { + prefixes := []string{"*", "[]"} // check pointer and arrays + for _, prefix := range prefixes { + if strings.TrimPrefix(t.String(), prefix) == strings.TrimPrefix(f.Type.String(), prefix) { + return nil, fmt.Errorf("bigquery: Go type %s cannot be represented as a parameter due to a cycle detected", t) + } + } pt, err := paramType(f.Type, v) if err != nil { return nil, err diff --git a/bigquery/params_test.go b/bigquery/params_test.go index fa6a293051d..ceb8af0dd64 100644 --- a/bigquery/params_test.go +++ b/bigquery/params_test.go @@ -282,10 +282,46 @@ func TestParamType(t *testing.T) { } } } - func TestParamTypeErrors(t *testing.T) { for _, val := range []interface{}{ - nil, uint(0), new([]int), make(chan int), + nil, uint(0), new([]int), make(chan int), map[string]interface{}{}, + } { + _, err := paramType(reflect.TypeOf(val), reflect.ValueOf(val)) + if err == nil { + t.Errorf("%v (%T): got nil, want error", val, val) + } + } + + type recArr struct { + RecArr []recArr + } + type recMap struct { + RecMap map[string]recMap + } + queryParam := QueryParameterValue{ + StructValue: map[string]QueryParameterValue{ + "nested": { + Type: StandardSQLDataType{ + TypeKind: "STRING", + }, + Value: "TEST", + }, + }, + } + standardSQL := StandardSQLDataType{ + ArrayElementType: &StandardSQLDataType{ + TypeKind: "NUMERIC", + }, + } + recursiveArr := recArr{ + RecArr: []recArr{}, + } + recursiveMap := recMap{ + RecMap: map[string]recMap{}, + } + // Recursive structs + for _, val := range []interface{}{ + queryParam, standardSQL, recursiveArr, recursiveMap, } { _, err := paramType(reflect.TypeOf(val), reflect.ValueOf(val)) if err == nil { From 869d8d2116c32dd3b4d3fcaf79d81c80dae23193 Mon Sep 17 00:00:00 2001 From: Alvaro Viebrantz Date: Mon, 24 Oct 2022 12:45:05 -0400 Subject: [PATCH 2/2] fix(bigquery): better error msg for cycle/recursion --- bigquery/params.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigquery/params.go b/bigquery/params.go index cffe6c1b9f8..bdbe9a94710 100644 --- a/bigquery/params.go +++ b/bigquery/params.go @@ -384,7 +384,7 @@ func paramType(t reflect.Type, v reflect.Value) (*bq.QueryParameterType, error) prefixes := []string{"*", "[]"} // check pointer and arrays for _, prefix := range prefixes { if strings.TrimPrefix(t.String(), prefix) == strings.TrimPrefix(f.Type.String(), prefix) { - return nil, fmt.Errorf("bigquery: Go type %s cannot be represented as a parameter due to a cycle detected", t) + return nil, fmt.Errorf("bigquery: Go type %s cannot be represented as a parameter due to an attribute cycle/recursion detected", t) } } pt, err := paramType(f.Type, v)