Changeset 0.22.0 (#93)

This commit is contained in:
2026-03-01 23:57:33 +00:00
parent 3423738286
commit 12e03cec8b
5 changed files with 385 additions and 3 deletions

View File

@@ -183,3 +183,70 @@ func TestSafeJSON_PaginatedWithCorrupt(t *testing.T) {
t.Fatalf("expected 500 for paginated response with corrupt item, got %d", w.Code)
}
}
// ── Driver buffer aliasing tests ────────────
// These verify the fix for the v0.21.7 corruption bug: scanJSON must
// copy []byte from the database driver, not alias it. Without the copy,
// rows.Next() can overwrite the buffer and corrupt previously-scanned
// json.RawMessage values in a paginated list.
func TestScanJSON_ByteSliceNotAliased(t *testing.T) {
var dest json.RawMessage
s := scanJSON(&dest)
// Simulate driver buffer with valid JSON
buf := []byte(`{"key":"value"}`)
if err := s.Scan(buf); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// Simulate driver reusing the buffer on next rows.Scan()
copy(buf, []byte(`invalid_json!!`))
// dest must still hold the original valid value
if !json.Valid(dest) {
t.Fatalf("dest corrupted after source buffer reuse: %q", dest)
}
if string(dest) != `{"key":"value"}` {
t.Fatalf("expected original value, got %q", dest)
}
}
func TestScanJSON_ByteSliceIsolation_MultiRow(t *testing.T) {
// Simulate scanning two rows through the same driver buffer,
// as happens in ListChannels when lib/pq reuses memory.
var dest1, dest2 json.RawMessage
// Row 1
buf := make([]byte, 64)
row1 := []byte(`{"row":1,"selector":"abc"}`)
copy(buf, row1)
s1 := scanJSON(&dest1)
if err := s1.Scan(buf[:len(row1)]); err != nil {
t.Fatalf("row 1 scan error: %v", err)
}
// Row 2 — driver reuses same buffer
row2 := []byte(`{"row":2}`)
copy(buf, row2)
s2 := scanJSON(&dest2)
if err := s2.Scan(buf[:len(row2)]); err != nil {
t.Fatalf("row 2 scan error: %v", err)
}
// Both must retain their original values
if string(dest1) != `{"row":1,"selector":"abc"}` {
t.Fatalf("dest1 corrupted by row 2 scan: %q", dest1)
}
if string(dest2) != `{"row":2}` {
t.Fatalf("dest2 unexpected value: %q", dest2)
}
// Both must be independently valid JSON
if !json.Valid(dest1) {
t.Fatalf("dest1 not valid JSON after multi-row scan: %q", dest1)
}
if !json.Valid(dest2) {
t.Fatalf("dest2 not valid JSON after multi-row scan: %q", dest2)
}
}