[erlang-questions] Destructor called twice on NIF resource

Sverker Eriksson sverker@REDACTED
Tue Feb 8 11:56:57 CET 2011


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