php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71387 Segfault in php_mysqlnd_rowp_read_text_protocol_aux()
Submitted: 2016-01-16 08:37 UTC Modified: 2016-02-07 04:22 UTC
Votes:3
Avg. Score:4.3 ± 0.9
Reproduced:3 of 3 (100.0%)
Same Version:2 (66.7%)
Same OS:1 (33.3%)
From: bugs dot php dot net at ss dot st dot tc Assigned:
Status: No Feedback Package: MySQLi related
PHP Version: 7.0.2 OS: Gentoo Linux
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2016-01-16 08:37 UTC] bugs dot php dot net at ss dot st dot tc
Description:
------------
Tested in 7.0.0, 7.0.1 and 7.0.2.
The problem doesn't happen when PHP is compiled with --enable-debug option, so here's all we've got:

#0  0x00000000007482aa in php_mysqlnd_rowp_read_text_protocol_aux ()
#1  0x00000000007508b2 in ?? ()
#2  0x00000000007517c5 in ?? ()
#3  0x00000000007520f6 in ?? ()
#4  0x00000000005d2618 in zif_mysqli_fetch_all ()
#5  0x000000000089027b in ?? ()
#6  0x000000000084a55b in execute_ex ()
#7  0x00000000008beb9e in zend_execute ()
#8  0x00000000007e6d5a in zend_execute_scripts ()
#9  0x0000000000765858 in php_execute_script ()
#10 0x00000000008c0e24 in ?? ()
#11 0x000000000046bf09 in main ()

We figured segfault happens on this line: https://github.com/php/php-src/blob/php-7.0.2/ext/mysqlnd/mysqlnd_wireprotocol.c#L1670 but didn't dig deeper.


After we removed as much as possible from our php script, we managed to narrow the problem down to just one query that was performed in a loop:

select id, f1, f2 from table where id>{$some_id} and f1 is not null order by id limit 100

The script always segfaults after a certain amount of queries done.
As soon as we change something in that query (add or remove field, change limit to 99 or 101), the number of performed queries before segfault changes (yet keeps steady as long as we don't touch the query anymore). For instance, with limit 100 it constantly takes 35 queries to segfault. With limit 101 we need 93 iterations. Without field "f2" it takes 83 iterations. With limit=102 segfault doesn't happen at all. And so on. We've also tried to add more mysql queries to another server/tables/databases, this also affects on the moment segfault happens, but it always keeps steady until we change something else. Could be a stack corruption, or something like that.


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-01-16 09:08 UTC] bugs dot php dot net at ss dot st dot tc
Worth mentioning that value of variable `len` in mysqlnd_wireprotocol.c:1670 was 8 (and that looks pretty normal among other values of `len` that we saw), which makes variable `p` a suspect.
 [2016-01-16 09:11 UTC] bugs dot php dot net at ss dot st dot tc
-Package: mysql +Package: MySQLi related
 [2016-01-16 09:11 UTC] bugs dot php dot net at ss dot st dot tc
(mistakenly set package to mysql instead of mysqli)
 [2016-01-16 09:18 UTC] php at etc dot chkgo dot com
Not sure if it would help, but f1 is varbinary(32000). And if we select concat(f1, f1) instead of just f1, segfault does not happen. It also does not happen if we include something like:

  $x = str_repeat('XXXXXXXXXXXXXXXXXXXXXXX', 1000);
  echo strlen($x); // without echo segfault still happens

into the loop. So any minor change to the code which affects memory may change the picture.
 [2016-01-25 04:22 UTC] laruence@php.net
-Status: Open +Status: Feedback
 [2016-01-25 04:22 UTC] laruence@php.net
Thank you for this bug report. To properly diagnose the problem, we
need a short but complete example script to be able to reproduce
this bug ourselves. 

A proper reproducing script starts with <?php and ends with ?>,
is max. 10-20 lines long and does not require any external 
resources such as databases, etc. If the script requires a 
database to demonstrate the issue, please make sure it creates 
all necessary tables, stored procedures etc.

Please avoid embedding huge scripts into the report.


 [2016-02-07 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.
 [2016-10-10 21:19 UTC] jbboehr at gmail dot com
Not 100% sure it's related, but I've run into an issue in the same function.


PHP 7.0.8-0ubuntu0.16.04.3 (cli) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.8-0ubuntu0.16.04.3, Copyright (c) 1999-2016, by Zend Technologies


The first time I ran valgrind, I got this:

==16316== Process terminating with default action of signal 11 (SIGSEGV)
==16316==    at 0x682D2A9: raise (pt-raise.c:35)
==16316==    by 0x17174A2E: nr_signal_reraise (util_signals.c:40)
==16316==    by 0x682D3CF: ??? (in /lib/x86_64-linux-gnu/libpthread-2.23.so)
==16316==    by 0x343C43: _emalloc (in /usr/bin/php7.0)
==16316==    by 0x9A55F26: php_mysqlnd_rowp_read_text_protocol_aux (in /usr/lib/php/20151012/mysqlnd.so)
==16316==    by 0x9A5D3F0: ??? (in /usr/lib/php/20151012/mysqlnd.so)
==16316==    by 0x9A5D8A4: ??? (in /usr/lib/php/20151012/mysqlnd.so)
==16316==    by 0x16F0FE73: php_mysqli_fetch_into_hash (in /usr/lib/php/20151012/mysqli.so)
==16316==    by 0x356C99: dtrace_execute_internal (in /usr/bin/php7.0)
==16316==    by 0x3EB93F: ??? (in /usr/bin/php7.0)
==16316==    by 0x3A6F8A: execute_ex (in /usr/bin/php7.0)
==16316==    by 0x356B30: dtrace_execute_ex (in /usr/bin/php7.0)


One of the next times, after futzing with the code to try and get more information, I got this one:

==3636== Process terminating with default action of signal 11 (SIGSEGV)
==3636==    at 0x682D2A9: raise (pt-raise.c:35)
==3636==    by 0x17174A2E: nr_signal_reraise (util_signals.c:40)
==3636==    by 0x682D3CF: ??? (in /lib/x86_64-linux-gnu/libpthread-2.23.so)
==3636==    by 0x343C43: _emalloc (in /usr/bin/php7.0)
==3636==    by 0x343EC0: _ecalloc (in /usr/bin/php7.0)
==3636==    by 0x215D12: timelib_get_time_zone_info (in /usr/bin/php7.0)
==3636==    by 0x217C35: timelib_set_timezone (in /usr/bin/php7.0)
==3636==    by 0x217157: timelib_update_ts (in /usr/bin/php7.0)
==3636==    by 0x1F2B43: zif_strtotime (in /usr/bin/php7.0)
==3636==    by 0x356C99: dtrace_execute_internal (in /usr/bin/php7.0)
==3636==    by 0x3EB93F: ??? (in /usr/bin/php7.0)
==3636==    by 0x3A6F8A: execute_ex (in /usr/bin/php7.0)


These both happen in a loop of several hundred queries. So far I've failed to make a reduced test case.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Apr 20 07:01:29 2024 UTC