From e7dc7826f19bf96483b019cda89639faebce6ed1 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Fri, 6 Oct 2023 18:57:57 +0100 Subject: [PATCH 1/2] ext/sqlite3: Use new F ZPP modifier --- ext/sqlite3/sqlite3.c | 81 +++++++++---------- ...3_trampoline_create_aggregate_no_leak.phpt | 80 ++++++++++++++++++ ...e3_trampoline_createcollation_no_leak.phpt | 44 ++++++++++ ...te3_trampoline_createfunction_no_leak.phpt | 45 +++++++++++ ...ite3_trampoline_setauthorizer_no_leak.phpt | 41 ++++++++++ 5 files changed, 248 insertions(+), 43 deletions(-) create mode 100644 ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt create mode 100644 ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt create mode 100644 ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt create mode 100644 ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_no_leak.phpt diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index c24a63cc88a4..444b7150af88 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -44,6 +44,13 @@ static int php_sqlite3_compare_stmt_zval_free(php_sqlite3_free_list **free_list, RETURN_THROWS(); \ } +#define SQLITE3_CHECK_INITIALIZED_FREE_TRAMPOLINE(db_obj, member, class_name, trampoline_fcc) \ + if (!(db_obj) || !(member)) { \ + zend_release_fcall_info_cache((trampoline_fcc)); \ + zend_throw_error(NULL, "The " #class_name " object has not been correctly initialised or is already closed"); \ + RETURN_THROWS(); \ + } + #define SQLITE3_CHECK_INITIALIZED_STMT(member, class_name) \ if (!(member)) { \ zend_throw_error(NULL, "The " #class_name " object has not been correctly initialised or is already closed"); \ @@ -942,13 +949,16 @@ PHP_METHOD(SQLite3, createFunction) zend_long flags = 0; db_obj = Z_SQLITE3_DB_P(object); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sf|ll", &sql_func, &sql_func_len, &fci, &fcc, &sql_func_num_args, &flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sF|ll", &sql_func, &sql_func_len, &fci, &fcc, &sql_func_num_args, &flags) == FAILURE) { + zend_release_fcall_info_cache(&fcc); RETURN_THROWS(); } - SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3) + SQLITE3_CHECK_INITIALIZED_FREE_TRAMPOLINE(db_obj, db_obj->initialised, SQLite3, &fcc); if (!sql_func_len) { + /* TODO Add warning/ValueError that name cannot be empty? */ + zend_release_fcall_info_cache(&fcc); RETURN_FALSE; } @@ -956,13 +966,6 @@ PHP_METHOD(SQLite3, createFunction) if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, flags | SQLITE_UTF8, func, php_sqlite3_callback_func, NULL, NULL) == SQLITE_OK) { func->func_name = estrdup(sql_func); - - if (!ZEND_FCC_INITIALIZED(fcc)) { - zend_is_callable_ex(&fci.function_name, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL); - /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal - * with it outselves. It is important that it is not refetched on every call, - * because calls may occur from different scopes. */ - } zend_fcc_dup(&func->func, &fcc); func->argc = sql_func_num_args; @@ -972,6 +975,7 @@ PHP_METHOD(SQLite3, createFunction) RETURN_TRUE; } efree(func); + zend_release_fcall_info_cache(&fcc); RETURN_FALSE; } @@ -990,14 +994,19 @@ PHP_METHOD(SQLite3, createAggregate) zend_long sql_func_num_args = -1; db_obj = Z_SQLITE3_DB_P(object); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sff|l", &sql_func, &sql_func_len, &step_fci, &step_fcc, &fini_fci, &fini_fcc, &sql_func_num_args) == FAILURE) { - RETURN_THROWS(); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sFF|l", &sql_func, &sql_func_len, &step_fci, &step_fcc, &fini_fci, &fini_fcc, &sql_func_num_args) == FAILURE) { + goto error; } - SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3) + /* Cannot use SQLITE3_CHECK_INITIALIZED_FREE_TRAMPOLINE() as we have 2 FCCs */ + if (!db_obj || !db_obj->initialised) { + zend_throw_error(NULL, "The SQLite3 object has not been correctly initialised or is already closed"); + goto error; + } if (!sql_func_len) { - RETURN_FALSE; + /* TODO Add warning/ValueError that name cannot be empty? */ + goto error; } func = (php_sqlite3_func *)ecalloc(1, sizeof(*func)); @@ -1005,19 +1014,7 @@ PHP_METHOD(SQLite3, createAggregate) if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, SQLITE_UTF8, func, NULL, php_sqlite3_callback_step, php_sqlite3_callback_final) == SQLITE_OK) { func->func_name = estrdup(sql_func); - if (!ZEND_FCC_INITIALIZED(step_fcc)) { - /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal - * with it outselves. It is important that it is not refetched on every call, - * because calls may occur from different scopes. */ - zend_is_callable_ex(&step_fci.function_name, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &step_fcc, NULL); - } zend_fcc_dup(&func->step, &step_fcc); - if (!ZEND_FCC_INITIALIZED(fini_fcc)) { - /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal - * with it outselves. It is important that it is not refetched on every call, - * because calls may occur from different scopes. */ - zend_is_callable_ex(&fini_fci.function_name, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fini_fcc, NULL); - } zend_fcc_dup(&func->fini, &fini_fcc); func->argc = sql_func_num_args; @@ -1028,6 +1025,14 @@ PHP_METHOD(SQLite3, createAggregate) } efree(func); + error: + if (ZEND_FCC_INITIALIZED(step_fcc)) { + zend_release_fcall_info_cache(&step_fcc); + } + if (ZEND_FCC_INITIALIZED(fini_fcc)) { + zend_release_fcall_info_cache(&fini_fcc); + } + RETURN_FALSE; } /* }}} */ @@ -1044,13 +1049,15 @@ PHP_METHOD(SQLite3, createCollation) zend_fcall_info_cache fcc; db_obj = Z_SQLITE3_DB_P(object); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &collation_name, &collation_name_len, &fci, &fcc) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sF", &collation_name, &collation_name_len, &fci, &fcc) == FAILURE) { RETURN_THROWS(); } - SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3) + SQLITE3_CHECK_INITIALIZED_FREE_TRAMPOLINE(db_obj, db_obj->initialised, SQLite3, &fcc); if (!collation_name_len) { + /* TODO Add warning/ValueError that name cannot be empty? */ + zend_release_fcall_info_cache(&fcc); RETURN_FALSE; } @@ -1058,12 +1065,6 @@ PHP_METHOD(SQLite3, createCollation) if (sqlite3_create_collation(db_obj->db, collation_name, SQLITE_UTF8, collation, php_sqlite3_callback_compare) == SQLITE_OK) { collation->collation_name = estrdup(collation_name); - if (!ZEND_FCC_INITIALIZED(fcc)) { - /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal - * with it outselves. It is important that it is not refetched on every call, - * because calls may occur from different scopes. */ - zend_is_callable_ex(&fci.function_name, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL); - } zend_fcc_dup(&collation->cmp_func, &fcc); collation->next = db_obj->collations; @@ -1072,6 +1073,7 @@ PHP_METHOD(SQLite3, createCollation) RETURN_TRUE; } efree(collation); + zend_release_fcall_info_cache(&fcc); RETURN_FALSE; } @@ -1317,10 +1319,10 @@ PHP_METHOD(SQLite3, setAuthorizer) zend_fcall_info_cache fcc; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_FUNC_OR_NULL(fci, fcc) + Z_PARAM_FUNC_NO_TRAMPOLINE_FREE_OR_NULL(fci, fcc) ZEND_PARSE_PARAMETERS_END(); - SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3) + SQLITE3_CHECK_INITIALIZED_FREE_TRAMPOLINE(db_obj, db_obj->initialised, SQLite3, &fcc); /* Clear previously set callback */ if (ZEND_FCC_INITIALIZED(db_obj->authorizer_fcc)) { @@ -1329,14 +1331,7 @@ PHP_METHOD(SQLite3, setAuthorizer) /* Only enable userland authorizer if argument is not NULL */ if (ZEND_FCI_INITIALIZED(fci)) { - if (!ZEND_FCC_INITIALIZED(fcc)) { - zend_is_callable_ex(&fci.function_name, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL); - /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal - * with it outselves. It is important that it is not refetched on every call, - * because calls may occur from different scopes. */ - } - db_obj->authorizer_fcc = fcc; - zend_fcc_addref(&db_obj->authorizer_fcc); + zend_fcc_dup(&db_obj->authorizer_fcc, &fcc); } RETURN_TRUE; diff --git a/ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt b/ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt new file mode 100644 index 000000000000..c7c7cf7e6bb9 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt @@ -0,0 +1,80 @@ +--TEST-- +SQLite3::createAggregate() use F ZPP for trampoline callback and does not leak +--EXTENSIONS-- +sqlite3 +--FILE-- + 0, 'values' => []]; + } + $context['total'] += (int) $arguments[2]; + $context['values'][] = $context['total']; + return $context; + } +} +$o = new TrampolineTest(); +$step = [$o, 'step']; +$finalize = [$o, 'finalize']; + +var_dump($db->createAggregate('', $step, $finalize, 1)); + +try { + var_dump($db->createAggregate('S', $step, $finalize, new stdClass())); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +try { + var_dump($db->createAggregate('S', $step, 'no_func', 1)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +try { + var_dump($db->createAggregate('S', 'no_func', $finalize, 1)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +try { + var_dump($db->createAggregate('S', $step, $finalize, 'not a number')); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "Invalid SQLite3 object:\n"; +$rc = new ReflectionClass(SQLite3::class); +$obj = $rc->newInstanceWithoutConstructor(); + +try { + var_dump($obj->createAggregate('S', $step, $finalize, 1)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +var_dump($db->createAggregate('S', $step, $finalize, 1)); + +echo "Closing database\n"; +var_dump($db->close()); +echo "Done\n"; +?> +--EXPECT-- +bool(false) +TypeError: SQLite3::createAggregate(): Argument #4 ($argCount) must be of type int, stdClass given +TypeError: SQLite3::createAggregate(): Argument #3 ($finalCallback) must be a valid callback, function "no_func" not found or invalid function name +TypeError: SQLite3::createAggregate(): Argument #2 ($stepCallback) must be a valid callback, function "no_func" not found or invalid function name +TypeError: SQLite3::createAggregate(): Argument #4 ($argCount) must be of type int, string given +Invalid SQLite3 object: +Error: The SQLite3 object has not been correctly initialised or is already closed +bool(true) +Closing database +bool(true) +Done diff --git a/ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt b/ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt new file mode 100644 index 000000000000..e4856b6c88b8 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt @@ -0,0 +1,44 @@ +--TEST-- +SQLite3::createFunction use F ZPP for trampoline callback and does not leak +--EXTENSIONS-- +sqlite3 +--FILE-- +createCollation('', $callback)); +try { + var_dump($db->createCollation('NAT', $callback, new stdClass())); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "Invalid SQLite3 object:\n"; +$rc = new ReflectionClass(SQLite3::class); +$obj = $rc->newInstanceWithoutConstructor(); + +try { + var_dump($obj->createCollation('NAT', $callback)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +var_dump($db->createCollation('NAT', $callback)); + +?> +--EXPECT-- +bool(false) +ArgumentCountError: SQLite3::createCollation() expects exactly 2 arguments, 3 given +Invalid SQLite3 object: +Error: The SQLite3 object has not been correctly initialised or is already closed +bool(true) diff --git a/ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt b/ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt new file mode 100644 index 000000000000..d386296990d7 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt @@ -0,0 +1,45 @@ +--TEST-- +SQLite3::createFunction use F ZPP for trampoline callback and does not leak +--EXTENSIONS-- +sqlite3 +--FILE-- +createfunction('', $callback)); + +try { + var_dump($db->createfunction('strtoupper', $callback, new stdClass())); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +echo "Invalid SQLite3 object:\n"; +$rc = new ReflectionClass(SQLite3::class); +$obj = $rc->newInstanceWithoutConstructor(); + +try { + var_dump($obj->createfunction('strtoupper', $callback)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +var_dump($db->createfunction('strtoupper', $callback)); + +?> +--EXPECT-- +bool(false) +TypeError: SQLite3::createFunction(): Argument #3 ($argCount) must be of type int, stdClass given +Invalid SQLite3 object: +Error: The SQLite3 object has not been correctly initialised or is already closed +bool(true) diff --git a/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_no_leak.phpt b/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_no_leak.phpt new file mode 100644 index 000000000000..331f4e1e63c9 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_no_leak.phpt @@ -0,0 +1,41 @@ +--TEST-- +SQLite3::setAuthorizer use F ZPP for trampoline callback and does not leak +--EXTENSIONS-- +sqlite3 +--FILE-- +enableExceptions(true); + +echo "Invalid SQLite3 object:\n"; +$rc = new ReflectionClass(SQLite3::class); +$obj = $rc->newInstanceWithoutConstructor(); + +try { + var_dump($obj->setAuthorizer($callback)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +$db->setAuthorizer($callback); + +?> +DONE +--EXPECT-- +Invalid SQLite3 object: +Error: The SQLite3 object has not been correctly initialised or is already closed +DONE From 9377c690249164f60073dbb40008d339a292d563 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 30 Apr 2024 22:06:00 +0100 Subject: [PATCH 2/2] Initialize FCI/FCC --- ext/sqlite3/sqlite3.c | 31 +++++++++---------- ...3_trampoline_create_aggregate_no_leak.phpt | 6 ++++ ...e3_trampoline_createcollation_no_leak.phpt | 7 +++++ ...te3_trampoline_createfunction_no_leak.phpt | 7 +++++ ...sqlite3_trampoline_setauthorizer_null.phpt | 26 ++++++++++++++++ 5 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_null.phpt diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 444b7150af88..d1ab0164567a 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -943,8 +943,8 @@ PHP_METHOD(SQLite3, createFunction) php_sqlite3_func *func; char *sql_func; size_t sql_func_len; - zend_fcall_info fci; - zend_fcall_info_cache fcc; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; zend_long sql_func_num_args = -1; zend_long flags = 0; db_obj = Z_SQLITE3_DB_P(object); @@ -989,8 +989,10 @@ PHP_METHOD(SQLite3, createAggregate) php_sqlite3_func *func; char *sql_func; size_t sql_func_len; - zend_fcall_info step_fci, fini_fci; - zend_fcall_info_cache step_fcc, fini_fcc; + zend_fcall_info step_fci = empty_fcall_info; + zend_fcall_info_cache step_fcc = empty_fcall_info_cache; + zend_fcall_info fini_fci = empty_fcall_info; + zend_fcall_info_cache fini_fcc = empty_fcall_info_cache; zend_long sql_func_num_args = -1; db_obj = Z_SQLITE3_DB_P(object); @@ -1026,12 +1028,8 @@ PHP_METHOD(SQLite3, createAggregate) efree(func); error: - if (ZEND_FCC_INITIALIZED(step_fcc)) { - zend_release_fcall_info_cache(&step_fcc); - } - if (ZEND_FCC_INITIALIZED(fini_fcc)) { - zend_release_fcall_info_cache(&fini_fcc); - } + zend_release_fcall_info_cache(&step_fcc); + zend_release_fcall_info_cache(&fini_fcc); RETURN_FALSE; } @@ -1045,8 +1043,8 @@ PHP_METHOD(SQLite3, createCollation) php_sqlite3_collation *collation; char *collation_name; size_t collation_name_len; - zend_fcall_info fci; - zend_fcall_info_cache fcc; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; db_obj = Z_SQLITE3_DB_P(object); if (zend_parse_parameters(ZEND_NUM_ARGS(), "sF", &collation_name, &collation_name_len, &fci, &fcc) == FAILURE) { @@ -1312,16 +1310,15 @@ PHP_METHOD(SQLite3, enableExceptions) /* {{{ Register a callback function to be used as an authorizer by SQLite. The callback should return SQLite3::OK, SQLite3::IGNORE or SQLite3::DENY. */ PHP_METHOD(SQLite3, setAuthorizer) { - php_sqlite3_db_object *db_obj; - zval *object = ZEND_THIS; - db_obj = Z_SQLITE3_DB_P(object); - zend_fcall_info fci; - zend_fcall_info_cache fcc; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_FUNC_NO_TRAMPOLINE_FREE_OR_NULL(fci, fcc) ZEND_PARSE_PARAMETERS_END(); + php_sqlite3_db_object *db_obj = Z_SQLITE3_DB_P(ZEND_THIS); + SQLITE3_CHECK_INITIALIZED_FREE_TRAMPOLINE(db_obj, db_obj->initialised, SQLite3, &fcc); /* Clear previously set callback */ diff --git a/ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt b/ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt index c7c7cf7e6bb9..31f8a2cbd47b 100644 --- a/ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt +++ b/ext/sqlite3/tests/sqlite3_trampoline_create_aggregate_no_leak.phpt @@ -28,6 +28,11 @@ $finalize = [$o, 'finalize']; var_dump($db->createAggregate('', $step, $finalize, 1)); +try { + var_dump($db->createAggregate(new stdClass(), $step, $finalize, new stdClass())); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} try { var_dump($db->createAggregate('S', $step, $finalize, new stdClass())); } catch (\Throwable $e) { @@ -68,6 +73,7 @@ echo "Done\n"; ?> --EXPECT-- bool(false) +TypeError: SQLite3::createAggregate(): Argument #1 ($name) must be of type string, stdClass given TypeError: SQLite3::createAggregate(): Argument #4 ($argCount) must be of type int, stdClass given TypeError: SQLite3::createAggregate(): Argument #3 ($finalCallback) must be a valid callback, function "no_func" not found or invalid function name TypeError: SQLite3::createAggregate(): Argument #2 ($stepCallback) must be a valid callback, function "no_func" not found or invalid function name diff --git a/ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt b/ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt index e4856b6c88b8..f1c4be0f9c78 100644 --- a/ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt +++ b/ext/sqlite3/tests/sqlite3_trampoline_createcollation_no_leak.phpt @@ -17,6 +17,12 @@ $o = new TrampolineTest(); $callback = [$o, 'NAT']; var_dump($db->createCollation('', $callback)); + +try { + var_dump($db->createCollation(new stdClass(), $callback)); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} try { var_dump($db->createCollation('NAT', $callback, new stdClass())); } catch (\Throwable $e) { @@ -38,6 +44,7 @@ var_dump($db->createCollation('NAT', $callback)); ?> --EXPECT-- bool(false) +TypeError: SQLite3::createCollation(): Argument #1 ($name) must be of type string, stdClass given ArgumentCountError: SQLite3::createCollation() expects exactly 2 arguments, 3 given Invalid SQLite3 object: Error: The SQLite3 object has not been correctly initialised or is already closed diff --git a/ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt b/ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt index d386296990d7..dea0f6c5210b 100644 --- a/ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt +++ b/ext/sqlite3/tests/sqlite3_trampoline_createfunction_no_leak.phpt @@ -18,6 +18,12 @@ $callback = [$o, 'strtoupper']; var_dump($db->createfunction('', $callback)); +try { + var_dump($db->createfunction(new stdClass(), $callback, new stdClass())); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + try { var_dump($db->createfunction('strtoupper', $callback, new stdClass())); } catch (\Throwable $e) { @@ -39,6 +45,7 @@ var_dump($db->createfunction('strtoupper', $callback)); ?> --EXPECT-- bool(false) +TypeError: SQLite3::createFunction(): Argument #1 ($name) must be of type string, stdClass given TypeError: SQLite3::createFunction(): Argument #3 ($argCount) must be of type int, stdClass given Invalid SQLite3 object: Error: The SQLite3 object has not been correctly initialised or is already closed diff --git a/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_null.phpt b/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_null.phpt new file mode 100644 index 000000000000..2cea279f077e --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_trampoline_setauthorizer_null.phpt @@ -0,0 +1,26 @@ +--TEST-- +SQLite3 user authorizer null +--EXTENSIONS-- +sqlite3 +--FILE-- +enableExceptions(true); + +$db->setAuthorizer(null); + +// This query should be accepted +var_dump($db->querySingle('SELECT 1;')); + +try { + // This one should fail + var_dump($db->querySingle('CREATE TABLE test (a, b);')); +} catch (\Exception $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECT-- +int(1) +NULL