ID:               47712
 Updated by:       johan...@php.net
 Reported By:      ninzya at inbox dot lv
-Status:           Open
+Status:           Assigned
 Bug Type:         MySQL related
 Operating System: Windows XP
 PHP Version:      5.3.0RC2
-Assigned To:      
+Assigned To:      mysql


Previous Comments:
------------------------------------------------------------------------

[2009-05-12 09:42:13] ninzya at inbox dot lv

This bug is still present in PHP 5.3.0RC2 and is critical to me.

------------------------------------------------------------------------

[2009-04-19 12:04:11] ninzya at inbox dot lv

Changed bug summary.

My configuration:
  Apache 2.2,
  PHP 5.3.0RC1 as module,
  Windows XP SP3,
  MySQL community server 5.1.33

Bug being hit during high concurrency running apache benchmark: "ab -c
30 -n 10000". See previous posts for details.

------------------------------------------------------------------------

[2009-04-12 15:08:30] ninzya at inbox dot lv

Please excuse me for the delay. I have been figuring out what's the
cause of this bug and finally i have something to come up with.

The problem is in mysql_free_result function. Not in itself, but it's
behavior has changed. Consider the following example from the PHP manual
on mysql_free_result:

Example #1 A mysql_free_result() example
<?php
$result = mysql_query("SELECT id,email FROM people WHERE id = '42'");
if (!$result) {
    echo 'Could not run query: ' . mysql_error();
    exit;
}
/* Use the result, assuming we're done with it afterwards */
$row = mysql_fetch_assoc($result);

/* Now we free up the result and continue on with our script */
mysql_free_result($result);

echo $row['id'];
echo $row['email'];
?>

This code with PHP 5.3.0 with mysqlnd will now fail under high
concurrency, because mysql_free_result will affect $row variable and
allow another threads to use it's zval to store data. I suspect that
mysql_free_result marks the referenced by $row data as 'free' and
another threads pick that zval up and work with it. As soon as you
release result, another thread may corrupt $row variable. Test this
example under high concurrency and you will get different values for
$row['id'] and $row['email']. Run 10000 req. test and some of them will
fail to produce correct output.

In my framework i use mysql_free_result before referencing last fetched
row of result set very often, that's why i hit this bug 'randomly'.

I have another example i just tested, this is part of my framework. The
idea is the same - mysql_free_result is being called before actually
using fetched data array.

  $con =mysql_pconnect( 'localhost', 'root', '');
  mysql_select_db( 'ewe10');
  $q =mysql_query( $sql ='SELECT id, title, keywords, descr,
template_id, `title`, `keywords`, `descr`, `template_id`
            FROM pages
          WHERE node_id =11
            AND alt_name =\'welcome\'
          LIMIT 0, 1;', $con);
  $row =mysql_fetch_assoc( $q);
  mysql_free_result( $q);
  
  if( $row['id'] ===null || $row['template_id'] !=8567 || $row['title']
!='My test page' || $row['keywords'] !='asdasd' || $row['descr']
!='asdasd') {
    trigger_error( 'FAIL!', E_USER_WARNING);
    trigger_error( 'SQL: ' .$sql, E_USER_WARNING);
    ob_start();
    var_dump( $row);
    trigger_error( ob_get_clean(), E_USER_WARNING);
    die('NOT OK');
  }

  die('OK');

SQL for the table:

CREATE TABLE  `ewe10`.`pages` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'unique page
id',
  `node_id` int(10) unsigned NOT NULL COMMENT 'node id in which this
page is',
  `title` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
COMMENT 'page title',
  `keywords` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
COMMENT 'page keywords',
  `descr` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT
'page description',
  `template_id` int(10) unsigned DEFAULT NULL COMMENT 'template this
page is using (if NULL, template was deleted from database and this page
is stored as a backup)',
  `type` enum('MAIN','PAGE') CHARACTER SET latin1 NOT NULL DEFAULT
'PAGE' COMMENT 'page type',
  `alt_name` varchar(45) CHARACTER SET latin1 NOT NULL COMMENT 'page
alternative name',
  `date_add` datetime NOT NULL COMMENT 'when page was added',
  PRIMARY KEY (`id`),
  UNIQUE KEY `NODE_ID_ALT_NAME` (`node_id`,`alt_name`) USING BTREE,
  KEY `FK_pages_templates` (`template_id`),
  KEY `TYPE` (`type`),
  KEY `FK_pages_map` (`node_id`),
  KEY `DATE_ADD` (`date_add`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED;

the only row in this table is shown on the screenshot i referenced in
previous report.

To address the issue more quickly, i would like to give you a hint -
after calling mysql_free_result there is no possibility to fetch any
more rows, so there's nothing to worry about mysql_fetch_*(), but there
is possibility that the last fetched row may be referenced. This means -
even if mysql_free_result was called, last fetched row must remain
locked in mysqlnd internal zval cache until the variable is
implicitly/explicitly unset.

------------------------------------------------------------------------

[2009-04-07 13:21:59] johan...@php.net

Can you give me some more details about your system and the
configuration, please.

I spent some time with load testing different configurations now using
mysqlnd, pconnects, and PHP's thread-safe mode and wasn't able to
reproduce this issue.

Maybe even try to come up with the shortest script possible showing the
issue ...

------------------------------------------------------------------------

[2009-03-25 12:24:45] ninzya at inbox dot lv

I guess i can not switch between libmysql and mysqlnd in PHP 5.3. I
have no tools to compile PHP myself with the proper library. If you know
where i can find PHP 5.3RC1 with libmysql, i would test it out right
away.

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/47712

-- 
Edit this bug report at http://bugs.php.net/?id=47712&edit=1

Reply via email to