Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Looks like I've solved the issue, which I'll outline here for the benefit of others.</p> <h2>What Happened</h2> <p>The cause of the segmentation fault was that I used <code>sprintf()</code> to assign a value to a <code>char *</code> pointer which had not been assigned a value. Here is the bad code:</p> <pre><code>char* ip_to_string(uint32_t ip) { unsigned char bytes[4]; bytes[0] = ip &amp; 0xFF; bytes[1] = (ip &gt;&gt; 8) &amp; 0xFF; bytes[2] = (ip &gt;&gt; 16) &amp; 0xFF; bytes[3] = (ip &gt;&gt; 24) &amp; 0xFF; char *ip_string; sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); return ip_string; } </code></pre> <p>The pointer <code>ip_string</code> does not have a value here, which means it points to nothing. Except, that's not entirely true. What it points to is <em>undefined</em>. It could point anywhere. So in assigning a value to it with <code>sprintf()</code>, I inadvertently overwrote a random bit of memory. I believe that the reason for the odd behaviour (though I never confirmed this) was that the undefined pointer was pointing to somewhere on the stack. This caused the computer to be confused when certain functions were called.</p> <p>One way to fix this is to allocate memory and then point the pointer to that memory, which can be accomplished with <code>malloc()</code>. That solution would look similar to this:</p> <pre><code>char* ip_to_string(uint32_t ip) { unsigned char bytes[4]; bytes[0] = ip &amp; 0xFF; bytes[1] = (ip &gt;&gt; 8) &amp; 0xFF; bytes[2] = (ip &gt;&gt; 16) &amp; 0xFF; bytes[3] = (ip &gt;&gt; 24) &amp; 0xFF; char *ip_string = malloc(16); sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); return ip_string; } </code></pre> <p>The problem with this is that every <code>malloc()</code> needs to be matched by a call to <code>free()</code>, or you have a memory leak. If I call <code>free(ip_string)</code> inside this function the returned pointer will be useless, and if I don't then I have to rely on the code that's calling this function to release the memory, which is pretty dangerous. </p> <p>As far as I can tell, the "right" solution to this is to pass an already allocated pointer to the function, such that it is the function's responsibility to fill pointed to memory. That way, calls to <code>malloc()</code> and <code>free()</code> can be made in the block of code. Much safer. Here's the new function:</p> <pre><code>char* ip_to_string(uint32_t ip, char *ip_string) { unsigned char bytes[4]; bytes[0] = ip &amp; 0xFF; bytes[1] = (ip &gt;&gt; 8) &amp; 0xFF; bytes[2] = (ip &gt;&gt; 16) &amp; 0xFF; bytes[3] = (ip &gt;&gt; 24) &amp; 0xFF; sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); return ip_string; } </code></pre> <h2>Answers to the Questions</h2> <p><em>What can cause a Java native function (in C) to segfault upon entry like this?</em></p> <p>If you assign a value to a pointer that hasn't been allocated memory, you may accidentally overwrite memory on the stack. This may not cause an immediate failure, but will probably cause problems when you call other functions later.</p> <p><em>What specific things can I look for that will help me squash this bug?</em></p> <p>Look for a segmentation fault like any other. Things like assigning a value to unallocated memory or dereferencing a null pointer. I'm not an expert on this, but I'm willing to bet that there are <a href="https://www.google.ca/search?q=how+to+find+a+segfault&amp;oq=how+to+find+a+segfault&amp;aqs=chrome..69i57j0.3481j0j7&amp;sourceid=chrome&amp;espv=210&amp;es_sm=119&amp;ie=UTF-8">many web resources</a> for this.</p> <p><em>How can I write code in the future that will help me avoid this problem?</em></p> <p>Be careful with pointers, especially when you are responsible for creating them. If you see a line of code that looks like this:</p> <pre><code>type *variable; </code></pre> <p>... then look for a line that looks like ...</p> <pre><code>variable = ...; </code></pre> <p>... and make sure that this line comes before writing to the pointed to memory.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload