php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #33965 [PATCH] NULL valued output parameter from stored procedures contain corrupt data
Submitted: 2005-08-02 14:01 UTC Modified: 2005-08-06 07:48 UTC
Votes:1
Avg. Score:1.0 ± 0.0
Reproduced:0 of 1 (0.0%)
From: paul dot robinson at groupbc dot com Assigned: fmk (profile)
Status: Closed Package: MSSQL related
PHP Version: 5CVS-2005-08-06 OS: Linux (RHEL 4)
Private report: No CVE-ID: None
 [2005-08-02 14:01 UTC] paul dot robinson at groupbc dot com
Description:
------------
MS SQL Server 2000, FreeTDS 0.63
Output parameters from a stored procedure call contain corrupt data when the result should be NULL. Its particularly noticable for variable length strings as output looks as though it just reads from a random pointer until it find a \0 !

No test is done on whether the output is NULL or not.

Diff below shows proposed change to fix this.
NOTE: This calls a function dbretisnull that is not currently implemented in the FreeTDS package but has been submitted as a proposed change.

19c19
< /* $Id: php_mssql.c,v 1.137.2.9 2005/04/12 17:46:06 fmk Exp $ */
---
> /* $Id: php_mssql.c,v 1.137.2.8 2005/02/25 23:25:33 fmk Exp $ */
324,326d323
< #ifndef HAVE_FREETDS
<       dbwinexit();
< #else
328d324
< #endif
978c974
<       int i, num_rets, type;
---
>       int i, num_rets, type, is_null;
992,1019c988,1022
<                                       switch (type) {
<                                               case SQLBIT:
<                                               case SQLINT1:
<                                               case SQLINT2:
<                                               case SQLINT4:
<                                                       convert_to_long_ex(&bind->zval);
<                                                       /* FIXME this works only on little endian machine !!! */
<                                                       Z_LVAL_P(bind->zval) = *((int *)(dbretdata(mssql_ptr->link,i)));
<                                                       break;
< 
<                                               case SQLFLT4:
<                                               case SQLFLT8:
<                                               case SQLFLTN:
<                                               case SQLMONEY4:
<                                               case SQLMONEY:
<                                               case SQLMONEYN:
<                                                       convert_to_double_ex(&bind->zval);
<                                                       Z_DVAL_P(bind->zval) = *((double *)(dbretdata(mssql_ptr->link,i)));
<                                                       break;
< 
<                                               case SQLCHAR:
<                                               case SQLVARCHAR:
<                                               case SQLTEXT:
<                                                       convert_to_string_ex(&bind->zval);
<                                                       Z_STRLEN_P(bind->zval) = dbretlen(mssql_ptr->link,i);
<                                                       Z_STRVAL_P(bind->zval) = estrndup(dbretdata(mssql_ptr->link,i),Z_STRLEN_P(bind->zval));
<                                                       break;
<                                               /* TODO binary */
---
>                                       /* Test column value for null flag and set value as required */
>                                       is_null = dbretisnull(mssql_ptr->link, i);
>                                       if (is_null) {
>                                               ZVAL_NULL(bind->zval);
>                                       }
>                                       else {
>                                               switch (type) {
>                                                       case SQLBIT:
>                                                       case SQLINT1:
>                                                       case SQLINT2:
>                                                       case SQLINT4:
>                                                               convert_to_long_ex(&bind->zval);
>                                                               /* FIXME this works only on little endian machine !!! */
>                                                               Z_LVAL_P(bind->zval) = *((int *)(dbretdata(mssql_ptr->link,i)));
>                                                               break;
> 
>                                                       case SQLFLT4:
>                                                       case SQLFLT8:
>                                                       case SQLFLTN:
>                                                       case SQLMONEY4:
>                                                       case SQLMONEY:
>                                                       case SQLMONEYN:
>                                                               convert_to_double_ex(&bind->zval);
>                                                               Z_DVAL_P(bind->zval) = *((double *)(dbretdata(mssql_ptr->link,i)));
>                                                               break;
> 
>                                                       case SQLCHAR:
>                                                       case SQLVARCHAR:
>                                                       case SQLTEXT:
>                                                               convert_to_string_ex(&bind->zval);
>                                                               Z_STRLEN_P(bind->zval) = dbretlen(mssql_ptr->link,i);
>                                                               Z_STRVAL_P(bind->zval) = estrndup(dbretdata(mssql_ptr->link,i),Z_STRLEN_P(bind->zval));
>                                                               break;
>                                                       /* TODO binary */
>                                               }

Reproduce code:
---------------
function if_null($out) {
	if(is_null($out)) {	return 'null';	}
	else {	return $out; }
}
$int0out =-1;
$varchar0out = -1;
$conn = mssql_connect (DBSERVER, USER, PASS);
mssql_select_db(DBDATABASE, $conn)
$query = mssql_init('usp_output_test', $conn);
mssql_bind($query, "@int0out", $int0out, SQLINT4, true, false);
mssql_bind($query, "@varchar0out", $varchar0out, SQLVARCHAR, true, false, 10);
$myset = mssql_execute($query);
if($line = mssql_fetch_array($myset)) {
	print "there was a result set!";
}
else {
	print "no resultset";
}
print if_null($int0out). " --int0out output</br>";
print if_null($varchar0out). " --varchar0out output</br>";		


Expected result:
----------------
null --int0out output
null --varchar0out output

Actual result:
--------------
null --int0out output
82$&#9508;,&#9565;d&#9829;n&#9555; --varchar0out output

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-08-02 18:34 UTC] sniper@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip


 [2005-08-02 18:50 UTC] paul dot robinson at groupbc dot com
Patches suggested are against Snapshot: php5-STABLE-200508021038.tar.gz

Although I haven't actually built an example using that snapshot today I have looked at the code which since it is unchanged would seem to exhibit the same problem.
 [2005-08-02 19:12 UTC] sniper@php.net
Provide patches in unified diff format (diff -u) and against PHP CVS HEAD (we're not likely to release any 5.0.x versions anymore). Put the diffs somewhere were people can download it and put the URLs here.




 [2005-08-05 16:57 UTC] paul dot robinson at groupbc dot com
Patch against php_mssql.c CVS version 1.149 can be found here:
http://cobweb.businesscollaborator.com/pdr/33965.patch

Rationale behind the patch was discussed here:
http://lists.ibiblio.org/pipermail/freetds/2005q3/018851.html
This has been verified to work with FreeTDS releases _after_ 0.63.
Without this patch output parameters that should be null will simply read random data.
 [2005-08-06 01:30 UTC] sniper@php.net
Frank, can you check this out?

 [2005-08-06 07:48 UTC] fmk@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 17:01:58 2024 UTC