# Segmentationfault in PHP extension

- Thread: https://externals.io/message/12649
- Original archive: https://news-web.php.net/php.internals/12649
- Started by Jan Gerritsen on 2004-09-08T14:42:59+00:00
- Messages: 1
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #12649 — Jan Gerritsen — 2004-09-08T14:42:59+00:00

URL: https://externals.io/message/12649#12649

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)
