Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xi_rope multiset panic with syntect plugin enabled #1275

Open
2 tasks done
bvinc opened this issue Jun 14, 2020 · 4 comments
Open
2 tasks done

xi_rope multiset panic with syntect plugin enabled #1275

bvinc opened this issue Jun 14, 2020 · 4 comments

Comments

@bvinc
Copy link
Contributor

bvinc commented Jun 14, 2020

  • I have searched existing issues and could not find my issue.
  • I have studied the documentation.

I'm running the latest master, using Linux and a custom frontend. I can reproduce this pretty easily by doing the following:

  1. Run xi with the syntect plugin.
  2. Setting auto_indent may be a requirement.
  3. Create a new view.
  4. Start typing really fast, including the space bar and enter.

I'll get a panic that looks like this:

[2020-06-14T20:18:31Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":"A"},"view_id":"view-id-3"}}
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/libunwind.rs:86
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:78
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:59
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1069
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1504
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:62
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:198
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:218
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:511
  11: rust_begin_unwind
             at src/libstd/panicking.rs:419
  12: core::panicking::panic_fmt
             at src/libcore/panicking.rs:111
  13: core::option::expect_failed
             at src/libcore/option.rs:1260
  14: core::option::Option<T>::expect
             at /home/brain/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/option.rs:347
  15: xi_rope::multiset::Subset::transform
             at /home/brain/.cargo/git/checkouts/xi-editor-968440e5b4201956/65911d9/rust/rope/src/multiset.rs:235
  16: xi_rope::multiset::Subset::transform_expand
             at /home/brain/.cargo/git/checkouts/xi-editor-968440e5b4201956/65911d9/rust/rope/src/multiset.rs:262
  17: xi_rope::engine::Engine::gc
             at /home/brain/.cargo/git/checkouts/xi-editor-968440e5b4201956/65911d9/rust/rope/src/engine.rs:598
  18: xi_core_lib::editor::Editor::gc_undos
             at /home/brain/.cargo/git/checkouts/xi-editor-968440e5b4201956/65911d9/rust/core-lib/src/editor.rs:320
  19: xi_core_lib::editor::Editor::dec_revs_in_flight
             at /home/brain/.cargo/git/checkouts/xi-editor-968440e5b4201956/65911d9/rust/core-lib/src/editor.rs:193

It appears to be hitting this expect statement in xi_rope::multiset::Subset::transform

.expect("self must cover all 0-regions of other")
@bvinc
Copy link
Contributor Author

bvinc commented Jun 14, 2020

All that seems to be required is:

  1. Type space.
  2. Type a letter.
  3. Hit enter and space quickly repeatedly and randomly.

Here's a log of everything I sent to the backend before it panicked this time.

[2020-06-14T20:58:03Z DEBUG gxi::rpc] CORE <-- {"method":"client_started","params":{"client_extras_dir":"/home/brain/.config/xi/plugins","config_dir":"/home/brain/.config/xi"}}
[2020-06-14T20:58:04Z DEBUG gxi::rpc] CORE <-- {"method":"set_theme","params":{"theme_name":"Gruvbox-N"}}
[2020-06-14T20:58:05Z DEBUG gxi::rpc] CORE <-- {"id"=0, "method": new_view, "params":{}}
[2020-06-14T20:58:05Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"scroll","params":[0,25],"view_id":"view-id-2"}}
[2020-06-14T20:58:07Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:07Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":"f"},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:08Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:09Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:10Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:10Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:10Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:10Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}
[2020-06-14T20:58:10Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert","params":{"chars":" "},"view_id":"view-id-2"}}
[2020-06-14T20:58:10Z DEBUG gxi::rpc] CORE <-- {"method":"edit","params":{"method":"insert_newline","params":{},"view_id":"view-id-2"}}

@bvinc
Copy link
Contributor Author

bvinc commented Jun 21, 2020

auto_indent being enabled may be a necessary requirement for reproducing this.

at engine.rs:598, here's an example of the values involved:

gc_dels Subset([Segment { len: 73, count: 0 }])
inserts Subset([Segment { len: 74, count: 0 }, Segment { len: 1, count: 1 }])

This is breaking the precondition for transform that self.count(CountMatcher::All) == other.count(CountMatcher::Zero)

@bvinc
Copy link
Contributor Author

bvinc commented Jun 21, 2020

I've captured the edit_rev methods and the gc calls to the engine and reproduced it. I've turned what I've logged into a test case. Unfortunately, I don't know enough to know where the bug lies or who is at fault. But this test case represents what happens:

    #[test]
    fn gc_7() {
        let mut engine = Engine::empty();
        engine.edit_rev(65536, 1, engine.get_head_rev_id().token(), Delta::simple_edit(Interval::new(0,10), Rope::from(" "), 0));
        let d2 = Delta{
            els: vec![DeltaElement::Copy(0,1), DeltaElement::Insert(Rope::from("f"))],
            base_len: 1,
        };
        engine.edit_rev(65536, 1, engine.get_head_rev_id().token(), d2);
        let d3 = Delta{
            els: vec![DeltaElement::Copy(0,2), DeltaElement::Insert(Rope::from("\n"))],
            base_len: 2,
        };
        engine.edit_rev(65536, 2, engine.get_head_rev_id().token(), d3);

        // THESE NEXT 2 EDITS ARE WEIRD.  They both happen on the same base
        // revision, but they're in 2 different undo groups.
        let rev_token = engine.get_head_rev_id().token();
        let d4 = Delta{
            els: vec![DeltaElement::Copy(0,3), DeltaElement::Insert(Rope::from(" "))],
            base_len: 3,
        };
        engine.edit_rev(65536, 3, rev_token, d4);

        let d5 = Delta{
            els: vec![DeltaElement::Copy(0,3), DeltaElement::Insert(Rope::from(" "))],
            base_len: 3,
        };
        engine.edit_rev(100, 2, rev_token, d5);

        let d6 = Delta{
            els: vec![DeltaElement::Copy(0,5), DeltaElement::Insert(Rope::from("f"))],
            base_len: 5,
        };
        engine.edit_rev(65536, 4, engine.get_head_rev_id().token(), d6);

        let gc : BTreeSet<usize> = [1].iter().cloned().collect();
        engine.gc(&gc);
        let gc : BTreeSet<usize> = [2].iter().cloned().collect();
        engine.gc(&gc);
        let gc : BTreeSet<usize> = [3].iter().cloned().collect();
        // this panics with 'self must cover all 0-regions of other'
        engine.gc(&gc);
    }

@bvinc
Copy link
Contributor Author

bvinc commented Jun 22, 2020

So what is happening is that the syntect plugin is inserting indentation (d5 above) after a newline. Inbetween the newline and the indentation edits, I'm quickly pressing the spacebar (d4 above). This is causing 2 edits to the same base revision, which is exactly what the engine is designed for. The problem is that the 2 edits to the same revision use different undo groups, and it receives the undo group 2 after it already receives undo group 3.

  • Is the engine expected to be able to receive out-of-order undo groups?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant