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,
               &quoted_key_str, &quoted_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,
               &quoted_key_str, &quoted_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,
         &quoted_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, &quote) == 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



Reply via email to