sqlite3_finalize() couses segfault
Status: Alpha
Brought to you by:
bfleisch
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
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;
Logged In: NO
Had the same problem and the patch fixes it.
Thanks,
François.
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.
@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>
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;
}