fix: yata fuzzing works now

This commit is contained in:
Zixuan Chen 2022-10-12 22:53:40 +08:00
parent d36c41b7cd
commit 7f728db495
6 changed files with 533 additions and 469 deletions

View file

@ -3,4 +3,4 @@ use crdt_list::{test, test::Action};
use libfuzzer_sys::fuzz_target;
use loro_core::container::text::tracker::yata::YataImpl;
fuzz_target!(|data: Vec<Action>| { test::test_with_actions::<YataImpl>(2, 5, data) });
fuzz_target!(|data: Vec<Action>| { test::test_with_actions::<YataImpl>(5, 100, data) });

View file

@ -27,7 +27,7 @@ struct CursorWithId<'tree> {
impl ContentMap {
#[inline]
pub(super) fn get_yspan_at_pos(&mut self, id: ID, pos: usize, len: usize) -> YSpan {
let (left, right) = self.get_sibling_at(pos);
let (left, right) = self.get_sibling_at_dumb(pos);
YSpan {
origin_left: left.as_ref().map(|x| x.id),
origin_right: right.as_ref().map(|x| x.id),
@ -37,6 +37,93 @@ impl ContentMap {
}
}
fn get_sibling_at_dumb(
&self,
pos: usize,
) -> (Option<CursorWithId<'_>>, Option<CursorWithId<'_>>) {
if let Some(cursor) = self.get(pos) {
let cursor: SafeCursor<'_, YSpan, YSpanTreeTrait> =
// SAFETY: we only change the lifetime of the cursor; the returned lifetime is kinda wrong in this situation
// because Bumpalo's lifetime is static due to the self-referential structure limitation; Maybe there is a better way?
unsafe { std::mem::transmute(cursor) };
let (mut prev, mut next) = match cursor.pos() {
Position::Start => {
let id = cursor.as_ref().id;
(
None,
Some(CursorWithId {
id,
cursor: cursor.unwrap(),
}),
)
}
Position::Middle => {
let id = cursor.as_ref().id;
let offset = cursor.offset();
let mut prev_offset_cursor = cursor.unwrap();
prev_offset_cursor.offset -= 1;
(
Some(CursorWithId {
id: id.inc(offset as i32 - 1),
cursor: prev_offset_cursor,
}),
Some(CursorWithId {
id: id.inc(offset as i32),
cursor: cursor.unwrap(),
}),
)
}
Position::End => {
let mut prev_offset_cursor = cursor.unwrap();
prev_offset_cursor.offset -= 1;
prev_offset_cursor.pos = Position::Middle;
(
Some(CursorWithId {
id: cursor.as_ref().last_id(),
cursor: prev_offset_cursor,
}),
None,
)
}
_ => {
unreachable!()
}
};
if prev.is_none() {
let mut prev_cursor = cursor.prev_elem();
if let Some(prev_inner) = prev_cursor {
let cursor = prev_inner;
let offset = cursor.as_ref().content_len() - 1;
let mut cursor = cursor.unwrap();
cursor.offset = offset;
cursor.pos = Position::Middle;
prev = Some(CursorWithId {
id: prev_inner.as_ref().last_id(),
cursor,
});
}
}
if next.is_none() {
let mut next_cursor = cursor.next_elem_start();
if let Some(next_inner) = next_cursor {
let mut cursor = next_inner.unwrap();
cursor.offset = 0;
cursor.pos = Position::Start;
next = Some(CursorWithId {
id: next_inner.as_ref().id,
cursor,
});
}
}
(prev, next)
} else {
(None, None)
}
}
/// When we insert a new [YSpan] at given position, we need to calculate its `originLeft` and `originRight`
fn get_sibling_at(&self, pos: usize) -> (Option<CursorWithId<'_>>, Option<CursorWithId<'_>>) {
if let Some(cursor) = self.get(pos) {
@ -83,6 +170,7 @@ impl ContentMap {
if cursor.as_ref().can_be_origin() {
let mut prev_offset_cursor = cursor.unwrap();
prev_offset_cursor.offset -= 1;
prev_offset_cursor.pos = Position::Middle;
(
Some(CursorWithId {
id: cursor.as_ref().last_id(),
@ -100,7 +188,7 @@ impl ContentMap {
};
if prev.is_none() {
let mut prev_cursor = cursor.prev_elem_end();
let mut prev_cursor = cursor.prev_elem();
while let Some(prev_inner) = prev_cursor {
if prev_inner.as_ref().status.is_activated() {
let cursor = prev_inner;
@ -114,7 +202,7 @@ impl ContentMap {
});
break;
}
prev_cursor = prev_inner.prev_elem_end();
prev_cursor = prev_inner.prev_elem();
}
}

View file

@ -1,11 +1,10 @@
use crdt_list::{
crdt::{GetOp, ListCrdt, OpSet},
crdt::{ListCrdt, OpSet},
yata::Yata,
};
use rle::{
range_map::{RangeMap, WithStartEnd},
rle_tree::{iter::IterMut, SafeCursorMut},
Sliceable,
};
use crate::id::{Counter, ID};
@ -109,22 +108,25 @@ impl ListCrdt for YataImpl {
container.vv.set_end(op.id.inc(op.len as i32));
// SAFETY: we know this is safe because in [YataImpl::insert_after] there is no access to shared elements
unsafe { crdt_list::yata::integrate::<Self>(container, op) };
container.check_consistency();
}
fn can_integrate(container: &Self::Container, op: &Self::OpUnit) -> bool {
if let Some(value) = op.origin_left {
if !container.id_to_cursor.has(value.into()) {
if !value.is_unknown() && !container.vv.includes(value) {
return false;
}
}
if let Some(value) = op.origin_right {
if !container.id_to_cursor.has(value.into()) {
if !value.is_unknown() && !container.vv.includes(value) {
return false;
}
}
if op.id.counter != 0 && !container.vv.includes(op.id.inc(-1)) {
return false;
}
true
}
@ -237,8 +239,8 @@ pub mod fuzz {
if aa != bb {
dbg!(aa.vec());
dbg!(bb.vec());
dbg!(&a.content);
dbg!(&b.content);
// dbg!(&a.content);
// dbg!(&b.content);
}
assert_eq!(aa, bb);
@ -288,13 +290,11 @@ pub mod fuzz {
return RleVec::new();
}
let spans = container.content.get_id_spans(pos, len);
spans
container.content.get_id_spans(pos, len)
}
fn integrate_delete_op(container: &mut Self::Container, op: Self::DeleteOp) {
container.update_spans(&op, StatusChange::Delete);
container.check_consistency();
}
}
@ -302,216 +302,429 @@ pub mod fuzz {
#[test]
fn issue_1() {
crdt_list::test::test_with_actions::<YataImpl>(
2,
3,
5,
vec! [
vec![
NewOp {
client_id: 18446743798824736406,
pos: 18446744073699196927,
client_id: 2,
pos: 2,
},
Delete {
client_id: 18446744073709551615,
client_id: 0,
pos: 0,
len: 7411535208244772857,
len: 2,
},
Delete {
client_id: 18446540664058413055,
pos: 10873349650923257855,
len: 18446603336204419555,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073702670335,
len: 18446744073709486335,
},
Delete {
client_id: 18446744073709551615,
pos: 11719107999768421119,
len: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768945314,
pos: 11719107999768421026,
},
Delete {
client_id: 10851025925718409122,
pos: 540508742418326,
len: 18446504380166307839,
},
Delete {
client_id: 18446744070052118527,
pos: 18446744073709551615,
len: 18446744073709524735,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551615,
len: 11719107999768421026,
},
NewOp {
client_id: 11719107997996196514,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11739092723114877602,
pos: 10880594044147376802,
},
Delete {
client_id: 18446743137406648319,
pos: 18446744073709551615,
len: 18446744073702670335,
},
Sync {
from: 18374686479688400896,
to: 18446744073709551615,
},
Delete {
client_id: 11719107999768421119,
pos: 11719107999768421026,
len: 18446744071947943842,
},
Delete {
client_id: 4294967297,
pos: 18446744073709551615,
len: 11719210655348162559,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 18446743672711193250,
},
Delete {
client_id: 11745387828182253567,
pos: 11719107999768421026,
len: 11719107999768421538,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
Delete {
client_id: 18417073299693934335,
pos: 18446744073709551510,
len: 18446744073709551615,
},
Delete {
client_id: 15914838024966373375,
pos: 15914838024376868060,
len: 15914635714237357276,
},
Sync {
from: 18374686479671623680,
to: 18446744073709551615,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551615,
len: 18446744073709551615,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073695461375,
len: 18446744073709551615,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551615,
len: 18446744073709551615,
},
Delete {
client_id: 18446744073558556672,
pos: 18446744073642442557,
len: 18446744073709551615,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551614,
len: 18446744073709551615,
client_id: 1,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Sync {
from: 0,
to: 0,
},
Sync {
from: 0,
to: 0,
},
Sync {
from: 0,
to: 0,
},
Sync {
from: 0,
to: 0,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551615,
len: 1099511627775,
},
Sync {
from: 11719107999774539526,
to: 11719107999768421026,
client_id: 0,
pos: 2,
len: 3,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
client_id: 0,
pos: 1,
},
NewOp {
client_id: 18446744072143151778,
pos: 18446744073709551615,
client_id: 0,
pos: 1,
},
NewOp {
client_id: 1,
pos: 2,
},
Delete {
client_id: 17144620962624171493,
pos: 16550640557684026861,
len: 18391177001763530213,
client_id: 0,
pos: 0,
len: 4,
},
Sync { from: 0, to: 1 },
Delete {
client_id: 1,
pos: 0,
len: 0,
},
NewOp {
client_id: 0,
pos: 3,
},
NewOp {
client_id: 1,
pos: 0,
},
Delete {
client_id: 12659530246668681215,
pos: 12659530246663417775,
len: 17144611899198910383,
client_id: 0,
pos: 0,
len: 2,
},
NewOp {
client_id: 0,
pos: 4,
},
Delete {
client_id: 12659589887623556589,
pos: 4221573655528072677,
len: 18446744073707847679,
client_id: 0,
pos: 0,
len: 1,
},
Sync { from: 0, to: 0 },
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 0,
},
Delete {
client_id: 12659530246663417775,
pos: 17127101077014949807,
len: 17144620962624171501,
client_id: 0,
pos: 1,
len: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 1,
pos: 0,
len: 1,
},
Sync { from: 0, to: 0 },
Delete {
client_id: 0,
pos: 3,
len: 2,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 2,
pos: 1,
len: 1,
},
Sync { from: 0, to: 0 },
Sync { from: 0, to: 0 },
Sync { from: 0, to: 0 },
Sync { from: 0, to: 0 },
Sync { from: 0, to: 0 },
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 2,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 2,
len: 1,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 3,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 2,
pos: 1,
len: 2,
},
Delete {
client_id: 2,
pos: 0,
len: 2,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 2,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 1,
pos: 0,
len: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 1,
pos: 0,
},
Sync { from: 0, to: 1 },
Delete {
client_id: 2,
pos: 4,
len: 4,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 1,
len: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
Delete {
client_id: 0,
pos: 0,
len: 2,
},
Delete {
client_id: 0,
pos: 0,
len: 4,
},
Sync { from: 0, to: 1 },
Delete {
client_id: 1,
pos: 0,
len: 0,
},
NewOp {
client_id: 0,
pos: 3,
},
NewOp {
client_id: 1,
pos: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 2,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 2,
},
NewOp {
client_id: 0,
pos: 2,
},
NewOp {
client_id: 0,
pos: 1,
},
Delete {
client_id: 0,
pos: 4,
len: 3,
},
NewOp {
client_id: 2,
pos: 3,
},
NewOp {
client_id: 1,
pos: 3,
},
NewOp {
client_id: 0,
pos: 1,
},
Delete {
client_id: 2,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
NewOp {
client_id: 0,
pos: 4,
},
Delete {
client_id: 0,
pos: 2,
len: 0,
},
Sync { from: 2, to: 2 },
Delete {
client_id: 2,
pos: 0,
len: 3,
},
Delete {
client_id: 0,
pos: 4,
len: 1,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 0,
len: 0,
},
Sync { from: 0, to: 0 },
Delete {
client_id: 0,
pos: 0,
len: 3,
},
Delete {
client_id: 0,
pos: 0,
len: 1,
},
Delete {
client_id: 1,
pos: 0,
len: 4,
},
NewOp {
client_id: 2,
pos: 0,
},
Delete {
client_id: 1,
pos: 0,
len: 0,
},
Delete {
client_id: 0,
pos: 1,
len: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 0,
pos: 1,
},
NewOp {
client_id: 2,
pos: 1,
},
NewOp {
client_id: 1,
pos: 4,
},
Delete {
client_id: 0,
pos: 1,
len: 4,
},
Delete {
client_id: 0,
pos: 4,
len: 3,
},
NewOp {
client_id: 2,
pos: 0,
},
],
)
@ -519,238 +732,9 @@ pub mod fuzz {
#[test]
fn normalize() {
let mut actions = vec![
NewOp {
client_id: 18446743798824736406,
pos: 18446744073709551615,
},
Delete {
client_id: 18446744069431361535,
pos: 18446744073709551615,
len: 18446744073709496575,
},
Delete {
client_id: 255,
pos: 1098353998080,
len: 18446744069414584320,
},
Delete {
client_id: 13093571490658779135,
pos: 18374688556288311293,
len: 12659530248010825727,
},
Delete {
client_id: 18446744073709551535,
pos: 10880696699727118335,
len: 18374967954648334335,
},
Delete {
client_id: 18417189201154932735,
pos: 10880696699727118335,
len: 10851025326177714175,
},
Delete {
client_id: 18402271027389267903,
pos: 18446743150291582975,
len: 18446744073709551615,
},
Sync {
from: 18427322270251745280,
to: 18374686481397256192,
},
Delete {
client_id: 16565928279328900863,
pos: 18374688556672476645,
len: 18446743137406648319,
},
Delete {
client_id: 18417189201154932735,
pos: 18446463698244468735,
len: 18446744073709551615,
},
Delete {
client_id: 11719108400766779391,
pos: 11719107999768421026,
len: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 12872029504375268002,
},
NewOp {
client_id: 18417188748414850710,
pos: 18410715272395746198,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744071947943935,
len: 8573222911,
},
Delete {
client_id: 18446744073709551615,
pos: 11719107999768444927,
len: 16565928279328924322,
},
NewOp {
client_id: 18446603336204419555,
pos: 18446744073709551397,
},
Delete {
client_id: 18446744073702670335,
pos: 18446744073709486335,
len: 18446744073709551615,
},
Delete {
client_id: 11719107999768421119,
pos: 11719107999768421026,
len: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719108000959603362,
},
NewOp {
client_id: 11719107999768421026,
pos: 18446641486849286818,
},
NewOp {
client_id: 136118438245406358,
pos: 18385382526639144704,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 18446744072143151778,
pos: 18446744073709551615,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
Delete {
client_id: 10880580798266119830,
pos: 18446744073709551615,
len: 18446744073709551615,
},
Delete {
client_id: 18436853815706648575,
pos: 18446744073709551615,
len: 18446744073709551615,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551615,
len: 17798225731663167487,
},
Delete {
client_id: 18446744073642442557,
pos: 18446744073709551615,
len: 18446744073709551615,
},
Delete {
client_id: 18446744073709551614,
pos: 11719108400766779391,
len: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 18446744073709527714,
pos: 18446744073709551615,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 18446744073709551522,
},
Delete {
client_id: 18446744073709551400,
pos: 18446744073709524480,
len: 18391293503297552383,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551615,
len: 18446744073709551615,
},
Delete {
client_id: 18446744035054846207,
pos: 72057576858009087,
len: 18383412203949654016,
},
Delete {
client_id: 18446744073709551615,
pos: 18446744073709551615,
len: 18446744073709551615,
},
Delete {
client_id: 11719107999768421026,
pos: 11719107999768421026,
len: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 18446743672711193250,
},
Delete {
client_id: 11745387828182253567,
pos: 11719107999768421026,
len: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
NewOp {
client_id: 11719107999768421026,
pos: 11719107999768421026,
},
];
let mut actions = vec![];
crdt_list::test::normalize_actions(&mut actions, 2, 5);
crdt_list::test::normalize_actions(&mut actions, 3, 5);
dbg!(actions);
}
}

View file

@ -312,8 +312,6 @@ impl<T: Rle, A: RleTreeTrait<T>> RleTree<T, A> {
}
}
}
self.debug_check();
}
pub fn update_range<U, F>(

View file

@ -168,7 +168,7 @@ impl<'tree, T: Rle, A: RleTreeTrait<T>> UnsafeCursor<'tree, T, A> {
/// # Safety
///
/// we need to make sure that the cursor is still valid
pub unsafe fn prev_elem_end(&self) -> Option<Self> {
pub unsafe fn prev_elem(&self) -> Option<Self> {
let leaf = self.leaf.as_ref();
if self.index > 0 {
return Some(Self::new(self.leaf, self.index - 1, 0, Position::Start, 0));
@ -316,9 +316,9 @@ impl<'tree, T: Rle, A: RleTreeTrait<T>> SafeCursor<'tree, T, A> {
}
#[inline]
pub fn prev_elem_end(&self) -> Option<Self> {
pub fn prev_elem(&self) -> Option<Self> {
// SAFETY: SafeCursor is a shared reference to the tree
unsafe { self.0.prev_elem_end().map(|x| Self(x)) }
unsafe { self.0.prev_elem().map(|x| Self(x)) }
}
#[inline]
@ -444,10 +444,10 @@ impl<'tree, T: Rle, A: RleTreeTrait<T>> SafeCursorMut<'tree, T, A> {
}
#[inline]
pub fn prev_elem_end(&self) -> Option<Self> {
pub fn prev_elem(&self) -> Option<Self> {
// SAFETY: SafeCursorMut is a exclusive reference to the tree so we are safe to
// get a reference to the element
unsafe { self.0.prev_elem_end().map(|x| Self(x)) }
unsafe { self.0.prev_elem().map(|x| Self(x)) }
}
#[inline]

View file

@ -272,8 +272,6 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
return Ok(());
}
self.check_balance_recursively();
self.check_children_parent_link();
updates.sort_by_key(|x| x.0);
let mut new_children: Vec<&'a mut Node<'a, T, A>> = Vec::new();
let mut self_children = std::mem::replace(&mut self.children, BumpVec::new_in(self.bump));
@ -333,8 +331,6 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
Err(ans_vec)
};
self.check_children_parent_link();
self.check_balance_recursively();
if result.is_err() && self.is_root() {
let mut new = result.unwrap_err();
assert!(new.len() == 1);
@ -344,8 +340,6 @@ impl<'a, T: Rle, A: RleTreeTrait<T>> InternalNode<'a, T, A> {
A::update_cache_internal(self);
A::update_cache_internal(inner);
self._create_level(new);
self.check();
self.check_balance_recursively();
Ok(())
} else {
result