<span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px; border-collapse: collapse; "><div>Hi list,</div><div><br></div><div>Over the last few months Basho has been seeing intermittent beam crashes with extremely large out of memory failures.  A customer just had a cluster crash with multiple nodes exiting close to the same time with huge allocation requests and we were able to get our hands on the coredumps for the first time.</div>
<div><br></div><div><div>eheap_alloc: Cannot allocate 18446744071662201696 bytes of memory (of type "heap_frag").</div><div>eheap_alloc: Cannot allocate 18446744071662201696 bytes of memory (of type "heap_frag").</div>
<div>eheap_alloc: Cannot allocate 18446744071662201696 bytes of memory (of type "heap_frag").</div><div><br></div></div><div>After analyzing using pstack, they all died in the same place</div><div><br></div><div>
<div>-----------------  lwp# 71 / thread# 71  --------------------</div><div> fffffd7fff0e1eca _lwp_kill () + a</div><div> fffffd7fff086fe9 raise () + 19</div><div> fffffd7fff065f60 abort () + 90</div><div> 0000000000473575 erl_exit () + 155</div>
<div> 000000000046110e erts_alc_fatal_error () + 1de</div><div> 0000000000461177 ???????? ()</div><div> 000000000049792d ???????? ()</div><div> 00000000004ddc8c new_binary () + ac</div><div> 00000000004d77f1 erts_term_to_binary () + 1e1</div>
<div> 0000000000538c95 process_main () + 8235</div><div> 00000000004bae0c ???????? ()</div><div> 00000000005a6c43 ???????? ()</div><div> fffffd7fff0dc39b _thr_setup () + 5b</div><div> fffffd7fff0dc5c0 _lwp_start ()</div></div>
<div><br></div><div>Digging into through the stack, in erts_term_to_binary the size for the result binary is computed as a Unit, then truncated and stored temporarily as a signed int. When new_binary is called it is given a signed int which is then converted back to a Uint for the allocation. </div>
<div><br></div><div>We've seen the crash on 64-bit Solaris/Linux systems where sizeof(int) == 4, sizeof(Uint) == 8. When converting from signed int to unsigned long the compiler helpfully sign extends the int to 8 bytes.  Any sizes >= 0x8000000 become 0xffffffff80000000 and above triggering the allocation failure.</div>
<div><br></div><div>Here's a small fragment to reproduce.</div><div><br></div><div><div>  Bin = list_to_binary([X rem 256 || X <- lists:seq(1, 65536)]). </div><div>  Blocks = 16#80000000 div size(Bin).</div><div>  BigBin = lists:duplicate(Blocks, Bin).</div>
<div>  term_to_binary(BigBin).</div></div><div><br></div><div>I've attached patches that changes new_binary to take a Uint size and fixed the cases where callers were casting the size argument to an (int).  I've also modified the temporary 'size' variable in erts_term_to_binary to be a Uint.</div>
<div>The first patch applies to the r13b04 and r14b01 tarballs and the other applies to the 'pu' branch on github as I pulled it today.</div><div><br></div><div>There were some other places in the code there are still problems but I decided to leave them to people that know more than I do.</div>
<div><br></div><div>The most important one is around iolists and bitstrings - io_list_len and bitstr_len both return integer lengths. I also noticed something in the ssl_tls_erl function - I wasn't sure if it was possible to send a very long buffer and prefix length. The code loader also uses ints, but it seems less likely to bite anybody.</div>
<div><br></div><div><div>erts/emulator/beam/binary.</div><div>670:    bin = new_binary(p, (byte *)NULL, i);                               // SHOULDFIX - io_list_len returns int</div><div>413:    bin = new_binary(BIF_P, (byte *)NULL, i);                        // SHOULDFIX - bitstr_len returns int</div>
</div><div><br></div><div><div>erts/emulator/beam/erl_bif_port.c</div><div>1281:    Eterm bin = new_binary(pca->p, NULL, plen+len);                       SSL TLS - two ints, probably size limited</div></div><div><br></div>
<div>I think there may also be problems checking the length of binaries when creating external binaries - the format only allows for a 32-bit unsigned length and I didn't see a check in enc_term when I glanced at it.</div>
<div><br></div><div>Hope it helps somebody,</div><div><br></div><div>Cheers, Jon Meredith.</div><div>Basho Technologies.</div></span>