php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #22362 Certain combinations of fseek() and fwrite() produce unexpected results
Submitted: 2003-02-21 13:58 UTC Modified: 2003-02-22 12:55 UTC
Votes:3
Avg. Score:5.0 ± 0.0
Reproduced:3 of 3 (100.0%)
Same Version:2 (66.7%)
Same OS:1 (33.3%)
From: php at codewhore dot org Assigned: wez (profile)
Status: Closed Package: Filesystem function related
PHP Version: 4.3.1 OS: Linux 2.4
Private report: No CVE-ID: None
 [2003-02-21 13:58 UTC] php at codewhore dot org
In PHP:

<?php
  $fp = fopen('./foo', 'w+');
  fwrite($fp, 'quxbar', 6);
  fseek($fp, 3, SEEK_SET);
  fread($fp, 1);
  fseek($fp, 4, SEEK_SET);
  fwrite($fp, '!', 1);
  fseek($fp, 0, SEEK_SET);
  $buf = fread($fp, 4095);
  echo "$buf\n";
?>

In C:

#include <stdio.h>

int main()
{
  static char buf[4096];
  FILE *f = fopen("./foo", "w+");
  fwrite("quxbar", 6, 1, f);
  fseek(f, 3, SEEK_SET);
  fread(&buf, 1, 1, f);
  fseek(f, 4, SEEK_SET);
  fwrite("!", 1, 1, f);
  fseek(f, 0, SEEK_SET);
  fread(&buf, 4095, 1, f);
  printf("%s\n", buf);
  return 0;
}

The PHP version outputs 'quxbar!.
The C version outputs 'quxb!r'.

In fact, for any PHP code of the structure:
<?php
  fseek($fp, $x, SEEK_SET);
  fread($fp, $n);
  fseek($fp, $y, SEEK_SET);
  fwrite($fp, '!', 1);
?>

the data from the fwrite always gets written to the end of the stream when $x < $y and $n is exactly 1. I can reproduce this with different whence parameters, but it seems to only happen with a seek followed by a single-byte read.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-02-21 14:43 UTC] php at codewhore dot org
I've verified that this behavior still exists in today's snapshot (php4-STABLE-200302212030.tar.gz).
 [2003-02-21 17:02 UTC] php at codewhore dot org
I'm still mostly lost, but commenting out the following segment of code fixes the problem for the test case. Obviously this isn't the solution, but I think I have it narrowed down to _php_stream_seek thinking that the underlying file position matches the seek offset when it doesn't in reality.

PHPAPI int _php_stream_seek(php_stream *stream, off_t offset, int whence TSRMLS_DC)
{
    /* not moving anywhere */
#if 0
    if ((offset == 0 && whence == SEEK_CUR) || (offset == stream->position && whence == SEEK_SET))
        return 0;
#endif
 [2003-02-21 17:44 UTC] php at codewhore dot org
FWIW, the problem also occurs in the following piece of code:

<?php
  $fp = fopen('./foo', 'w+');
  fwrite($fp, 'quxbar', 6);
  fseek($fp, 3, SEEK_SET);
  fread($fp, 1);
  fwrite($fp, '!', 1);
  fseek($fp, 0, SEEK_SET);
  $buf = fread($fp, 4095);
  echo "$buf\n";
?>

There's no fseek() between the fread() and fwrite(), so my previous theory seems to be quite wrong. I'll do more digging as time permits...
 [2003-02-21 18:40 UTC] wez@php.net
Save yourself some energy :)

I'm going to look into this this weekend; I know precisely
how to fix this, and it most likely not something you
would have time to think of by the time I've sorted it
out :)

I will update this report when it is fixed and you will be able to try the fix using a stable snapshot.

Thanks for your efforts so far!
 [2003-02-21 19:38 UTC] php at codewhore dot org
Thanks. Glad I could be of (some) help. :)
 [2003-02-21 20:46 UTC] wez@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php4-STABLE-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php4-win32-STABLE-latest.zip

Try the next stable snapshot.
 [2003-02-22 12:55 UTC] php at codewhore dot org
I just pulled from the PHP_4_3 branch of CVS, and the problem is indeed fixed.

Thanks again. :)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Apr 24 18:01:28 2024 UTC