重复使用PDO语句var会导致进程崩溃


Reusing PDO statement var crashes the process

我正在重用一个变量来存储两个不同的PDO-mysql语句:

$stmt=$dbh->prepare("SELECT ....");   
$stmt->execute();
$stmt=$dbh->prepare("UPDATE ....");
//crash here: 
//*** Error in `/opt/lampp/bin/httpd': free(): invalid pointer: 0xf4a028dc ***
//*** Error in `/opt/lampp/bin/httpd': free(): invalid pointer: 0xf4a028dc ***
//[Mon Jun 03 19:53:48.691674 2013] [core:notice] [pid 20249] AH00052: child pid 25933 exit //signal Aborted (6)
//[Mon Jun 03 19:53:48.691727 2013] [core:notice] [pid 20249] AH00052: child pid 25952 exit //signal Aborted (6)

但如果我使用$stmt2=$dbh->prepare("UPDATE…."(;没有发生任何奇怪的事情,语句执行良好。如果我启用准备模拟,它也不会有问题:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,true);

在执行第一条语句后,我尝试了$stmt->closeCursor()unset($stmt)(以及它们两者(,产生了相同的崩溃。我使用的是PHP 5.4.7。为什么会发生这种情况?这是一个bug还是一个非常奇怪的功能?

[UPDATE]我从examplep切换到OpenSUSE 12.3默认Apache(2.2.22(和PHP(5.3.17(,仍然得到相同的错误,但有更详细的转储日志:http://paste2.org/d0BtdOHI

[UPDATE2]我也确认过,当使用MySQL 5.5.27而不是MariaDB 5.5.29作为服务器时会发生这种情况,所以它与我的脚本完全融合,而且非常通用(我也会尝试使用centos虚拟机,以防我的发行版出现一些与glibc相关的问题…(,在不同版本的apache、MySQL和php中都会发生,但仍然不知道原因是什么。。。

[UPDATE3]看起来CentOS6.4比它好得多,让我可以毫无问题地运行脚本,而且由于它是我在生产中使用的,我想没有什么可担心的。不管怎样,我真的很想知道这里发生了什么。。。

我对这次延迟更新表示歉意,但我在PDO(Sybase(方面也遇到了类似的问题,我可以确认,绝对应该避免在不取消设置或设置为null的情况下重新使用语句变量。

在PHP中,每当我们覆盖一个变量值时,它都会首先创建新的变量,然后替换并销毁旧的值。在大多数情况下,这不是问题(除了为分配一个变量花费双倍的内存之外(,但对于语句来说,这是完全不同的,因为它在创建第二个语句时不会关闭第一个语句或光标,而且一些数据库驱动程序无法很好地处理同一PDO连接中的多个语句。

根据您使用的驱动程序,PDOStatement::closeCursor()可能无法关闭该语句,因此问题仍然存在(位于http://www.php.net/manual/en/pdostatement.closecursor.php我们可以看到它取决于驱动程序,否则它将使用不关闭语句的PDO默认值(。

因此,在这种情况下,PDO::prepare()之间的unset()会产生所有差异:

$stmt=$dbh->prepare("SELECT ....");   
$stmt->execute();
unset($stmt); // or $stmt = null; --> statement is destroyed at PDO
$stmt=$dbh->prepare("UPDATE ....");