PHP 4.0 Bug #4768: zend_get_parameters_ex() trashes parameters if param_count < ARG_COUNT(ht)
| From: | clcollie at mindspring dot com | Date: | Fri, 02 Jun 2000 07:54:19 +0000 |
| Subject: | PHP 4.0 Bug #4768: zend_get_parameters_ex() trashes parameters if param_count < ARG_COUNT(ht) | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-20022@lists.php.net to get a copy of this message | ||
From: clcollie@mindspring.com
Operating system: Linux (Mandrake 7.0)
PHP version: 4.0 Release Candidate 2
PHP Bug Type: Scripting Engine problem
Bug description: zend_get_parameters_ex() trashes parameters if param_count < ARG_COUNT(ht)
Synopsis:
it appears that zend_get_parameter_array_ex() may corrupt values if called for
param_count < ARG_COUNT(ht)
Background:
im in the process of implementing an ANSI like sscanf() and fscanf(). a common
routine, php_internal_sscanf(), is referenced by both routines to perform the
actual work.
PHPAPI int php_internal_sscanf(char *string,char *format, int ht,int
varstart,zval **return_value)
the prototype for (f|s)scanf() is :
mixed sscanf($string,$format,...)
mixed sscanf($file_handle,$format,...)
(f|s)scanf works in two modes : with and without variables passed by reference.
without variables, it returns an array of elements parsed from the literal
string. this seems to work fine (subject to further testing). when variables
are passed in, the function modifies the variables directly (as in "c").
this is where the issue lies. every time i pass in more than 2 variables, the
value of the first two variables are hosed.
Details:
in PHP_FUNCTION(sscanf) i do the following :
if ((ARG_COUNT(ht) < 2) || (zend_get_parameters_ex(ht,2,&literal,&format)
== FAILURE)) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex( literal );
convert_to_string_ex( format );
php_internal_sscanf( (*literal)->value.str.val,
(*format)->value.str.val,
ht, 2, &return_value );
in php_sscanf_internal, i check the validity of format, then i grab the
all the other parameters as an array from ht :
zval ***args
args = (zval ***)emalloc(ARG_COUNT(ht) * sizeof(zval **));
if (zend_get_parameters_array_ex(ARG_COUNT(ht), args) == FAILURE) {
efree(args);
COMPLAIN_LOUDLY; /* you get the point */
return FAILURE
}
i need to do things in this two-phase this way to allow the internal scanning
routine to do work for both fscanf() and scanf(). actually in my testing, it
does not even reach this far (the validation above it fails on the bogus
values).
Setup:
Linux Mandrake 7.0 running on a Pentium (classic) 166Mhz, 64M.
PHP 4.0.0
'./configure' '--with-apxs' '--enable-calendar'
'--with-gd=shared' '--with-imap'
'--with-mcal=/usr/local/lib' '--with-mysql' '--with-pgsql'
'--enable-trans-sid'
'--enable-wddx' '--enable-sysvshm' '--enable-sysvmem'
'--with-regex=php'
'--with-gdbm' '--with-mhash' '--enable-memory_limit'
'--enable-ftp'
'--with-cybercash' '--with-ldap'
thread safety disabled
allow_call_time_pass_reference on
Analysis :
as far as i can reduce it, the problem seems to be in PHP_FUNCTION(sscanf) with
the zend_get_parameters_ex() function. if only two parameters are passed in,
then all is well. if more parameters are passed than is first retrieved, then
the values assigned to the first two variables are either "", "-1", or
"0" .
i verified this by inserting zend_printf() calls just as after the
convert_to_string_ex() calls to output the values of the string variables.
Postscript:
just to investigate other alternatives, i changed the prototype for php_scanf_internal to :
PHPAPI int php_sscanf_internal(char *string,char *format,int ht,int argCount,zval ***args,
int varStart,pval **return_value);
(note ht is needed to be able to check that all variables are passed by reference)
i made the corresponding changes in PHP_FUNCTION(sscanf) and PHP_FUNCTION(fscanf) to read the
entire param array, getting the appropriate values from there, then passing the array
php_sscanf_internal(). from initial indications, it seems to pass values correctly, backing my
feeling that zend_get_parameters_ex() may be doing something funny.
Bottom Line:
any insight is appreciated. if this is a WAD, then it should be note in the developer
documentation to spare someone else the trouble.
clayton collie
PHP Enthusiast (PHPnut!)