Skip to content

Commit a0b4d1b

Browse files
committed
cli/doctor: handle truncated rows gracefully in zipdir
When debug doctor is run on zipdir files which are corrupt / incomplete it can end up crashing. This patch aims to generate a more productive error message if any row does not have enough fields in any file format. Currently this always hits an index out of range error. Fixes: #147722 Release note: None
1 parent 79e136a commit a0b4d1b

17 files changed

+421
-0
lines changed

pkg/cli/doctor.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ func fromZipDir(
376376
if checkIfFileExists(zipDirPath, "system.descriptor.txt") {
377377
if err := slurp(zipDirPath, "system.descriptor.txt", func(row string) error {
378378
fields := strings.Fields(row)
379+
if len(fields) != 2 {
380+
return errors.Errorf("expected 2 fields, got %d in system.descriptors.txt", len(fields))
381+
}
379382
last := len(fields) - 1
380383
i, err := strconv.Atoi(fields[0])
381384
if err != nil {
@@ -432,6 +435,9 @@ func fromZipDir(
432435
if checkIfFileExists(zipDirPath, namespaceFileName) {
433436
if err := slurp(zipDirPath, namespaceFileName, func(row string) error {
434437
fields := strings.Fields(row)
438+
if len(fields) != 4 {
439+
return errors.Errorf("expected 4 fields, got %d in system.namespace.txtq", len(fields))
440+
}
435441
parID, err := strconv.Atoi(fields[0])
436442
if err != nil {
437443
return errors.Wrapf(err, "failed to parse parent id %s", fields[0])
@@ -505,6 +511,9 @@ func fromZipDir(
505511
if checkIfFileExists(zipDirPath, "crdb_internal.system_jobs.txt") {
506512
if err := slurp(zipDirPath, "crdb_internal.system_jobs.txt", func(row string) error {
507513
fields := strings.Fields(row)
514+
if len(fields) < 6 {
515+
return errors.Errorf("expected at least 6 fields, got %d in crdb_internal.system_jobs.txt", len(fields))
516+
}
508517
md := jobs.JobMetadata{}
509518
md.State = jobs.State(fields[1])
510519

pkg/cli/doctor_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,42 @@ func TestDoctorZipDir(t *testing.T) {
260260
})
261261
})
262262

263+
t.Run("examine", func(t *testing.T) {
264+
out, err := c.RunWithCapture("debug doctor examine zipdir testdata/doctor/debugzip-bad-descriptors 21.1-52")
265+
if err != nil {
266+
t.Fatal(err)
267+
}
268+
269+
// Using datadriven allows TESTFLAGS=-rewrite.
270+
datadriven.RunTest(t, datapathutils.TestDataPath(t, "doctor", "test_examine_zipdir_bad_descriptors"), func(t *testing.T, td *datadriven.TestData) string {
271+
return out
272+
})
273+
})
274+
275+
t.Run("examine", func(t *testing.T) {
276+
out, err := c.RunWithCapture("debug doctor examine zipdir testdata/doctor/debugzip-bad-jobs 21.1-52")
277+
if err != nil {
278+
t.Fatal(err)
279+
}
280+
281+
// Using datadriven allows TESTFLAGS=-rewrite.
282+
datadriven.RunTest(t, datapathutils.TestDataPath(t, "doctor", "test_examine_zipdir_bad_jobs"), func(t *testing.T, td *datadriven.TestData) string {
283+
return out
284+
})
285+
})
286+
287+
t.Run("examine", func(t *testing.T) {
288+
out, err := c.RunWithCapture("debug doctor examine zipdir testdata/doctor/debugzip-bad-namespace 21.1-52")
289+
if err != nil {
290+
t.Fatal(err)
291+
}
292+
293+
// Using datadriven allows TESTFLAGS=-rewrite.
294+
datadriven.RunTest(t, datapathutils.TestDataPath(t, "doctor", "test_examine_zipdir_bad_namespace"), func(t *testing.T, td *datadriven.TestData) string {
295+
return out
296+
})
297+
})
298+
263299
// Regression test (for #104347) to ensure that quoted table names get properly parsed in system.namespace.
264300
t.Run("examine", func(t *testing.T) {
265301
out, err := c.RunWithCapture("debug doctor examine zipdir testdata/doctor/debugzip-with-quotes")

pkg/cli/testdata/doctor/debugzip-bad-descriptors/crdb_internal.system_jobs.txt

Lines changed: 55 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
few
3+
fields
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
something might have happened
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
parentID parentSchemaID name id
2+
0 0 defaultdb 100
3+
0 0 postgres 102
4+
0 0 system 1
5+
1 0 public 29
6+
1 29 comments 24
7+
1 29 database_role_settings 44
8+
1 29 descriptor 3
9+
1 29 descriptor_id_seq 7
10+
1 29 eventlog 12
11+
1 29 external_connections 53
12+
1 29 job_info 54
13+
1 29 jobs 15
14+
1 29 join_tokens 41
15+
1 29 lease 11
16+
1 29 locations 21
17+
1 29 migrations 40
18+
1 29 mvcc_statistics 64
19+
1 29 namespace 30
20+
1 29 privileges 52
21+
1 29 protected_ts_meta 31
22+
1 29 protected_ts_records 32
23+
1 29 rangelog 13
24+
1 29 region_liveness 9
25+
1 29 replication_constraint_stats 25
26+
1 29 replication_critical_localities 26
27+
1 29 replication_stats 27
28+
1 29 reports_meta 28
29+
1 29 role_id_seq 48
30+
1 29 role_members 23
31+
1 29 role_options 33
32+
1 29 scheduled_jobs 37
33+
1 29 settings 6
34+
1 29 span_configurations 47
35+
1 29 span_count 51
36+
1 29 span_stats_buckets 56
37+
1 29 span_stats_samples 57
38+
1 29 span_stats_tenant_boundaries 58
39+
1 29 span_stats_unique_keys 55
40+
1 29 sql_instances 46
41+
1 29 sqlliveness 39
42+
1 29 statement_activity 61
43+
1 29 statement_bundle_chunks 34
44+
1 29 statement_diagnostics 36
45+
1 29 statement_diagnostics_requests 35
46+
1 29 statement_execution_insights 66
47+
1 29 statement_statistics 42
48+
1 29 table_statistics 20
49+
1 29 task_payloads 59
50+
1 29 tenant_id_seq 63
51+
1 29 tenant_settings 50
52+
1 29 tenant_tasks 60
53+
1 29 tenant_usage 45
54+
1 29 tenants 8
55+
1 29 transaction_activity 62
56+
1 29 transaction_execution_insights 65
57+
1 29 transaction_statistics 43
58+
1 29 zones 5
59+
100 0 public 101
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
too few fields

pkg/cli/testdata/doctor/debugzip-bad-jobs/system.descriptor.txt

Lines changed: 63 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
something might have happened
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
parentID parentSchemaID name id
2+
0 0 defaultdb 100
3+
0 0 postgres 102
4+
0 0 system 1
5+
1 0 public 29
6+
1 29 comments 24
7+
1 29 database_role_settings 44
8+
1 29 descriptor 3
9+
1 29 descriptor_id_seq 7
10+
1 29 eventlog 12
11+
1 29 external_connections 53
12+
1 29 job_info 54
13+
1 29 jobs 15
14+
1 29 join_tokens 41
15+
1 29 lease 11
16+
1 29 locations 21
17+
1 29 migrations 40
18+
1 29 mvcc_statistics 64
19+
1 29 namespace 30
20+
1 29 privileges 52
21+
1 29 protected_ts_meta 31
22+
1 29 protected_ts_records 32
23+
1 29 rangelog 13
24+
1 29 region_liveness 9
25+
1 29 replication_constraint_stats 25
26+
1 29 replication_critical_localities 26
27+
1 29 replication_stats 27
28+
1 29 reports_meta 28
29+
1 29 role_id_seq 48
30+
1 29 role_members 23
31+
1 29 role_options 33
32+
1 29 scheduled_jobs 37
33+
1 29 settings 6
34+
1 29 span_configurations 47
35+
1 29 span_count 51
36+
1 29 span_stats_buckets 56
37+
1 29 span_stats_samples 57
38+
1 29 span_stats_tenant_boundaries 58
39+
1 29 span_stats_unique_keys 55
40+
1 29 sql_instances 46
41+
1 29 sqlliveness 39
42+
1 29 statement_activity 61
43+
1 29 statement_bundle_chunks 34
44+
1 29 statement_diagnostics 36
45+
1 29 statement_diagnostics_requests 35
46+
1 29 statement_execution_insights 66
47+
1 29 statement_statistics 42
48+
1 29 table_statistics 20
49+
1 29 task_payloads 59
50+
1 29 tenant_id_seq 63
51+
1 29 tenant_settings 50
52+
1 29 tenant_tasks 60
53+
1 29 tenant_usage 45
54+
1 29 tenants 8
55+
1 29 transaction_activity 62
56+
1 29 transaction_execution_insights 65
57+
1 29 transaction_statistics 43
58+
1 29 zones 5
59+
100 0 public 101

0 commit comments

Comments
 (0)