|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78066 PHP eats the first byte of a program that comes from process substitution
Submitted: 2019-05-25 16:52 UTC Modified: 2019-07-15 14:30 UTC
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: octalbugsphp at alvarezp dot org Assigned: nikic (profile)
Status: Closed Package: *General Issues
PHP Version: 7.3.5 OS: Linux
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Bug Type:
From: octalbugsphp at alvarezp dot org
New email:
PHP Version: OS:


 [2019-05-25 16:52 UTC] octalbugsphp at alvarezp dot org
PHP eats the first byte of a program that comes from process substitution

After discussion in ##php at Freenode this was found (see the third line, lseek)

$ strace php -f <(echo -- '<?php print("hello\n"); ?>') 2>&1 | grep -A 5 'openat.*/dev/fd/63'
openat(AT_FDCWD, "/dev/fd/63", O_RDONLY) = 3
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
read(3, "-- <?php print(\"hello\\n\"); ?>\n", 4096) = 30
lseek(3, 0, SEEK_SET)                   = -1 ESPIPE (Illegal seek)
lstat("/dev/fd/63", {st_mode=S_IFLNK|0500, st_size=64, ...}) = 0
readlink("/dev/fd/63", "pipe:[6195898]", 4096) = 14

Test script:
[  0][Sat May 25 11:05:07 -0500 -- alvarezp@alvarezp-samsung:~]
$ php -f <(echo '<?php print("hello\n"); ?>')
?php print("hello\n"); ?>

[  0][Sat May 25 11:05:11 -0500 -- alvarezp@alvarezp-samsung:~]
$ php -f <(echo ' <?php print("hello\n"); ?>')

[  0][Sat May 25 11:05:19 -0500 -- alvarezp@alvarezp-samsung:~]
$ php -f <(echo -- '<?php print("hello\n"); ?>')
- hello

Expected result:
The script should run as expected. The first byte should prevail as part of the script.

Actual result:
The first byte is eaten and not interpreted at all.


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2019-05-25 16:53 UTC] simon at ikanobori dot jp
Being part of that discussion, it is important to note that process substitution returns the path to an anonymous pipe which stops existing after the process finishes.
 [2019-05-25 20:03 UTC]

I was able to reproduce the problem with a small test C snippet that mimics what php-src is doing:


#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
    FILE *fp;

    fp = fopen(argv[1], "rb");
    char a = fgetc(fp);
    char ch;
    while(1) {
        ch = fgetc(fp);
        if(feof(fp)) {
        printf("%c", ch);

    return 0;


`rewind()` fills `errno` with the value `29` which means `Illegal seek`.

The lines

char a = fgetc(fp);

mimic what php-src is doing here on line 606 and 620:

It calls fgetc() to find out if shebang exists on the file pointer but rewind() doesn't work correctly.
 [2019-05-25 20:07 UTC]
... Call the above snippet as specified in the bug report:

gcc test.c

./a.out <(echo '<?php print("hello"); ?>')



?php print("hello"); ?>
 [2019-05-25 20:23 UTC]
As pipes are simply not seekable a possible fix could be implemented by checking errno for ESPIPE as described here and either let it fail or do some /tmp redirect magic.
 [2019-05-25 20:31 UTC]
We should probably move handling of shebang lines into the lexer.
 [2019-05-25 20:40 UTC] octalbugsphp at alvarezp dot org
It should break all instances where the script file is a fifo.

Blame shows commit 71ea95354b [1]:

    MFH: Corrected fix for bug #46844 to only trigger on the 1st line of CLI

    opened files.

Which in turn references bug #46844:

    First line of included files not output if they begin with #


 [2019-07-15 14:30 UTC]
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Fri Jun 18 19:01:23 2021 UTC