summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/quicklist.c39
-rw-r--r--src/t_list.c2
-rw-r--r--tests/integration/corrupt-dump.tcl4
3 files changed, 26 insertions, 19 deletions
diff --git a/src/quicklist.c b/src/quicklist.c
index 5666aab22..ec5409533 100644
--- a/src/quicklist.c
+++ b/src/quicklist.c
@@ -861,7 +861,7 @@ REDIS_STATIC void _quicklistInsert(quicklist *quicklist, quicklistEntry *entry,
/* Populate accounting flags for easier boolean checks later */
if (!_quicklistNodeAllowInsert(node, fill, sz)) {
- D("Current node is full with count %d with requested fill %lu",
+ D("Current node is full with count %d with requested fill %d",
node->count, fill);
full = 1;
}
@@ -1244,31 +1244,36 @@ int quicklistIndex(const quicklist *quicklist, const long long idx,
initEntry(entry);
entry->quicklist = quicklist;
- if (!forward) {
- index = (-idx) - 1;
- n = quicklist->tail;
- } else {
- index = idx;
- n = quicklist->head;
- }
-
+ index = forward ? idx : (-idx) - 1;
if (index >= quicklist->count)
return 0;
+ /* Seek in the other direction if that way is shorter. */
+ int seek_forward = forward;
+ unsigned long long seek_index = index;
+ if (index > (quicklist->count - 1) / 2) {
+ seek_forward = !forward;
+ seek_index = quicklist->count - 1 - index;
+ }
+
+ n = seek_forward ? quicklist->head : quicklist->tail;
while (likely(n)) {
- if ((accum + n->count) > index) {
+ if ((accum + n->count) > seek_index) {
break;
} else {
D("Skipping over (%p) %u at accum %lld", (void *)n, n->count,
accum);
accum += n->count;
- n = forward ? n->next : n->prev;
+ n = seek_forward ? n->next : n->prev;
}
}
if (!n)
return 0;
+ /* Fix accum so it looks like we seeked in the other direction. */
+ if (seek_forward != forward) accum = quicklist->count - n->count - accum;
+
D("Found node: %p at accum %llu, idx %llu, sub+ %llu, sub- %llu", (void *)n,
accum, index, index - accum, (-index) - 1 + accum);
@@ -1278,7 +1283,7 @@ int quicklistIndex(const quicklist *quicklist, const long long idx,
entry->offset = index - accum;
} else {
/* reverse = need negative offset for tail-to-head, so undo
- * the result of the original if (index < 0) above. */
+ * the result of the original index = (-idx) - 1 above. */
entry->offset = (-index) - 1 + accum;
}
@@ -1852,7 +1857,7 @@ int quicklistTest(int argc, char *argv[], int accurate) {
unsigned int sz;
long long lv;
ql_info(ql);
- quicklistPop(ql, QUICKLIST_HEAD, &data, &sz, &lv);
+ assert(quicklistPop(ql, QUICKLIST_HEAD, &data, &sz, &lv));
assert(data != NULL);
assert(sz == 32);
if (strcmp(populate, (char *)data))
@@ -1870,7 +1875,7 @@ int quicklistTest(int argc, char *argv[], int accurate) {
unsigned int sz;
long long lv;
ql_info(ql);
- quicklistPop(ql, QUICKLIST_HEAD, &data, &sz, &lv);
+ assert(quicklistPop(ql, QUICKLIST_HEAD, &data, &sz, &lv));
assert(data == NULL);
assert(lv == 55513);
ql_verify(ql, 0, 0, 0, 0);
@@ -2735,9 +2740,11 @@ int quicklistTest(int argc, char *argv[], int accurate) {
if (step == 1) {
for (int i = 0; i < list_sizes[list] / 2; i++) {
unsigned char *data;
- quicklistPop(ql, QUICKLIST_HEAD, &data, NULL, NULL);
+ assert(quicklistPop(ql, QUICKLIST_HEAD, &data,
+ NULL, NULL));
zfree(data);
- quicklistPop(ql, QUICKLIST_TAIL, &data, NULL, NULL);
+ assert(quicklistPop(ql, QUICKLIST_TAIL, &data,
+ NULL, NULL));
zfree(data);
}
}
diff --git a/src/t_list.c b/src/t_list.c
index 72be6fe6a..6fbf9ee0d 100644
--- a/src/t_list.c
+++ b/src/t_list.c
@@ -405,7 +405,7 @@ void addListRangeReply(client *c, robj *o, long start, long end, int reverse) {
while(rangelen--) {
listTypeEntry entry;
- listTypeNext(iter, &entry);
+ serverAssert(listTypeNext(iter, &entry)); /* fail on corrupt data */
quicklistEntry *qe = &entry.entry;
if (qe->value) {
addReplyBulkCBuffer(c,qe->value,qe->sz);
diff --git a/tests/integration/corrupt-dump.tcl b/tests/integration/corrupt-dump.tcl
index fab15fc7b..ff956796c 100644
--- a/tests/integration/corrupt-dump.tcl
+++ b/tests/integration/corrupt-dump.tcl
@@ -82,7 +82,7 @@ test {corrupt payload: valid zipped hash header, dup records} {
test {corrupt payload: quicklist big ziplist prev len} {
start_server [list overrides [list loglevel verbose use-exit-on-panic yes crash-memcheck-enabled no] ] {
r config set sanitize-dump-payload no
- r restore key 0 "\x0E\x01\x13\x13\x00\x00\x00\x0E\x00\x00\x00\x02\x00\x00\x02\x61\x00\x0E\x02\x62\x00\xFF\x09\x00\x49\x97\x30\xB2\x0D\xA1\xED\xAA"
+ r restore key 0 "\x0e\x01\x1b\x1b\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x02\x61\x00\x04\x02\x62\x00\x04\x02\x63\x00\x19\x02\x64\x00\xff\x09\x00\xec\x42\xe9\xf5\xd6\x19\x9e\xbd"
catch {r lindex key -2}
assert_equal [count_log_message 0 "crashed by signal"] 0
assert_equal [count_log_message 0 "ASSERTION FAILED"] 1
@@ -107,7 +107,7 @@ test {corrupt payload: quicklist ziplist wrong count} {
# we'll be able to push, but iterating on the list will assert
r lpush key header
r rpush key footer
- catch { [r lrange key -1 -1] }
+ catch { [r lrange key 0 -1] }
assert_equal [count_log_message 0 "crashed by signal"] 0
assert_equal [count_log_message 0 "ASSERTION FAILED"] 1
}