Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix detection of image formats in system gd #12029

Closed
wants to merge 6 commits into from

Conversation

orlitzky
Copy link
Contributor

We currently get false positives when checking for, say, AVIF support in the system libgd: #12019

I replaced the existing link tests with run tests of a little gd program that seems to do the trick.

ext/gd/config.m4 Show resolved Hide resolved
@petk
Copy link
Member

petk commented Aug 24, 2023

Very good find. Thanks, @orlitzky

Yes, the libgd seems to need some patches from the php-src or some further code adjustments at least. Because with the bundled libgd all of these seem to work ok. I can't think of the better way at the moment so let's go with this. Seems good.

Also, let's add this to PHP-8.1 so we have current maintained branches all fixed.

I'll check for more soon...

@orlitzky
Copy link
Contributor Author

Thanks! Cross-compilation makes it past ./configure now.

I was wondering why upstream libgd might have left those stub functions enabled. It looks intentional, so... maybe it's to avoid changing the API/ABI based on build-time choices?

This PR reveals some more test failures (in addition the remaining few in #11252) when the system gd lacks PNG support.They're easy to fix though and I'll work on it when this is done.

@petk
Copy link
Member

petk commented Aug 27, 2023

There is this constant HAVE_GD_JPG which was inconsistently named in the past. Perhaps something like this instead of renaming all occurrences to HAVE_GD_JPEG out there:

--- a/ext/gd/config.m4
+++ b/ext/gd/config.m4
@@ -140,9 +140,9 @@ AC_DEFUN([PHP_GD_JISX0208],[
 
 
 dnl Build and run a program to determine if GD has support for the given
-dnl format. The sole argument is the proper-noun-capitalized name of the
+dnl format. The first argument is the proper-noun-capitalized name of the
 dnl format -- basically the word Foo in gdImageCreateFromFoo -- such as
-dnl Png. If support for format Foo exists, HAVE_GD_FOO will be defined
+dnl Png. If support for format Foo exists, 2nd argument will be defined
 dnl to 1. The reason for this charade is that gd defines "junk" versions
 dnl of each gdImageCreateFromFoo function even when it does not support
 dnl the Foo format. Those junk functions display a warning but eventually
@@ -171,7 +171,7 @@ int main(int argc, char** argv) {
   return 0;
 } ]])],[
     AC_MSG_RESULT([yes])
-    AC_DEFINE(HAVE_GD_[]m4_toupper($1), 1, [ ])
+    AC_DEFINE([$2], 1, [ ])
   ],[
     AC_MSG_RESULT([no])
   ],[
@@ -182,13 +182,13 @@ int main(int argc, char** argv) {
 ])
 
 AC_DEFUN([PHP_GD_CHECK_VERSION],[
-  PHP_GD_CHECK_FORMAT([Png])
-  PHP_GD_CHECK_FORMAT([Avif])
-  PHP_GD_CHECK_FORMAT([Webp])
-  PHP_GD_CHECK_FORMAT([Jpeg])
-  PHP_GD_CHECK_FORMAT([Xpm])
-  PHP_GD_CHECK_FORMAT([Bmp])
-  PHP_GD_CHECK_FORMAT([Tga])
+  PHP_GD_CHECK_FORMAT([Png],[HAVE_GD_PNG])
+  PHP_GD_CHECK_FORMAT([Avif],[HAVE_GD_AVIF])
+  PHP_GD_CHECK_FORMAT([Webp],[HAVE_GD_WEBP])
+  PHP_GD_CHECK_FORMAT([Jpeg],[HAVE_GD_JPG])
+  PHP_GD_CHECK_FORMAT([Xpm],[HAVE_GD_XPM])
+  PHP_GD_CHECK_FORMAT([Bmp],[HAVE_GD_BMP])
+  PHP_GD_CHECK_FORMAT([Tga],[HAVE_GD_TGA])
   PHP_CHECK_LIBRARY(gd, gdFontCacheShutdown,           [AC_DEFINE(HAVE_GD_FREETYPE,          1, [ ])], [], [ $GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdVersionString,               [AC_DEFINE(HAVE_GD_LIBVERSION,        1, [ ])], [], [ $GD_SHARED_LIBADD ])
   PHP_CHECK_LIBRARY(gd, gdImageGetInterpolationMethod, [AC_DEFINE(HAVE_GD_GET_INTERPOLATION, 1, [ ])], [], [ $GD_SHARED_LIBADD ])

Currently we look for gdImageStringFT() to determine whether or not gd
has freetype support... but that function always exists. This leads
PHP to believe that gd has freetype support when it does not, and can
lead to build failures (GH 12019).

The gdFontCacheShutdown() function, on the other hand, is only present
when gd was built with freetype support. Let's use that instead.
We currently check for, say, AVIF support by attempting to link a
program that calls libgd's gdImageCreateFromAvif() function. But
perversely, that function always exists in libgd; moreover when AVIF
support is missing it emits a warning and returns normally. Thus
our straightforward link test becomes not so straightforward.

This commit adds a new macro PHP_GD_CHECK_FORMAT that compiles, links,
and runs a test program instead. The test program overrides that "emit
a warning" handler so that the program actually fails if the format
we're looking for is not supported. This fixes detection of AVIF and
the other formats we check for in an external libgd.

Closes phpGH-12019
I don't actually know how to remove BMP support from libgd, but PHP
has a ./configure test for it, so we should probably treat it as
optional.
The AC_RUN_IFELSE inside PHP_GD_CHECK_FORMAT was missing its third
argument, namely what to do when the user is cross-compiling. Its
absence is not immediately fatal, but it does cause ./configure to
bail out if the user attempts to cross-compile. We add a pessimistic
default (format not supported) for that case to allow ./configure to
proceed.
The new gd format detection macro accidentally renames HAVE_GD_JPG to
HAVE_GD_JPEG because gd uses "Jpeg" in its function names. But this
would break consumers for no reason. Instead we require the caller to
pass in the name of the constant explicitly, and when checking for
Jpeg support, we pass in HAVE_GD_JPG.

Thanks to Peter Kokot for the suggestion.
We know what these constants indicate, so it doesn't hurt to explain
them via the third argument to AC_DEFINE.
@orlitzky
Copy link
Contributor Author

There is this constant HAVE_GD_JPG which was inconsistently named in the past. Perhaps something like this instead of renaming all occurrences to HAVE_GD_JPEG out there:

Hi, sorry for the delay, I never got the email notification for this comment and it took me a few months to independently wonder what ever happened to this PR.

I've implemented your suggestion. Renaming the constant was unintentional.

@petk
Copy link
Member

petk commented Dec 22, 2023

Looks good to me. I'll recheck it in the following days and move forward with merging this soon...

@petk
Copy link
Member

petk commented Dec 23, 2023

Hello, looks ok now, yes. I'll only add this change into the PR if that's fine with you and merge this in the following day(s) to master branch:

diff --git a/ext/gd/config.m4 b/ext/gd/config.m4
index c427a29f31..c453c0f38d 100644
--- a/ext/gd/config.m4
+++ b/ext/gd/config.m4
@@ -153,7 +153,7 @@ AC_DEFUN([PHP_GD_CHECK_FORMAT],[
   LIBS="${LIBS} ${GD_SHARED_LIBADD}"
   AC_MSG_CHECKING([for working gdImageCreateFrom$1 in libgd])
   AC_LANG_PUSH([C])
-  AC_RUN_IFELSE([AC_LANG_SOURCE([[
+  AC_RUN_IFELSE([AC_LANG_SOURCE([
 #include <stdio.h>
 #include <unistd.h>
 #include <gd.h>
@@ -166,11 +166,13 @@ void exit1(int priority, const char *format, va_list args) {
 /* Override the default gd_error_method with one that
    actually causes the program to return an error. */
 int main(int argc, char** argv) {
-  FILE* f = NULL;
+  m4_if([$1],[Xpm],
+  [char* f = "test.xpm"],
+  [FILE* f = NULL]);
   gdSetErrorMethod(exit1);
   gdImagePtr p = gdImageCreateFrom$1(f);
   return 0;
-} ]])],[
+}])],[
     AC_MSG_RESULT([yes])
     AC_DEFINE($2, 1, [Does gdImageCreateFrom$1 work?])
   ],[

Because the gdImageCreateFromXpm expects char * type, otherwise warning is emitted:

warning: passing argument 1 of ‘gdImageCreateFromXpm’ from incompatible pointer type [-Wincompatible-pointer-types]
   13 |             gdImagePtr p = gdImageCreateFromXpm(f);
      |                                                 ^
      |                                                 |
      |                                                 FILE *

and somehow test waits for the user input with certain build configurations. Other functions are OK.

@orlitzky
Copy link
Contributor Author

Yeah good catch, I didn't notice the different argument type. Thanks again.

@petk petk linked an issue Dec 27, 2023 that may be closed by this pull request
@petk
Copy link
Member

petk commented Dec 27, 2023

Merged to master via 85e5635 Thank you @orlitzky 🎉

@petk petk closed this Dec 27, 2023
@orlitzky
Copy link
Contributor Author

No problem, thanks for your help with this.

@todeveni
Copy link
Contributor

Also, let's add this to PHP-8.1 so we have current maintained branches all fixed.

Will this be backported to maintained branches or is it PHP 8.4 only?

@petk
Copy link
Member

petk commented Feb 25, 2024

I guess we could add it to PHP-8.2. I was a bit worried for the existing builds out there if it might cause issues. 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Image format detection false positives with external GD
3 participants