[erlang-bugs] enif_make_badarg crashes is_binary

Mikael Pettersson mikpe@REDACTED
Tue Feb 22 09:37:05 CET 2011


Steve Vinoski writes:
 > I was recently writing a nif and had one C function returning an
 > ERL_NIF_TERM that was then being passed to a second C function. The
 > second one checked the passed term using
 > enif_inspect_iolist_as_binary(), and it crashed. I debugged it and
 > it's apparently caused by the fact that the ERL_NIF_TERM being passed
 > was returned from enif_make_badarg(), so it was a 0. It caused this
 > error on my Macbook Pro:
 > 
 > Program received signal EXC_BAD_ACCESS, Could not access memory.
 > Reason: KERN_INVALID_ADDRESS at address: 0xfffffffe
 > 
 > The reason for that invalid address is the is_binary(x) macro at the
 > beginning of enif_inspect_iolist_as_binary(). It expands to
 > 
 >     if (((!(((((term)))) & (0x3 -0x2))) && (((*((Eterm*) (((((term)))
 > - 0x2)))) & (0x3F -(0x3 << 2))) == (0x0|(0x8 << 2))))) {
 > 
 > The first test, which I believe comes from _unchecked_is_boxed(x),
 > passes because it's testing !0 which of course is 1, then the second
 > test which I believe is _unchecked_boxed_val(x) fails with the invalid
 > address error because the code more or less dereferences a null
 > pointer.
 > 
 > I think the fix is to make macros like is_binary(x) first check the
 > term using is_value(x).

No.  Non-values are emphatically NOT permitted inside Erlang process
heaps, live BEAM VM registers, live terms, or as parameters to internal
C functions (except for very few special cases).  The non-values are
very private to the VM, and are (as I recall, it's been a while since
I wrote that code), limited to (a) indicating exception returns from
C BIFs (handled immediately by beam_emu), (b) temporary magic markers
during GC, and (c) signalling error returns from some internal C
functions.  In no case is a non-value allowed to leak into
application-visible Erlang state.

The fix, therefore, is to catch whatever produced that non-value
(error from a C function?) and turn that into an error return or
Erlang exception rather than trying to pass it on as a valid term.

/Mikael


More information about the erlang-bugs mailing list