Closed evnu closed 6 years ago
I added some debugging output:
fn roundtrip<'a>(env: NifEnv<'a>, args: &[NifTerm<'a>]) -> NifResult<NifTerm<'a>> {
let original: NifTerm = args[0].decode()?;
eprintln!("{:?}", original);
let binary = original.to_binary();
let roundtripped: NifTerm = binary.to_term(env);
eprintln!("{:?}", roundtripped);
Ok((1, roundtripped).encode(env))
}
Resulting run:
mix run -e RustlerCoreDump.test
Compiling NIF crate :rustler_core_dump (native/rustler_core_dump)...
Compiling rustler_core_dump v0.1.0 (file:///home/mo/tools/rustler_core_dump/native/rustler_core_dump)
Finished dev [unoptimized + debuginfo] target(s) in 0.47 secs
#Reference<0.441875240.1587806209.52051>
#Ref<0.441875240.1587806209.52051>
<cp/header:0x0000000000000000>
A similar bug was fixed with OTP 20.3.7:
OTP-15080 Application(s): erts
Fixed bug in enif_binary_to_term which could cause memory corruption for immediate terms (atoms, small integers, pids, ports, empty lists).
I can still trigger the segfault with the example above.
@evnu Could you test it again on latest master?
ah, you beat me to it @hansihe
The example does not segfault any more, thank you! I needed to adapt the conversion into a Term as to_binary()
now returns an OwnedBinary
:
let roundtripped: Term = binary.release(env).to_term(env);
Note that the resulting roundtripped
does not equal the value put into the NIF:
eprintln!("{:?}", original == roundtripped); #=> false
Converting it within Elixir with :erlang.binary_to_term/1
produces the original value again, though. I guess I would need to use env::binary_to_term()
to convert back into the original term.
I am able to reproduce a core dump with the simple
roundtrip()
function below (see https://github.com/evnu/rustler_core_dump). The function takes a term, encodes it into a binary, reencodes into a term and returns that term wrapped with a1
within a tuple.When I use the following Elixir implementation to load the nif, running
test
results in a core dump.Note that inspecting the resulting
reference
assigned after roundtrip seems to be crucial: I need to eitherIO.inspect(reference)
or match with{1, ^reference} = roundtrip(reference)
to reproduce this.Running the Example
Version Information
rust:
Elixir:
mix.lock
: