php / php/php-src

Apache Segmentation fault (11) disappears after print_r on a variable. can't understand...

オープン
#10,430 コメント 34 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

Bug Status: Needs Triage
主要言語
C
スター
40.4k
フォーク
8.1k
平均マージ
2日 13時間
マージ済み PR(30日)
96

説明

Description

Sorry this problem appears within a big application and I didn't find a short php code reproducing the problem.
So I try to put the maximum explanations here.

In some cases I get this message in error log :
[core:notice] [pid 910] AH00051: child pid 23361 exit signal Segmentation fault (11), possible coredump in /etc/apache2

I found this message always appears twice because, when I get it, the index.php is executed a second time.
To find that, I put an errog_log('deb') at the very beginning of the index.php and an error_log('fin') at the last instruction.
In the log, I got :

[Tue Jan 24 10:50:37.515447 2023] [php:notice] [pid 23488] [client 127.0.0.1:49088] deb, referer: http://localhost/wer/index.php
[Tue Jan 24 10:50:40.193277 2023] [php:notice] [pid 23488] [client 127.0.0.1:49088] fin, referer: http://localhost/wer/index.php
[Tue Jan 24 10:50:40.856392 2023] [php:notice] [pid 23835] [client 127.0.0.1:49102] deb, referer: http://localhost/wer/index.php

[Tue Jan 24 10:50:41.479629 2023] [core:notice] [pid 910] AH00051: child pid 23488 exit signal Segmentation fault (11), possible coredump in /etc/apache2
[Tue Jan 24 10:50:43.102831 2023] [php:notice] [pid 23835] [client 127.0.0.1:49102] fin, referer: http://localhost/wer/index.php
[Tue Jan 24 10:50:43.482049 2023] [core:notice] [pid 910] AH00051: child pid 23835 exit signal Segmentation fault (11), possible coredump in /etc/apache2

So, index.php seems to be executed twice.
However, if I error_log the expected HTML result in the log, it is totally correct. (and I get it twice...)
But nothing is sent to the navigator.

Bypass

Step by step, I found a bypass : the problem disappears when I put a print_r of some object at the right place.
For example :

This caused the problem :

$ret = SG_Operation::execFonctionSansParametre($this, $o, $nom, $p2, $p1, $contexte);
//print_r($ret, true);

And this works correctly :

$ret = SG_Operation::execFonctionSansParametre($this, $o, $nom, $p2, $p1, $contexte);
print_r($ret, true);

It works too if I add :

$ret = unserialize(serialize($ret);

If the dumps of the object before and after the problem are identical.

I tried some other features which don't work :

$obj = SG_Operation::execFonctionSansParametre($this, $o, $nom, $p2, $p1, $contexte);
$ret = $obj;

or

$obj = SG_Operation::execFonctionSansParametre($this, $o, $nom, $p2, $p1, $contexte);
$ret = clone $obj;
Research notes

I found that the bypass does work if I just add the '''print_r''' as the first line of the __construct function of one of my classes :

/** SynerGaia contient la classe SG_Nombre de traitement des nombres */
defined("SYNERGAIA_PATH_TO_ROOT") or die('403.14 - Directory listing denied.');

/** Pour ajouter les méthodes et propriétés spécifiques de l'application créées par le compilateur */
if (file_exists(SYNERGAIA_PATH_TO_VAR . 'SG_Nombre_trait.php')) {
    include_once SYNERGAIA_PATH_TO_VAR . 'SG_Nombre_trait.php';
} else {
    /** trait vide par défaut */
    trait SG_Nombre_trait{};
}
/**
 * SG_Nombre : Classe SynerGaia de gestion d'un nombre
 * @since 0.0
 * @version 2.9
 */
class SG_Nombre extends SG_Objet {
    // complément de classe créée par compilation
    use SG_Nombre_trait;

    /** string Type SynerGaia '@Nombre' */
    const TYPESG = '@Nombre';
    
    /** string Type SynerGaia  */
    public $typeSG = self::TYPESG;

    /** integer|float Valeur interne du nombre (null par défaut) */
    public $valeur;
    
    /** string Unité de mesure (pas encore géré) */
    public $unite = '';

    /**
     * Construction de l'objet
     * @since 1.0.7
     * @version 2.4 si rien : 0
     * @version 2.9.1 getTexte pour unité
     * @param any $pQuelqueChose valeur à partir de laquelle le SG_Nombre est créé
     * @param any $pUnite code unité ou ou objet @Unite de la quantité
     */
    function __construct($pQuelqueChose = null, $pUnite = null)
    {
print_r($this, true); // bypass bug #10430
        $tmpTypeSG = SG_Objet::getTypeSG($pQuelqueChose);
        switch ($tmpTypeSG) {
            case 'integer' :
                $this -> valeur = (double)$pQuelqueChose;
                break;
            case 'double' :
                $this -> valeur = $pQuelqueChose;
                break;
            case 'string' :
                if ($pQuelqueChose !== '') {
                    $floatString = $pQuelqueChose;
                    $floatString = str_replace(" ", "", $floatString);
                    $floatString = str_replace(",", ".", $floatString);
                    $this -> valeur = floatval($floatString);
                } else {
                    $this -> valeur = null;
                }
                break;
            case '@Formule' :
                $tmpNombre = new SG_Nombre($pQuelqueChose -> getResult());
                $this -> valeur = $tmpNombre -> valeur;
                break;
            case '@Nombre' :
                $this -> valeur = $pQuelqueChose -> valeur;
                $this -> unite = $pQuelqueChose -> unite;
                break;
            case 'NULL' :
                $this -> valeur = 0; //null;
                break;
            default :
                // Si objet SynerGaia
                if (substr($tmpTypeSG, 0, 1) === '@') {
                    $this -> valeur = $pQuelqueChose -> toFloat();
                }
        }
        if($pUnite) {
            $this -> unite = SG_Texte::getTexte($pUnite);
        }
    }

I also remark when the bypass works, the new class has been called by an instruction like :

$class = "MyClass";
$obj = new $class();

But, I can't make a short PHP program reproducing the problem.

Environment
PHP 8.1.2-1ubuntu2.10 (cli) (built: Jan 16 2023 15:19:49) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.2-1ubuntu2.10, Copyright (c), by Zend Technologies

on Ubuntu 22.04.1 LTS

I hope I'm clear enough clear...
Pierre Frappé (France)

PHP Version

first PHP 8.1.2, and now 8.2.1 (no change)
JIT tracing

Operating System

Ubuntu 22.04.1 LTS

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、issue には再現コードがないため、報告を短い PHP リプロデューサーに絞り込むことから始めます。PHP 8.1/8.2 の JIT トレーシング環境で、SG_Operation::execFonctionSansParametre、動的な構築、SG_Nombre::__construct、および print_r または serialize の回避策の周辺で segfault を再現します。完了の条件は、アプリケーションや Apache ではなく PHP に切り分けられる再現可能な失敗が得られることです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
apache, php
領域
backend
issue の種類
バグ
難易度
5/5
見積もり時間
1週間以上
活発さ
停滞
明瞭さ
説明が足りない
初心者へのやさしさ
20/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。