Zulip Chat Archive

Stream: general

Topic: Strange memory error from FFI


Schrodinger ZHU Yifan (Aug 14 2023 at 15:02):

Help needed!

I was still working on a hashset/hashmap binding to lean: https://github.com/SchrodingerZhu/hashbrown4lean

The idea was to check and ensure the exclusivity of an lean_external_object whenever a mutation happens. However, I run into segfault with this approach. I have reduced the code to an example that does nothing but check and ensure the exclusivity:

In Rust,

#[no_mangle]
pub unsafe extern "C" fn lean_hashbrown_test(
    obj: lean_obj_arg,
    _hash: u64,
    _target: lean_obj_arg,
    _eq_closure: lean_obj_arg,
    _hash_closure: lean_obj_arg,
) -> lean_obj_res {
    println!("test invoked");
    let obj = exlusive_hashset(obj);
    obj
}
unsafe fn exlusive_hashset(set: lean_obj_arg) -> lean_obj_res {
    if lean_is_exclusive(set) {
        println!("target is exclusive: {:?}", set);
        set
    } else {
        println!("target is not exclusive: {:?}", set);
        let inner: *mut HashSet = get_data_from_external(set);
        let cloned = Box::into_raw(Box::new((*inner).clone()));
        let new_set = lean_alloc_external(HASHSET_CLASS, cloned as *mut c_void);
        println!("new set: {:?}", new_set);
        for i in (*inner).iter() {
            lean_inc(*i.as_ref());
        }
        lean_dec_ref(set);
        new_set
    }
}

In lean:

opaque HashSetPointed : (α : Type)  NonemptyType
def HashSet (α : Type) : Type := (HashSetPointed α).type
instance : Nonempty (HashSet α) := (HashSetPointed α).property

@[extern "lean_hashbrown_hashset_len"]
opaque HashSet.len : {α : Type}  @& HashSet α  USize

@[extern "lean_hashbrown_hashset_create"]
opaque HashSet.mk : {α : Type}  HashSet α

@[extern "lean_hashbrown_test"]
private opaque HashSet.test : {α : Type}
   HashSet α  UInt64  α  @&(α  Bool)  @&(α  UInt64)  HashSet α

@[extern "lean_hashbrown_register_hashset_class"]
private opaque registerHashSetClass : IO PUnit

@[extern "lean_hashbrown_register_hashset_iter_class"]
private opaque registerHashSetIterClass : IO PUnit

@[init]
private def initModule : IO Unit := do
 registerHashSetClass
 registerHashSetIterClass

def main : IO Unit := do
  let set : HashSet Nat := HashSet.mk
  let hash := 1
  let target := 1
  let check := λ x => x == 1
  let hashFn := λ x => 1
  let set := set.test hash target check hashFn
  IO.println s!"Hello, {set.len}!"

Yet, it still crashes:

  ./build/bin/swisstable
lean_set_st_header(0x7fe686cd6f38, 0, 2)
   0: lean_hashbrown::ffi::lean_set_st_header
             at ./src/ffi.rs:128:71
   1: lean_hashbrown::ffi::lean_alloc_ctor
             at ./src/ffi.rs:145:5
   2: lean_hashbrown::ffi::lean_io_result_mk_ok
             at ./src/ffi.rs:151:13
   3: lean_hashbrown_register_hashset_class
             at ./src/set.rs:103:5
   4: l___private_Main_0__initModule
   5: initialize_Main
   6: main
   7: __libc_start_call_main
             at /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   8: __libc_start_main_impl
             at /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
   9: _start

lean_set_st_header(0x7fe686cd6f38, 0, 2)
   0: lean_hashbrown::ffi::lean_set_st_header
             at ./src/ffi.rs:128:71
   1: lean_hashbrown::ffi::lean_alloc_ctor
             at ./src/ffi.rs:145:5
   2: lean_hashbrown::ffi::lean_io_result_mk_ok
             at ./src/ffi.rs:151:13
   3: lean_hashbrown_register_hashset_iter_class
             at ./src/set.rs:110:5
   4: initialize_Main
   5: main
   6: __libc_start_call_main
             at /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   7: __libc_start_main_impl
             at /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
   8: _start

lean_alloc_small_object(sz: 24)
   0: lean_hashbrown::ffi::lean_alloc_small_object
             at ./src/ffi.rs:163:13
   1: lean_hashbrown::ffi::lean_alloc_external
             at ./src/ffi.rs:177:15
   2: lean_hashbrown_hashset_create
             at ./src/set.rs:52:15
   3: initialize_Main
   4: main
   5: __libc_start_call_main
             at /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   6: __libc_start_main_impl
             at /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
   7: _start

lean_set_st_header(0x7fe686cd6f38, 254, 0)
   0: lean_hashbrown::ffi::lean_set_st_header
             at ./src/ffi.rs:128:71
   1: lean_hashbrown::ffi::lean_alloc_external
             at ./src/ffi.rs:178:5
   2: lean_hashbrown_hashset_create
             at ./src/set.rs:52:15
   3: initialize_Main
   4: main
   5: __libc_start_call_main
             at /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   6: __libc_start_main_impl
             at /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
   7: _start

hashset_foreach(0x5576de6423d0, 0x7fe686cd6f20)
   0: lean_hashbrown::set::hashset_foreach
             at ./src/set.rs:65:53
   1: lean_mark_persistent
   2: initialize_Main
   3: main
   4: __libc_start_call_main
             at /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   5: __libc_start_main_impl
             at /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
   6: _start

lean_dec_ref(0x7fe686cd6f20), m_rc = 1
test invoked
target is not exclusive: 0x7fe686cd6f38
lean_alloc_small_object(sz: 24)
   0: lean_hashbrown::ffi::lean_alloc_small_object
             at ./src/ffi.rs:163:13
   1: lean_hashbrown::ffi::lean_alloc_external
             at ./src/ffi.rs:177:15
   2: lean_hashbrown::set::exlusive_hashset
             at ./src/set.rs:139:23
   3: lean_hashbrown_test
             at ./src/set.rs:281:15
   4: _lean_main
   5: main
   6: __libc_start_call_main
             at /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   7: __libc_start_main_impl
             at /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
   8: _start

lean_set_st_header(0x7fe686cd6f09, 254, 0)
   0: lean_hashbrown::ffi::lean_set_st_header
             at ./src/ffi.rs:128:71
   1: lean_hashbrown::ffi::lean_alloc_external
             at ./src/ffi.rs:178:5
   2: lean_hashbrown::set::exlusive_hashset
             at ./src/set.rs:139:23
   3: lean_hashbrown_test
             at ./src/set.rs:281:15
   4: _lean_main
   5: main
   6: __libc_start_call_main
             at /usr/src/debug/glibc/glibc/csu/../sysdeps/nptl/libc_start_call_main.h:58:16
   7: __libc_start_main_impl
             at /usr/src/debug/glibc/glibc/csu/../csu/libc-start.c:360:3
   8: _start

thread '<unnamed>' panicked at 'misaligned pointer dereference: address must be a multiple of 0x4 but is 0x7fe686cd6f09', src/ffi.rs:129:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread caused non-unwinding panic. aborting.

Details are committed to the repo.

Schrodinger ZHU Yifan (Aug 14 2023 at 15:15):

Ok, I found the problem!

                    object * fn = lean_alloc_closure((void*)mark_persistent_fn, 1, 0);
                    lean_to_external(o)->m_class->m_foreach(lean_to_external(o)->m_data, fn);
                    lean_dec(fn);
                    break;

it is assumed that foreach accepts @& Fn. I did not notice that and corrupted the heap.


Last updated: Dec 20 2023 at 11:08 UTC