@@ -157,8 +157,26 @@ func decodeCMetadata(md *C.char) arrow.Metadata {
157157
158158// convert a C.ArrowSchema to an arrow.Field to maintain metadata with the schema
159159func importSchema (schema * CArrowSchema ) (ret arrow.Field , err error ) {
160+ if schema == nil {
161+ return ret , fmt .Errorf ("%w: nil ArrowSchema" , arrow .ErrInvalid )
162+ }
160163 // always release, even on error
161164 defer C .ArrowSchemaRelease (schema )
165+ if schema .format == nil {
166+ return ret , fmt .Errorf ("%w: ArrowSchema format is nil" , arrow .ErrInvalid )
167+ }
168+ if schema .n_children < 0 {
169+ return ret , fmt .Errorf ("%w: ArrowSchema n_children cannot be negative: %d" , arrow .ErrInvalid , schema .n_children )
170+ }
171+ if int64 (schema .n_children ) > maxIntValue () {
172+ return ret , fmt .Errorf ("%w: ArrowSchema n_children is too large: %d" , arrow .ErrInvalid , schema .n_children )
173+ }
174+ if _ , err := checkedMul (int64 (schema .n_children ), int64 (unsafe .Sizeof (uintptr (0 )))); err != nil {
175+ return ret , fmt .Errorf ("%w: ArrowSchema children pointer array is too large" , arrow .ErrInvalid )
176+ }
177+ if schema .n_children > 0 && schema .children == nil {
178+ return ret , fmt .Errorf ("%w: ArrowSchema children is nil with n_children %d" , arrow .ErrInvalid , schema .n_children )
179+ }
162180
163181 var childFields []arrow.Field
164182 if schema .n_children > 0 {
@@ -181,12 +199,18 @@ func importSchema(schema *CArrowSchema) (ret arrow.Field, err error) {
181199
182200 // copies the c-string here, but it's very small
183201 f := C .GoString (schema .format )
202+ if f == "" {
203+ return ret , fmt .Errorf ("%w: ArrowSchema format is empty" , arrow .ErrInvalid )
204+ }
184205 // handle our non-parameterized simple types.
185206 dt , ok := formatToSimpleType [f ]
186207 if ok {
187208 ret .Type = dt
188209
189210 if schema .dictionary != nil {
211+ if ! arrow .IsInteger (ret .Type .ID ()) {
212+ return ret , fmt .Errorf ("%w: dictionary index type must be an integer" , arrow .ErrInvalid )
213+ }
190214 valueField , err := importSchema (schema .dictionary )
191215 if err != nil {
192216 return ret , err
@@ -215,7 +239,10 @@ func importSchema(schema *CArrowSchema) (ret arrow.Field, err error) {
215239 case "w" : // fixed size binary is "w:##" where ## is the byteWidth
216240 byteWidth , err := strconv .Atoi (val )
217241 if err != nil {
218- return ret , err
242+ return ret , fmt .Errorf ("%w: invalid fixed-size binary format %q: %v" , arrow .ErrInvalid , f , err )
243+ }
244+ if byteWidth <= 0 {
245+ return ret , fmt .Errorf ("%w: fixed-size binary byte width must be positive: %d" , arrow .ErrInvalid , byteWidth )
219246 }
220247 dt = & arrow.FixedSizeBinaryType {ByteWidth : byteWidth }
221248 case "d" : // decimal types are d:<precision>,<scale>[,<bitsize>] size is assumed 128 if left out
@@ -258,37 +285,85 @@ func importSchema(schema *CArrowSchema) (ret arrow.Field, err error) {
258285 }
259286
260287 if f [0 ] == '+' { // types with children
288+ if len (f ) < 2 {
289+ return ret , fmt .Errorf ("%w: invalid nested type format %q" , arrow .ErrInvalid , f )
290+ }
261291 switch f [1 ] {
262292 case 'l' : // list
293+ if f != "+l" {
294+ return ret , fmt .Errorf ("%w: invalid list type format %q" , arrow .ErrInvalid , f )
295+ }
296+ if len (childFields ) != 1 {
297+ return ret , fmt .Errorf ("%w: list type must have exactly 1 child" , arrow .ErrInvalid )
298+ }
263299 dt = arrow .ListOfField (childFields [0 ])
264300 case 'L' : // large list
301+ if f != "+L" {
302+ return ret , fmt .Errorf ("%w: invalid large list type format %q" , arrow .ErrInvalid , f )
303+ }
304+ if len (childFields ) != 1 {
305+ return ret , fmt .Errorf ("%w: large list type must have exactly 1 child" , arrow .ErrInvalid )
306+ }
265307 dt = arrow .LargeListOfField (childFields [0 ])
266308 case 'v' : // list view/large list view
309+ if (f != "+vl" && f != "+vL" ) || len (childFields ) != 1 {
310+ return ret , fmt .Errorf ("%w: invalid list view type format %q or child count %d" , arrow .ErrInvalid , f , len (childFields ))
311+ }
267312 switch f [2 ] {
268313 case 'l' :
269314 dt = arrow .ListViewOfField (childFields [0 ])
270315 case 'L' :
271316 dt = arrow .LargeListViewOfField (childFields [0 ])
317+ default :
318+ return ret , fmt .Errorf ("%w: invalid list view type format %q" , arrow .ErrInvalid , f )
272319 }
273320 case 'w' : // fixed size list is w:# where # is the list size.
274- listSize , err := strconv .Atoi (strings .Split (f , ":" )[1 ])
321+ if len (childFields ) != 1 {
322+ return ret , fmt .Errorf ("%w: fixed-size list type must have exactly 1 child" , arrow .ErrInvalid )
323+ }
324+ _ , size , ok := strings .Cut (f , ":" )
325+ if ! ok {
326+ return ret , fmt .Errorf ("%w: invalid fixed-size list format %q" , arrow .ErrInvalid , f )
327+ }
328+ listSize , err := strconv .Atoi (size )
275329 if err != nil {
276- return ret , err
330+ return ret , fmt .Errorf ("%w: invalid fixed-size list format %q: %v" , arrow .ErrInvalid , f , err )
331+ }
332+ if listSize <= 0 || int64 (listSize ) > 1 << 31 - 1 {
333+ return ret , fmt .Errorf ("%w: fixed-size list size must be in the range [1, %d]: %d" , arrow .ErrInvalid , 1 << 31 - 1 , listSize )
277334 }
278335
279336 dt = arrow .FixedSizeListOfField (int32 (listSize ), childFields [0 ])
280337 case 's' : // struct
338+ if f != "+s" {
339+ return ret , fmt .Errorf ("%w: invalid struct type format %q" , arrow .ErrInvalid , f )
340+ }
281341 dt = arrow .StructOf (childFields ... )
282342 case 'r' : // run-end encoded
343+ if f != "+r" {
344+ return ret , fmt .Errorf ("%w: invalid run-end encoded type format %q" , arrow .ErrInvalid , f )
345+ }
283346 if len (childFields ) != 2 {
284347 return ret , fmt .Errorf ("%w: run-end encoded arrays must have 2 children" , arrow .ErrInvalid )
285348 }
286349 dt = arrow .RunEndEncodedOf (childFields [0 ].Type , childFields [1 ].Type )
287350 case 'm' : // map type is basically a list of structs.
288- st := childFields [0 ].Type .(* arrow.StructType )
351+ if f != "+m" {
352+ return ret , fmt .Errorf ("%w: invalid map type format %q" , arrow .ErrInvalid , f )
353+ }
354+ if len (childFields ) != 1 {
355+ return ret , fmt .Errorf ("%w: map type must have exactly 1 child" , arrow .ErrInvalid )
356+ }
357+ st , ok := childFields [0 ].Type .(* arrow.StructType )
358+ if ! ok || st .NumFields () != 2 {
359+ return ret , fmt .Errorf ("%w: map child must be a struct with exactly 2 fields" , arrow .ErrInvalid )
360+ }
289361 dt = arrow .MapOf (st .Field (0 ).Type , st .Field (1 ).Type )
290362 dt .(* arrow.MapType ).KeysSorted = (schema .flags & C .ARROW_FLAG_MAP_KEYS_SORTED ) != 0
291363 case 'u' : // union
364+ if len (f ) < 3 {
365+ return ret , fmt .Errorf ("%w: invalid union type format %q" , arrow .ErrInvalid , f )
366+ }
292367 var mode arrow.UnionMode
293368 switch f [2 ] {
294369 case 'd' :
0 commit comments