PHP Bug #79714

  110733
June 26, 2020 11:20 henry.wood.dk@gmail.com (Henrik Skov)
Hi list !

I am still trying to solve bug 79714 (See: 
https://bugs.php.net/bug.php?id=79714)

I am no expert at C and/or the PHP Core at all so I need a little advice 
from you guys.

Seeing lines 3238-3314 in /ext/phar/phar.c (from php-src repo):

static zend_op_array *phar_compile_file(zend_file_handle *file_handle, 
int type) /* {{{ */
{
     zend_op_array *res;
     char *name = NULL;
     int failed;
     phar_archive_data *phar;

     if (!file_handle || !file_handle->filename) {
         return phar_orig_compile_file(file_handle, type);
     }
     if (strstr(file_handle->filename, ".phar") && 
!strstr(file_handle->filename, "://")) {
         if (SUCCESS == 
phar_open_from_filename((char*)file_handle->filename, 
strlen(file_handle->filename), NULL, 0, 0, &phar, NULL)) {
             if (phar->is_zip || phar->is_tar) {
                 zend_file_handle f = *file_handle;

                 /* zip or tar-based phar */
                 spprintf(&name, 4096, "phar://%s/%s", 
file_handle->filename, ".phar/stub.php");
                 if (SUCCESS == phar_orig_zend_open((const char *)name, 
&f)) {

                     efree(name);
                     name = NULL;

                     f.filename = file_handle->filename;
                     if (f.opened_path) {
                         efree(f.opened_path);
                     }
                     f.opened_path = file_handle->opened_path;
                     f.free_filename = file_handle->free_filename;

                     switch (file_handle->type) {
                         case ZEND_HANDLE_STREAM:
                             if (file_handle->handle.stream.closer && 
file_handle->handle.stream.handle) {
file_handle->handle.stream.closer(file_handle->handle.stream.handle);
                             }
                             file_handle->handle.stream.handle = NULL;
                             break;
                         default:
                             break;
                     }
                     *file_handle = f;
                 }
             } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
                 zend_file_handle_dtor(file_handle);
                 /* compressed phar */
                 file_handle->type = ZEND_HANDLE_STREAM;
                 /* we do our own reading directly from the phar, don't 
change the next line */
                 file_handle->handle.stream.handle  = phar;
                 file_handle->handle.stream.reader  = 
phar_zend_stream_reader;
                 file_handle->handle.stream.closer  = NULL;
                 file_handle->handle.stream.fsizer  = 
phar_zend_stream_fsizer;
                 file_handle->handle.stream.isatty  = 0;
                 phar->is_persistent ?
php_stream_rewind(PHAR_G(cached_fp)[phar->phar_pos].fp) :
                     php_stream_rewind(phar->fp);
             }
         }
     }

     zend_try {
         failed = 0;
         CG(zend_lineno) = 0;
         res = phar_orig_compile_file(file_handle, type);
     } zend_catch {
         failed = 1;
         res = NULL;
     } zend_end_try();

     if (name) {
         efree(name);
     }

     if (failed) {
         zend_bailout();
     }

     return res;
}

I *think* that what maybe would fix this bug is if line 3299 (res = 
phar_orig_compile_file(file_handle, type);)
was - if BCGEN extension is loaded - is affected so that 
phar_orig_compile_file was changed to point to another function.

Let's imagine that phar_orig_compile_file pointed to 
bcgen_phar_compile_file() which was then implemented by BCGEN:

ZendAccelerator.h (of BCGEN): (Link: 
https://github.com/vjardin/bcgen/blob/a863b8d596cebb698a491f7475903f5aa3664719/ZendAccelerator.h)

zend_op_array *bcgen_phar_compile_file(zend_file_handle *file_handle, 
int type);


ZendAccelerator.c (of BCGEN): (Link: 
https://github.com/vjardin/bcgen/blob/a863b8d596cebb698a491f7475903f5aa3664719/ZendAccelerator.c)

zend_op_array *bcgen_phar_compile_file(zend_file_handle *file_handle, 
int type) {

     if (!file_handle->filename || !ZCG(enabled) || !accel_startup_ok) {
             /* The Accelerator is disabled, act as if without BCGEN */
         return zend_compile(file_handle, type);
     } else {
         /* Use the zend_compile replacement of BCGEN for this file */
         return persistent_load_file(file_handle, type);
     }
}

Now, for my question:

How can I make sure that phar_orig_compile_file() points to 
bcgen_phar_compile_file() when line 3299 of /ext/phar/phar.c is hit 
*WITHOUT* changing line 3299 if - and only if BCGEN module is present ?

Would a #define do it ?

(something like:
#define phar_orig_compile_file bcgen_phar_compile_file
in ZendAccelerator.h (of BCGEN) (Link: 
https://github.com/vjardin/bcgen/blob/a863b8d596cebb698a491f7475903f5aa3664719/ZendAccelerator.h)

NOTE: /ext/phar/phar.c already has this on line 3230:

zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, 
int type);

which would conflict with my - proposed - define/solution or ?

Please advice !

If it is inappropriate to ask for coding advice on this list, I do 
apologize for this mail !

Thank you in advance !


Best regards,

Henrik Skov
Secuno A/S