God Money, I’ll do anything for you

The loop

1
2
3
4
5
<?php
while ($read < $n && (false !== ($buf = fread($this->sock, $n - $read)))) {
    /* ... */
}
?>

contains a subtle bug. Go ahead, read the relevant function documentation and see if you can spot it.

PHP’s fread function directly maps the C library’s fread function. As TBlue explains, the C fread function returns 0 when reading at the end of a stream. PHP does the simplest possible thing with this and returns an empty string; to determine that the stream is at end of file, programs must check with feof as well.

Most modern languages realize that explicitly checking for errors is a fairly error-prone convention. Java’s InputStream.read(byte[]) methods return -1 on EOF (and only on EOF) and raise exceptions on errors. Python’s File-like objects convention supports mechanisms other than raw byte reads (primarily, iteration) that make stopping at end of file implicit, on top of only returning an empty string at end of input (as with Java, Python raises exceptions when a stream read fails). Not PHP, though! In PHP, the loop above has to look like

1
2
3
4
5
6
<?php
while ($read < $n && !feof($this->sock) && (false !== ($buf = fread($this->sock, $n - 
$read)))) {
    /* ... */
}
?>

Encountered in the wild: php-amqplib bug #12.

One Response to “God Money, I’ll do anything for you”

  1. Taavi Burns says:

    This is kind of like how str_split() behaves:

    <?php
    var_dump(str_split('ab')); // array('a','b')
    var_dump(str_split('a'));  // array('a')
    var_dump(str_split(''));   // array('') ?? WTF ??

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped=""> (Syntax highlighting)