Hello,
i try to write an extension for PHP. But I have problems managing the memory correctly.
Every time I try to run the attached script, I get segmentation errors, after the script is finished. I could not work out what the problem is. I guess I am using one of the Zend/PHP API functions wrongly, but even studying the source of the API functions didn’t help me to find my memory problem.
I think I am freeing some memory which I shouldn’t free, ore I pass a zval structure without increasing the refcount where I should do so,..
I hope someone of you more experienced PHP programmers has the time to have a look at my code, I don’t know where to look anymore.
Thx Jan Gerritsen
This is the relevant Code of my extension, the PHP script i use for testing is below. The function which get called first is PHP_FUNCTION(url_quote_data).
static void url_quote_string_wrapper(char * src_str, int src_str_leng,
char ** quoted_str, int * quoted_str_leng)
{ // allocate temp_buffer, O(src_str_leng) == 3 * src_str_leng
char * buffer =
(char *) emalloc( sizeof(char) * (src_str_leng * 3 + 1) ); // Quote special chars
int src_count, dest_count;
for(src_count = dest_count=0; src_count<src_str_leng; ++src_count)
{
switch(src_str[src_count])
{
case '"' :
buffer[dest_count++] = '%';
buffer[dest_count++] = '2';
buffer[dest_count++] = '2';
break;
case '\'' :
buffer[dest_count++] = '%';
buffer[dest_count++] = '2';
buffer[dest_count++] = '7';
break;
case '.' :
buffer[dest_count++] = '%';
buffer[dest_count++] = '2';
buffer[dest_count++] = 'E';
break;
case '/' :
buffer[dest_count++] = '%';
buffer[dest_count++] = '2';
buffer[dest_count++] = 'F';
break;
case '\\' :
buffer[dest_count++] = '%';
buffer[dest_count++] = '5';
buffer[dest_count++] = 'C';
break;
default :
buffer[dest_count++] = src_str[src_count];
break;
}
}// Terminate buffer string buffer[dest_count] = 0;
// Save buffer (*quoted_str) = (char*) safe_estrndup(buffer, dest_count); (*quoted_str_leng) = dest_count;
// Free temporary used memory efree(buffer); }
static void url_quote_data_wrapper(HashTable *src_ht, HashTable *dest_ht, void (*quote_function)(char *, int, char **, int *))
static int rec_counter = 0;
zval **src_ht_entry;
/* Get start postion of the array */ HashPosition pos; zend_hash_internal_pointer_reset_ex(src_ht, &pos);
/* For each element of the array */
while ( zend_hash_get_current_data_ex(src_ht,
(void **)&src_ht_entry, &pos) == SUCCESS)
{
/*
Quote array key
*/
char *key_str = NULL;
uint key_str_len = 0;
ulong key_num = 0;
int quoted_key_str_leng = 0;
char * quoted_key_str = NULL;
switch (zend_hash_get_current_key_ex(src_ht,
&key_str, &key_str_len, &key_num, 0, &pos))
{
case HASH_KEY_IS_STRING:
quote_function(key_str, key_str_len,
"ed_key_str, "ed_key_str_leng);
key_str = NULL;
key_str_len = 0;
break; case HASH_KEY_IS_LONG:
key_str = (char *) emalloc(255);
snprintf(key_str, 255, "%d", key_num);
key_str_len = strlen(key_str) + 1; quote_function(key_str, key_str_len,
"ed_key_str, "ed_key_str_leng);
efree(key_str);
key_str = NULL;
key_str_len = 0;
break; default:
continue;
break;
} /*
Quote array data
*/
zval *quoted_data;
if( (*src_ht_entry)->type == IS_ARRAY )
{
/* It is an array, start recursiv call */
MAKE_STD_ZVAL(quoted_data);
array_init(quoted_data);
rec_counter++;
url_quote_data_wrapper(Z_ARRVAL_PP(src_ht_entry),
Z_ARRVAL_P(quoted_data), quote_function);
rec_counter--; }
else
{
/* Convert data to string and quote it */ SEPARATE_ZVAL(src_ht_entry);
convert_to_string_ex(src_ht_entry); int data_buffer_used;
char * data_buffer;
quote_function(Z_STRVAL_PP(src_ht_entry),
Z_STRLEN_PP(src_ht_entry), &data_buffer,
&data_buffer_used); MAKE_STD_ZVAL(quoted_data);
ZVAL_STRINGL(quoted_data, data_buffer, data_buffer_used, 0);
zval_dtor(*src_ht_entry); // delete seperated zval
} /*
Add data to array
*/
quoted_data->refcount++;
if( zend_hash_add(dest_ht, quoted_key_str, quoted_key_str_leng,
"ed_data, sizeof(zval*), NULL) == FAILURE )
{
zend_error(E_ERROR, "Update of ht failed");
}
efree(quoted_key_str); // Step forward in array
zend_hash_move_forward_ex(src_ht, &pos);
}
}
/* {{{ proto array url_quote_data(array array_to_quote [, bool quote]) */ PHP_FUNCTION(url_quote_data) { int argument_count = ZEND_NUM_ARGS(); if( argument_count != 1 && argument_count != 2 ) { WRONG_PARAM_COUNT; }
zval *array_to_quote;
zend_bool quote;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|b",
&array_to_quote, "e) == FAILURE)
{
RETURN_FALSE;
} // Check if we have to quote, or dequote the array keys and values
void (*quote_function)(char *, int, char **, int *);
if( argument_count == 2 && ! quote )
{
quote_function = url_dequote_string_wrapper;
}
else
{
quote_function = url_quote_string_wrapper;
} // Call quote function
array_init(return_value);
url_quote_data_wrapper(Z_ARRVAL_P(array_to_quote),
Z_ARRVAL_P(return_value), quote_function);
}
/* }}} */
/*****************************************************/ PHP Script
<?php
if(!extension_loaded('url')) {
dl('url.' . PHP_SHLIB_SUFFIX);
}$url = new URL_base();
$data = array(
"aaa\"aaa" => "aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa'aaa" => "aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa.aaa" => "aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa/aaa" => "aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa\\aaa" => "aaa\"aaa'aaa.aaa/aaa\\aaa",
"x" => array (
"aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa\"aaa'aaa.aaa/aaa\\aaa",
"aaa\"aaa'aaa.aaa/aaa\\aaa",
),
"y" => array (
array( "a", "b", "c"),
array( "a", "b", "c"),
array( "a", "b", "c"),
),
"z" => array (
array(
array( "a", "b", "c"),
array( "a", "b", "c"),
array( "a", "b", "c"),
),
array(
array( "a", "b", "c"),
array( "a", "b", "c"),
array( "a", "b", "c"),
),
),
);echo "Call: \n"; $dequoted_data = $url->dequote_data($url->quote_data($data));
echo "\nEnd of PHP script\n"; ?> /*****************************************************/
Output: Call:
End of PHP script Speicherzugriffsfehler (Segmentationfault)
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
