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