Skip to content

Commit 854ccfc

Browse files
authored
fix(bigquery): avoid stack overflow on query param with recursive types (#6890)
Resolves #6884
1 parent afbecb6 commit 854ccfc

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

bigquery/params.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"math/big"
2222
"reflect"
2323
"regexp"
24+
"strings"
2425
"time"
2526

2627
"cloud.google.com/go/civil"
@@ -380,6 +381,12 @@ func paramType(t reflect.Type, v reflect.Value) (*bq.QueryParameterType, error)
380381
return nil, err
381382
}
382383
for _, f := range fields {
384+
prefixes := []string{"*", "[]"} // check pointer and arrays
385+
for _, prefix := range prefixes {
386+
if strings.TrimPrefix(t.String(), prefix) == strings.TrimPrefix(f.Type.String(), prefix) {
387+
return nil, fmt.Errorf("bigquery: Go type %s cannot be represented as a parameter due to an attribute cycle/recursion detected", t)
388+
}
389+
}
383390
pt, err := paramType(f.Type, v)
384391
if err != nil {
385392
return nil, err

bigquery/params_test.go

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,46 @@ func TestParamType(t *testing.T) {
282282
}
283283
}
284284
}
285-
286285
func TestParamTypeErrors(t *testing.T) {
287286
for _, val := range []interface{}{
288-
nil, uint(0), new([]int), make(chan int),
287+
nil, uint(0), new([]int), make(chan int), map[string]interface{}{},
288+
} {
289+
_, err := paramType(reflect.TypeOf(val), reflect.ValueOf(val))
290+
if err == nil {
291+
t.Errorf("%v (%T): got nil, want error", val, val)
292+
}
293+
}
294+
295+
type recArr struct {
296+
RecArr []recArr
297+
}
298+
type recMap struct {
299+
RecMap map[string]recMap
300+
}
301+
queryParam := QueryParameterValue{
302+
StructValue: map[string]QueryParameterValue{
303+
"nested": {
304+
Type: StandardSQLDataType{
305+
TypeKind: "STRING",
306+
},
307+
Value: "TEST",
308+
},
309+
},
310+
}
311+
standardSQL := StandardSQLDataType{
312+
ArrayElementType: &StandardSQLDataType{
313+
TypeKind: "NUMERIC",
314+
},
315+
}
316+
recursiveArr := recArr{
317+
RecArr: []recArr{},
318+
}
319+
recursiveMap := recMap{
320+
RecMap: map[string]recMap{},
321+
}
322+
// Recursive structs
323+
for _, val := range []interface{}{
324+
queryParam, standardSQL, recursiveArr, recursiveMap,
289325
} {
290326
_, err := paramType(reflect.TypeOf(val), reflect.ValueOf(val))
291327
if err == nil {

0 commit comments

Comments
 (0)