amacneil / amacneil/dbmate

TrimLeadingSQLComments reads past line bounds on single-character lines (potential panic / wrong skip)

Offen
#828 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Go
Sterne
7.4k
Forks
379
Ø Merge
6 Min.
Gemergte PRs (30 T.)
1

Beschreibung

## Description

`dbutil.TrimLeadingSQLComments` indexes `line[0:2]` without checking that the line has at least two bytes. For a one-character line inside the leading-comment block, this either panics or silently compares bytes beyond the end of the current line, so the function can crash or wrongly drop a data line from a schema dump.

*This report is based on static analysis of the source (master); I have not executed the code.*

- Version: master (`pkg/dbutil/dbutil.go`)
- Database: affects all drivers using this helper for dump post-processing (postgres, mysql, sqlite)
- Operating System: any

## Location

- File: `pkg/dbutil/dbutil.go`
- Function: `TrimLeadingSQLComments`
- Relevant code path:

```go
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
line := scanner.Bytes()

if preamble && (len(line) == 0 || bytes.Equal(line[0:2], []byte("--"))) {
continue
}
...
```

## Problem

The preamble check tests `len(line) == 0 || bytes.Equal(line[0:2], []byte("--"))`. When `len(line) == 1`, the expression `line[0:2]` slices past the end of the token:

1. **Panic case:** Go slicing requires `high <= cap(s)`. If the underlying array shared by `scanner.Bytes()` does not have two addressable bytes after the token start, `line[0:2]` panics with *slice bounds out of range*. `bufio.Scanner.Bytes()` returns a view into the scanner's internal buffer, whose remaining capacity at that offset depends on buffer growth/sliding — so whether this panics depends on where the line sits in the buffer, not just on its length.
2. **Wrong-comparison case:** when capacity happens to be sufficient, `bytes.Equal(line[0:2], ...)` still reads a byte that is not part of the current line (the following newline, or stale bytes from a previous read chunk after the scanner reuses its buffer). The comparison result is then determined by unrelated buffer content: if those bytes happen to be `"--"`, a legitimate one-character data line is silently skipped and removed from the dump; otherwise it is kept.

## Steps To Reproduce

Conceptually, call:

```go
dbutil.TrimLeadingSQLComments([]byte("-- header\n-\nSELECT 1;\n"))
```

The second line (`-`, length 1) reaches the `preamble` branch with `len(line) == 1`, forcing evaluation of `line[0:2]`. Whether this panics or miscompares depends on the scanner's internal buffer state at that offset (see above). A unit test with inputs engineered around the ~4KB scanner-buffer boundary should expose both modes.

## Expected Behavior

A one-character line should simply fail the "is it a comment?" test (it cannot start with `--`) and be preserved in the output, without any out-of-bounds access.

## Actual Behavior

`line[0:2]` performs an out-of-bounds-capacity slice for length-1 lines: potential panic, and an unreliable comparison that can drop lines from schema dumps processed by `DumpSchema` implementations.

## Impact

`TrimLeadingSQLComments` post-processes `pg_dump`/`mysqldump` output in the postgres, mysql and sqlite drivers. A crash aborts dumping; the wrong-skip mode would corrupt `schema.sql` by deleting a real line from the dumped SQL. Both failure modes are silent or confusing for users.

## Suggested Direction

Guard the slice, e.g. `len(line) >= 2 && bytes.Equal(line[0:2], []byte("--"))` (the zero-length case is already handled), and add table-driven cases with single-character lines inside and after the preamble.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.