|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2004-08-09 11:54 UTC] edwin at rabbito dot org
Description:
------------
When trying to retrieve a date field from an Access 97 database, the actual data returned is different from PHP4 (PHP 4 returns a timestamp, whereas PHP 5 returns a date, ie) 02/04/04 instead of a timestamp). By calling the code (as attached) in PHP5, PHP does not return error gracefully, but crashes.
(seems to be something that is not yet fixed in bug#29392)
Reproduce code:
---------------
$security="C:\access97.mdw";
$user="access";
$password="access";
$dsn="Driver={Microsoft Access Driver (*.mdb)}; DBQ=$database;SystemDB=$security;Uid=$user;Pwd=$password";
$db = new COM("ADODB.Connection");
$db->open($dsn);
$query="SELECT DateField1 FROM [Table1];";
$rs = $db->execute($query);
if (!$rs->EOF()) {
echo strlen($rs->Fields(0)->Value);
}
Expected result:
----------------
Either an error should be returned due to invalid type ($rs->Fields(0)->Value in date type), or the actual length the the date string.
Actual result:
--------------
PHP crashed
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Mon Oct 27 10:00:01 2025 UTC |
I've dug into the COM error reported here and believe I have discovered the issue. The problem is that com_object_cast() (in com_handlers.c) assumes that the readobj and writeobj parameters will never be the same object. That appears to work fine, except when the type conversion request comes from the convert_object_to_type() macro (zend_operators.c, line 264). In this case readobj == writeobj and we end up with an access violation. Since _convert_to_string() uses convert_object_to_type(), and _convert_to_string() is used when you try to strlen() an object, com_object_cast() fails in the code from this bug report. Based on using sxe_object_cast() from the SimpleXML extension as a example, I think that the freeing of the writeobj needs to be the last thing done in the function rather than the first. The attached patch uses that function as a model to move the zval_dtor() call to the end. I also feel that the ZVAL_NULL(writeobj) should move after the CDNO_FETCH(readobj). It seems to work as is, but only becuase CDNO_FETCH() isn't checking that what is passed to it is really an object. I've played with this patch some and it seems to be holding, but I'm looking at this with limited understanding of how the objects are really being passed around so there may be an interaction here I'm not seeing. With the patch applied, this PHP code: echo strlen($rs->Fields(0)->Value), "\n"; echo date("F j, Y", variant_date_to_timestamp($rs->Fields(0)->Value)), "\n"; echo date("F j, Y", variant_date_to_timestamp($rs->Fields(0))), "\n"; echo $rs->Fields(0)->Value, "\n"; echo $rs->Fields(0), "\n"; returns correct values in all five cases (for my test database): 8 January 1, 2001 January 1, 2001 1/1/2001 1/1/2001 --- php-5.0.1\ext\com_dotnet\com_handlers.c Wed Jul 28 19:48:26 2004 +++ com_handlers.c Thu Aug 19 15:18:45 2004 @@ -521,17 +521,17 @@ static int com_object_cast(zval *readobj, zval *writeobj, int type, int should_free TSRMLS_DC) { + zval free_obj; php_com_dotnet_object *obj; VARIANT v; VARTYPE vt = VT_EMPTY; if (should_free) { - zval_dtor(writeobj); + free_obj = *writeobj; } - ZVAL_NULL(writeobj); - obj = CDNO_FETCH(readobj); + ZVAL_NULL(writeobj); VariantInit(&v); if (V_VT(&obj->v) == VT_DISPATCH) { @@ -569,6 +569,9 @@ php_com_zval_from_variant(writeobj, &v, obj->code_page TSRMLS_CC); VariantClear(&v); + if (should_free) { + zval_dtor(&free_obj); + } return SUCCESS; }