Project

Profile

Help

Bug #6197

closed

PHP - SIGSEGV in zend_mm_alloc_small or in Java_java_lang_ProcessEnvironment_environ

Added by Thibault Liardon 7 months ago. Updated 3 months ago.

Status:
Closed
Priority:
Normal
Category:
PHP Extension function
Start date:
2023-09-15
Due date:
% Done:

100%

Estimated time:
Found in version:
12.3
Fixed in version:
12.4.2
Platforms:

Description

Hi there,

I am trying to use Saxon to run XSLT transformations from PHP. I am encountering systematic crashes when using the PHP extension with code that exercises PHP's autoloading features or is more than a trivial example script (Composer, Symfony, PHPUnit, or a simple autoloader).

What I did:

  1. Use PHP 8.2.10 on Fedora 38 x86-64 and Saxon 12.3 PHP extension.
  2. I built the PHP extension myself, you can find the RPM package to install it and the spec file used there: http://tinyurl.com/5n8v9jyz (my goal is to package it so that other people and myself can install it easily). And here is the repository: https://gitlab.com/saxon-packaging/saxon-package/-/tree/php/saxonphp?ref_type=heads
  3. I wrote a simple test script that loads Composer and creates a new instance of Saxon and another class from a library:
<?php

require_once __DIR__ . '/vendor/autoload.php';

$processor = new \Saxon\SaxonProcessor();
$input = file_get_contents(__DIR__.'/input.xml');
$xdmDoc = $processor->parseXmlFromString($input);
$processor = $processor->newXslt30Processor();

$compiled = $processor->compileFromString(
   file_get_contents(__DIR__.'/template.xslt')
);
$args = [];
$result = $compiled->transformToString($xdmDoc);

echo $result;

echo "\n";
$r = new Symfony\Component\HttpFoundation\Response();
echo var_dump($r);

What I found: Because of the reassignment between $processor on line 8, I get a SIGSEGV.

I then opened an issue on PHP's issue tracker: https://github.com/php/php-src/issues/12124

With their helpfull suggestions, I narrowed the set of conditions that trigger the SIGSEGV:

Reassignment Composer Simple autoloader Symfony Result
X X KO
X X KO
X X X KO
X OK
X X KO
X OK
X OK

Here is the GDB backtrace:

(gdb) bt
#0  zend_mm_alloc_small (bin_num=5, heap=0x7ffff7200040) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_alloc.c:1313
#1  zend_mm_alloc_heap (size=<optimized out>, heap=0x7ffff7200040) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_alloc.c:1384
#2  _emalloc (size=<optimized out>) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_alloc.c:2601
#3  0x00005555557d057a in zend_string_alloc (persistent=false, len=20) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_string.h:152
#4  zend_string_init (persistent=false, len=20, 
    str=0x7ffff73413ce "HTTP_PARTIAL_CONTENT = 206;\n    public const HTTP_MULTI_STATUS = 207;          // RFC4918\n    public const HTTP_ALREADY_REPORTED = 208;      // RFC5842\n    public const HTTP_IM_USED = 226;", ' ' <repeats 12 times>...) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_string.h:174
#5  lex_scan (zendlval=zendlval@entry=0x7fffffff9160, elem=0x7fffffff91f8) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:9818
#6  0x00005555557e72a0 in zendlex (elem=elem@entry=0x7fffffff91f8) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_compile.c:1802
#7  0x00005555557c7883 in zendparse () at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_parser.c:4758
#8  0x00005555557ca656 in zend_compile (type=type@entry=2) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:601
#9  0x00005555557cbdff in compile_file (file_handle=0x7fffffff9e80, type=2) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:655
#10 0x00007fffe32b9256 in phar_compile_file (file_handle=0x7fffffff9e80, type=2) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/ext/phar/phar.c:3355
#11 0x00005555557cbec1 in compile_filename (type=type@entry=2, filename=filename@entry=0x7ffff7255150) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:706
#12 0x0000555555841f8f in zend_include_or_eval (inc_filename_zv=<optimized out>, type=2) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute.c:4799
#13 0x0000555555850f6f in ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER () at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:38960
#14 0x0000555555879886 in execute_ex (ex=0x193600) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:59407
--Type <RET> for more, q to quit, c to continue without paging--
#15 0x00005555557fdbf8 in zend_call_function (fci=fci@entry=0x7fffffffa1c0, fci_cache=<optimized out>, fci_cache@entry=0x7fffffffa1a0) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:949
#16 0x00005555557fdf87 in zend_call_known_function (fn=0x7ffff7204cd8, object=<optimized out>, called_scope=<optimized out>, retval_ptr=retval_ptr@entry=0x0, param_count=param_count@entry=1, params=params@entry=0x7fffffffa250, 
    named_params=0x0) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:1043
#17 0x00005555556fba15 in spl_perform_autoload (class_name=0x7ffff727b0f0, lc_name=0x7ffff727b190) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/ext/spl/php_spl.c:445
#18 0x00005555557fcd77 in zend_lookup_class_ex (name=name@entry=0x7ffff727b0f0, key=0x7ffff727b190, flags=flags@entry=512) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:1209
#19 0x00005555557fe3ea in zend_fetch_class_by_name (class_name=0x7ffff727b0f0, key=<optimized out>, fetch_type=fetch_type@entry=512) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:1705
#20 0x000055555584dbb7 in ZEND_NEW_SPEC_CONST_UNUSED_HANDLER () at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:10277
#21 0x0000555555878190 in execute_ex (ex=0x193600) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:56949
#22 0x0000555555881e11 in zend_execute (op_array=0x7ffff7290000, return_value=<optimized out>) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:60408
#23 0x000055555580cdeb in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=3) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend.c:1833
#24 0x00005555557a3bda in php_execute_script (primary_file=primary_file@entry=0x7fffffffc940) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/main/main.c:2542
#25 0x00005555558f9e7b in do_cli (argc=2, argv=0x555555e10900) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/sapi/cli/php_cli.c:964
#26 0x00005555556413a9 in main (argc=2, argv=0x555555e10900) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/sapi/cli/php_cli.c:1333

Here the zbactrace:

(gdb) zbacktrace
[0x7ffff72132c0] Composer\Autoload\includeFile("/home/u1/code/test2/vendor/composer/../symfony/http-foundation/Response.php") /home/u1/code/test2/vendor/composer/ClassLoader.php:571 
[0x7ffff7213220] Composer\Autoload\ClassLoader->loadClass("Symfony\Component\HttpFoundation\Response") /home/u1/code/test2/vendor/composer/ClassLoader.php:428 
[0x7ffff7213020] (main) /home/u1/code/test2/simple_test_ko.php:17 

Finally, I built PHP from source with debug enabled, as well as Saxon PHP extension:

PHP 8.2.10 (cli) (built: Sep  6 2023 12:02:56) (NTS DEBUG)
Copyright (c) The PHP Group
Zend Engine v4.2.10, Copyright (c) Zend Technologies

But this time, even the case without reassignment and without composer with the simple autoloader did not work:


// Registers a new loader.
spl_autoload_register(function ($class_name) {
    echo sprintf(">> Autoloading '%s' <<", $class_name);
    require_once __DIR__ . '/SimpleClass.php';
});

$processor = new \Saxon\SaxonProcessor();
$input = file_get_contents(__DIR__.'/input.xml');
$xdmDoc = $processor->parseXmlFromString($input);
$processor3 = $processor->newXslt30Processor();

$compiled = $processor3->compileFromString(
    file_get_contents(__DIR__.'/template.xslt')
);
$args = [];
$result = $compiled->transformToString($xdmDoc);

echo $result;

echo "\n";
$o = new Dummy\Ns1\SimpleClass('Hello');
echo "\n";
$o->write();
echo "\n";
echo var_dump($o);
New Thread 0x7fffe4fff6c0 (LWP 254722)]

Thread 1 "php" received signal SIGSEGV, Segmentation fault.
0x00007fffe851eac7 in Java_java_lang_ProcessEnvironment_environ () from /lib64/libsaxon-hec-12.3.so
(gdb) bt
#0  0x00007fffe851eac7 in Java_java_lang_ProcessEnvironment_environ () from /lib64/libsaxon-hec-12.3.so
#1  0x00007fffe717d8da in ?? () from /lib64/libsaxon-hec-12.3.so
#2  0x3030303030303030 in ?? ()
#3  0x3038203130203130 in ?? ()
#4  0x00007fffe717d8c7 in ?? () from /lib64/libsaxon-hec-12.3.so
#5  0x00007fffffffac50 in ?? ()
#6  0x0000000000000000 in ?? ()
(gdb) source ./.gdbinit 
(gdb) zbacktrace
[0x7ffff7616250] Saxon\SaxonProcessor->__construct() [internal function]
[0x7ffff7616020] (main) /home/tli/perso/test2/simple_test_ko2.php:9 
(gdb) 

My opinion and that of the people that commented on the issue on GitHub so far is that we can exclude a problem in PHP's core.

Does anyone here encountered something similar when using Saxon with PHP ?


Files

0_fix_php8_XsltExecutable.patch (793 Bytes) 0_fix_php8_XsltExecutable.patch Thibault Liardon, 2023-12-02 20:55
Actions #1

Updated by Martin Honnen 7 months ago

Do you get SaxonC to run at all in that debug enabled PHP build you did? It is not quite clear whether the code not using Saxon (i.e. the autoloader and your SimpleClass) are part of the cause of the crash.

I run the other sample with a normal PHP 8.1 under Ubuntu 22.01 and checked that the reuse of the $processor variable for two different SaxonC objects indeed makes the code crash although there it looks as if SaxonC runs through and outputs its result, the crash happens later.

Anyway, you will have to wait for Saxonica's O'Neil to investigate that problem with the PHP extension.

Actions #2

Updated by O'Neil Delpratt 7 months ago

  • Category set to PHP Extension function
  • Assignee set to O'Neil Delpratt
  • Priority changed from Low to Normal

Hi,

I managed to reproduce the segmentation fault running with Symfony on my linux box. It is indeed a SaxonC bug.

The reassigning of the created SaxonProcessor object is causing a GC action on the SaxonProcessor, which the extension tries to delete later. Hence the seg error.

The following code also causes the segmentation error:

$xslt30processor = (new \Saxon\SaxonProcessor())->newXslt30Processor();

I am investigating a resolution to this problem. The workaround is to not reassign the processor variable.

Actions #3

Updated by Thibault Liardon 7 months ago

O'Neil Delpratt wrote in #note-2:

[...] I managed to reproduce the segmentation fault running with Symfony on my linux box. It is indeed a SaxonC bug. [...] I am investigating a resolution to this problem. The workaround is to not reassign the processor variable.

Hi,

From what I understand from your comment, you were able to run Saxon + Symfony + no reassignment without any error while creating new classes after?

If so, I will have to try again, because I wasn't able to produce and return a Symfony Response object while running Saxon with the following code:

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class TestController extends AbstractController
{

    // This is a non-working route, triggered by the use of SaxonProcessor
    // and the creation of a Response.
    // This works too with PHPUnit.
    #[Route('/test', name: 'app_test')]
    public function index(): Response
    {
        $processor = new \Saxon\SaxonProcessor();
        $input = file_get_contents(__DIR__.'/../../input.xml');
        $xdmDoc = $processor->parseXmlFromString($input);
        $processor3 = $processor->newXslt30Processor();
        $compiled = $processor3->compileFromString(
            file_get_contents(__DIR__.'/../../template.xslt')
        );
        $args = [];
        $result = $compiled->transformToString($xdmDoc);

        // Below is the error trigger.
        // If you add 'echo $result; exit;', the transformed result will be shown correctly.
        $response = new Response($result);

        // Never reached.
        return $response;
    }
}
Actions #4

Updated by O'Neil Delpratt 7 months ago

I ran the example in the initial bug entry to reproduce the error. I think it was running with Symfony because code: $r = new Symfony\Component\HttpFoundation\Response(); would not work otherwise. I then modified the code with the setup: Saxon + Symfony + no reassignment and it ran without error.

I tried to run the code in comment #3 but currently hitting the PHP error:

PHP Fatal error:  Uncaught Error: Class "Symfony\Bundle\FrameworkBundle\Controller\AbstractController" not found in /home/ond1/work/repository/temp/libsaxon-EEC-linux-amd64-v12.3/samples/php/example2.php:9
Stack trace:
#0 {main}
  thrown in /home/ond1/work/repository/temp/libsaxon-EEC-linux-amd64-v12.3/samples/php/example2.php on line 9
Actions #5

Updated by Thibault Liardon 7 months ago

O'Neil Delpratt wrote in #note-4:

I ran the example in the initial bug entry to reproduce the error. I think it was running with Symfony because code: $r = new Symfony\Component\HttpFoundation\Response(); would not work otherwise. I then modified the code with the setup: Saxon + Symfony + no reassignment and it ran without error.

I tried to run the code in comment #3 but currently hitting the PHP error:

PHP Fatal error:  Uncaught Error: Class "Symfony\Bundle\FrameworkBundle\Controller\AbstractController" not found in /home/ond1/work/repository/temp/libsaxon-EEC-linux-amd64-v12.3/samples/php/example2.php:9
Stack trace:
#0 {main}
  thrown in /home/ond1/work/repository/temp/libsaxon-EEC-linux-amd64-v12.3/samples/php/example2.php on line 9

Hi O'Neil,

I am sorry, I have not been clear enough in my examples with Symfony. You need to set up a whole new Symfony framework project to run them. The reason AbstractController is missing is because the whole Symfony framework dependencies and project structure is required.

I will produce soon a ContainerFile / Docker file that installs everything so anyone without prior Symfony knowledge can reproduce it.

Actions #6

Updated by Thibault Liardon 7 months ago

Thibault Liardon wrote in #note-5:

I will produce soon a ContainerFile / Docker file that installs everything so anyone without prior Symfony knowledge can reproduce it.

Finally, here it is: https://gitlab.com/saxon-packaging/saxon-debug/saxon-debug

The repository contains:

  • A Containerfile to build a container to test the code.
  • The Symfony application with a test route that uses Saxon.
  • Tests PHP scripts that starts with 1_[...], 2_[...], ..., the files suffixed with control are the same but without Saxon, to establish that the code is indeed working.
  • A PHPUnit test with Saxon.

The file HOWTO_REPRODUCE.txt gives the instructions to build and start the containers, and how to execute the code.

The container is based on Fedora 38, and I built and ran it on a Fedora 38 x86-64 host, with Podman. All Podman commands should be replaced by Docker commands if you are using Docker.

Actions #7

Updated by O'Neil Delpratt 7 months ago

  • Status changed from New to In Progress

Thanks for providing the container. I will take a look at it.

Current progress: I have added some object reference counting for the memory management of the \Saxon\SaxonProcessor object. No longer getting the segmentation fault, but PHP is not calling its wrapper destructor again. Therefore I am now looking at the refcount and macros provided by the PHP Zend framework to manage the memory of the objects

Actions #8

Updated by O'Neil Delpratt 7 months ago

Hi,

I ran the PHPUnit test with my patched code and it ran without the seg fault. But some of the php scripts are throwing seg fault.

Actions #9

Updated by O'Neil Delpratt 5 months ago

I have made several improvements to the memory management of the SaxonC PHP extension. Please can you give SaxonC 12.4 try and let us know if it unblocks you.

Actions #10

Updated by Thibault Liardon 5 months ago

Hi O'Neil,

Great news! Do you have a patch file I can apply, or an URL I could pull from?

Actions #11

Updated by Martin Honnen 5 months ago

I think O'Neil was trying to tell you that there is a new SaxonC release (12.4 yesterday, today replaced by 12.4.1); you can download it from https://www.saxonica.com/download/c.xml.

Actions #12

Updated by Thibault Liardon 5 months ago

Oh ok thanks. I tried with the release 12.4.1

Unfortunately I wasn't able to build it first using the same setup I used for 12.3, I got the following errors:

/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:269:28: warning: NULL used in arithmetic [-Wpointer-arith]
  269 |       if (Z_TYPE_P(val) != NULL) {
      |                            ^~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:341:16: error: 'argument' was not declared in this scope; did you mean 'arguments'?
  341 |         delete argument[i];
      |                ^~~~~~~~
      |                arguments
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:343:17: error: type 'int' argument given to 'delete', expected pointer
  343 |       delete [] argument_length;
      |                 ^~~~~~~~~~~~~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:363:16: error: 'argument' was not declared in this scope; did you mean 'arguments'?
  363 |         delete argument[i];
      |                ^~~~~~~~
      |                arguments
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:365:17: error: type 'int' argument given to 'delete', expected pointer
  365 |       delete [] argument_length;
      |                 ^~~~~~~~~~~~~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp: In function 'void zim_XsltExecutable_callFunctionReturningString(zend_execute_data*, zval*)':
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:412:28: warning: NULL used in arithmetic [-Wpointer-arith]
  412 |       if (Z_TYPE_P(val) != NULL) {
      |                            ^~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp: In function 'void zim_XsltExecutable_callFunctionReturningFile(zend_execute_data*, zval*)':
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:498:28: warning: NULL used in arithmetic [-Wpointer-arith]
  498 |       if (Z_TYPE_P(val) != NULL) {
      |                            ^~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp: In function 'void zim_XsltExecutable_setInitialTemplateParameters(zend_execute_data*, zval*)':
/builddir/build/BUILD/php-saxon-12.4.1/php8_XsltExecutable.cpp:847:28: warning: NULL used in arithmetic [-Wpointer-arith]
  847 |       if (Z_TYPE_P(val) != NULL) {
      |                            ^~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_saxon.cpp: In function 'void zim_SaxonProcessor_createXdmMapValue(zend_execute_data*, zval*)':
/builddir/build/BUILD/php-saxon-12.4.1/php8_saxon.cpp:241:28: warning: NULL used in arithmetic [-Wpointer-arith]
  241 |       if (Z_TYPE_P(val) != NULL) {
      |                            ^~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_saxon.cpp: In function 'void zim_SaxonProcessor_createXdmArrayValue(zend_execute_data*, zval*)':
/builddir/build/BUILD/php-saxon-12.4.1/php8_saxon.cpp:331:28: warning: NULL used in arithmetic [-Wpointer-arith]
  331 |       if (Z_TYPE_P(val) != NULL) {
      |                            ^~~~
/builddir/build/BUILD/php-saxon-12.4.1/php8_saxon.cpp: In function 'void zim_XdmFunctionItem_call(zend_execute_data*, zval*)':
/builddir/build/BUILD/php-saxon-12.4.1/php8_saxon.cpp:2763:30: warning: NULL used in arithmetic [-Wpointer-arith]
 2763 |         if (Z_TYPE_P(val) != NULL) {
      |                              ^~~~
make: *** [Makefile:210: php8_saxon.lo] Error 1

So I made the patch file 0_fix_php8_XsltExecutable.patch that you can find attached to this message, and I was able to build it successfully.

Then I ran the tests I made (https://gitlab.com/saxon-packaging/saxon-debug/saxon-debug), and they are still failing.

Thread 1 "php" received signal SIGSEGV, Segmentation fault.
zend_mm_alloc_small (bin_num=5, heap=0x7ffff7200040)
    at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_alloc.c:1313
Downloading source file /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_alloc.c
1313                    heap->free_slot[bin_num] = p->next_free_slot;                                                 
Missing separate debuginfos, use: dnf debuginfo-install php-cli-8.2.13-1.fc38.x86_64
(gdb) source .gdbinit 
(gdb) bt
#0  zend_mm_alloc_small (bin_num=5, heap=0x7ffff7200040)
    at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_alloc.c:1313
#1  zend_mm_alloc_heap (size=<optimized out>, heap=0x7ffff7200040)
    at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_alloc.c:1384
#2  _emalloc (size=<optimized out>) at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_alloc.c:2601
#3  0x00005555557d071a in zend_string_alloc (persistent=false, len=20)
    at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_string.h:152
#4  zend_string_init (persistent=false, len=20, 

(gdb) zbacktrace 
[0x7ffff7213170] Composer\Autoload\includeFile("/home/tli/perso/test2/vendor/composer/../symfony/http-foundation/Resp
onse.php") /home/tli/perso/test2/vendor/composer/ClassLoader.php:571 
[0x7ffff72130f0] Composer\Autoload\ClassLoader->loadClass("Symfony\Component\HttpFoundation\Response") 
/home/tli/perso/test2/vendor/composer/ClassLoader.php:428 
[0x7ffff7213020] (main) /home/tli/perso/test2/1_composer_test_ko_reassignement_and_new_object.php:20 
Actions #13

Updated by O'Neil Delpratt 5 months ago

Thanks for your feedback for the patch. Apologies on the compile issues.

Actions #14

Updated by O'Neil Delpratt 5 months ago

Hi,

I am struggling to reproduce the failure using the container.

I have followed the instructions in https://gitlab.com/saxon-packaging/saxon-debug/saxon-debug/-/blob/master/HOWTO_REPRODUCE.txt?ref_type=heads

On line 27: Go to http://localhost:8000/test

prints:

# unable to fetch the response from the backend: unexpected EOF

Also if I run the phpunit with the command:

run vendor/phpunit/phpunit/phpunit --filter testControlWorks

I get the message:

Starting program: /usr/bin/php vendor/phpunit/phpunit/phpunit --filter testControlWorks
warning: Error disabling address space randomization: Function not implemented
warning: Could not trace the inferior process.
warning: ptrace: Operation not permitted
During startup program exited with code 127.
(gdb) 
Actions #15

Updated by Thibault Liardon 4 months ago

Hi

I am struggling to reproduce the failure using the container.

I have followed the instructions in https://gitlab.com/saxon-packaging/saxon-debug/saxon-debug/-/blob/master/HOWTO_REPRODUCE.txt?ref_type=heads

On line 27: Go to http://localhost:8000/test

prints:

# unable to fetch the response from the backend: unexpected EOF

Ok. That is strange because I ran again the instructions just after a fresh clone. Did you successfully reach the step at line 26 when you send 'continue' in the GDB prompt?

And where did you see that 'unable to fetch the response from the backend: unexpected EOF' message? On my computer the message is displayed in the browser, this is normal. But do you see something in GDB?

Also if I run the phpunit with the command:

run vendor/phpunit/phpunit/phpunit --filter testControlWorks

I get the message:

Starting program: /usr/bin/php vendor/phpunit/phpunit/phpunit --filter testControlWorks
warning: Error disabling address space randomization: Function not implemented
warning: Could not trace the inferior process.
warning: ptrace: Operation not permitted
During startup program exited with code 127.
(gdb) 

I think the problem is due to Docker, if it is what you are using, as I am on Fedora with Podman. I found this StackOverflow comment about the errors that may be of use.

Maybe run the container with:

podman run -dt --publish 8000:8000 --cap-add SYS_PTRACE

 --volume $(pwd):/opt/app:z --name tsaxon tsaxon:latest /bin/bash

https://stackoverflow.com/questions/42029834/gdb-in-docker-container-returns-ptrace-operation-not-permitted

Here are all my commands and output without '--cap-add SYS_PTRACE':

[tli@wspangolin saxon-debug]$ podman exec -ti tsaxon /bin/bash
[root@13999aeba527 app]# composer install
PHP Warning:  Saxon\XdmValue::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmItem::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmNode::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmAtomicValue::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmFunctionItem::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmMap::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmArray::__toString() implemented without string return type in Unknown on line 0
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating autoload files
108 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

Run composer recipes at any time to see the status of your Symfony recipes.

Executing script cache:clear [OK]
Executing script assets:install public [OK]

[root@13999aeba527 app]# gdb php
GNU gdb (GDB) Fedora Linux 13.2-4.fc38
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from php...
Reading symbols from /usr/lib/debug/usr/bin/php-8.2.10-1.fc38.x86_64.debug...
warning: File "/opt/app/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
	add-auto-load-safe-path /opt/app/.gdbinit
line to your configuration file "/root/.config/gdb/gdbinit".
To completely disable this security protection add
	set auto-load safe-path /
line to your configuration file "/root/.config/gdb/gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
	info "(gdb)Auto-loading safe path"
(gdb) run vendor/phpunit/phpunit/phpunit --filter testControlWorks
Starting program: /usr/bin/php vendor/phpunit/phpunit/phpunit --filter testControlWorks
warning: Error disabling address space randomization: Function not implemented

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.fedoraproject.org/>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
[Thread debugging using libthread_db enabled]                                                                         
Using host libthread_db library "/lib64/libthread_db.so.1".
PHP Warning:  Saxon\XdmValue::__toString() implemented without string return type in Unknown on line 0                
PHP Warning:  Saxon\XdmItem::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmNode::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmAtomicValue::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmFunctionItem::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmMap::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmArray::__toString() implemented without string return type in Unknown on line 0
[Detaching after vfork from child process 410]
PHPUnit 9.6.11 by Sebastian Bergmann and contributors.

Testing 
.                                                                   1 / 1 (100%)

Time: 00:00.013, Memory: 4.00 MB

OK (1 test, 1 assertion)
[Inferior 1 (process 407) exited normally]
(gdb) run vendor/phpunit/phpunit/phpunit --filter testFails
Starting program: /usr/bin/php vendor/phpunit/phpunit/phpunit --filter testFails
warning: Error disabling address space randomization: Function not implemented
[Thread debugging using libthread_db enabled]                                                                         
Using host libthread_db library "/lib64/libthread_db.so.1".
PHP Warning:  Saxon\XdmValue::__toString() implemented without string return type in Unknown on line 0                
PHP Warning:  Saxon\XdmItem::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmNode::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmAtomicValue::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmFunctionItem::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmMap::__toString() implemented without string return type in Unknown on line 0
PHP Warning:  Saxon\XdmArray::__toString() implemented without string return type in Unknown on line 0
[Detaching after vfork from child process 412]
PHPUnit 9.6.11 by Sebastian Bergmann and contributors.

Testing 
[New Thread 0x7fe85f1ff6c0 (LWP 413)]

Thread 1 "php" received signal SIGSEGV, Segmentation fault.
zend_mm_alloc_small (bin_num=5, heap=0x7fe867a00040)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_alloc.c:1313
1313			heap->free_slot[bin_num] = p->next_free_slot;
(gdb) bt
#0  zend_mm_alloc_small (bin_num=5, heap=0x7fe867a00040)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_alloc.c:1313
#1  zend_mm_alloc_heap (size=<optimized out>, heap=0x7fe867a00040)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_alloc.c:1384
#2  _emalloc (size=<optimized out>) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_alloc.c:2601
#3  0x000055dcc5dd057a in zend_string_alloc (persistent=false, len=17)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_string.h:152
#4  zend_string_init (persistent=false, len=17, 
    str=0x7fe867afe8f9 "customComparators, $comparator);\n\n        $comparator->setFactory($this);\n    }\n\n    /**\n     * Unregisters a comparator.\n     *\n     * This comparator will no longer be considered by getComparatorFor"...) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_string.h:174
#5  lex_scan (zendlval=zendlval@entry=0x7ffe5c2994d0, elem=0x7ffe5c299568)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:9818
#6  0x000055dcc5de72a0 in zendlex (elem=elem@entry=0x7ffe5c299568)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_compile.c:1802
#7  0x000055dcc5dc7883 in zendparse () at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_parser.c:4758
#8  0x000055dcc5dca656 in zend_compile (type=type@entry=2)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:601
#9  0x000055dcc5dcbdff in compile_file (file_handle=0x7ffe5c29a470, type=2)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:655
#10 0x00007fe8669df256 in phar_compile_file (file_handle=0x7ffe5c29a470, type=2)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/ext/phar/phar.c:3355
#11 0x00007fe8678c4473 in opcache_compile_file (file_handle=file_handle@entry=0x7ffe5c29a470, type=type@entry=2, 
    op_array_p=op_array_p@entry=0x7ffe5c29a370)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/ext/opcache/ZendAccelerator.c:1824
#12 0x00007fe8678c722f in persistent_compile_file (file_handle=0x7ffe5c29a470, type=2)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/ext/opcache/ZendAccelerator.c:2168
#13 0x000055dcc5dcbec1 in compile_filename (type=type@entry=2, filename=filename@entry=0x55dcc6e79840)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_language_scanner.c:706
#14 0x000055dcc5e41f8f in zend_include_or_eval (inc_filename_zv=<optimized out>, type=2)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute.c:4799
#15 0x000055dcc5e50f6f in ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLER ()
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:38960
#16 0x000055dcc5e79886 in execute_ex (ex=0x204cb0)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:59407
s#17 0x000055dcc5dfdbf8 in zend_call_function (fci=fci@entry=0x7ffe5c29a7b0, fci_cache=<optimized out>, 
    fci_cache@entry=0x7ffe5c29a790) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:949
#18 0x000055dcc5dfdf87 in zend_call_known_function (fn=0x55dcc7761570, object=<optimized out>, 
    called_scope=<optimized out>, retval_ptr=retval_ptr@entry=0x0, param_count=param_count@entry=1, 
    params=params@entry=0x7ffe5c29a840, named_params=0x0)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:1043
#19 0x000055dcc5cfba15 in spl_perform_autoload (class_name=0x55dcc6e797f8, lc_name=0x55dcc6eb1e00)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/ext/spl/php_spl.c:445
#20 0x000055dcc5dfcd77 in zend_lookup_class_ex (name=name@entry=0x55dcc6e797f8, key=0x55dcc6eb1e00, 
    flags=flags@entry=512) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:1209
#21 0x000055dcc5dfe3ea in zend_fetch_class_by_name (class_name=0x55dcc6e797f8, key=<optimized out>, 
    fetch_type=fetch_type@entry=512) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_execute_API.c:1705
#22 0x000055dcc5e4e5e7 in ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER ()
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:6886
#23 0x000055dcc5e77f5d in execute_ex (ex=0x204cb0)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:56641
#24 0x000055dcc5e81e11 in zend_execute (op_array=0x7fe867a87200, return_value=<optimized out>)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend_vm_execute.h:60408
#25 0x000055dcc5e0cdeb in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, 
--Type <RET> for more, q to quit, c to continue without paging--
    file_count=file_count@entry=3) at /usr/src/debug/php-8.2.10-1.fc38.x86_64/Zend/zend.c:1833
#26 0x000055dcc5da3bda in php_execute_script (primary_file=primary_file@entry=0x7ffe5c29cf30)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/main/main.c:2542
#27 0x000055dcc5ef9e7b in do_cli (argc=4, argv=0x55dcc6724cb0)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/sapi/cli/php_cli.c:964
#28 0x000055dcc5c413a9 in main (argc=4, argv=0x55dcc6724cb0)
    at /usr/src/debug/php-8.2.10-1.fc38.x86_64/sapi/cli/php_cli.c:1333
(gdb) source .gdbinit 
(gdb) zbacktrace 
[0x7fe867a14ec0] Symfony\Component\ErrorHandler\DebugClassLoader->loadClass("SebastianBergmann\Comparator\Factory") 
/opt/app/vendor/symfony/error-handler/DebugClassLoader.php:296 
[0x7fe867a14e30] PHPUnit\Framework\TestCase->unregisterCustomComparators() 
/opt/app/vendor/phpunit/phpunit/src/Framework/TestCase.php:2551 
[0x7fe867a14d60] PHPUnit\Framework\TestCase->runBare() 
/opt/app/vendor/phpunit/phpunit/src/Framework/TestCase.php:1291 
[0x7fe867a14b10] PHPUnit\Framework\TestResult->run(object[0x7fe867a14b60]) 
/opt/app/vendor/phpunit/phpunit/src/Framework/TestResult.php:728 
[0x7fe867a148d0] PHPUnit\Framework\TestCase->run(object[0x7fe867a14920]) 
/opt/app/vendor/phpunit/phpunit/src/Framework/TestCase.php:964 
[0x7fe867a14780] PHPUnit\Framework\TestSuite->run(object[0x7fe867a147d0]) 
/opt/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684 
[0x7fe867a14630] PHPUnit\Framework\TestSuite->run(object[0x7fe867a14680]) 
/opt/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684 
[0x7fe867a144e0] PHPUnit\Framework\TestSuite->run(object[0x7fe867a14530]) 
/opt/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php:684 
[0x7fe867a14250] PHPUnit\TextUI\TestRunner->run(object[0x7fe867a142a0], reference, reference, true) 
/opt/app/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:651 
[0x7fe867a14170] PHPUnit\TextUI\Command->run(array(3)[0x7fe867a141c0], true) 
/opt/app/vendor/phpunit/phpunit/src/TextUI/Command.php:144 
[0x7fe867a140d0] PHPUnit\TextUI\Command->main() /opt/app/vendor/phpunit/phpunit/src/TextUI/Command.php:97 
[0x7fe867a14020] (main) /opt/app/vendor/phpunit/phpunit/phpunit:107 
(gdb)
Actions #16

Updated by O'Neil Delpratt 4 months ago

Thanks for the update. I will try it again. Also how can I add and use a more recent version of SaxonC or use my own version?

Actions #17

Updated by Thibault Liardon 4 months ago

O'Neil Delpratt wrote in #note-16:

Thanks for the update. I will try it again. Also how can I add and use a more recent version of SaxonC or use my own version?

The debug container built by the Containerfile is using the Saxon RPM package I built with Fedora Copr. What you could do is to add a line to build the container with your own version of the PHP extension.

Example to add on line 32:

COPY your-php-saxon-extension.so /usr/lib64/php/modules/saxon.so
Actions #18

Updated by O'Neil Delpratt 4 months ago

Hi Thibault,

Thank you for your post in comment # 15. I have now reproduced the segmentation error.

Actions #19

Updated by O'Neil Delpratt 4 months ago

Update:

I have now managed to run the container with my own built version of the SaxonC PHP extension which is useful for the investigation. Thanks Thibault for your comment in #note-17

What is interesting is under this environment the xpathExamples.php sample is crashing with a SIGSEGV, Segmentation fault in the 5th example where we call setContextItem.

(gdb) bt
#0  __strcmp_avx2 () at ../sysdeps/x86_64/multiarch/strcmp-avx2.S:283
#1  0x00007f82be52124f in zim_XPathProcessor_setContextItem(_zend_execute_data*, _zval_struct*) () from /usr/lib64/php/modules/saxon.so
#2  0x000055e20bc815ff in ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER () at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_vm_execute.h:1842
#3  execute_ex (ex=0x55e200000320) at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_vm_execute.h:56077
#4  0x000055e20bc82251 in zend_execute (op_array=0x7f82c1c91000, return_value=<optimized out>) at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend_vm_execute.h:60409
#5  0x000055e20bc0d15b in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=file_count@entry=3) at /usr/src/debug/php-8.2.13-1.fc38.x86_64/Zend/zend.c:1838
#6  0x000055e20bba3d5a in php_execute_script (primary_file=primary_file@entry=0x7ffcf0bc67f0) at /usr/src/debug/php-8.2.13-1.fc38.x86_64/main/main.c:2542
#7  0x000055e20bcfaf8b in do_cli (argc=2, argv=0x55e20e030cf0) at /usr/src/debug/php-8.2.13-1.fc38.x86_64/sapi/cli/php_cli.c:964
#8  0x000055e20ba413f9 in main (argc=2, argv=0x55e20e030cf0) at /usr/src/debug/php-8.2.13-1.fc38.x86_64/sapi/cli/php_cli.c:1333
Actions #20

Updated by O'Neil Delpratt 4 months ago

I think I figured out the cause of the memory corruption. If I comment out the efree(obj) in the following code then the PHPUnit tests succeeds.

`void SaxonProcessor_free_storage(zend_object *object) {

saxonProcessor_object *obj;

obj = (saxonProcessor_object *)((char *)object - XtOffsetOf(saxonProcessor_object, std));

SaxonProcessor *saxonProc = obj->saxonProcessor; if (saxonProc != nullptr) { delete saxonProc; } zend_object_std_dtor(object);

//efree(obj); - corrupts memory }`

I am failing to understand how and if I should free the saxonProcessor_object given as obj.

In the create_handler function I created the obj as follows:

saxonProcessor_object *obj = (saxonProcessor_object *)ecalloc( 1, sizeof(saxonProcessor_object) + zend_object_properties_size(type));

I then changed it to the following:

saxonProcessor_object *obj = (saxonProcessor_object *)zend_object_alloc(sizeof(saxonProcessor_object), type);

Actions #21

Updated by Thibault Liardon 3 months ago

Oh great!

May I suggest you create a patch file so I can apply it to my repository and run tests? I think I should write a few new that will create a lot of objects and work with them to see how it behaves.

Actions #22

Updated by O'Neil Delpratt 3 months ago

  • Status changed from In Progress to AwaitingInfo

Yes fine. I have sent test releases privately by email. Please confirm if the problem is now resolved.

Actions #23

Updated by Thibault Liardon 3 months ago

Hello O'Neil,

Great news: I ran the tests from my container after building the PHP Saxon 12.4.1 you have provided. They all completed successfully, with the PHP process terminating normally, both with the simple test scripts and while running with PHPUnit and inside Symfony.

I didn't do anything yet for the 'load' tests.

Actions #24

Updated by O'Neil Delpratt 3 months ago

  • Status changed from AwaitingInfo to Resolved
  • % Done changed from 0 to 100

Thanks for confirming this. I am marking this bug issue now as resolved. Thank you for you patience.

We are working on a maintenance release which will contain this patch and hopefully will be ready in the next few days.

Actions #25

Updated by O'Neil Delpratt 3 months ago

  • Status changed from Resolved to Closed
  • Fixed in version set to 12.4.2

Fix applied in SaxonC 12.4.2 maintenance release

Please register to edit this issue

Also available in: Atom PDF