apache / apache/cassandra-gocql-driver

parseType panics on bare CompositeType or unterminated type string (index out of range)

Open
#1,963 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
2.7k
Forks
658
PR merge metrics
No merged PRs in 30d

Description

## Summary

`parseType`'s composite-type branch indexes `ast.params[count-1]` **without checking that the parsed `CompositeType` class actually has parameters**. A schema metadata string of exactly `"org.apache.cassandra.db.marshal.CompositeType"` (no parameter list) parses into a node with zero params, and line 2259 then evaluates `ast.params[-1]` — a guaranteed `panic: index out of range [-1]` inside library code. An unterminated `(` in the type string panics the same way inside `parseParamNodes`.

## Location

- File: [`metadata.go`](https://github.com/apache/cassandra-gocql-driver/blob/00fc2909c64a7529fe49fb31b0fa8662342ebe69/metadata.go)
- Function: `(*typeParser).parse`, COMPOSITE_TYPE branch (line ~2255–2259)
- Contributing: `(*typeParser).parseParamNodes` — returns `(nil, true)` when the class name is not followed by `(`, so an empty param list is a normal, successful parse outcome

```go
if strings.HasPrefix(ast.name, COMPOSITE_TYPE) {
count := len(ast.params)

// look for a collections param
last := ast.params[count-1] // ← count can be 0
```

```go
for t.input[t.index] != ')' { // ← no bounds check; unterminated '(' runs off the end
```

## Problem

The parser assumes every `CompositeType(...)` node carries at least one parameter (its validator looks for a trailing `ColumnToCollectionType`). But `parseClassNode`/`parseParamNodes` explicitly treat a missing parameter list as valid (`// the params are optional`). The two assumptions collide: any input where the parsed AST is a bare `COMPOSITE_TYPE` class reaches `params[-1]`.

A second, related path: while scanning parameter nodes, the loop condition reads `t.input[t.index]` without first checking `t.index < len(t.input)`, so a truncated type string ending in `(` (or in `name:` form without a closing paren) also panics instead of returning a parse error.

Both are reachable through normal library entry points — `parseType` is called while interpreting `system_schema`-derived type strings (validator / clustering order definitions), so a malformed or unexpected value coming back from a node becomes a process crash rather than a returned error.

## Trigger / Reproduction

Static analysis finding — not confirmed by execution; derived from the parser control flow at `trunk` (`00fc2909`):

```go
res, err := parseType(session, "org.apache.cassandra.db.marshal.CompositeType")
// → panic: runtime error: index out of range [-1]

res, err = parseType(session, "org.apache.cassandra.db.marshal.CompositeType(")
// → panic: index out of range [len(input)]
```

(For the second case the exact byte sequence needs to route through `nextIdentifier` such that the scan reaches end-of-input mid-loop; both stem from the missing bounds/emptiness checks.)

## Expected Behavior

Malformed or degenerate type strings should produce `err` (e.g. `fmt.Errorf("type '%s' has no parameters", t.input)`), consistent with how other malformed inputs are handled elsewhere in the parser; callers already degrade gracefully to `unknownTypeInfo` when parsing reports failure.

## Actual Behavior

Library panic propagates out of `KeyspaceMetadata` fetching / schema refresh.

## Impact

A single unexpected validator string (from an unusual legacy table, a broken schema, or a fuzzed/foreign node) crashes the entire client process during schema metadata retrieval. This is user-reachable data-driven input, so it must be handled as an error path, not assumed-valid.

## Suggested Direction

1. Guard the composite branch: if `count == 0`, return a parse error.
2. Add `t.index >= len(t.input)` checks to the `parseParamNodes` loop and return `(nil, false)` on truncation.
3. Consider adding these two inputs to `fuzz.go`'s corpus for `parseType`.

Contributor guide

Open the contributing guide

Research direction

Start in metadata.go at (*typeParser).parse and parseParamNodes, then trace the two reproduction strings through parseType. Confirm that bare or truncated CompositeType inputs return errors rather than panicking, and add regression coverage or the inputs to fuzz.go's parseType corpus as appropriate.

Written by the indexing model from the issue text.

Assessment

Tech stack
cassandra, go
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.