php-vips-ext icon indicating copy to clipboard operation
php-vips-ext copied to clipboard

Segfaut in test suite

Open remicollet opened this issue 4 years ago • 9 comments

Probably since recent changes in libvips

Using PHP 7.4, 8.0 with libvips 8.11.3

TEST 12/33 [tests/012.phpt]
========DIFF========
002+ Termsig=11
========DONE========
FAIL new_from_buffer works [tests/012.phpt] 

TEST 33/33 [tests/042.phpt]
========DIFF========
004+ 
005+ Termsig=11
========DONE========
FAIL can set metadata [tests/042.phpt] 
========================================

remicollet avatar Sep 05 '21 06:09 remicollet

(gdb) bt
#0  0x00007ffff7fa0ec0 in  ()
#1  0x00007ffff04327de in vips_area_free () at /lib64/libvips.so.42
#2  0x00007ffff0439226 in vips_area_unref () at /lib64/libvips.so.42
#3  0x00007ffff7571ed8 in g_value_unset () at /lib64/libgobject-2.0.so.0
#4  0x00007ffff0448584 in meta_free () at /lib64/libvips.so.42
#5  0x00007ffff7444442 in g_hash_table_remove_all_nodes.part () at /lib64/libglib-2.0.so.0
#6  0x00007ffff74450a3 in g_hash_table_remove_all () at /lib64/libglib-2.0.so.0
#7  0x00007ffff7448822 in g_hash_table_destroy () at /lib64/libglib-2.0.so.0
#8  0x00007ffff0448ad9 in vips.meta_destroy () at /lib64/libvips.so.42
#9  0x00007ffff0441900 in vips_image_finalize () at /lib64/libvips.so.42
#10 0x00007ffff7558a70 in g_object_unref () at /lib64/libgobject-2.0.so.0
#11 0x00007ffff043aaf8 in vips.object_set_member () at /lib64/libvips.so.42
#12 0x00007ffff043adb0 in vips_object_set_property () at /lib64/libvips.so.42
#13 0x00007ffff755a5b6 in object_set_property () at /lib64/libgobject-2.0.so.0
#14 0x00007ffff755c789 in g_object_set_valist () at /lib64/libgobject-2.0.so.0
#15 0x00007ffff755ca44 in g_object_set () at /lib64/libgobject-2.0.so.0
#16 0x00007ffff0431b85 in vips_object_dispose_argument () at /lib64/libvips.so.42
#17 0x00007ffff04350a3 in vips_argument_map () at /lib64/libvips.so.42
#18 0x00007ffff043512b in vips_object_dispose () at /lib64/libvips.so.42
#19 0x00007ffff75589e8 in g_object_unref () at /lib64/libgobject-2.0.so.0
#20 0x00007ffff044017f in vips_cache_remove () at /lib64/libvips.so.42
#21 0x00007ffff044627d in vips_cache_drop_all () at /lib64/libvips.so.42
#22 0x00007ffff046091a in vips_shutdown () at /lib64/libvips.so.42
#23 0x00007ffff7692247 in __run_exit_handlers () at /lib64/libc.so.6
#24 0x00007ffff76923f0 in on_exit () at /lib64/libc.so.6
#25 0x000055555563c261 in main (argc=68, argv=0x555555e21230) at /usr/src/debug/php-7.4.23-1.fc33.remi.x86_64/sapi/cli/php_cli.c:1398

remicollet avatar Sep 05 '21 06:09 remicollet

I was able to reproduce this. It only seems to happen when one or more loadable modules are installed. See for example:

$ sudo dnf --setopt=install_weak_deps=False install vips-devel
$ make test > test.log 2>&1 && echo "Succeed" || echo "Failed"
Succeed
$ sudo dnf install vips-jxl vips-magick-im6 vips-openslide vips-poppler
$ make test > test.log 2>&1 && echo "Succeed" || echo "Failed"
Failed
$ grep "FAILED TEST SUMMARY" -B1 -A4 test.log
=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
new_from_buffer works [tests/012.phpt]
can set metadata [tests/042.phpt]
=====================================================================

(Tested on Fedora 34)

Perhaps the loadable module is somehow unloaded prior to vips_shutdown? Though, the g_module_make_resident call should ensure that it never gets unloaded. https://github.com/libvips/libvips/blob/4d079f169103f45c7d866d49a54598be0278e7d6/libvips/module/jxl.c#L75-L77

Let me investigate this further.

kleisauke avatar Sep 05 '21 09:09 kleisauke

It seems that the test suite passes when the ZEND_DONT_UNLOAD_MODULES=1 environment variable is set.

$ ZEND_DONT_UNLOAD_MODULES=1 make test

So, the PHP vips extension (vips.so) will probably need to link with -Wl,-z,nodelete. I also had a go with this patch for libvips:

z-nodelete.patch
diff --git a/configure.ac b/configure.ac
index 1111111..2222222 100644
--- a/configure.ac
+++ b/configure.ac
@@ -466,6 +466,20 @@ else
   fi
 fi
 
+SAVE_LDFLAGS="$LDFLAGS"
+LDFLAGS="$LDFLAGS -Wl,-z,nodelete"
+AC_MSG_CHECKING([whether linker understands -z nodelete])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
+  [
+    AC_MSG_RESULT([yes])
+    LDFLAGS_Z_NODELETE="-Wl,-z,nodelete"
+  ],[
+    AC_MSG_RESULT([no])
+    LDFLAGS_Z_NODELETE=""
+  ])
+LDFLAGS="$SAVE_LDFLAGS"
+AC_SUBST(LDFLAGS_Z_NODELETE)
+
 # check for gtk-doc
 GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
 
diff --git a/libvips/Makefile.am b/libvips/Makefile.am
index 1111111..2222222 100644
--- a/libvips/Makefile.am
+++ b/libvips/Makefile.am
@@ -58,6 +58,7 @@ libvips_la_LIBADD = \
 	@VIPS_LIBS@
 
 libvips_la_LDFLAGS = \
+	$(LDFLAGS_Z_NODELETE) \
 	-no-undefined \
 	-version-info @LIBRARY_CURRENT@:@LIBRARY_REVISION@:@LIBRARY_AGE@ 
 
@@ -107,6 +108,7 @@ MODULE_CPPFLAGS = \
 	$(REQUIRED_CFLAGS)
 
 MODULE_LDFLAGS = \
+	$(LDFLAGS_Z_NODELETE) \
 	-no-undefined \
 	-shared \
 	-module \

But that resulted in the same segfault.

kleisauke avatar Sep 05 '21 11:09 kleisauke

Linking the extension with -Wl,-z,nodelete could possibly also result that this code is no longer necessary: https://github.com/libvips/php-vips-ext/blob/310b02998f6de42549a77e6a2097e343f1da104c/vips.c#L2010-L2043 (untested)

kleisauke avatar Sep 05 '21 11:09 kleisauke

Above hack is only for mod_php, and the segfault occurs with cli sapi

Also notice that it may not work, as in various distribution, PHP use RTLD_NOW (build using --enable-rtld-now for security / safety reasons)

remicollet avatar Sep 06 '21 06:09 remicollet

I confirm, building the ext with -Wl,-z,nodelete avoid the segfault

remicollet avatar Sep 06 '21 07:09 remicollet

Great, thanks for confirming. Commit https://github.com/kleisauke/php-vips-ext/commit/f08dc82d066b600cff73720cd040e5d7d50c36eb should ensure that the extension is always linked with -Wl,-z,nodelete. I'll open a PR for that soon.

In that commit, I've also removed the hack mentioned above, as I think it's no longer needed. However, I couldn't reproduce issue https://github.com/libvips/php-vips/issues/26 with version 1.0.2 of the extension, so I'm not sure if it's completely safe to remove that (maybe it was only needed for older Apache versions?).

kleisauke avatar Sep 06 '21 09:09 kleisauke

BTW, does test 029.phpt still need to be investigated? I noticed that it is excluded in the spec file, see: https://git.remirepo.net/cgit/rpms/php/pecl/php-pecl-vips.git/tree/php-pecl-vips.spec?id=e9d2156a981132b47f4f01c852182e54e058831f#n180

Perhaps the vips_error_buffer contained more errors than expected. If so, we may need to apply the following patch:

diff --git a/tests/029.phpt b/tests/029.phpt
index 1111111..2222222 100644
--- a/tests/029.phpt
+++ b/tests/029.phpt
@@ -14,7 +14,7 @@ can get error messages
   $msg = vips_error_buffer();
 
   if ($err == -1 &&
-    $msg == "add: not one band or 3 bands\n") {
+    strpos($msg, "add: not one band or 3 bands\n") !== false) {
     echo "pass";
   }
 ?>

kleisauke avatar Sep 06 '21 10:09 kleisauke

A (draft-)pull request has been made for this at #44.

kleisauke avatar Sep 06 '21 12:09 kleisauke