<div>I have some code that reads (infrequently) small amounts of data from /dev/urandom,  and because this is pretty infrequent,  I simply open the handle and close it every time I need some random bytes.   </div><div><br>
</div><div>The problem is that I recently discovered that,  thanks to buffering within GHC,   I was actually reading 8096 bytes when I only need 16 bytes,  and thus wasting entropy.   Moreover  calling hSetBuffering  handle NoBuffering did not change this behavior.   </div>
<div><br></div><div>I&#39;m not sure if this behavior is a bug or a feature,  but in any case it&#39;s unacceptable for dealing with /dev/urandom.   Probably the simplest way to fix this is to write a little C helper function that will read from /dev/urandom for me,  so that I have precise control over the system calls involved.     But I&#39;m curious if GHC can manage this use case correctly;   I&#39;ve just started digging into the <a href="http://GHC.IO">GHC.IO</a> code myself.</div>
<div><br></div><div>Best,</div><div>Leon</div><div><br></div><div><pre style="font-size:13px;margin-bottom:0px;margin-top:0px"><span style="color:rgb(51,51,51)">{-#</span> <span style="color:rgb(79,67,113)">LANGUAGE</span> <span style="color:rgb(79,67,113)">BangPatterns</span><span>,</span> <span style="color:rgb(79,67,113)">ViewPatterns</span> <span>#-</span><span>}</span>

<span style="color:rgb(57,116,96)">import</span>           <span style="color:rgb(79,67,113)">Control</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">Applicative</span>
<span style="color:rgb(57,116,96)">import</span>           <span style="color:rgb(79,67,113)">Data</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">Bits</span>
<span style="color:rgb(57,116,96)">import</span>           <span style="color:rgb(79,67,113)">Data</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">Word</span><span>(</span><span style="color:rgb(79,67,113)">Word64</span><span>)</span>
<span style="color:rgb(57,116,96)">import</span> <span style="color:rgb(57,116,96)">qualified</span> <span style="color:rgb(79,67,113)">Data</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">ByteString</span> <span style="color:rgb(57,116,96)">as</span> <span style="color:rgb(79,67,113)">S</span>
<span style="color:rgb(57,116,96)">import</span> <span style="color:rgb(57,116,96)">qualified</span> <span style="color:rgb(79,67,113)">Data</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">ByteString</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">Lazy</span> <span style="color:rgb(57,116,96)">as</span> <span style="color:rgb(79,67,113)">L</span>
<span style="color:rgb(57,116,96)">import</span>           <span style="color:rgb(79,67,113)">Data</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">ByteString</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">Internal</span> <span>(</span><span style="color:rgb(51,51,51)">c2w</span><span>)</span>
<span style="color:rgb(57,116,96)">import</span> <span style="color:rgb(57,116,96)">qualified</span> <span style="color:rgb(79,67,113)">System</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">IO</span>        <span style="color:rgb(57,116,96)">as</span> <span style="color:rgb(79,67,113)">IO</span>
<span style="color:rgb(57,116,96)">import</span> <span style="color:rgb(57,116,96)">qualified</span> <span style="color:rgb(79,67,113)">Data</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">Binary</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">Get</span>        <span style="color:rgb(57,116,96)">as</span> <span style="color:rgb(79,67,113)">Get</span>

<span>showHex</span> <span>::</span> <span style="color:rgb(79,67,113)">Word64</span> <span>-&gt;</span> <span style="color:rgb(79,67,113)">S</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">ByteString</span>
<span>showHex</span> <span style="color:rgb(51,51,51)">n</span> <span>=</span> <span style="color:rgb(51,51,51)">s</span>
  <span style="color:rgb(57,116,96)">where</span>
    <span>(</span><span style="color:rgb(51,51,51)">!</span><span style="color:rgb(51,51,51)">s</span><span>,</span><span style="color:rgb(57,116,96)">_</span><span>)</span> <span>=</span> <span style="color:rgb(79,67,113)">S</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">unfoldrN</span> <span style="color:rgb(79,67,113)">16</span> <span style="color:rgb(51,51,51)">f</span> <span style="color:rgb(51,51,51)">n</span>

    <span style="color:rgb(51,51,51)">f</span> <span style="color:rgb(51,51,51)">n</span> <span>=</span> <span style="color:rgb(79,67,113)">Just</span> <span>(</span><span style="color:rgb(51,51,51)">char</span> <span>(</span><span style="color:rgb(51,51,51)">n</span> <span style="color:rgb(51,51,51)">`shiftR`</span> <span style="color:rgb(79,67,113)">60</span><span>)</span><span>,</span> <span style="color:rgb(51,51,51)">n</span> <span style="color:rgb(51,51,51)">`shiftL`</span> <span style="color:rgb(79,67,113)">4</span><span>)</span>

    <span style="color:rgb(51,51,51)">char</span> <span>(</span><span style="color:rgb(51,51,51)">fromIntegral</span> <span>-&gt;</span> <span style="color:rgb(51,51,51)">i</span><span>)</span>
      <span>|</span> <span style="color:rgb(51,51,51)">i</span> <span style="color:rgb(51,51,51)">&lt;</span> <span style="color:rgb(79,67,113)">10</span>    <span>=</span> <span>(</span><span style="color:rgb(51,51,51)">c2w</span> <span>&#39;0&#39;</span> <span style="color:rgb(85,85,85)">-</span>  <span style="color:rgb(79,67,113)">0</span><span>)</span> <span style="color:rgb(51,51,51)">+</span> <span style="color:rgb(51,51,51)">i</span>
      <span>|</span> <span style="color:rgb(51,51,51)">otherwise</span> <span>=</span> <span>(</span><span style="color:rgb(51,51,51)">c2w</span> <span>&#39;a&#39;</span> <span style="color:rgb(85,85,85)">-</span> <span style="color:rgb(79,67,113)">10</span><span>)</span> <span style="color:rgb(51,51,51)">+</span> <span style="color:rgb(51,51,51)">i</span>

<span>twoRandomWord64s</span> <span>::</span> <span style="color:rgb(79,67,113)">IO</span> <span>(</span><span style="color:rgb(79,67,113)">Word64</span><span>,</span><span style="color:rgb(79,67,113)">Word64</span><span>)</span>
<span>twoRandomWord64s</span> <span>=</span> <span style="color:rgb(79,67,113)">IO</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">withBinaryFile</span> <span style="color:rgb(54,99,84)">&quot;/dev/urandom&quot;</span> <span style="color:rgb(79,67,113)">IO</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">ReadMode</span> <span style="color:rgb(51,51,51)">$</span> <span>\</span><span style="color:rgb(51,51,51)">handle</span> <span>-&gt;</span> <span style="color:rgb(57,116,96)">do</span>
   <span style="color:rgb(79,67,113)">IO</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">hSetBuffering</span> <span style="color:rgb(51,51,51)">handle</span> <span style="color:rgb(79,67,113)">IO</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(79,67,113)">NoBuffering</span>
   <span style="color:rgb(79,67,113)">Get</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">runGet</span> <span>(</span><span style="color:rgb(79,67,113)">(,)</span> <span style="color:rgb(51,51,51)">&lt;$&gt;</span> <span style="color:rgb(79,67,113)">Get</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">getWord64host</span> <span style="color:rgb(51,51,51)">&lt;*&gt;</span> <span style="color:rgb(79,67,113)">Get</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">getWord64host</span><span>)</span> <span style="color:rgb(51,51,51)">&lt;$&gt;</span> <span style="color:rgb(79,67,113)">L</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">hGet</span> <span style="color:rgb(51,51,51)">handle</span> <span style="color:rgb(79,67,113)">16</span>

<span>main</span> <span>=</span> <span style="color:rgb(57,116,96)">do</span>
   <span>(</span><span style="color:rgb(51,51,51)">x</span><span>,</span><span style="color:rgb(51,51,51)">y</span><span>)</span> <span>&lt;-</span> <span style="color:rgb(51,51,51)">twoRandomWord64s</span>
   <span style="color:rgb(79,67,113)">S</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">hPutStrLn</span> <span style="color:rgb(79,67,113)">IO</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">stdout</span> <span>(</span><span style="color:rgb(79,67,113)">S</span><span style="color:rgb(51,51,51)">.</span><span style="color:rgb(51,51,51)">append</span> <span>(</span><span style="color:rgb(51,51,51)">showHex</span> <span style="color:rgb(51,51,51)">x</span><span>)</span> <span>(</span><span style="color:rgb(51,51,51)">showHex</span> <span style="color:rgb(51,51,51)">y</span><span>)</span><span>)</span>


<span style="color:rgb(85,85,85)">{- Relevant part of strace:

open(&quot;/dev/urandom&quot;, O_RDONLY|O_NOCTTY|O_NONBLOCK) = 3
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 9), ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7ffff367e528) = -1 EINVAL (Invalid argument)
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7ffff367e528) = -1 EINVAL (Invalid argument)
read(3, &quot;N\304\4\367/\26c\&quot;\3218\237f\214yKg~i\310\r\262\&quot;\224H\340y\n\376V?\265\344&quot;..., 8096) = 8096
close(3)                                = 0

-}</span></pre></div>