From 425acb28c428fc5ee621794d1cc857fad5d1852f Mon Sep 17 00:00:00 2001 From: Gyu-Ho Lee Date: Tue, 8 Nov 2016 10:49:44 -0800 Subject: [PATCH] mvcc: return -1 for wrong watcher range key >= end Fix https://github.com/coreos/etcd/issues/6819. --- mvcc/watcher.go | 7 +++++++ mvcc/watcher_test.go | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/mvcc/watcher.go b/mvcc/watcher.go index abd8e73e4..9468d4269 100644 --- a/mvcc/watcher.go +++ b/mvcc/watcher.go @@ -15,6 +15,7 @@ package mvcc import ( + "bytes" "errors" "sync" @@ -99,6 +100,12 @@ type watchStream struct { // Watch creates a new watcher in the stream and returns its WatchID. // TODO: return error if ws is closed? func (ws *watchStream) Watch(key, end []byte, startRev int64, fcs ...FilterFunc) WatchID { + // prevent wrong range where key >= end lexicographically + // watch request with 'WithFromKey' has empty-byte range end + if len(end) != 0 && bytes.Compare(key, end) != -1 { + return -1 + } + ws.mu.Lock() defer ws.mu.Unlock() if ws.closed { diff --git a/mvcc/watcher_test.go b/mvcc/watcher_test.go index 3fc78e01c..3d259d1f1 100644 --- a/mvcc/watcher_test.go +++ b/mvcc/watcher_test.go @@ -153,6 +153,28 @@ func TestWatcherWatchPrefix(t *testing.T) { } } +// TestWatcherWatchWrongRange ensures that watcher with wrong 'end' range +// does not create watcher, which panics when canceling in range tree. +func TestWatcherWatchWrongRange(t *testing.T) { + b, tmpPath := backend.NewDefaultTmpBackend() + s := WatchableKV(newWatchableStore(b, &lease.FakeLessor{}, nil)) + defer cleanup(s, b, tmpPath) + + w := s.NewWatchStream() + defer w.Close() + + if id := w.Watch([]byte("foa"), []byte("foa"), 1); id != -1 { + t.Fatalf("key == end range given; id expected -1, got %d", id) + } + if id := w.Watch([]byte("fob"), []byte("foa"), 1); id != -1 { + t.Fatalf("key > end range given; id expected -1, got %d", id) + } + // watch request with 'WithFromKey' has empty-byte range end + if id := w.Watch([]byte("foo"), []byte{}, 1); id != 0 { + t.Fatalf("\x00 is range given; id expected 0, got %d", id) + } +} + func TestWatchDeleteRange(t *testing.T) { b, tmpPath := backend.NewDefaultTmpBackend() s := newWatchableStore(b, &lease.FakeLessor{}, nil)