php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62707 nextRowset causes segfault when using libmysql
Submitted: 2012-07-31 19:09 UTC Modified: 2020-12-11 09:54 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (50.0%)
From: keithm at aoeex dot com Assigned: nikic (profile)
Status: Closed Package: PDO MySQL
PHP Version: 5.4.5 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: keithm at aoeex dot com
New email:
PHP Version: OS:

 

 [2012-07-31 19:09 UTC] keithm at aoeex dot com
Description:
------------
Using PDO with the MySQL driver built using libmysql

pdo_mysql
PDO Driver for MySQL => enabled
Client API version => 5.5.25a


After calling a stored procedure I have the following lines to eat up the 
results before running more queries:

do { try { $queueStmt->fetch(); } catch (Exception $e){} } while ($queueStmt-
>nextRowset());

When using libmysql this results in a segfault when calling nextRowset.



Test script:
---------------
<?php

$db = new PDO('mysql:host=localhost;dbname=bugtest', 'bugtest', 'bugtest', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$sql = 'DROP TABLE IF EXISTS testtbl';
$db->exec($sql);

$sql = 'DROP PROCEDURE IF EXISTS testproc';
$db->exec($sql);

$sql = 'CREATE TABLE testtbl (pk INT NOT NULL AUTO_INCREMENT PRIMARY KEY, data VARCHAR(10), nextrun DATETIME)';
$db->exec($sql);

$sql = "INSERT INTO testtbl (data, nextrun) VALUES ('asdf', UTC_TIMESTAMP()),('defg', UTC_TIMESTAMP()),('higk', UTC_TIMESTAMP()),('lmnop', UTC_TIMESTAMP())";
$db->exec($sql);

$sql = 'CREATE PROCEDURE testproc() NOT DETERMINISTIC MODIFIES SQL DATA BEGIN DECLARE nextId INT; SELECT pk INTO nextId FROM testtbl WHERE nextrun=(SELECT MIN(nextrun) FROM testtbl) LIMIT 1; UPDATE testtbl SET nextrun=UTC_TIMESTAMP()+INTERVAL 1 DAY WHERE pk=nextId; SELECT * FROM testtbl WHERE pk=nextId; END';
$db->exec($sql);

$queueSql = 'CALL testproc()';
$queueStmt = $db->prepare($queueSql);

$queueStmt->execute();
$row=$queueStmt->fetch(PDO::FETCH_ASSOC);
do { try { $queueStmt->fetch(); } catch (Exception $e){} } while ($queueStmt->nextRowset());

echo "Success";


Expected result:
----------------
Success


Actual result:
--------------
Segmentation fault


Patches

pdo_mysql_nextRowset.patch (last revision 2012-07-31 19:10 UTC by keithm at aoeex dot com)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-08-01 02:03 UTC] aharvey@php.net
-Assigned To: +Assigned To: mysql
 [2012-10-26 09:27 UTC] uw@php.net
Here's a proper test:

--TEST--
Bug #62707 (nextRowset causes segfault when using libmysql)
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();

$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
	die(sprintf("skip Cannot determine MySQL Server version\n"));

$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 50000)
	die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
		$matches[0], $matches[1], $matches[2], $version));
?>
--FILE--
<?php
require dirname(__FILE__) . '/mysql_pdo_test.inc';
$db = MySQLPDOTest::factory();

$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$db->exec('DROP PROCEDURE IF EXISTS p');
$db->exec('CREATE PROCEDURE p() BEGIN SELECT 1 AS "one"; SET @myvar = 1; SELECT 2 AS "two", 3 AS "three"; END');

$stmt = $db->query("CALL p()");
do {
	var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} while ($stmt->nextRowset());
var_dump($stmt->errorInfo());

$stmt = $db->query('SELECT 4 AS "four"');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
var_dump($stmt->errorInfo());
print "done!";
?>
--EXPECTF--
array(1) {
  [0]=>
  array(1) {
    ["one"]=>
    int(1)
  }
}
array(1) {
  [0]=>
  array(2) {
    ["two"]=>
    int(2)
    ["three"]=>
    int(3)
  }
}
array(3) {
  [0]=>
  string(5) "00000"
  [1]=>
  NULL
  [2]=>
  NULL
}
array(1) {
  [0]=>
  array(1) {
    ["four"]=>
    int(4)
  }
}
array(3) {
  [0]=>
  string(5) "00000"
  [1]=>
  NULL
  [2]=>
  NULL
}
done!
 [2012-10-26 09:31 UTC] uw@php.net
Your patch will unveil a leak. Workaround: don't use PDO, SP and libmysql. Go mysqlnd.
 [2014-01-01 12:36 UTC] felipe@php.net
-Package: PDO related +Package: PDO MySQL
 [2017-10-24 08:07 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: mysql +Assigned To:
 [2020-12-11 09:54 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 [2020-12-11 09:54 UTC] nikic@php.net
The segfault has already been fixed earlier, the leak is addressed in https://github.com/php/php-src/commit/c927c831e65cdf6aa6152d49820e58e6288a5dcc.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Dec 22 02:01:28 2024 UTC