[erlang-questions] Destructor called twice on NIF resource

Erik Axling axling@REDACTED
Tue Feb 8 22:06:33 CET 2011


And I thought I understood the resources by now :-). But now I'm not sure
what to do at all. The resources that I allocate using enif_alloc_resource/2
shouldn't refer to each other and if they do then it's a mistake on my
part(or it could be that I have missed something fundamental about
resources?).

The create_standard_nif function allocates a resource and creates a handle
with enif_make_resource. Then I call release and hope that the GC will take
care of the rest. The user should be able create as many nets as possible so
the create_standard_nif should create resources independent of each other
which I thought it did today. Therefore I find it hard to understand where I
should use enif_keep_resource and where I should call release?

/Erik Axling

On Tue, Feb 8, 2011 at 11:56 AM, Sverker Eriksson
<sverker@REDACTED>wrote:

> Hi Erik
>
> You have NIF resources that refer to each other. I think you need to  use
> enif_keep_resource() to get that to play nice with the GC.
>
> If resource A have a pointer to resource B, then you need to do
> enif_keep_resource(B) to let the GC know that you have a reference of your
> own to B. If you don't, then the GC may destruct B while A is still alive
> with an invalid pointer to a dead B.
>
> If A stops referring to B (if A is destructed for example), then you need
> to call enif_release_resource(B) to let the GC know that you no longer have
> a reference of your own to B.
>
> A resource can only be destructed when the initial call to alloc_resource
> plus all calls to keep_resource have been balanced by an equal number of
> calls to release_resource.
>
>
> Tip of the day:
> Run debug emulator during development to (maybe) get better fault
> identification when you do something wrong in your NIFs.
> Read "How to Build a Debug Enabled Erlang RunTime System" in INSTALL.md.
>
> Calling enif_release_resource one time to many will for example be detected
> by the debug emulator.
>
> /Sverker, Erlang/OTP
>
>
> Erik Axling wrote:
>
>> Hello!
>>
>> I've been creating NIFs for a C-library and when I'm starting to run EUnit
>> tests on them it fails with a seg fault. It seems that the destructor for
>> a
>> resource is called twice which leads to the error as the pointer has
>> already
>> been freed.  I do not unserdtand why this happens though
>>
>> If I run the code myself in a shell it doesn't fail but then I am not
>> executing it inside of functions which, I guess, gets another behaviour
>> for
>> the GC.  But if I compile the eunit test suite file and run the individual
>> functions myself it also fails but with a different seg fault this time:
>>
>> fann_nif.c: https://gist.github.com/815506
>> fannerl_test.erl: https://gist.github.com/815543
>>
>> First fault:
>> $ ./rebar eunit
>> GNU gdb (GDB) 7.2-ubuntu
>> Copyright (C) 2010 Free Software Foundation, Inc.
>> License GPLv3+: GNU GPL version 3 or later <
>> http://gnu.org/licenses/gpl.html
>>  This is free software: you are free to change and redistribute it.
>> There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
>> and "show warranty" for details.
>> This GDB was configured as "i686-linux-gnu".
>> For bug reporting instructions, please see:
>> <http://www.gnu.org/software/gdb/bugs/>...
>> Reading symbols from /usr/local/lib/erlang/erts-5.8.1/bin/erlexec...done.
>> (gdb) r
>> Starting program: /usr/local/lib/erlang/erts-5.8.1/bin/erlexec +B -boot
>> start_clean -noshell -noshell -noinput -run escript start -extra ./rebar
>> eunit
>> process 3188 is executing new program:
>> /usr/local/lib/erlang/erts-5.8.1/bin/beam.smp
>> [Thread debugging using libthread_db enabled]
>> [New Thread 0xb7d03b70 (LWP 3191)]
>> [New Thread 0xb7ffdb70 (LWP 3192)]
>> [New Thread 0xb7502b70 (LWP 3193)]
>> [New Thread 0xb7ff4b70 (LWP 3194)]
>> [New Thread 0xb6d01b70 (LWP 3195)]
>> [New Thread 0xb6500b70 (LWP 3196)]
>> ==> fannerl (eunit)
>> test/fannerl_tests.erl:8: exiting create_test
>> Destroy the fann pointer
>> test/fannerl_tests.erl:13: exiting get_mse_test
>> test/fannerl_tests.erl:19: before last get
>> test/fannerl_tests.erl:21: after last get
>> testing to see if we get here
>> Destroy the fann pointer
>> Destroy the fann pointer
>> *** glibc detected *** /usr/local/lib/erlang/erts-5.8.1/bin/beam.smp:
>> free(): invalid pointer: 0x082da1d0 ***
>> ======= Backtrace: =========
>> /lib/libc.so.6(+0x6c501)[0x225501]
>> /lib/libc.so.6(+0x6dd70)[0x226d70]
>> /lib/libc.so.6(cfree+0x6d)[0x229e5d]
>> /usr/local/lib/libfann.so.2(fann_destroy+0x43)[0x493343]
>>
>> /home/dude/projects/fannerl/.eunit/../priv/fannerl_nif.so(+0x27cd)[0x4857cd]
>> /usr/local/lib/erlang/erts-5.8.1/bin/beam.smp[0x814397a]
>> ======= Memory map: ========
>> 00110000-0012c000 r-xp 00000000 08:01 8920592    /lib/ld-2.12.1.so
>> 0012c000-0012d000 r--p 0001b000 08:01 8920592    /lib/ld-2.12.1.so
>> 0012d000-0012e000 rw-p 0001c000 08:01 8920592    /lib/ld-2.12.1.so
>> 0012e000-0012f000 r-xp 00000000 00:00 0          [vdso]
>> 0012f000-00131000 r-xp 00000000 08:01 8920620    /lib/libutil-2.12.1.so
>> 00131000-00132000 r--p 00001000 08:01 8920620    /lib/libutil-2.12.1.so
>> 00132000-00133000 rw-p 00002000 08:01 8920620    /lib/libutil-2.12.1.so
>> 00133000-00135000 r-xp 00000000 08:01 8920604    /lib/libdl-2.12.1.so
>> 00135000-00136000 r--p 00001000 08:01 8920604    /lib/libdl-2.12.1.so
>> 00136000-00137000 rw-p 00002000 08:01 8920604    /lib/libdl-2.12.1.so
>> 00137000-0015b000 r-xp 00000000 08:01 8920605    /lib/libm-2.12.1.so
>> 0015b000-0015c000 r--p 00023000 08:01 8920605    /lib/libm-2.12.1.so
>> 0015c000-0015d000 rw-p 00024000 08:01 8920605    /lib/libm-2.12.1.so
>> 0015d000-00193000 r-xp 00000000 08:01 8912994    /lib/libncurses.so.5.7
>> 00193000-00195000 r--p 00035000 08:01 8912994    /lib/libncurses.so.5.7
>> 00195000-00196000 rw-p 00037000 08:01 8912994    /lib/libncurses.so.5.7
>> 00196000-001ab000 r-xp 00000000 08:01 8920615    /lib/
>> libpthread-2.12.1.so
>> 001ab000-001ac000 ---p 00015000 08:01 8920615    /lib/
>> libpthread-2.12.1.so
>> 001ac000-001ad000 r--p 00015000 08:01 8920615    /lib/
>> libpthread-2.12.1.so
>> 001ad000-001ae000 rw-p 00016000 08:01 8920615    /lib/
>> libpthread-2.12.1.so
>> 001ae000-001b0000 rw-p 00000000 00:00 0
>> 001b0000-001b7000 r-xp 00000000 08:01 8920617    /lib/librt-2.12.1.so
>> 001b7000-001b8000 r--p 00006000 08:01 8920617    /lib/librt-2.12.1.so
>> 001b8000-001b9000 rw-p 00007000 08:01 8920617    /lib/librt-2.12.1.so
>> 001b9000-00310000 r-xp 00000000 08:01 8920601    /lib/libc-2.12.1.so
>> 00310000-00312000 r--p 00157000 08:01 8920601    /lib/libc-2.12.1.so
>> 00312000-00313000 rw-p 00159000 08:01 8920601    /lib/libc-2.12.1.so
>> 00313000-00316000 rw-p 00000000 00:00 0
>> 00316000-0031d000 r-xp 00000000 08:01 4987538
>>  /usr/local/lib/erlang/lib/crypto-2.0.1/priv/lib/crypto.so
>> 0031d000-0031e000 r--p 00006000 08:01 4987538
>>  /usr/local/lib/erlang/lib/crypto-2.0.1/priv/lib/crypto.so
>> 0031e000-0031f000 rw-p 00007000 08:01 4987538
>>  /usr/local/lib/erlang/lib/crypto-2.0.1/priv/lib/crypto.so
>> 0031f000-00454000 r-xp 00000000 08:01 8913384    /lib/libcrypto.so.0.9.8
>> 00454000-0045c000 r--p 00134000 08:01 8913384    /lib/libcrypto.so.0.9.8
>> 0045c000-0046b000 rw-p 0013c000 08:01 8913384    /lib/libcrypto.so.0.9.8
>> 0046b000-0046e000 rw-p 00000000 00:00 0
>> 0046e000-00481000 r-xp 00000000 08:01 8913090    /lib/libz.so.1.2.3.4
>> 00481000-00482000 r--p 00012000 08:01 8913090    /lib/libz.so.1.2.3.4
>> 00482000-00483000 rw-p 00013000 08:01 8913090    /lib/libz.so.1.2.3.4
>> 00483000-0048b000 r-xp 00000000 08:01 6034321
>>  /home/dude/projects/fannerl/priv/fannerl_nif.so
>> 0048b000-0048c000 r--p 00007000 08:01 6034321
>>  /home/dude/projects/fannerl/priv/fannerl_nif.so
>> 0048c000-0048d000 rw-p 00008000 08:01 6034321
>>  /home/dude/projects/fannerl/priv/fannerl_nif.so
>> 0048d000-0049d000 r-xp 00000000 08:01 3814722
>>  /usr/local/lib/libfann.so.2.0.1
>> 0049d000-0049e000 r--p 0000f000 08:01 3814722
>>  /usr/local/lib/libfann.so.2.0.1
>> 0049e000-0049f000 rw-p 00010000 08:01 3814722
>>  /usr/local/lib/libfann.so.2.0.1
>> 0049f000-004b9000 r-xp 00000000 08:01 8912975    /lib/libgcc_s.so.1
>> 004b9000-004ba000 r--p 00019000 08:01 8912975    /lib/libgcc_s.so.1
>> 004ba000-004bb000 rw-p 0001a000 08:01 8912975    /lib/libgcc_s.so.1
>> 08048000-081d3000 r-xp 00000000 08:01 3809922
>>  /usr/local/lib/erlang/erts-5.8.1/bin/beam.smp
>> 081d3000-081d4000 r--p 0018a000 08:01 3809922
>>  /usr/local/lib/erlang/erts-5.8.1/bin/beam.smp
>> 081d4000-08201000 rw-p 0018b000 08:01 3809922
>>  /usr/local/lib/erlang/erts-5.8.1/bin/beam.smp
>> 08201000-082e2000 rw-p 00000000 00:00 0          [heap]
>> b5700000-b5708000 rw-p 00000000 00:00 0
>> b5708000-b5800000 ---p 00000000 00:00 0
>> b588a000-b5d00000 rw-p 00000000 00:00 0
>> b5d00000-b5d01000 ---p 00000000 00:00 0
>> b5d01000-b6501000 rw-p 00000000 00:00 0
>> b6501000-b6502000 ---p 00000000 00:00 0
>> b6502000-b6d02000 rw-p 00000000 00:00 0
>> b6d02000-b6d03000 ---p 00000000 00:00 0
>> b6d03000-b7503000 rw-p 00000000 00:00 0
>> b7503000-b7504000 ---p 00000000 00:00 0
>> b7504000-b7fed000 rw-p 00000000 00:00 0
>> b7fef000-b7ff0000 rw-p 00000000 00:00 0
>> b7ff0000-b7ff1000 ---p 00000000 00:00 0
>> b7ff1000-b7ff5000 rw-p 00000000 00:00 0
>> b7ff5000-b7ff6000 ---p 00000000 00:00 0
>> b7ff6000-b8000000 rw-p 00000000 00:00 0
>> bffdf000-c0000000 rw-p 00000000 00:00 0          [stack]
>>
>> Program received signal SIGABRT, Aborted.
>> [Switching to Thread 0xb6d01b70 (LWP 3195)]
>> 0x0012e416 in ?? ()
>> (gdb) where
>> #0  0x0012e416 in ?? ()
>> #1  0x001e3941 in raise () from /lib/libc.so.6
>> #2  0x001e6e42 in abort () from /lib/libc.so.6
>> #3  0x0021b305 in ?? () from /lib/libc.so.6
>> #4  0x00225501 in ?? () from /lib/libc.so.6
>> #5  0x00226d70 in ?? () from /lib/libc.so.6
>> #6  0x00229e5d in free () from /lib/libc.so.6
>> #7  0x00493343 in fann_destroy (ann=0x0) at fann.c:786
>> #8  0x004857cd in destroy_fann_pointer (env=0xb6d01144,
>> resource=0x82849c0)
>>    at c_src/fann_nif.c:130
>> #9  0x0814397a in nif_resource_dtor (bin=0x82849a8) at beam/erl_nif.c:1176
>> #10 0x080c6946 in erts_bin_free (offheap=0xb5bc35f8) at
>> beam/erl_binary.h:294
>> #11 erts_cleanup_offheap (offheap=0xb5bc35f8) at beam/erl_message.c:174
>> #12 0x080d8a8c in delete_process (p=0xb5bc34f4, pix_lock=<value optimized
>> out>)
>>    at beam/erl_process.c:8328
>> #13 continue_exit_process (p=0xb5bc34f4, pix_lock=<value optimized out>)
>>    at beam/erl_process.c:9370
>> #14 0x0814d90e in process_main () at beam/beam_emu.c:2976
>> #15 0x080d165e in sched_thread_func (vesdp=0xb7dff000)
>>    at beam/erl_process.c:3635
>> #16 0x081b1485 in thr_wrapper (vtwd=0xbfffee10) at pthread/ethread.c:106
>> #17 0x0019bcc9 in start_thread () from /lib/libpthread.so.0
>> #18 0x0028969e in clone () from /lib/libc.so.6
>> (gdb)
>>
>> second error:
>> Erlang R14B (erts-5.8.1) [source] [smp:2:2] [rq:2] [async-threads:0]
>> [kernel-poll:false]
>>
>> Eshell V5.8.1  (abort with ^G)
>> 1> l(fannerl).
>> {module,fannerl}
>> 2> c("test/fannerl_tests").
>> {ok,fannerl_tests}
>> 3> fannerl
>> fannerl          fannerl_tests
>> 3> fannerl_tests:create_test().
>> test/fannerl_tests.erl:8: exiting create_test
>> ok
>> 4> fannerl_tests:get_mse_test().
>> Destroy the fann pointer
>>                        test/fannerl_tests.erl:13: exiting get_mse_test
>> ok
>> 5> fannerl_tests:activation_function_test().
>> Destroy the fann pointer
>>                        test/fannerl_tests.erl:19: before last get
>> test/fannerl_tests.erl:21: after last get
>> testing to see if we get here
>>                             Destroy the fann pointer
>>
>> Program received signal SIGSEGV, Segmentation fault.
>> [Switching to Thread 0xb6d01b70 (LWP 3214)]
>> 0x002268ac in ?? () from /lib/libc.so.6
>> (gdb) where
>> #0  0x002268ac in ?? () from /lib/libc.so.6
>> #1  0x00229e5d in free () from /lib/libc.so.6
>> #2  0x00326549 in fann_destroy (ann=0xa3c4517b) at fann.c:811
>> #3  0x003187cd in destroy_fann_pointer (env=0xb6d010c4,
>> resource=0x82833f8)
>>    at c_src/fann_nif.c:130
>> #4  0x0814397a in nif_resource_dtor (bin=0x82833e0) at beam/erl_nif.c:1176
>> #5  0x080c6946 in erts_bin_free (offheap=0xb7eccba0) at
>> beam/erl_binary.h:294
>> #6  erts_cleanup_offheap (offheap=0xb7eccba0) at beam/erl_message.c:174
>> #7  0x080d8a8c in delete_process (p=0xb7ecca9c, pix_lock=<value optimized
>> out>)
>>    at beam/erl_process.c:8328
>> #8  continue_exit_process (p=0xb7ecca9c, pix_lock=<value optimized out>)
>>    at beam/erl_process.c:9370
>> #9  0x0814c14e in terminate_proc (c_p=0xb7ecca9c, pc=<value optimized
>> out>,
>>    reg=<value optimized out>, bf=0x80af500) at beam/beam_emu.c:5363
>> #10 handle_error (c_p=0xb7ecca9c, pc=<value optimized out>,
>>    reg=<value optimized out>, bf=0x80af500) at beam/beam_emu.c:5238
>> #11 0x081539d5 in process_main () at beam/beam_emu.c:2260
>> #12 0x080d165e in sched_thread_func (vesdp=0xb7dff000)
>>    at beam/erl_process.c:3635
>> #13 0x081b1485 in thr_wrapper (vtwd=0xbfffee90) at pthread/ethread.c:106
>> #14 0x0019bcc9 in start_thread () from /lib/libpthread.so.0
>> #15 0x0028969e in clone () from /lib/libc.so.6
>>
>> /Erik Axling
>>
>>
>>
>
>


More information about the erlang-questions mailing list