Bug #78066 [Com]: PHP eats the first byte of a program that comes from process substitution
| From: | xatenev@php.net | Date: | Sat, 25 May 2019 20:23:26 +0000 |
| Subject: | Bug #78066 [Com]: PHP eats the first byte of a program that comes from process substitution | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-220991@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78066&edit=1
ID: 78066
Comment by: xatenev@php.net
Reported by: octalbugsphp at alvarezp dot org
Summary: PHP eats the first byte of a program that comes from
process substitution
Status: Open
Type: Bug
Package: *General Issues
Operating System: Linux
PHP Version: 7.3.5
Block user comment: N
Private report: N
New Comment:
As pipes are simply not seekable a possible fix could be implemented by checking errno for ESPIPE as
described here http://man7.org/linux/man-pages/man3/errno.3.html
and either let it fail or do some /tmp redirect magic.
Previous Comments:
------------------------------------------------------------------------
[2019-05-25 20:07:32] xatenev@php.net
... Call the above snippet as specified in the bug report:
gcc test.c
./a.out <(echo '<?php print("hello"); ?>')
-----------------------------
Output:
?php print("hello"); ?>
------------------------------------------------------------------------
[2019-05-25 20:03:45] xatenev@php.net
Hi,
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);
rewind(fp);
char ch;
while(1) {
ch = fgetc(fp);
if(feof(fp)) {
break;
}
printf("%c", ch);
}
return 0;
}
-------------------------------------
rewind() fills errno with the value 29 which means
Illegal seek.
The lines
char a = fgetc(fp);
rewind(fp);
mimic what php-src is doing here on line 606 and 620:
https://github.com/php/php-src/blob/e6f86fb17cd3a2dfe94ca1a0113a23194cb1915a/sapi/cli/php_cli.c#L606-L620
It calls fgetc() to find out if shebang exists on the file pointer but rewind() doesn't work
correctly.
------------------------------------------------------------------------
[2019-05-25 16:53:55] 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 16:52:01] octalbugsphp at alvarezp dot org
Description:
------------
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"); ?>')
hello
[ 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.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78066&edit=1