Skip to content

Commit 188c66a

Browse files
authored
Merge pull request #11924 from tangcong/fix-crc-mismatch
wal: fix crc mismatch crash bug
2 parents 732df43 + 02b9ad3 commit 188c66a

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

CHANGELOG-3.5.md

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Note that any `etcd_debugging_*` metrics are experimental and subject to change.
119119
- Previously, server restore fails if it had crashed after persisting raft hard state but before saving snapshot.
120120
- See https://github.com/etcd-io/etcd/issues/10219 for more.
121121
- Improve logging around snapshot send and receive.
122+
- Add [missing CRC checksum check in WAL validate method otherwise causes panic](https://github.com/etcd-io/etcd/pull/11924).
122123

123124
### Package `embed`
124125

wal/wal.go

+8
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,14 @@ func ValidSnapshotEntries(lg *zap.Logger, walDir string) ([]walpb.Snapshot, erro
567567
snaps = append(snaps, loadedSnap)
568568
case stateType:
569569
state = mustUnmarshalState(rec.Data)
570+
case crcType:
571+
crc := decoder.crc.Sum32()
572+
// current crc of decoder must match the crc of the record.
573+
// do no need to match 0 crc, since the decoder is a new one at this case.
574+
if crc != 0 && rec.Validate(crc) != nil {
575+
return nil, ErrCRCMismatch
576+
}
577+
decoder.updateCRC(rec.Crc)
570578
}
571579
}
572580
// We do not have to read out all the WAL entries

wal/wal_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -1052,3 +1052,60 @@ func TestValidSnapshotEntries(t *testing.T) {
10521052
t.Errorf("expected walSnaps %+v, got %+v", expected, walSnaps)
10531053
}
10541054
}
1055+
1056+
// TestValidSnapshotEntriesAfterPurgeWal ensure that there are many wal files, and after cleaning the first wal file,
1057+
// it can work well.
1058+
func TestValidSnapshotEntriesAfterPurgeWal(t *testing.T) {
1059+
oldSegmentSizeBytes := SegmentSizeBytes
1060+
SegmentSizeBytes = 64
1061+
defer func() {
1062+
SegmentSizeBytes = oldSegmentSizeBytes
1063+
}()
1064+
p, err := ioutil.TempDir(os.TempDir(), "waltest")
1065+
if err != nil {
1066+
t.Fatal(err)
1067+
}
1068+
defer os.RemoveAll(p)
1069+
snap0 := walpb.Snapshot{Index: 0, Term: 0}
1070+
snap1 := walpb.Snapshot{Index: 1, Term: 1}
1071+
state1 := raftpb.HardState{Commit: 1, Term: 1}
1072+
snap2 := walpb.Snapshot{Index: 2, Term: 1}
1073+
snap3 := walpb.Snapshot{Index: 3, Term: 2}
1074+
state2 := raftpb.HardState{Commit: 3, Term: 2}
1075+
func() {
1076+
w, err := Create(zap.NewExample(), p, nil)
1077+
if err != nil {
1078+
t.Fatal(err)
1079+
}
1080+
defer w.Close()
1081+
1082+
// snap0 is implicitly created at index 0, term 0
1083+
if err = w.SaveSnapshot(snap1); err != nil {
1084+
t.Fatal(err)
1085+
}
1086+
if err = w.Save(state1, nil); err != nil {
1087+
t.Fatal(err)
1088+
}
1089+
if err = w.SaveSnapshot(snap2); err != nil {
1090+
t.Fatal(err)
1091+
}
1092+
if err = w.SaveSnapshot(snap3); err != nil {
1093+
t.Fatal(err)
1094+
}
1095+
for i := 0; i < 128; i++ {
1096+
if err = w.Save(state2, nil); err != nil {
1097+
t.Fatal(err)
1098+
}
1099+
}
1100+
1101+
}()
1102+
files, _, err := selectWALFiles(nil, p, snap0)
1103+
if err != nil {
1104+
t.Fatal(err)
1105+
}
1106+
os.Remove(p + "/" + files[0])
1107+
_, err = ValidSnapshotEntries(zap.NewExample(), p)
1108+
if err != nil {
1109+
t.Fatal(err)
1110+
}
1111+
}

0 commit comments

Comments
 (0)