Edit report at http://bugs.php.net/bug.php?id=53551&edit=1
ID: 53551 Updated by: u...@php.net Reported by: eddawley at gmail dot com Summary: PDOStatement execute segfaults for pdo_mysql driver Status: Assigned Type: Bug Package: PDO related Operating System: Centos 5 PHP Version: 5.3.4 Assigned To: mysql Block user comment: N Private report: N New Comment: 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 */ Previous Comments: ------------------------------------------------------------------------ [2010-12-17 20:58:27] 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' ------------------------------------------------------------------------ [2010-12-17 20:44:00] ka...@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 19:38:02] 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-16 22:58:35] ka...@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-15 22:31:18] 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: ---------------- [...@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: -------------- [...@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 ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/bug.php?id=53551&edit=1