ss3681755
NIFs raise Segmentation Fault while loading function has try catch block to handle the exception
I am working on integrating a C++ api with Elixir, by using NIFs. Now whenever I load the NIF, I want to initialize some variables/data which will be persisted across NIF calls. I was trying to achieve the same by load function mentioned in the ERL_NIF_INIT call. But I am observing some weird behavior out of load function. Please have a look at the below mentioned example and then I’ll explain the issue further:
#include <erl_nif.h>
static ERL_NIF_TERM sample(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_atom(env, "ok");
}
static ErlNifFunc nif_funcs[] = {{"sample", 1, sample}};
static int load(ErlNifEnv *env, void **priv_data, ERL_NIF_TERM load_info) {
try {
1 / 0; // nif loads if this is the case
int x = 1 / 0; // float point exception segmentation fault when used this line
} catch (...) {
return 1;
}
return 0;
}
ERL_NIF_INIT(Elixir.Sample, nif_funcs, load, NULL, NULL, NULL);
Now closely observe the load function containing the try/catch block, when I use 1 / 0; expression in the body of try block, NIF is loaded but when the expression 1 / 0; is replaced by int x = 1 / 0; erlang vm fails to load NIF and crashes with floating point exception segmentation fault even if I have added the try/catch block to handle the exception. Can someone explain this to me? I really need help here.
Here is the elixir code used for interfacing:
defmodule Sample do
@on_load :load_nifs
def load_nifs do
:ok =
:sample
|> :code.priv_dir()
|> Path.join("sample")
|> :erlang.load_nif("0.0.1")
end
def sample(_) do
raise "sample/1 Function not implemented"
end
end
Command used to compile NIF g++ -fPIC -shared sample.cpp -o sample.so
P.S. - Thanks for your time to read this, I really appreciate it.
Most Liked
OvermindDL1
C++ does not have an exception for a divide by zero, rather that is Undefined Behaviour, meaning the C++ compiler is allowed to do whatever it wants from give you back invalid data to crashing to wiping your entire system, everything is allowed, and a try/catch cannot stop it. This is why untrusted input to division should always be checked for zero first in C/C++.
EDIT: If you’re curious the spec defines it as UB in section 5.6.4 of the C++ standard (at least in the version I have here).
OvermindDL1
Because Undefined Behavior allows for anything, and most of they time they screw with the optimizers in weird ways.
al2o3cr
The word “exception” in that message refers to a hardware exception, not the C++ kind.
In fact, modern compilers don’t generate any code at all for the catch section in your example because they can determine it will never execute:
Note that if you switch to the 1 / 0; version, the compiler omits the division entirely because it sees the result is completely unused. TBH I’m not sure why assigning the value to a local variable (that immediately goes out-of-scope) doesn’t do this too.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








