Menu

#8 sqlite3_finalize() couses segfault

open
nobody
None
5
2008-04-02
2008-04-02
Anonymous
No

Hello, in php_sqlite3_stmt_resource_destruction() sqlite3_finalize() couses segfault if statement was finalized before (i.e. during call of sqlite3_query_close() ), to prevent this double finalizing please add followin code to php_sqlite3_stmt_resource_destruction():

if(me->stmt) {
sqlite3_finalize(me->stmt);
me->stmt = NULL;
}

and to PHP_FUNCTION(sqlite3_query_close):

if(stmt->stmt) {
err = sqlite3_finalize ( stmt->stmt);
stmt->stmt = NULL;
}

Best regards
Dmitri

Discussion

  • Nobody/Anonymous

    Logged In: NO

    following patch fixes this problem and problem with bind parameters in select queries:

    --- php_sqlite3.orig.c Wed Apr 04 16:17:00 2007
    +++ php_sqlite3.c Fri Apr 04 12:20:39 2008
    @@ -118,8 +118,10 @@
    php_sqlite3_stmt_resource_destruction ( zend_rsrc_list_entry *rsrc TSRMLS_DC)
    {
    php_sqlite3_stmt_resource *me = (php_sqlite3_stmt_resource*) rsrc->ptr;
    -
    - sqlite3_finalize(me->stmt);
    + if(me->stmt) {
    + sqlite3_finalize(me->stmt);
    + me->stmt = NULL;
    + }
    efree (me);
    }

    @@ -572,6 +574,7 @@
    ZVAL_TO_STMT (stmt, &z_stmt);

    err = sqlite3_step(stmt->stmt);
    + sqlite3_reset(stmt->stmt);
    if (dofree)
    zend_list_delete(stmt->rsrc_id);

    @@ -759,10 +762,12 @@
    return;

    ZVAL_TO_STMT (stmt, &z_stmt);
    -
    - err = sqlite3_finalize ( stmt->stmt);
    -
    - zend_list_delete(Z_RESVAL_P(z_stmt));
    + err = 0;
    + if(stmt->stmt) {
    + err = sqlite3_finalize ( stmt->stmt);
    + stmt->stmt = NULL;
    + }
    + zend_list_delete(Z_RESVAL_P(z_stmt));

    if (err) RETURN_FALSE ;
    RETURN_TRUE;

     
  • Nobody/Anonymous

    Logged In: NO

    Had the same problem and the patch fixes it.

    Thanks,
    François.

     
  • Nobody/Anonymous

    Logged In: NO

    One question tho: is that part of the patch necessary (if so why)?:

    @@ -572,6 +574,7 @@
    ZVAL_TO_STMT (stmt, &z_stmt);

    err = sqlite3_step(stmt->stmt);
    + sqlite3_reset(stmt->stmt);
    if (dofree)
    zend_list_delete(stmt->rsrc_id);

    François.

     
  • Dmitri Vinogradov

    @François:

    <quote>
    The sqlite3_reset() function is called to reset a prepared statement object back to its initial state, ready to be re-executed...
    </quote>

     
  • Dmitri Vinogradov

    This summarized patch fixes following issues:

    1. double call of sqlite3_finalize()
    2. reuse of prepared statements with bind parameters in select queries bug fixed
    3. corrupted / truncated BLOB values bug fixed
    4. second parameter of sqlite3_create_function() can be any valid php callback, not only string function

    --- php_sqlite3.orig.c Wed Apr 04 15:17:00 2007
    +++ php_sqlite3.c Tue Nov 18 10:51:12 2008
    @@ -92,7 +92,7 @@
    typedef struct
    {
    char* func_name; /* SQL function name */
    - char* cb_name; /* PHP Callback name */
    + zval* cb_name; /* PHP Callback name */
    int cb_num_args; /* # arguments */
    php_sqlite3_resource *me;
    } php_sqlite3_func_t;
    @@ -118,8 +118,10 @@
    php_sqlite3_stmt_resource_destruction ( zend_rsrc_list_entry *rsrc TSRMLS_DC)
    {
    php_sqlite3_stmt_resource *me = (php_sqlite3_stmt_resource*) rsrc->ptr;
    -
    - sqlite3_finalize(me->stmt);
    + if(me->stmt) {
    + sqlite3_finalize(me->stmt);
    + me->stmt = NULL;
    + }
    efree (me);
    }

    @@ -572,6 +574,7 @@
    ZVAL_TO_STMT (stmt, &z_stmt);

    err = sqlite3_step(stmt->stmt);
    + sqlite3_reset(stmt->stmt);
    if (dofree)
    zend_list_delete(stmt->rsrc_id);

    @@ -588,7 +591,10 @@
    {
    int col;
    zval* col_val;
    -
    + const void* blob_val;
    + int blob_len;
    +
    +
    array_init(return_value);

    for (col=0; col < sqlite3_column_count(stmt->stmt); col++)
    @@ -611,8 +617,9 @@
    break;

    case SQLITE_BLOB:
    - ZVAL_STRINGL(col_val, estrdup(sqlite3_column_blob(stmt->stmt, col)),
    - sqlite3_column_bytes(stmt->stmt, col), 1);
    + blob_val = sqlite3_column_blob(stmt->stmt, col);
    + blob_len = sqlite3_column_bytes(stmt->stmt, col);
    + ZVAL_STRINGL(col_val, estrndup(blob_val, blob_len), blob_len, 1);
    break;

    case SQLITE_NULL:
    @@ -759,10 +766,12 @@
    return;

    ZVAL_TO_STMT (stmt, &z_stmt);
    -
    - err = sqlite3_finalize ( stmt->stmt);
    -
    - zend_list_delete(Z_RESVAL_P(z_stmt));
    + err = 0;
    + if(stmt->stmt) {
    + err = sqlite3_finalize ( stmt->stmt);
    + stmt->stmt = NULL;
    + }
    + zend_list_delete(Z_RESVAL_P(z_stmt));

    if (err) RETURN_FALSE ;
    RETURN_TRUE;
    @@ -817,17 +826,12 @@
    zval*** z_cb_params;
    zval** z_param;
    zval* z_retval;
    - zval* z_cb_name;
    int n;
    php_sqlite3_func_t* func;

    func = (php_sqlite3_func_t*) sqlite3_user_data(ctxt);

    - MAKE_STD_ZVAL(z_cb_name);
    - ZVAL_STRING (z_cb_name, func->cb_name, 0);
    -
    -
    /*
    * fill in callback parameters
    */
    @@ -865,12 +869,12 @@
    * now call the user function ...
    */

    - err = call_user_function_ex (CG(function_table), NULL, z_cb_name, &z_retval, nargs, z_cb_params, 0, NULL TSRMLS_CC );
    + err = call_user_function_ex (EG(function_table), NULL, func->cb_name, &z_retval, nargs, z_cb_params, 0, NULL TSRMLS_CC );

    if (err != SUCCESS)
    {
    if (z_retval) zval_dtor(z_retval);
    - sqlite3_result_error(ctxt, "function called failed.", -1);
    + sqlite3_result_error(ctxt, "function call failed.", -1);
    return;
    }

    @@ -905,7 +909,7 @@
    }

    /* }}}
    - {{{ bool sqlite3_create_function(resource sqlite3, string function_name, int nb_args)
    + {{{ bool sqlite3_create_function(resource sqlite3, mixed callback, int nb_args)
    */

    PHP_FUNCTION(sqlite3_create_function)
    @@ -916,32 +920,48 @@
    zval* z_rs;
    char* func_name;
    int func_name_len;
    - char* cb_name;
    - int cb_name_len;
    + zval* callback;
    + char* cbname = NULL;
    int cb_num_args;
    int err;

    if(ZEND_NUM_ARGS() != 4) WRONG_PARAM_COUNT;

    - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"rsls", &z_rs,
    + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"rslz", &z_rs,
    &func_name, &func_name_len,
    &cb_num_args,
    - &cb_name, &cb_name_len)==FAILURE)
    + &callback)==FAILURE)
    return;

    + if (!zend_is_callable(callback, 0, &cbname)) {
    + php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname);
    + efree(cbname);
    + RETURN_FALSE;
    + }
    + efree(cbname);
    +
    +
    ZVAL_TO_S3_HANDLE (me, &z_rs);

    func = (php_sqlite3_func_t*) emalloc (sizeof(php_sqlite3_func_t));

    - func->func_name = estrdup(func_name);
    - func->cb_name = estrdup(cb_name);
    - func->cb_num_args = cb_num_args;
    - func->me = me;
    -
    - err = sqlite3_create_function(me->handle, func_name, cb_num_args, SQLITE_ANY, func, php_sqlite3_user_function_cb, NULL, NULL);
    + err = sqlite3_create_function(
    + me->handle, func_name, cb_num_args,
    + SQLITE_ANY, func, php_sqlite3_user_function_cb, NULL, NULL);

    - if (err == SQLITE_ERROR)
    + if (err == SQLITE_ERROR) {
    RETURN_FALSE;
    + } else {
    +
    +
    + MAKE_STD_ZVAL(func->cb_name);
    + *(func->cb_name) = *callback;
    + zval_copy_ctor(func->cb_name);
    +
    + func->func_name = estrdup(func_name);
    + func->cb_num_args = cb_num_args;
    + func->me = me;
    + }

    RETURN_TRUE;
    }

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.