php-imagine / Imagine

PHP Object Oriented image manipulation library
https://imagine.readthedocs.io
Other
4.42k stars 530 forks source link

Segmentation fault with GD on 1.3.1 #826

Closed mnocon closed 2 years ago

mnocon commented 2 years ago

Hi!

Issue description

Our CI tests started failing yesterday with errors similar to Failed to load resource: the server responded with a status of 502 (Bad Gateway). The logs look like this:

web_1       | 2022-03-16T10:20:53.320977547Z 172.19.0.4 - - [16/Mar/2022:10:20:53 +0000] "POST /api/ezp/v2/user/sessions HTTP/1.1" 201 584 "-" "Symfony HttpClient/Curl" "-"
web_1       | 2022-03-16T10:20:53.504025837Z 172.19.0.4 - - [16/Mar/2022:10:20:53 +0000] "GET /api/ezp/v2/content/objects/52/versions/1 HTTP/1.1" 200 5112 "-" "Symfony HttpClient/Curl" "-"
web_1       | 2022-03-16T10:20:53.683592022Z 2022/03/16 10:20:53 [error] 9#9: *4 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 172.19.0.4, server: localhost, request: "GET /api/ezp/v2/content/binary/images/52-183-1/variations/medium HTTP/1.1", upstream: "fastcgi://172.19.0.4:9000", host: "web"
app_1       | 2022-03-16T10:20:53.688494227Z [16-Mar-2022 10:20:53] WARNING: [pool www] child 208 exited on signal 11 (SIGSEGV - core dumped) after 79.766833 seconds from start

It started happening right after 1.3.0/1.3.1 has been released and it disappears when a Composer conflict with imagine/imagine:^1.3.0 is added (see: https://github.com/ezsystems/ezplatform-rest/pull/92 for a failing and passing CI build).

What version of Imagine are you using?

1.3.1

What's the PHP version you are using?

7.3

What's the imaging library you are using [gd/imagick/gmagick/any]?

gd

What's the imaging library configuration

root@1021939f0ff2:/var/www# php --ri gd

gd

GD Support => enabled
GD Version => bundled (2.1.0 compatible)
FreeType Support => enabled
FreeType Linkage => with freetype
FreeType Version => 2.6.3
GIF Read Support => enabled
GIF Create Support => enabled
JPEG Support => enabled
libJPEG Version => 6b
PNG Support => enabled
libPNG Version => 1.6.28
WBMP Support => enabled
XPM Support => enabled
libXpm Version => 30411
XBM Support => enabled
JIS-mapped Japanese Font Support => enabled

Directive => Local Value => Master Value
gd.jpeg_ignore_warning => 1 => 1

Minimal PHP code to reproduce the error:

I don't have a reproducer yet, I am still gathering more data about this issue - I was not able to reproduce it locally, even when using the same PHP Docker image that we use on CI. I will try to extract the core dump and analyse what's happening there. I wish I had more data, but given that 1.3.x is a fresh release I think it's important to let you know that the behaviour has changed between the 1.2.x and 1.3.x releases.

I will update this issue as soon as I have more information.

mlocati commented 2 years ago

Without more details it's rather hard to see what's going wrong...

ProRezak commented 2 years ago

Approve, have same issue

AlexSuvorovKirov commented 2 years ago

Confirm a problem

ponytime commented 2 years ago

Without more details have the same issue

AntonOkulov commented 2 years ago

Apache error: End of script output before headers: index.php after this: $this->getImagine()->open($filePath)

ovgray commented 2 years ago

I have the same issue with ver 1.3.1, php ver 7.3, using gd.

Doing local development on Windows with symfony cli server.

Server crashes when it reaches this:
$imagine - new Imagine\Gd\Imagine(); $image = $imagine->open($filePath);

I'm not very skilled at debugging, but the crash seems to occur where \Imagine\Factory\ClassFactoryInterface::createImage() creates a new \Imagine\Gd\Image.

Server does not crash with imagine/imagine ver 1.2.4. Also, the code fragment containing Imagine\Gd\Imagine::open seems to run without error in a phpunit test.

mlocati commented 2 years ago

In order to fix this issue, we need to know what's going wrong. And in order to know what's going wrong, we need:

  1. the image that's causing the problem
  2. the exact version of PHP
  3. the exact version of the imagick PHP module
  4. the exact version of the imagemagick system library

To get the info for points 2., 3., and 4.:

if the problem occurs in a web application

Simply create a sample php file on the server with the following contents:

 <?php phpinfo(INFO_GENERAL); phpinfo(INFO_MODULES);

By visiting the page with the browser:

if the problem occurs in a CLI environment:

ovgray commented 2 years ago

Crash occurs opening any one of several different jpg image files.

php version is 7.3.5 phpinfo has no "imagick" section. $ php -ri imagick PHP Parse error: syntax error, unexpected end of file in Command line code on line 1 ` Parse error: syntax error, unexpected end of file in Command line code on line 1`

php -m confirms it contains no imagick module

hgabka commented 2 years ago

Same problem for me. Imagine open causes segfault. Tried nginx and apache, both have problem. Using PHP 7.3. GD library, no imagick installed.

mlocati commented 2 years ago

Same answer: in order to fix the issue we need to be able to reproduce it

ovgray commented 2 years ago

Same answer: in order to fix the issue we need to be able to reproduce it

@mlocati Are you saying that the information I supplied is insufficient to reproduce the issue? Have you successfully run (new Imagine\Gd\Imagine())->open($filepath) on an image file with a copy of php 7.3 compiled without an imagick module?

mlocati commented 2 years ago

@ovgray the CI tests should already do that

ovgray commented 2 years ago

@mlocati

@ovgray the CI tests should already do that

Have you considered the possibility that your CI tests are using a version of php 7.3 that has an imagick module?

When I look at e.g. https://github.com/php-imagine/Imagine/runs/3935559862?check_suite_focus=true, the two php 7.3 versions are labelled "gd-gimagick (Docker)" and "gd-imagick (Docker)". Does that mean the php versions have gimagick and imagick modules, respectively?

mnocon commented 2 years ago

Hi, I've created a repo that allowed me to reproduce this issue: https://github.com/mnocon/imagine-segfault-reproducer

Please let me know if anything is unclear

You can also see that if you downgrade to imagine 1.2.x then the segmentation fault does not occur.

ausi commented 2 years ago

This seems to be a PHP bug to me. I was able to reduce the reproducer down to a single file that still causes the segmentation fault:

<?php

function y($x, $y, $z)
{
    switch ($a->a()) {
        default:
            $s = '' . $b;
    }
    $c = array($b);

    switch ($a->a()) {
        case A::B:
            $e = 0;
            $f = 0;
            if (!empty($d[''])) {
                $e = 0;
            } else {
                if (!isset($d[''])) {
                    if (isset($d[''])) {
                        $d[''] = $d[''];
                    }
                }
                if (isset($d[''])) {
                    $e = a(0, a(0, $d['']));
                }
            }
        case A::B:
            if (!isset($d[''])) {
                if (isset($d[''])) {
                    $d[''] = round((0 - $d['']) * 0 * 0);
                }
            }
            if (isset($d[''])) {
                if ($d[''] < 0 || $d[''] > 0) {
                    new Z('');
                }
            }
            if (!isset($d[''])) {
                if (isset($d[''])) {
                    $d[''] = $d[''];
                }
            }
            if (isset($d[''])) {
                $g[] = $d[''];
            }
            break;
        case A::B:
            if (isset($d[''])) {
                $g[] = $d[''];
            }
            break;
        case A::B:
            if (!isset($d[''])) {
                if (isset($d[''])) {
                    $d[''] = $d[''];
                }
            }
            if (isset($d[''])) {
                if ($d[''] < 0) {
                    new Z('');
                }
                $g[] = $d[''];
            }
            break;
    }
}

echo "Success!";

The source of this weird looking function is here: https://github.com/php-imagine/Imagine/blob/303cf356f2393916e6e494d0ecfff60546dd0ab0/src/Gd/Image.php#L638-L735

PHP Version of the reproducer from @mnocon :

PHP 7.3.29 (cli) (built: Aug 17 2021 14:00:32) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.29, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.29, Copyright (c) 1999-2018, by Zend Technologies
    with blackfire v1.74.1~linux-x64-non_zts73, https://blackfire.io, by Blackfire
mnocon commented 2 years ago

Thanks for investigating!

What would be the options here? Two things come to my mind: 1) Refactor this function to work around the PHP bug IF the 1.3.x series should support PHP 7.3 and if it's even possible 2) Bump the minimum required version to PHP 7.4 for the 1.3.x series (including the already released 1.3.0 and 1.3.1 tags IMHO)

What do you think?

mlocati commented 2 years ago

It seems an opcache bug in particular: by disabling it we don't have the segfault anymore

mlocati commented 2 years ago

I guess we'd need some help from @cmb69 here...

cmb69 commented 2 years ago

Hmm, if there is an OPcache bug in PHP 7.3, it won't be resolved anyway. Does this issue also happen with PHP 8.0?

mnocon commented 2 years ago

It does not happen on PHP 8.0 and 8.1 (on the images that I use):

PHP 8.0.16 (cli) (built: Feb 18 2022 21:20:58) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.16, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.16, Copyright (c), by Zend Technologies
    with blackfire v1.74.1~linux-x64-non_zts80, https://blackfire.io, by Blackfire
PHP 8.1.3 (cli) (built: Feb 18 2022 19:37:16) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.3, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.3, Copyright (c), by Zend Technologies
    with blackfire v1.74.1~linux-x64-non_zts81, https://blackfire.io, by Blackfire

I've added them to the reproducer, just in case

ausi commented 2 years ago

What would be the options here?

PHP 7.3 reached its end of life so you need to get your distro to patch this in their PHP 7.3 package I think. There is also to note that not all 7.3 builds seem to affected by this (see https://3v4l.org/AYCSU for example).

Refactoring this function to avoid the error should be possible, as many changes in this method I tested stopped the segmentation fault from appearing. I’m not sure if it is the responsibility of the Imagine project, @mlocati has to decide this I think. If desired, I can provide a pull request that does such a “workaround”. already happend in the meantime in #828

mlocati commented 2 years ago

828 seems to work just fine

mlocati commented 2 years ago

If someone else can confirm that #828 works, I'll merge it and publish a new release

cmb69 commented 2 years ago

There is also to note that not all 7.3 builds seem to affected by this (see https://3v4l.org/AYCSU for example).

Note, though, that 3v4l.org runs with OPcache disabled.