Page 1 of 1

-2147483648 is not a valid MySQL result resource

Posted: Sun Mar 14, 2010 3:06 pm
by bad250979day
Please help me

I found PHP warning messages on my PHP script, as follows:

PHP Warning: mysql_num_rows(): -2147483648 is not a valid MySQL result resource in /home/andalabs/mobisuite/mobisuite/store_fronts/sf/handler/mt_sender.php on line 46
PHP Warning: mysql_fetch_array(): -2147483648 is not a valid MySQL result resource in /home/andalabs/mobisuite/mobisuite/store_fronts/sf/handler/mt_sender.php on line 49
PHP Warning: mysql_free_result(): -2147483648 is not a valid MySQL result resource in /home/andalabs/mobisuite/mobisuite/store_fronts/sf/handler/mt_sender.php on line 53

These messages is quite confusing, since the problem is not related to supplied argument.

Could anybody give an explanation about warning messages above?

Re: -2147483648 is not a valid MySQL result resource

Posted: Sun Mar 14, 2010 3:26 pm
by Darhazer
seems like max int overflow problem - for example running 64 bit code on 32 bit application (or more likely using 32 bit extension on 64 bit PHP). Can you post some code anyway?

Re: -2147483648 is not a valid MySQL result resource

Posted: Sun Mar 14, 2010 3:55 pm
by bad250979day
Hi Darhazer,

I edited some code, so we can only see part of the code that causing the problem. So here's the code:

<?php

for (; ; ) {

...

$conn = false;

if (!$conn || !mysql_ping($conn)) {
$conn = mysql_connect(DB_HOST, DB_USERNAME, DB_PASSWORD);
}

if ($conn !== FALSE) {
mysql_select_db(DB_NAME) OR DIE ('Can\'t use database : ' . mysql_error());

$sql = "SELECT
request_id,
session_id,
store_front_channel,
msisdn,
operator_code,
short_code,
message,
request_type
FROM
tbl_content_request
WHERE
request = 1 AND
retry = 0 AND
process = 0
ORDER BY request_date ASC";

$result = mysql_query($sql, $conn);

if ($result !== FALSE && mysql_ping($conn)) {
$rec_count = ((!mysql_ping($conn) || $conn === FALSE) ? 0 : mysql_num_rows($result)); // <== warning message line 46
$data_query = array();

if ($conn !== FALSE && mysql_ping($conn)) {
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { // <== warning message line 49
array_push($data_query, $row);
}
}

if ($conn !== FALSE && mysql_ping($conn)) {
mysql_free_result($result); // <== warning message line 53
}

...
}
}

if ($conn) {
mysql_close($conn);
}


}

?>

FYI, the script runs as service, so i put infinite loop inside the code. It run well for some days, but there's always a time when the script generated warning messages that made server HDD full

Hope you can help me

Re: -2147483648 is not a valid MySQL result resource

Posted: Sun Mar 14, 2010 7:09 pm
by Darhazer
Probably when your application make too many queries, the counter for resource identificators gets overflowed. I'm not sure how resource identificators work actually and how you can reset/reuse the numbrers
Running this on 64 bit server may resolve your issue, but if this is really the problem, then even on 64 bit system you'll run out of identificators at some time...

Re: -2147483648 is not a valid MySQL result resource

Posted: Mon Mar 15, 2010 7:17 pm
by Zlobcho
Hi,

As Maxim said, it's all about integer overflow. Yes, in php, resource type is actually of type long (signed). Below is detailed explanation with code samples (taken from the source);

(for simplicity I will replace the code we're not interested in with ...)

Code: Select all

 
#define IS_RESOURCE 7
 
typedef struct _zval_struct zval;
 
struct _zval_struct {
    /* Variable information */
    zvalue_value value;     /* value */
    ...
    zend_uchar type;    /* active type */
    ...
};
 
typedef union _zvalue_value {
    long lval;                  /* long value */
        ...
} zvalue_value;
 
zval is the basic of all data types in php (long, double, string, resource, object). So all we need to know is that _zval_struct.value is actually zvalue_value structure, which has lval member of type long (signed). Now let's move forward;

Now, mysql_connect actually makes a call to php_mysql_do_connect, so let's just there.

Code: Select all

 
link = (long) index_ptr->ptr;
ptr = zend_list_find(link,&type);   /* check if the link is still there */
if (ptr && (type==le_link || type==le_plink)) {
    zend_list_addref(link);
    Z_LVAL_P(return_value) = link;
    php_mysql_set_default_link(link TSRMLS_CC);
    Z_TYPE_P(return_value) = IS_RESOURCE;
    efree(hashed_details);
    MYSQL_DO_CONNECT_CLEANUP();
    return;
}
...
ZEND_REGISTER_RESOURCE(return_value, mysql, le_link);
 
So here we have our "link" resource casted to (long), then we set the value and the type and register the resource. ZEND_REGISTER_RESOURCE is macros so below is the actual implementation:

Code: Select all

 
#define ZEND_REGISTER_RESOURCE(rsrc_result, rsrc_pointer, rsrc_type)  \
    zend_register_resource(rsrc_result, rsrc_pointer, rsrc_type);
 
ZEND_API int zend_register_resource(zval *rsrc_result, void *rsrc_pointer, int rsrc_type)
{
    int rsrc_id;
 
    rsrc_id = zend_list_insert(rsrc_pointer, rsrc_type);
    
    if (rsrc_result) {
        rsrc_result->value.lval = rsrc_id;
        rsrc_result->type = IS_RESOURCE;
    }
 
    return rsrc_id;
}
 
ZEND_API int zend_list_insert(void *ptr, int type)
{
    int index;
    zend_rsrc_list_entry le;
    TSRMLS_FETCH();
 
    le.ptr=ptr;
    le.type=type;
    le.refcount=1;
 
    index = zend_hash_next_free_element(&EG(regular_list));
 
    zend_hash_index_update(&EG(regular_list), index, (void *) &le, sizeof(zend_rsrc_list_entry), NULL);
    return index;
}
 
Now we have inserted the resource and we have its index (which is signed int). So far we've covered the way zend is creative resource links, now let's see how he validates and retrieves them.

Code: Select all

 
PHP_FUNCTION(mysql_num_rows)
{
    zval *result;
    MYSQL_RES *mysql_result;
    
    ...
    
    ZEND_FETCH_RESOURCE(mysql_result, MYSQL_RES *, &result, -1, "MySQL result", le_result);
    
    /* conversion from int64 to long happing here */
    Z_LVAL_P(return_value) = (long) mysql_num_rows(mysql_result);
    Z_TYPE_P(return_value) = IS_LONG;
}
 
Note, ZEND_FETCH_RESOURCE is macros, below is the implementation:

Code: Select all

 
ZEND_API void *zend_fetch_resource(zval **passed_id TSRMLS_DC, int default_id, char *resource_type_name, int *found_resource_type, int num_resource_types, ...)
{
    int id;
    int actual_resource_type;
    void *resource;
    va_list resource_types;
    int i;
    char *space;
    char *class_name;
 
    if (default_id==-1) { /* use id */
        ... /* id validation done here */
        id = (*passed_id)->value.lval;
    } else {
        id = default_id;
    }
 
    resource = zend_list_find(id, &actual_resource_type);
    if (!resource) {
        if (resource_type_name) {
            class_name = get_active_class_name(&space TSRMLS_CC);
            zend_error(E_WARNING, "%s%s%s(): %d is not a valid %s resource", class_name, space, get_active_function_name(TSRMLS_C), id, resource_type_name);
        }
        return NULL;
    }
        ...
}
 
Ok, its clear what happens here, zend_list_find is not able to find the id in the list;

Code: Select all

 
ZEND_API void *_zend_list_find(int id, int *type TSRMLS_DC)
{
    zend_rsrc_list_entry *le;
 
    if (zend_hash_index_find(&EG(regular_list), id, (void **) &le)==SUCCESS) {
        *type = le->type;
        return le->ptr;
    } else {
        *type = -1;
        return NULL;
    }
}
 
This is what is happening behind the doors. And now little hint about integer overflow. long (signed) can be between LONG_MIN and LONG_MAX, which on 32bit OS has values in range from -2147483647 to 2147483647. (You can try a little experiment, run this with php: var_dump(-2147483680) and see the result)

Sorry for the long post and hope this helps, you need to rethink the way you are doing this. Good luck. :)