php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79270 segfault in libodbc.so.2.0.0 with ReflectionFunction($functio)->getParameters()
Submitted: 2020-02-13 11:22 UTC Modified: 2020-11-30 14:51 UTC
Votes:2
Avg. Score:4.0 ± 1.0
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: martin dot aschenbrenner at erwinmueller dot de Assigned:
Status: Open Package: PDO ODBC
PHP Version: 7.3.14 OS: Linux Ubuntu 18.04 x86_64
Private report: No CVE-ID: None
 [2020-02-13 11:22 UTC] martin dot aschenbrenner at erwinmueller dot de
Description:
------------
getting randomly (approximately each second request) following segfault:

kernel: php-fpm7.3[17905]: segfault at 860 ip 00007f7e4e77cec0 sp 00007ffdcda8b040 error 4 in libodbc.so.2.0.0[7f7e4e765000+62000]

some strange behaviors:
- uncommenting line 17 fixes the issue.
- also execution someReflection() with same parameter and an even number of times the issue doesn't occur.


additional info:
- libodbc1 package: 2.3.4-1.1ubuntu3
- php is executed by fpm
- affects php versions 7.1.33, 7.2.27, 7.3.14, 7.4.2 (not more tested)

Test script:
---------------
<?php
class Core {
  public $conn;
  public function __construct() {
    $this->circularReference = $this;
  }

  public function connect() {
    $this->conn = new PDO("odbc:mysql");
  }

  public $stm;

  function createStm( string $foo ) {
    $this->connect();
    $this->stm = $this->conn->prepare("SELECT * FROM mytable");
//    $this->stm = NULL;
  }
}

function someReflection( $function ) {
  $rParameters = (new \ReflectionFunction($function))->getParameters();
}

someReflection("implode");

$app = new Core;
$app->createStm("bar");


Patches

bug79270.patch (last revision 2020-11-05 11:47 UTC by cmb@php.net)

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-10-01 08:48 UTC] cmb@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: cmb
 [2020-10-01 08:48 UTC] cmb@php.net
I cannot reproduce this.  If you're still experiencing this
segfault with any of the actively supported PHP versions[1], can
you please provide a backtrace[2]?

[1] <https://www.php.net/supported-versions.php>
[2] <https://bugs.php.net/bugs-generating-backtrace.php>
 [2020-10-11 04:22 UTC] php-bugs at lists dot php dot net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Re-Opened". Thank you.
 [2020-10-16 21:10 UTC] alexander dot stix at erwinmueller dot de
I was able to consistently reproduce this behaviour with php-7.4.11 fpm but not when having the --enable-debug option enabled
 [2020-10-16 21:15 UTC] cmb@php.net
-Status: No Feedback +Status: Open
 [2020-10-16 21:15 UTC] cmb@php.net
Thanks!  Would that also happen with the CLI SAPI, or is this FPM specific?
 [2020-10-16 21:30 UTC] alexander dot stix at erwinmueller dot de
It also happens with the CLI SAPI.
 [2020-10-19 07:50 UTC] cmb@php.net
-Status: Assigned +Status: Feedback
 [2020-10-19 07:50 UTC] cmb@php.net
I cannot reproduce the reported behavior with a non debug build.
Could you please provide a stack backtrace[1], so we have at least
some idea what might be wrong there?

[1] <https://bugs.php.net/bugs-generating-backtrace.php>
 [2020-10-19 16:10 UTC] alexander dot stix at erwinmueller dot de
#0  0x00007f36ff9e2a50 in ?? () from /lib/x86_64-linux-gnu/libodbc.so.2
#1  0x000056403f7559f2 in odbc_stmt_dtor (stmt=<optimized out>) at /tmp/php-7.4.11/ext/pdo_odbc/odbc_stmt.c:148
#2  0x000056403f74f5cd in php_pdo_free_statement (stmt=0x7f36fcc98300) at /tmp/php-7.4.11/ext/pdo/pdo_stmt.c:2272
#3  0x000056403f94cbc2 in zend_objects_store_free_object_storage (objects=objects@entry=0x5640407820e8 <executor_globals+840>, fast_shutdown=fast_shutdown@entry=1 '\001') at /tmp/php-7.4.11/Zend/zend_objects_API.c:104
#4  0x000056403f907055 in shutdown_executor () at /tmp/php-7.4.11/Zend/zend_execute_API.c:342
#5  0x000056403f916993 in zend_deactivate () at /tmp/php-7.4.11/Zend/zend.c:1198
#6  0x000056403f8b4d6b in php_request_shutdown (dummy=<optimized out>) at /tmp/php-7.4.11/main/main.c:1921
#7  0x000056403f9a0454 in do_cli (argc=2, argv=0x5640415f1910) at /tmp/php-7.4.11/sapi/cli/php_cli.c:1132
#8  0x000056403f5a7698 in main (argc=2, argv=0x5640415f1910) at /tmp/php-7.4.11/sapi/cli/php_cli.c:1359
 [2020-10-20 11:09 UTC] cmb@php.net
-Status: Feedback +Status: Open -Assigned To: cmb +Assigned To:
 [2020-10-20 11:09 UTC] cmb@php.net
Thanks for the stack backtrace!  Apparently, there is a serious
issue when the statement handle is freed during shutdown[1].  I
still cannot reproduce this, and from looking at the
implementation, I cannot find anything obviously wrong.  Maybe an
ODBC trace of running the script can bring some insights.  On the
other hand, the fact that this would be related to constructing a
ReflectionFunction, hints at a more general memory management
issue.  This might be debuggable using valgrind; you can find a
description in the phpinternalsbook[2] (just ignore the C code
snippets and respective details).

[1] <https://github.com/php/php-src/blob/php-7.4.11/ext/pdo_odbc/odbc_stmt.c#L148>
[2] <http://www.phpinternalsbook.com/php7/memory_management/memory_debugging.html#before-starting>
 [2020-11-05 11:20 UTC] cmb@php.net
Thanks for the valgrind report.  I've moved the full report to a
Gist[1] to keep this ticket more lucid.  I'm ignoring the
Conditional jump or move depends on uninitialised value(s) in
zend_string_equal_val() , because these only occur under valgrind
and might be false positives.  So the first relevant items are:

==2860== Conditional jump or move depends on uninitialised value(s)
==2860==    at 0x9440B70: my_SQLFreeStmtExtended (in /usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so)
==2860==    by 0x9441014: my_SQLFreeStmt (in /usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so)
==2860==    by 0x9433993: free_connection_stmts (in /usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so)
==2860==    by 0x94339B0: SQLDisconnect (in /usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so)
==2860==    by 0x58703D9: SQLDisconnect (in /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0)
==2860==    by 0x504AF1: odbc_handle_closer (odbc_driver.c:131)
==2860==    by 0x4F6B68: dbh_free (pdo_dbh.c:1515)
==2860==    by 0x6FDBC1: zend_objects_store_free_object_storage (zend_objects_API.c:104)
==2860==    by 0x6B8054: shutdown_executor (zend_execute_API.c:342)
==2860==    by 0x6C7992: zend_deactivate (zend.c:1198)
==2860==    by 0x665D6A: php_request_shutdown (main.c:1921)
==2860==    by 0x751453: do_cli (php_cli.c:1132)
==2860== 
==2860== Invalid read of size 4
==2860==    at 0x589BE37: ??? (in /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0)
==2860==    by 0x58769F7: ??? (in /usr/lib/x86_64-linux-gnu/libodbc.so.2.0.0)
==2860==    by 0x5069F1: odbc_stmt_dtor (odbc_stmt.c:148)
==2860==    by 0x5005CC: php_pdo_free_statement (pdo_stmt.c:2272)
==2860==    by 0x6FDBC1: zend_objects_store_free_object_storage (zend_objects_API.c:104)
==2860==    by 0x6B8054: shutdown_executor (zend_execute_API.c:342)
==2860==    by 0x6C7992: zend_deactivate (zend.c:1198)
==2860==    by 0x665D6A: php_request_shutdown (main.c:1921)
==2860==    by 0x751453: do_cli (php_cli.c:1132)
==2860==    by 0x358697: main (php_cli.c:1359)

That shows that the issue happens during shutdown, namely in
zend_objects_store_free_object_storage() which is supposed to call
the free_object handlers of the objects in reverse order of their
creation, i.e. first the statement and then the database handle.
For some reason, in your case dbh_free() is called before
php_pdo_free_statement(), though, causing a crash.

[1] <https://gist.github.com/cmb69/337c02a21d6d7a9fd29f8d725f052945>
 [2020-11-05 11:38 UTC] cmb@php.net
-Assigned To: +Assigned To: cmb
 [2020-11-05 11:38 UTC] cmb@php.net
> […] supposed to call the free_object handlers of the objects in
> reverse order of their creation […]

I just learned that this is not true.  I'll have a closer look.
 [2020-11-05 11:47 UTC] cmb@php.net
The following patch has been added/updated:

Patch Name: bug79270.patch
Revision:   1604576850
URL:        https://bugs.php.net/patch-display.php?bug=79270&patch=bug79270.patch&revision=1604576850
 [2020-11-05 11:48 UTC] cmb@php.net
Could you please try the attached bug79270.patch?
 [2020-11-09 14:17 UTC] cmb@php.net
The following pull request has been associated:

Patch Name: Fix #79270: segfault in libodbc.so.2.0.0
On GitHub:  https://github.com/php/php-src/pull/6413
Patch:      https://github.com/php/php-src/pull/6413.patch
 [2020-11-10 01:18 UTC] alexander dot stix at erwinmueller dot de
The attached patch didn't fix the issue.
 [2020-11-10 17:25 UTC] cmb@php.net
Ugh, yeah, that patch can't work.  I'll have a closer look.
 [2020-11-30 14:51 UTC] cmb@php.net
-Status: Assigned +Status: Open -Assigned To: cmb +Assigned To:
 [2020-11-30 14:51 UTC] cmb@php.net
Hmm, no feedback on the improved PR, which is an ugly hack anyway;
a "clean" solution would require to store pointers to allocated
handles in the db handles, what is not an option for any stable
version for BC reasons.  And actually I tend to regard this as
upstream bug (driver or driver manager).
 [2020-12-01 19:50 UTC] alexander dot stix at erwinmueller dot de
I'm sorry, I thought you meant to come back with another solution.

The improved PR does in fact solve the Issue.

I was able to reproduce the bug with the MySQL driver and the IBM i Access ODBC driver, so it would either be a somewhat common driver bug or a bug in unixODBC?
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 12:01:29 2024 UTC