php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #53551 PDOStatement execute segfaults for pdo_mysql driver
Submitted: 2010-12-15 22:31 UTC Modified: 2011-01-31 10:25 UTC
From: eddawley at gmail dot com Assigned: mysql
Status: Closed Package: PDO related
PHP Version: 5.3.4 OS: Centos 5
Private report: No CVE-ID:
 [2010-12-15 22:31 UTC] eddawley at gmail dot com
Description:
------------
A segfault will occur when a PDOStatement is reused after failing due to a NOT 
NULL integrity constraint.  This occurred when using the pdo_mysql driver as 
opposed to the mysqlnd driver.

Also to avoid confusion, I was only able to test this on PHP 5.3.2.  I could find 
nothing in the changelogs that would imply this bug has been fixed.  I 
unfortunately did not have the time to free up hardware or vms for an upgrade.

Test script:
---------------
$dbh = new PDO('mysql:host=127.0.0.1;dbname=foo', 'user', 'pass');
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);

$createSql = "CREATE TABLE `foo` (
  `count` bigint(20) unsigned NOT NULL DEFAULT '0'
)";

$dbh->exec('drop table if exists foo');
$dbh->exec($createSql);
$dbh->exec("insert into foo set `count` = 1 ");

$sql = 'UPDATE foo SET `count` = :count';
$stmt = $dbh->prepare($sql);

$values = array (
  'count' => NULL,
);

echo "1\n";
$stmt->execute($values);
var_dump($stmt->errorInfo());

echo "2\n";
$stmt->execute($values);
var_dump($stmt->errorInfo());

echo "\ndone\n";


Expected result:
----------------
[ed@foo ~]$ php ed.php
1
array(3) {
  [0]=>
  string(5) "23000"
  [1]=>
  int(1048)
  [2]=>
  string(29) "Column 'count' cannot be null"
}
2
array(3) {
  [0]=>
  string(5) "23000"
  [1]=>
  int(1048)
  [2]=>
  string(29) "Column 'count' cannot be null"
}
done


Actual result:
--------------
[ed@foo ~]$ php ed.php
1
array(3) {
  [0]=>
  string(5) "23000"
  [1]=>
  int(1048)
  [2]=>
  string(29) "Column 'count' cannot be null"
}
2
Segmentation fault (core dumped)



Core was generated by `php ed.php'.
Program terminated with signal 11, Segmentation fault.
[New process 16072]
#0  0x00000000005aa8be in pdo_mysql_stmt_param_hook (stmt=0xe5c12e8, 
param=0xe5c1a78, event_type=<value optimized out>) at /tmp/php-
5.3.2/ext/pdo_mysql/mysql_statement.c:490
490                                     b->is_null = &S->in_null[param-
>paramno];
(gdb) bt
#0  0x00000000005aa8be in pdo_mysql_stmt_param_hook (stmt=0xe5c12e8, 
param=0xe5c1a78, event_type=<value optimized out>) at /tmp/php-
5.3.2/ext/pdo_mysql/mysql_statement.c:490
#1  0x00000000005a34d9 in really_register_bound_param (param=0x7ffff7cb9990, 
stmt=0xe5c12e8, is_param=1) at /tmp/php-5.3.2/ext/pdo/pdo_stmt.c:408
#2  0x00000000005a4940 in zim_PDOStatement_execute (ht=<value optimized out>, 
return_value=0xe5c18d0, return_value_ptr=<value optimized out>, this_ptr=<value 
optimized out>, 
    return_value_used=<value optimized out>) at /tmp/php-
5.3.2/ext/pdo/pdo_stmt.c:474
#3  0x0000000000789059 in zend_do_fcall_common_helper_SPEC 
(execute_data=0x2ae09210b050) at /tmp/php-5.3.2/Zend/zend_vm_execute.h:313
#4  0x000000000075f98e in execute (op_array=0xe5be920) at /tmp/php-
5.3.2/Zend/zend_vm_execute.h:104
#5  0x000000000073c439 in zend_execute_scripts (type=8, retval=0x0, 
file_count=3) at /tmp/php-5.3.2/Zend/zend.c:1194
#6  0x00000000006ea968 in php_execute_script (primary_file=0x7ffff7cbc190) at 
/tmp/php-5.3.2/main/main.c:2260
#7  0x00000000007c617e in main (argc=2, argv=0x7ffff7cbc408) at /tmp/php-
5.3.2/sapi/cli/php_cli.c:1192
(gdb) print *param
$1 = {paramno = 0, name = 0xe5c0750 ":count", namelen = 6, max_value_len = 0, 
parameter = 0xe5c1900, param_type = PDO_PARAM_STR, driver_params = 0x0, 
driver_data = 0x0, 
  stmt = 0xe5c12e8, is_param = 1}
(gdb) print param
$2 = (struct pdo_bound_param_data *) 0xe5c1a78


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-12-16 01:29 UTC] felipe@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: mysql
 [2010-12-16 22:58 UTC] kalle@php.net
I cannot reproduce with php-trunk using pdo_mysql linked to mysqlnd on Windows:

C:\php>php test.php
1
array(3) {
  [0]=>
  string(5) "00000"
  [1]=>
  NULL
  [2]=>
  NULL
}
2
array(3) {
  [0]=>
  string(5) "00000"
  [1]=>
  NULL
  [2]=>
  NULL
}

done

C:\php>php -v
PHP 5.3.99-dev (cli) (built: Dec 11 2010 12:14:13)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2010 Zend Technologies
 [2010-12-17 19:38 UTC] eddawley at gmail dot com
I would like to add that this happens for other mysql-level errors.  For 
example, the following will also cause a segfault when reused:

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a 
child 
row: a foreign key constraint fails ...

SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for 
column...

And again, this was noticed with the pdo_mysql driver.  NOT the mysqlnd native 
driver.
 [2010-12-17 20:44 UTC] kalle@php.net
MySQLnd is not a driver, its a library backend. MySQL, MySQLi and PDO_MySQL can all be powered by either libmysql or mysqlnd.

So what you are saying is that you built pdo_mysql against libmysql which segfaults?
 [2010-12-17 20:58 UTC] eddawley at gmail dot com
Sorry, I didn't realize I was being unclear.  The segfault is occurring with PDO 
using libmysql.

Here are my relevant configure options:

'--with-mysql=mysqlnd' '--with-mysqli' '--with-pdo-mysql'
 [2011-01-06 12:03 UTC] uw@php.net
That fix should do it, however, I'd like to wait until Johannes returns from vacation and reviews it. PDO is a bit of a beast. With the fix the code should neither crash nor leak, nor behave differently from PDO_SQlite. Anyway, the result is still pretty, well, PDOish weird: error codes not cleaned up properly upon rebinding. Not my cup of coffee...

Index: ext/pdo_mysql/mysql_statement.c                                          
===================================================================             
--- ext/pdo_mysql/mysql_statement.c     (Revision 307155)                       
+++ ext/pdo_mysql/mysql_statement.c     (Arbeitskopie)    
@@ -141,10 +141,12 @@                                                           
                                                                                
        /* (re)bind the parameters */                                           
        if (mysql_stmt_bind_param(S->stmt, S->params) || mysql_stmt_execute(S->stmt)) {
+               /*                                                                     
                if (S->params) {                                                       
                        efree(S->params);                                              
                        S->params = 0;                                                 
                }                                                                      
+               */                                                                     
                pdo_mysql_error_stmt(stmt);                                            
                if (mysql_stmt_errno(S->stmt) == 2057) {                               
                        /* CR_NEW_STMT_METADATA makes the statement unusable */
 [2011-01-14 15:57 UTC] johannes@php.net
Automatic comment from SVN on behalf of johannes
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=307478
Log: - Fix #53551 (PDOStatement execute segfaults for pdo_mysql driver)
 [2011-01-31 10:25 UTC] uw@php.net
-Status: Assigned +Status: Closed
 [2011-01-31 10:25 UTC] uw@php.net
See SVN note
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 18 15:02:26 2014 UTC