[erlang-questions] Are binaries relocatable?

Hynek Vychodil <>
Sat Aug 30 07:07:06 CEST 2014


Thanks for your answer very much. If I understand it correctly this way it
should be safe:

     ErlNifBinary bin;
     if (!enif_is_binary(env, argv[0]))
         return enif_make_badarg(env);

     ErlNifEnv *priv_env = enif_alloc_env();
     ERL_NIF_TERM term = enif_make_copy(priv_env, argv[0]);
     ErlNifBinary bin;
     enif_inspect_binary(priv_env, term, &bin);
     entry->content.bin = (struct my_bin){.env = priv_env, .size =
bin.size, .data = bin.data};

And now mine entry->content.bin.data should be safe but unfortunately it
still eventually hangs whole VM after few thousands cycles of referencing
this data

        CacheEntryRes_t *res = enif_alloc_resource(dc_entry_type,
sizeof(CacheEntryRes_t));
        unless (res) return insufficient_memory(env);
        res->entry = entry;
        ERL_NIF_TERM result = enif_make_resource_binary(env, res,
                entry->content.bin.data, entry->content.bin.size);
        enif_release_resource(res);
        return result;

I do mine own reference count and release by

       enif_free_env(entry->content.bin.env);

It hangs only if I replace enif_alloc() + memcpy() and enif_free() version
with above one :-(

Thanks
     Hynek


On Fri, Aug 29, 2014 at 3:02 PM, Sverker Eriksson <
> wrote:

> On 08/28/2014 03:09 PM, Hynek Vychodil wrote:
>
>> Hi all,
>> I would like to know if binaries are relocatable. If I have binary
>> parameter
>>
>>      ErlNifBinary bin;
>>      if (!enif_inspect_binary(env, argv[0], &bin))
>>          return enif_make_badarg(env);
>>
>> I store binary in mine own environment
>>
>>      ErlNifEnv *priv_env = enif_alloc_env();
>>      enif_make_copy(priv_env, argv[0]);
>>
>> Can I then rely on bin.data pointing into same memory until I free
>> enif_free_env(priv_env) ?
>>
> No.
> Your bin.data is refering to the original term argv[0] in 'env' which is
> only valid until the NIF returns.
> You must do enif_inspect_binary on the copy in order to get a safe pointer
> that is valid until you do enif_free_env(priv_env).
>
>
>
>    I'm asking because I would like to avoid copying
>> and share data or even return it using enif_make_resource_binary to catch
>> and
>> count references.
>>
> Whether a copied binary share data with its original is implementation
> dependent. Today big binaries (>64 bytes) are shared
> and small binaries are copied between environments.
>
>
>  I have code which makes copy of binary data but when I switch to reference
>> bin.data it hangs whole VM. I would like to know if I make some mistake in
>> mine code and it should work or it is wrong idea at all.
>>
>>
>>  There is a known bug when calling enif_make_copy after
> enif_inspect_binary
> that can cause the binary to get reallocated and thus the bin.data pointer
> to get invalid
> before the NIF returns. To detect this bug, you can call
> enif_inspect_binary(env,argv[0],&bin2)
> after enif_make_copy and check if bin2.data != bin.data.
>
> This bug has been lingering as I thought it was an exotic scenario
> (apparently not) and I have
> been a bit unsure how to fix it without ruin performance.
>
>
> /Sverker, Erlang/OTP
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20140830/81b3c01b/attachment.html>


More information about the erlang-questions mailing list