ID: 48745 Updated by: theta...@php.net Reported By: theta...@php.net Status: Feedback Bug Type: MySQL related Operating System: Solaris 10 x86 PHP Version: 5.3.0 Assigned To: mysql New Comment:
Here is code to reproduce the bug, it crashes CLI, too: Just create any database and a table in mysql and run this code on it: the problematic function is mysql_list_fields() which is deprecated and does no longer seem to work correct with mysql_field_*() functions. After I cahnged the code in the Contenido database abstraction to instead create a dummy query (select * from table limit 1), like it was done in the Contenido database code for mysqli, it works also with mysql. Maybe, if mysqlnd does not support this, mysql_list_fields() should simply do the same dummy command. <?php $res = array(); mysql_connect('localhost', 'contenido', 'contenido'); $id = mysql_list_fields('contenido', 'con_data'); $count = @mysql_num_fields($id); for ($i=0; $i<$count; $i++) { $res[$i]["table"] = @mysql_field_table ($id, $i); $res[$i]["name"] = @mysql_field_name ($id, $i); $res[$i]["type"] = @mysql_field_type ($id, $i); $res[$i]["len"] = @mysql_field_len ($id, $i); $res[$i]["flags"] = @mysql_field_flags ($id, $i); } mysql_free_result($id); print_r($res); ?> Previous Comments: ------------------------------------------------------------------------ [2009-06-30 18:11:17] theta...@php.net Hi Johannes, I am still working on a simple test script. But what I can say is, that when I changed Contenido's config to use mysqli, it does not crash anymore. I found the place where the mysql_field_table is called, but I cannot see any problems there (this is from the included conlib): /* public: return table metadata */ function metadata($table = "", $full = false) { $count = 0; $id = 0; $res = array(); /* * Due to compatibility problems with Table we changed the behavior * of metadata(); * depending on $full, metadata returns the following values: * * - full is false (default): * $result[]: * [0]["table"] table name * [0]["name"] field name * [0]["type"] field type * [0]["len"] field length * [0]["flags"] field flags * * - full is true * $result[]: * ["num_fields"] number of metadata records * [0]["table"] table name * [0]["name"] field name * [0]["type"] field type * [0]["len"] field length * [0]["flags"] field flags * ["meta"][field name] index of field named "field name" * This last one could be used if you have a field name, but no index. * Test: if (isset($result['meta']['myfield'])) { ... */ // if no $table specified, assume that we are working with a query // result if ($table) { $this->connect(); $id = @mysql_list_fields($this->Database, $table); if (!$id) { $this->halt("Metadata query failed."); return false; } } else { $id = $this->Query_ID; if (!$id) { $this->halt("No query specified."); return false; } } $count = @mysql_num_fields($id); // made this IF due to performance (one if is faster than $count if's) if (!$full) { for ($i=0; $i<$count; $i++) { $res[$i]["table"] = @mysql_field_table ($id, $i); $res[$i]["name"] = @mysql_field_name ($id, $i); $res[$i]["type"] = @mysql_field_type ($id, $i); $res[$i]["len"] = @mysql_field_len ($id, $i); $res[$i]["flags"] = @mysql_field_flags ($id, $i); } } else { // full $res["num_fields"]= $count; for ($i=0; $i<$count; $i++) { $res[$i]["table"] = @mysql_field_table ($id, $i); $res[$i]["name"] = @mysql_field_name ($id, $i); $res[$i]["type"] = @mysql_field_type ($id, $i); $res[$i]["len"] = @mysql_field_len ($id, $i); $res[$i]["flags"] = @mysql_field_flags ($id, $i); $res["meta"][$res[$i]["name"]] = $i; } } // free the result only if we were called on a table if ($table) { @mysql_free_result($id); } return $res; } The same code in the other mysqli looks like this and works: /* public: return table metadata */ function metadata($table = "", $full = false) { global $mysqli_type; $count = 0; $id = 0; $res = array (); /* * Due to compatibility problems with Table we changed the behavior * of metadata(); * depending on $full, metadata returns the following values: * * - full is false (default): * $result[]: * [0]["table"] table name * [0]["name"] field name * [0]["type"] field type * [0]["len"] field length * [0]["flags"] field flags * * - full is true * $result[]: * ["num_fields"] number of metadata records * [0]["table"] table name * [0]["name"] field name * [0]["type"] field type * [0]["len"] field length * [0]["flags"] field flags * ["meta"][field name] index of field named "field name" * This last one could be used if you have a field name, but no index. * Test: if (isset($result['meta']['myfield'])) { ... */ // if no $table specified, assume that we are working with a query // result if ($table) { $this->connect(); $id = mysqli_query($this->Link_ID, sprintf("SELECT * FROM %s LIMIT 1", $table)); if (!$id) { $this->halt("Metadata query failed."); return false; } } else { $id = $this->Query_ID; if (!$id) { $this->halt("No query specified."); return false; } } $count = mysqli_num_fields($id); // made this IF due to performance (one if is faster than $count if's) if (!$full) { for ($i = 0; $i < $count; $i ++) { $finfo = mysqli_fetch_field($id); $res[$i]["table"] = $finfo->table; $res[$i]["name"] = $finfo->name; $res[$i]["type"] = $mysqli_type[$finfo->type]; $res[$i]["len"] = $finfo->max_length; $res[$i]["flags"] = $finfo->flags; } } else { // full $res["num_fields"] = $count; for ($i = 0; $i < $count; $i ++) { $finfo = mysqli_fetch_field($id); $res[$i]["table"] = $finfo->table; $res[$i]["name"] = $finfo->name; $res[$i]["type"] = $finfo->type; $res[$i]["len"] = $finfo->max_length; $res[$i]["flags"] = $finfo->flags; $res["meta"][$res[$i]["name"]] = $i; } } // free the result only if we were called on a table if ($table) { mysqli_free_result($id); } return $res; } You can download the whole project Contenido from www.contenido.org (it is quite famous in Germany). Just install and try to login using the default setting (mysql database extension) and mysqlnd installed. Uwe ------------------------------------------------------------------------ [2009-06-30 17:57:31] johan...@php.net Thank you for this bug report. To properly diagnose the problem, we need a short but complete example script to be able to reproduce this bug ourselves. A proper reproducing script starts with <?php and ends with ?>, is max. 10-20 lines long and does not require any external resources such as databases, etc. If the script requires a database to demonstrate the issue, please make sure it creates all necessary tables, stored procedures etc. Please avoid embedding huge scripts into the report. ------------------------------------------------------------------------ [2009-06-30 17:34:58] theta...@php.net During analyzing the core dump, I found the following: (gdb) print mysql_result $5 = (MYSQLND_RES *) 0x0 This is NULL, so ZEND_FETCH_RESOURCE(mysql_result, MYSQL_RES *, &result, -1, "MySQL result", le_result) did not work. Maybe this is the problem? ------------------------------------------------------------------------ [2009-06-30 17:14:14] theta...@php.net I saved the core dump and may supply other variable printouts if needed. Sorry, that I did not found that bug during my RC tests. ------------------------------------------------------------------------ [2009-06-30 17:08:41] theta...@php.net Description: ------------ Installed PHP 5.3 today on our Solaris server running with NSAPI as SAPI module (which is not the problem here). Our test environment with some applications like MediaWiki and our own PHP scripts worked as exspected. We are using the new mysqlnd, because under solaris 10 with Blastwave mysql libs you have problems with compiling (libs are 32/64 bit dual, mysql_config only return 64 bit params, php should be compiled as 32bit, see my php_dev mail after RC4). Mysqlnd works super, mediawiki runs much faster than before. With one application, which was not tested before, we have a problem. The content managment system Contenido 4.8.12 (www.condenido.org) works in the frontend without problem, so the website is running, but the backend crashes PHP with an SIGSEGV. The stacktrace is attached. Contenido uses the old mysql extension (which also uses mysqlnd). Reproduce code: --------------- I do not exectly know at which portion of contenido's code it crashes. It seems that Z_STRLEN_P(return_value) = strlen(mysql_field->table) produces a sigsegv (mysql_field->table == NULL): Expected result: ---------------- It should not crash the webserver process. Actual result: -------------- Program terminated with signal 11, Segmentation fault. #0 0xfc3925e2 in php_mysql_field_info (ht=0, return_value=0xa5b157c, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1, tsrm_ls=0xa61f228, entry_type=2) at /pangaea/install/php-5.3.0/ext/mysql/php_mysql.c:2410 2410 Z_STRLEN_P(return_value) = strlen(mysql_field->table); (gdb) where #0 0xfc3925e2 in php_mysql_field_info (ht=0, return_value=0xa5b157c, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1, tsrm_ls=0xa61f228, entry_type=2) at /pangaea/install/php-5.3.0/ext/mysql/php_mysql.c:2410 #1 0xfc56ce5d in zend_do_fcall_common_helper_SPEC (execute_data=0xa406f20, tsrm_ls=0xa1315e0) at /pangaea/install/php-5.3.0/Zend/zend_vm_execute.h:313 #2 0xfc56bce2 in execute (op_array=0xa511654, tsrm_ls=0xa1315e0) at /pangaea/install/php-5.3.0/Zend/zend_vm_execute.h:104 #3 0xfc54a103 in zend_execute_scripts (type=8, tsrm_ls=0xa1315e0, retval=0x0, file_count=3) at /pangaea/install/php-5.3.0/Zend/zend.c:1188 #4 0xfc4f5562 in php_execute_script (primary_file=0xebbe7cb8, tsrm_ls=0xa1315e0) at /pangaea/install/php-5.3.0/main/main.c:2196 #5 0xfc5d5916 in php5_execute (pb=0x82efe08, sn=0x9b9939c, rq=0x9b99414) at /pangaea/install/php-5.3.0/sapi/nsapi/nsapi.c:1040 #6 0xfecfb147 in func_exec_str () from /pangaea/webserver70/lib/libns-httpd40.so #7 0xfecfbd2a in INTfunc_exec_directive () from /pangaea/webserver70/lib/libns-httpd40.so #8 0xfed009d6 in INTservact_service () from /pangaea/webserver70/lib/libns-httpd40.so #9 0xfed01a39 in INTservact_handle_processed () from /pangaea/webserver70/lib/libns-httpd40.so #10 0xfed5e358 in __1cLHttpRequestUUnacceleratedRespond6M_v_ () from /pangaea/webserver70/lib/libns-httpd40.so #11 0xfed5d5ba in __1cLHttpRequestNHandleRequest6MpnGnetbuf_I_i_ () from /pangaea/webserver70/lib/libns-httpd40.so #12 0xfed5be90 in __1cNDaemonSessionDrun6M_v_ () from /pangaea/webserver70/lib/libns-httpd40.so #13 0xfeb861fc in ThreadMain () from /pangaea/webserver70/lib/libnsprwrap.so #14 0xfe0bb6c9 in _pt_root () from /pangaea/webserver70/lib/libnspr4.so #15 0xfd37fd36 in _thr_setup () from /lib/libc.so.1 #16 0xfd380020 in L3_doit () from /lib/libc.so.1 #17 0xfb2d0400 in ?? () #18 0x00000000 in ?? () (gdb) print *mysql_field $2 = {name = 0x0, org_name = 0x0, table = 0x0, org_table = 0x0, db = 0x0, catalog = 0x0, def = 0x0, length = 0, max_length = 0, name_length = 0, org_name_length = 0, table_length = 0, org_table_length = 0, db_length = 0, catalog_length = 0, def_length = 0, flags = 0, decimals = 0, charsetnr = 0, type = MYSQL_TYPE_DECIMAL, root = 0x0, root_len = 0} ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=48745&edit=1