Skip to content

Fix soundness bug on Multicursor #4

New issue

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

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

Already on GitHub? # to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Conversation

yjh0502
Copy link

@yjh0502 yjh0502 commented Apr 3, 2020

MultiCursor is currently unsound because of wrong lifetime. For example following example crashes with use-after-free.

    let multi = {
        let mut cursor = db.cursor();
        cursor.get_trail(0).unwrap();
        let cursors = vec![std::cell::RefCell::new(cursor)];
        traildb::MultiCursor::new(&cursors)
    };

    for _ev in multi {
        //
    }

with valgrind output

==1193941== Invalid read of size 8
==1193941==    at 0x15F269: tdb_cursor_next (traildb.h:304)
==1193941==    by 0x15F269: tdb_multi_cursor_next (tdb_multi_cursor.c:190)
==1193941==    by 0x14E536: <traildb::MultiCursor as core::iter::traits::iterator::Iterator>::next (lib.rs:519)
==1193941==    by 0x11AC82: simple::main (simple.rs:52)
==1193941==    by 0x11CFDF: std::rt::lang_start::{{closure}} (rt.rs:67)
==1193941==    by 0x16A322: {{closure}} (rt.rs:52)
==1193941==    by 0x16A322: std::panicking::try::do_call (panicking.rs:305)
==1193941==    by 0x16C266: __rust_maybe_catch_panic (lib.rs:86)
==1193941==    by 0x16ACFF: try<i32,closure-0> (panicking.rs:281)
==1193941==    by 0x16ACFF: catch_unwind<closure-0,i32> (panic.rs:394)
==1193941==    by 0x16ACFF: std::rt::lang_start_internal (rt.rs:51)
==1193941==    by 0x11CFB8: std::rt::lang_start (rt.rs:67)
==1193941==    by 0x11B119: main (in /home/jihyun/r/g/traildb-rust/target/debug/examples/simple)
==1193941==  Address 0x73f85e0 is 16 bytes inside a block of size 24 free'd
==1193941==    at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1193941==    by 0x14E1E1: <traildb::Cursor as core::ops::drop::Drop>::drop (lib.rs:460)
==1193941==    by 0x1534DE: core::ptr::drop_in_place (mod.rs:174)
==1193941==    by 0x11853E: core::ptr::drop_in_place (mod.rs:174)
==1193941==    by 0x118526: core::ptr::drop_in_place (mod.rs:174)
==1193941==    by 0x1188D4: core::ptr::drop_in_place (mod.rs:174)
==1193941==    by 0x116119: <alloc::vec::Vec<T> as core::ops::drop::Drop>::drop (vec.rs:2320)
==1193941==    by 0x118680: core::ptr::drop_in_place (mod.rs:174)
==1193941==    by 0x11AC3E: simple::main (simple.rs:50)
==1193941==    by 0x11CFDF: std::rt::lang_start::{{closure}} (rt.rs:67)
==1193941==    by 0x16A322: {{closure}} (rt.rs:52)
==1193941==    by 0x16A322: std::panicking::try::do_call (panicking.rs:305)
==1193941==    by 0x16C266: __rust_maybe_catch_panic (lib.rs:86)

I make following changes

  • fix lifetime annotation on MultiCursor::new
  • remove std::cell::RefCell from MultiCursor::new. I'm not sure why it uses RefCell, but it seems it's okay without RefCell.
  • rustfmt
  • add MultiCursor::from_iter. It allows users to write more ergonomic code like,
let cursors = vec![cursor];
let multi: traildb::MultiCursor = cursors.iter().collect(); // could be shorter if compiler could infer correct type for multi

@19h
Copy link
Collaborator

19h commented May 8, 2020

Thanks @yjh0502.

I'm a bit unhappy that there were so many formatting-only changes that it took some time to spot the actual changes you made. There are some things I'd have mentioned in this comment but I will do a proper code-review instead and annotate the patch.

ptrs.push(ptr);
}
pub fn new(cursors: &'a [Cursor<'a>]) -> MultiCursor<'a> {
use std::iter::FromIterator;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you put the FromIterator inclusion into the method itself?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trait is only used for the method, so I thought it's better to include the trait inside the method. We could also use cursors.into_iter().collect() instead of Self::from_iter(cursors). Does it sound better?

let mut multi_cursor = MultiCursor::new(&cursors);
let mut cursor1 = cursors[0].borrow_mut();
let mut cursor2 = cursors[1].borrow_mut();
let mut cursors = vec![db.cursor(), db.cursor()];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so much better..

@19h
Copy link
Collaborator

19h commented May 8, 2020

Is there a particular rustfmt configuration you used for the reformatted methods or did you do that manually? If it was for me I'd apply that formatting project-wide.

@19h
Copy link
Collaborator

19h commented May 8, 2020

I'll keep this pending for a few days to give @knutin the ability to chime in.

@yjh0502
Copy link
Author

yjh0502 commented May 9, 2020

Sorry for noisy patch. I should made seperated rustfmt commit.
I'm using default rustfmt options without any customization. It seems most options included in rustfmt.toml are deprecated on latest rustfmt.

jihyun@dev:~/r/traildb-rust$ cat rustfmt.toml
fn_brace_style = "PreferSameLine"
struct_trailing_comma = "Always"
enum_trailing_comma = true
fn_empty_single_line = false
impl_empty_single_line = false
jihyun@dev:~/r/traildb-rust$ cargo fmt
Warning: Unknown configuration option `enum_trailing_comma`
Warning: Unknown configuration option `fn_brace_style`
Warning: Unknown configuration option `fn_empty_single_line`
Warning: Unknown configuration option `impl_empty_single_line`
Warning: Unknown configuration option `struct_trailing_comma`
Warning: Unknown configuration option `enum_trailing_comma`
Warning: Unknown configuration option `fn_brace_style`
Warning: Unknown configuration option `fn_empty_single_line`
Warning: Unknown configuration option `impl_empty_single_line`
Warning: Unknown configuration option `struct_trailing_comma`
Warning: Unknown configuration option `enum_trailing_comma`
Warning: Unknown configuration option `fn_brace_style`
Warning: Unknown configuration option `fn_empty_single_line`
Warning: Unknown configuration option `impl_empty_single_line`
Warning: Unknown configuration option `struct_trailing_comma`
Warning: Unknown configuration option `enum_trailing_comma`
Warning: Unknown configuration option `fn_brace_style`
Warning: Unknown configuration option `fn_empty_single_line`
Warning: Unknown configuration option `impl_empty_single_line`
Warning: Unknown configuration option `struct_trailing_comma`
Warning: Unknown configuration option `enum_trailing_comma`
Warning: Unknown configuration option `fn_brace_style`
Warning: Unknown configuration option `fn_empty_single_line`
Warning: Unknown configuration option `impl_empty_single_line`
Warning: Unknown configuration option `struct_trailing_comma`

@knutin
Copy link
Member

knutin commented May 11, 2020

Looks good, thanks for the patch @yjh0502!

Maybe we should just remove the rustfmt.toml and apply rustfmt to everything with the new default settings.

@JayKickliter
Copy link
Collaborator

Maybe we should just remove the rustfmt.toml and apply rustfmt to everything with the new default settings.

Yeah, sorry. I started this project when I had lots of opinions and little experience. These days I never customize rustfmt.

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

Successfully merging this pull request may close these issues.

4 participants