Segfault в PHP без php журнала ошибок. Как отлаживать? - PullRequest
1 голос
/ 20 февраля 2020

У меня есть скрипт, использующий com_do tnet, который при определенных обстоятельствах делает PHP segfault (не уверен, что segfault является техническим правильным термином).

Использование PHP 7.4.2 NTS 32bit on Windows 2019 64bit. Та же ошибка происходит при использовании FCGI или CLI. Тот же скрипт работал с PHP 7.0.30. В случае FCGI в журнале Apache есть только эта ошибка:

[...] [fcgid:warn] [pid ...] (OS 109)The pipe has been ended.  : [client ...] mod_fcgid: get overlap result error
[...] [fcgid:warn] [pid ...] (OS 109)The pipe has been ended.  : [client ...] mod_fcgid: ap_pass_brigade failed in handle_request_ipc function

В журнале событий, журнале приложений, есть событие Application Error с идентификатором 1000:

Faulting application name: php-cgi.exe, version: 7.4.2.0, time stamp: 0x5e273bd1
Faulting module name: php7.dll, version: 7.4.2.0, time stamp: 0x5e274c52
Exception code: 0xc0000005
Fault offset: 0x004a1554
Faulting process id: 0x1d3c
Faulting application start time: 0x01d5e7035b9ba103
Faulting application path: F:\wamp\bin\php\php7.4.2nts86\php-cgi.exe
Faulting module path: F:\wamp\bin\php\php7.4.2nts86\php7.dll
Report Id: 83f813df-1bda-48f9-89f6-2374f9b04af5
Faulting package full name: 
Faulting package-relative application ID:

И событие 1001 Windows Error Reporting

Fault bucket 1785407568804712926, type 1
Event Name: APPCRASH
Response: Not available
Cab Id: 0

Problem signature:
P1: php-cgi.exe
P2: 7.4.2.0
P3: 5e273bd1
P4: php7.dll
P5: 7.4.2.0
P6: 5e274c52
P7: c0000005
P8: 004a1554
P9: 
P10: 

Attached files:
[Temp files no longer on disk]

These files may be available here:
\\?\C:\ProgramData\Microsoft\Windows\WER\ReportArchive\AppCrash_php-cgi.exe_db93fdd1eb9fce3ac32a6e96e418914fb9fca_32a55e52_0a30ae4b

Analysis symbol: 
Rechecking for solution: 0
Report Id: 83f813df-1bda-48f9-89f6-2374f9b04af5
Report Status: 268435456
Hashed bucket: 85fc32c6322e070cd8c70ab96de611de
Cab Guid: 0

Файл WER\ReportArchive не содержит интересных данных.

Мне не удалось найти точное место в коде где ошибка происходит. Это происходит при чтении данных с использованием модуля com_do tnet.

if($this->statement->State == 1){
    $result = [];
    while(!$this->statement->EOF) {
        $row = [];
        for( $x = 0; $x < $this->statement->Fields->Count; $x++) {
            $name = $this->statement->Fields[$x]->Name;
            $value = $this->statement->Fields[$x]->Value;
            $row[$name] = $value;
        }
        $this->statement->MoveNext();
        $result[] = $row;
    }
    return $result;
}

Ошибка появляется во всех проверенных источниках данных, как только я читаю более 9000–9500 строк. Кажется, это не связано с самими данными.

Минимальный код, который приводит к ошибке:

if($this->statement->State == 1){
    $result = [];
    while(!$this->statement->EOF) {
        $row = [];
        $row[] = '';                   // <==
        $this->statement->MoveNext();
        $result[] = $row;              // <==
    }
    return $result;
}

Нет ошибки при удалении одной из двух отмеченных строк со стрелой. Здесь содержимое $result и com-объект совершенно не связаны, и даже в этом случае PHP отказывает, если существует более 9000 циклов. Число строк, приводящих к ошибке, похоже, не изменяется ни в зависимости от источника данных, ни между двумя фрагментами кода, приведенными выше.

Здесь это интересно не является ошибкой, даже если $row = ['']; функционально эквивалентно $row = []; $row[] = ''; (сверху).

if($this->statement->State == 1){
    $result = [];
    while(!$this->statement->EOF) {
        $row = [''];
        $this->statement->MoveNext();
        $result[] = $row;
    }
    return $result;
}

Вот и я в конце своих знаний. Кажется, вещи больше не ведут себя логически. Как я мог сузить проблему? Любой совет?

Редактировать: PHP 7.3.15 не влияет, только PHP 7.4.2.

...