From f24e6d09672ab7161355a65fb1000b69426648fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 8 May 2024 23:49:41 +0200 Subject: [PATCH 1/5] Migrate ext/dba resources to objects Related to https://wiki.php.net/rfc/resource_to_object_conversion and https://github.com/php/php-tasks/issues/6 --- Zend/Optimizer/zend_func_infos.h | 2 - ext/dba/dba.c | 424 ++++++++++++++----------- ext/dba/dba.stub.php | 51 ++- ext/dba/dba_arginfo.h | 29 +- ext/dba/php_dba.h | 6 + ext/dba/tests/bug36436.phpt | 3 +- ext/dba/tests/dba015.phpt | 11 +- ext/dba/tests/dba_db4_018.phpt | 11 +- ext/dba/tests/default_handler_ini.phpt | 3 +- ext/dba/tests/gh9155.phpt | 3 +- ext/dba/tests/value_errors_open.phpt | 3 +- 11 files changed, 319 insertions(+), 227 deletions(-) diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 30927dd8f7631..8ebd9e228728b 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -77,8 +77,6 @@ static const func_info_t func_infos[] = { F1("date_sunrise", MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE), F1("date_sunset", MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_FALSE), F1("date_sun_info", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_FALSE|MAY_BE_ARRAY_OF_TRUE|MAY_BE_ARRAY_OF_LONG), - FN("dba_popen", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("dba_open", MAY_BE_RESOURCE|MAY_BE_FALSE), FN("dba_key_split", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE), F1("dba_handlers", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING), FN("dba_list", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 0b847ed66de88..5f2daa5d75b43 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -57,6 +57,7 @@ PHP_MINFO_FUNCTION(dba); ZEND_BEGIN_MODULE_GLOBALS(dba) const char *default_handler; const dba_handler *default_hptr; + HashTable connections; ZEND_END_MODULE_GLOBALS(dba) ZEND_DECLARE_MODULE_GLOBALS(dba) @@ -64,6 +65,7 @@ ZEND_DECLARE_MODULE_GLOBALS(dba) #define DBA_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(dba, v) static PHP_GINIT_FUNCTION(dba); +static PHP_GSHUTDOWN_FUNCTION(dba); zend_module_entry dba_module_entry = { STANDARD_MODULE_HEADER, @@ -77,7 +79,7 @@ zend_module_entry dba_module_entry = { PHP_DBA_VERSION, PHP_MODULE_GLOBALS(dba), PHP_GINIT(dba), - NULL, + PHP_GSHUTDOWN(dba), NULL, STANDARD_MODULE_PROPERTIES_EX }; @@ -132,8 +134,9 @@ static zend_string* php_dba_make_key(HashTable *key) #define DBA_RELEASE_HT_KEY_CREATION() if (key_ht) {zend_string_release_ex(key_str, false);} -#define DBA_FETCH_RESOURCE(info, id) \ - if ((info = (dba_info *)zend_fetch_resource2(Z_RES_P(id), "DBA identifier", le_db, le_pdb)) == NULL) { \ +#define CHECK_DBA_CONNECTION(info) \ + if (info == NULL) { \ + zend_throw_error(NULL, "DBA connection has already been closed"); \ RETURN_THROWS(); \ } @@ -232,35 +235,20 @@ static const dba_handler handler[] = { #endif /* cdb/cdb_make and ini are no option here */ -static int le_db; static int le_pdb; -/* }}} */ - -/* {{{ dba_fetch_resource -PHPAPI void dba_fetch_resource(dba_info **pinfo, zval **id) -{ - dba_info *info; - DBA_ID_FETCH - *pinfo = info; -} -*/ -/* }}} */ -/* {{{ dba_get_handler -PHPAPI dba_handler *dba_get_handler(const char* handler_name) -{ - const dba_handler *hptr; - for (hptr = handler; hptr->name && strcasecmp(hptr->name, handler_name); hptr++); - return hptr; -} -*/ +static zend_class_entry *dba_connection_ce; +static zend_object_handlers dba_connection_object_handlers; /* }}} */ /* {{{ dba_close */ -static void dba_close(dba_info *info) +static void dba_close_info(dba_info *info) { + ZEND_ASSERT(info != NULL && "connection has already been closed"); + if (info->hnd) { info->hnd->close(info); + info->hnd = NULL; } ZEND_ASSERT(info->path); zend_string_release_ex(info->path, info->flags&DBA_PERSISTENT); @@ -280,43 +268,82 @@ static void dba_close(dba_info *info) php_stream_close(info->lock.fp); } } - pefree(info, info->flags&DBA_PERSISTENT); + + pefree(info, info->flags & DBA_PERSISTENT); + info = NULL; } -/* }}} */ -/* {{{ dba_close_rsrc */ -static void dba_close_rsrc(zend_resource *rsrc) +static int remove_pconnection_from_list(zval *zv, void *p) { - dba_info *info = (dba_info *)rsrc->ptr; + zend_resource *le = Z_RES_P(zv); - dba_close(info); + if (le->ptr == p) { + return ZEND_HASH_APPLY_REMOVE; + } + + return ZEND_HASH_APPLY_KEEP; } -/* }}} */ -/* {{{ dba_close_pe_rsrc_deleter */ -static int dba_close_pe_rsrc_deleter(zval *el, void *pDba) +static void close_pconnection(zend_resource *rsrc) { - if (Z_RES_P(el)->ptr == pDba) { - if (Z_DELREF_P(el) == 0) { - return ZEND_HASH_APPLY_REMOVE; - } else { - return ZEND_HASH_APPLY_KEEP | ZEND_HASH_APPLY_STOP; - } - } else { - return ZEND_HASH_APPLY_KEEP; + dba_info *info = (dba_info *) rsrc->ptr; + + dba_close_info(info); + + rsrc->ptr = NULL; +} + +static void dba_close_connection(dba_connection *connection) +{ + bool persistent = connection->info->flags & DBA_PERSISTENT; + + if (!persistent) { + dba_close_info(connection->info); + } + + connection->info = NULL; + + if (connection->hash) { + zend_hash_del(&DBA_G(connections), connection->hash); + zend_string_release_ex(connection->hash, persistent); + connection->hash = NULL; } } -/* }}} */ -/* {{{ dba_close_pe_rsrc */ -static void dba_close_pe_rsrc(zend_resource *rsrc) +static zend_object *dba_connection_create_object(zend_class_entry *class_type) { - dba_info *info = (dba_info *)rsrc->ptr; + dba_connection *intern = zend_object_alloc(sizeof(dba_info), class_type); - /* closes the resource by calling dba_close_rsrc() */ - zend_hash_apply_with_argument(&EG(persistent_list), dba_close_pe_rsrc_deleter, info); + zend_object_std_init(&intern->std, class_type); + object_properties_init(&intern->std, class_type); + + return &intern->std; +} + +static zend_function *dba_connection_get_constructor(zend_object *object) +{ + zend_throw_error(NULL, "Cannot directly construct Dba\\Connection, use dba_open() or dba_popen() instead"); + return NULL; +} + +static inline dba_connection *dba_connection_from_obj(zend_object *obj) +{ + return (dba_connection *)((char *)(obj) - XtOffsetOf(dba_connection, std)); +} + +#define Z_DBA_CONNECTION_P(zv) dba_connection_from_obj(Z_OBJ_P(zv)) +#define Z_DBA_INFO_P(zv) Z_DBA_CONNECTION_P(zv)->info + +static void dba_connection_free_obj(zend_object *obj) +{ + dba_connection *connection = dba_connection_from_obj(obj); + + if (connection->info) { + dba_close_connection(connection); + } + + zend_object_std_dtor(&connection->std); } -/* }}} */ /* {{{ PHP_INI */ static ZEND_INI_MH(OnUpdateDefaultHandler) @@ -351,16 +378,34 @@ static PHP_GINIT_FUNCTION(dba) #endif dba_globals->default_handler = ""; dba_globals->default_hptr = NULL; + zend_hash_init(&dba_globals->connections, 0, NULL, NULL, true); + GC_MAKE_PERSISTENT_LOCAL(&dba_globals->connections); } /* }}} */ +static PHP_GSHUTDOWN_FUNCTION(dba) +{ + zend_hash_destroy(&dba_globals->connections); +} + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(dba) { REGISTER_INI_ENTRIES(); - le_db = zend_register_list_destructors_ex(dba_close_rsrc, NULL, "dba", module_number); - le_pdb = zend_register_list_destructors_ex(dba_close_pe_rsrc, dba_close_rsrc, "dba persistent", module_number); + le_pdb = zend_register_list_destructors_ex(NULL, close_pconnection, "dba persistent", module_number); register_dba_symbols(module_number); + + dba_connection_ce = register_class_Dba_Connection(); + dba_connection_ce->create_object = dba_connection_create_object; + dba_connection_ce->default_object_handlers = &dba_connection_object_handlers; + + memcpy(&dba_connection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + dba_connection_object_handlers.offset = XtOffsetOf(dba_connection, std); + dba_connection_object_handlers.free_obj = dba_connection_free_obj; + dba_connection_object_handlers.get_constructor = dba_connection_get_constructor; + dba_connection_object_handlers.clone_obj = NULL; + dba_connection_object_handlers.compare = zend_objects_not_comparable; + return SUCCESS; } /* }}} */ @@ -412,10 +457,11 @@ static void php_dba_update(INTERNAL_FUNCTION_PARAMETERS, int mode) ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_ARRAY_HT_OR_STR(key_ht, key_str) Z_PARAM_STR(value) - Z_PARAM_RESOURCE(id); + Z_PARAM_OBJECT_OF_CLASS(id, dba_connection_ce); ZEND_PARSE_PARAMETERS_END(); - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); DBA_WRITE_CHECK(info); if (key_ht) { @@ -434,22 +480,14 @@ static void php_dba_update(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ php_find_dbm */ static dba_info *php_dba_find(const zend_string *path) { - zend_resource *le; - dba_info *info; - zend_long numitems, i; - - numitems = zend_hash_next_free_element(&EG(regular_list)); - for (i=1; itype == le_db || le->type == le_pdb) { - info = (dba_info *)(le->ptr); - if (zend_string_equals(path, info->path)) { - return (dba_info *)(le->ptr); - } + zval *zv; + + ZEND_HASH_FOREACH_VAL(&DBA_G(connections), zv) { + dba_info *info = Z_DBA_INFO_P(zv); + if (info && zend_string_equals(path, info->path)) { + return info; } - } + } ZEND_HASH_FOREACH_END(); return NULL; } @@ -469,13 +507,12 @@ static zend_always_inline zend_string *php_dba_zend_string_dup_safe(zend_string } -#define FREE_PERSISTENT_RESOURCE_KEY() if (persistent_resource_key) {zend_string_release_ex(persistent_resource_key, false);} +#define FREE_RESOURCE_KEY() efree(resource_key); /* {{{ php_dba_open */ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) { dba_mode_t modenr; - dba_info *info, *other; const dba_handler *hptr; const char *error = NULL; int lock_mode, lock_flag = 0; @@ -495,7 +532,6 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) zend_long map_size = 0; zend_long driver_flags = DBA_DEFAULT_DRIVER_FLAGS; bool is_flags_null = true; - zend_string *persistent_resource_key = NULL; if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "PS|S!lll!", &path, &mode, &handler_str, &permission, &map_size, &driver_flags, &is_flags_null)) { @@ -525,34 +561,37 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) RETURN_THROWS(); } + char *resource_key; + size_t resource_key_len = spprintf(&resource_key, 0, + "dba_%d_%s_%s_%s", persistent, ZSTR_VAL(path), ZSTR_VAL(mode), handler_str ? ZSTR_VAL(handler_str) : "" + ); + if (persistent) { zend_resource *le; - if (handler_str) { - persistent_resource_key = zend_string_concat3( - ZSTR_VAL(path), ZSTR_LEN(path), - ZSTR_VAL(mode), ZSTR_LEN(mode), - ZSTR_VAL(handler_str), ZSTR_LEN(handler_str) - ); - } else { - persistent_resource_key = zend_string_concat2( - ZSTR_VAL(path), ZSTR_LEN(path), - ZSTR_VAL(mode), ZSTR_LEN(mode) - ); - } - /* try to find if we already have this link in our persistent list */ - if ((le = zend_hash_find_ptr(&EG(persistent_list), persistent_resource_key)) != NULL) { - FREE_PERSISTENT_RESOURCE_KEY(); + if ((le = zend_hash_str_find_ptr(&EG(persistent_list), resource_key, resource_key_len)) != NULL) { if (le->type != le_pdb) { // TODO This should never happen + FREE_RESOURCE_KEY(); RETURN_FALSE; } - info = (dba_info *)le->ptr; + object_init_ex(return_value, dba_connection_ce); + dba_connection *connection = Z_DBA_CONNECTION_P(return_value); + connection->info = (dba_info *)le->ptr; + connection->hash = zend_string_init(resource_key, resource_key_len, persistent); + if (persistent) { + GC_MAKE_PERSISTENT_LOCAL(connection->hash); + } - GC_ADDREF(le); - RETURN_RES(zend_register_resource(info, le_pdb)); + if (zend_hash_exists(&DBA_G(connections), connection->hash)) { + zend_hash_del(&DBA_G(connections), connection->hash); + } + + zend_hash_add_new(&DBA_G(connections), connection->hash, return_value); + FREE_RESOURCE_KEY(); + return; } } @@ -560,7 +599,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) hptr = DBA_G(default_hptr); if (!hptr) { php_error_docref(NULL, E_WARNING, "No default handler selected"); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_FALSE; } ZEND_ASSERT(hptr->name); @@ -570,7 +609,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (!hptr->name) { php_error_docref(NULL, E_WARNING, "Handler \"%s\" is not available", ZSTR_VAL(handler_str)); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_FALSE; } } @@ -594,18 +633,18 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (ZSTR_LEN(mode) == 0) { zend_argument_value_error(2, "cannot be empty"); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_THROWS(); } if (ZSTR_LEN(mode) > 3) { zend_argument_value_error(2, "must be at most 3 characters"); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_THROWS(); } if (ZSTR_LEN(mode) == 3) { if (ZSTR_VAL(mode)[2] != 't') { zend_argument_value_error(2, "third character must be \"t\""); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_THROWS(); } is_test_lock = true; @@ -618,7 +657,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) case '-': if ((hptr->flags & DBA_LOCK_ALL) == 0) { php_error_docref(NULL, E_WARNING, "Locking cannot be disabled for handler %s", hptr->name); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_FALSE; } is_lock_ignored = true; @@ -640,7 +679,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) break; default: zend_argument_value_error(2, "second character must be one of \"d\", \"l\", \"-\", or \"t\""); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_THROWS(); } } else { @@ -709,7 +748,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) break; default: zend_argument_value_error(2, "first character must be one of \"r\", \"w\", \"c\", or \"n\""); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_THROWS(); } if (!lock_file_mode) { @@ -718,17 +757,17 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (is_test_lock) { if (is_lock_ignored) { zend_argument_value_error(2, "cannot combine mode \"-\" (no lock) and \"t\" (test lock)"); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_THROWS(); } if (!lock_mode) { if ((hptr->flags & DBA_LOCK_ALL) == 0) { php_error_docref(NULL, E_WARNING, "Handler %s uses its own locking which doesn't support mode modifier t (test lock)", hptr->name); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_FALSE; } else { php_error_docref(NULL, E_WARNING, "Handler %s doesn't uses locking for this mode which makes modifier t (test lock) obsolete", hptr->name); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); RETURN_FALSE; } } else { @@ -736,22 +775,36 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } } - info = pemalloc(sizeof(dba_info), persistent); - memset(info, 0, sizeof(dba_info)); - info->path = php_dba_zend_string_dup_safe(path, persistent); - info->mode = modenr; - info->file_permission = permission; - info->map_size = map_size; - info->driver_flags = driver_flags; - info->flags = (hptr->flags & ~DBA_LOCK_ALL) | (lock_flag & DBA_LOCK_ALL) | (persistent ? DBA_PERSISTENT : 0); - info->lock.mode = lock_mode; + zval *connection_zval; + dba_connection *connection; + if ((connection_zval = zend_hash_str_find(&DBA_G(connections), resource_key, resource_key_len)) == NULL) { + object_init_ex(return_value, dba_connection_ce); + connection = Z_DBA_CONNECTION_P(return_value); + + connection->info = pecalloc(1, sizeof(dba_info), persistent); + connection->info->path = php_dba_zend_string_dup_safe(path, persistent); + connection->info->mode = modenr; + connection->info->file_permission = permission; + connection->info->map_size = map_size; + connection->info->driver_flags = driver_flags; + connection->info->flags = (hptr->flags & ~DBA_LOCK_ALL) | (lock_flag & DBA_LOCK_ALL) | (persistent ? DBA_PERSISTENT : 0); + connection->info->lock.mode = lock_mode; + connection->hash = zend_string_init(resource_key, resource_key_len, persistent); + if (persistent) { + GC_MAKE_PERSISTENT_LOCAL(connection->hash); + } + } else { + ZVAL_COPY(return_value, connection_zval); + connection = Z_DBA_CONNECTION_P(return_value); + } /* if any open call is a locking call: * check if we already have a locking call open that should block this call * the problem is some systems would allow read during write */ if (hptr->flags & DBA_LOCK_ALL) { - if ((other = php_dba_find(info->path)) != NULL) { + dba_info *other; + if ((other = php_dba_find(connection->info->path)) != NULL) { if ( ( (lock_mode&LOCK_EX) && (other->lock.mode&(LOCK_EX|LOCK_SH)) ) || ( (other->lock.mode&LOCK_EX) && (lock_mode&(LOCK_EX|LOCK_SH)) ) ) { @@ -767,91 +820,92 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (is_db_lock) { lock_name = ZSTR_VAL(path); } else { - spprintf(&lock_name, 0, "%s.lck", ZSTR_VAL(info->path)); + spprintf(&lock_name, 0, "%s.lck", ZSTR_VAL(connection->info->path)); if (!strcmp(file_mode, "r")) { zend_string *opened_path = NULL; /* when in read only mode try to use existing .lck file first */ /* do not log errors for .lck file while in read only mode on .lck file */ lock_file_mode = "rb"; - info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, &opened_path); + connection->info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, &opened_path); if (opened_path) { zend_string_release_ex(opened_path, 0); } } - if (!info->lock.fp) { + if (!connection->info->lock.fp) { /* when not in read mode or failed to open .lck file read only. now try again in create(write) mode and log errors */ lock_file_mode = "a+b"; } } - if (!info->lock.fp) { + if (!connection->info->lock.fp) { zend_string *opened_path = NULL; - info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path); - if (info->lock.fp) { + connection->info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path); + if (connection->info->lock.fp) { if (is_db_lock) { ZEND_ASSERT(opened_path); /* replace the path info with the real path of the opened file */ - zend_string_release(info->path); - info->path = php_dba_zend_string_dup_safe(opened_path, persistent); + zend_string_release_ex(connection->info->path, persistent); + connection->info->path = php_dba_zend_string_dup_safe(opened_path, persistent); } } if (opened_path) { zend_string_release_ex(opened_path, 0); + opened_path = NULL; } } if (!is_db_lock) { efree(lock_name); } - if (!info->lock.fp) { - dba_close(info); + if (!connection->info->lock.fp) { /* stream operation already wrote an error message */ - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); + zval_ptr_dtor(return_value); RETURN_FALSE; } - if (!php_stream_supports_lock(info->lock.fp)) { + if (!php_stream_supports_lock(connection->info->lock.fp)) { error = "Stream does not support locking"; } - if (php_stream_lock(info->lock.fp, lock_mode)) { + if (php_stream_lock(connection->info->lock.fp, lock_mode)) { error = "Unable to establish lock"; /* force failure exit */ } } /* centralised open stream for builtin */ if (!error && (hptr->flags&DBA_STREAM_OPEN)==DBA_STREAM_OPEN) { - if (info->lock.fp && is_db_lock) { - info->fp = info->lock.fp; /* use the same stream for locking and database access */ + if (connection->info->lock.fp && is_db_lock) { + connection->info->fp = connection->info->lock.fp; /* use the same stream for locking and database access */ } else { - info->fp = php_stream_open_wrapper(ZSTR_VAL(info->path), file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL); + connection->info->fp = php_stream_open_wrapper(ZSTR_VAL(connection->info->path), file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL); } - if (!info->fp) { - dba_close(info); + if (!connection->info->fp) { /* stream operation already wrote an error message */ - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) { /* Needed because some systems do not allow to write to the original * file contents with O_APPEND being set. */ - if (SUCCESS != php_stream_cast(info->fp, PHP_STREAM_AS_FD, (void*)&info->fd, 1)) { + if (SUCCESS != php_stream_cast(connection->info->fp, PHP_STREAM_AS_FD, (void*)&connection->info->fd, 1)) { php_error_docref(NULL, E_WARNING, "Could not cast stream"); - dba_close(info); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); + zval_ptr_dtor(return_value); RETURN_FALSE; #ifdef F_SETFL } else if (modenr == DBA_CREAT) { - int flags = fcntl(info->fd, F_GETFL); - fcntl(info->fd, F_SETFL, flags & ~O_APPEND); + int flags = fcntl(connection->info->fd, F_GETFL); + fcntl(connection->info->fd, F_SETFL, flags & ~O_APPEND); #elif defined(PHP_WIN32) } else if (modenr == DBA_CREAT && need_creation && !restarted) { - if (info->lock.fp != NULL) { - php_stream_free(info->lock.fp, persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE); + if (connection->info->lock.fp != NULL) { + php_stream_free(connection->info->lock.fp, persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE); } - if (info->fp != info->lock.fp) { - php_stream_free(info->fp, persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE); + if (connection->info->fp != connection->info->lock.fp) { + php_stream_free(connection->info->fp, persistent ? PHP_STREAM_FREE_CLOSE_PERSISTENT : PHP_STREAM_FREE_CLOSE); } - info->fp = NULL; - info->lock.fp = NULL; - info->fd = -1; + connection->info->fp = NULL; + connection->info->lock.fp = NULL; + connection->info->fd = -1; lock_file_mode = "r+b"; @@ -862,8 +916,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } } - if (error || hptr->open(info, &error) == FAILURE) { - dba_close(info); + if (error || hptr->open(connection->info, &error) == FAILURE) { if (EXPECTED(!EG(exception))) { if (error) { php_error_docref(NULL, E_WARNING, "Driver initialization failed for handler: %s: %s", hptr->name, error); @@ -871,24 +924,24 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) php_error_docref(NULL, E_WARNING, "Driver initialization failed for handler: %s", hptr->name); } } - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); + zval_ptr_dtor(return_value); RETURN_FALSE; } - info->hnd = hptr; + connection->info->hnd = hptr; if (persistent) { - ZEND_ASSERT(persistent_resource_key); - if (zend_register_persistent_resource_ex(persistent_resource_key, info, le_pdb) == NULL) { - dba_close(info); + if (zend_register_persistent_resource(resource_key, resource_key_len, connection->info, le_pdb) == NULL) { php_error_docref(NULL, E_WARNING, "Could not register persistent resource"); - FREE_PERSISTENT_RESOURCE_KEY(); + FREE_RESOURCE_KEY(); + zval_ptr_dtor(return_value); RETURN_FALSE; } - FREE_PERSISTENT_RESOURCE_KEY(); } - RETURN_RES(zend_register_resource(info, (persistent ? le_pdb : le_db))); + zend_hash_add_new(&DBA_G(connections), connection->hash, return_value); + FREE_RESOURCE_KEY(); } /* }}} */ @@ -910,15 +963,22 @@ PHP_FUNCTION(dba_open) PHP_FUNCTION(dba_close) { zval *id; - dba_info *info = NULL; + dba_connection *connection = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &id, dba_connection_ce) == FAILURE) { RETURN_THROWS(); } - DBA_FETCH_RESOURCE(info, id); + connection = Z_DBA_CONNECTION_P(id); + CHECK_DBA_CONNECTION(connection->info); + + bool persistent = connection->info->flags & DBA_PERSISTENT; - zend_list_close(Z_RES_P(id)); + dba_close_connection(connection); + + if (persistent) { + zend_hash_apply_with_argument(&EG(persistent_list), remove_pconnection_from_list, (void *) connection->info); + } } /* }}} */ @@ -932,10 +992,11 @@ PHP_FUNCTION(dba_exists) ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ARRAY_HT_OR_STR(key_ht, key_str) - Z_PARAM_RESOURCE(id); + Z_PARAM_OBJECT_OF_CLASS(id, dba_connection_ce); ZEND_PARSE_PARAMETERS_END(); - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); if (key_ht) { key_str = php_dba_make_key(key_ht); @@ -964,7 +1025,7 @@ PHP_FUNCTION(dba_fetch) ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 3, 3) Z_PARAM_ARRAY_HT_OR_STR(key_ht, key_str) Z_PARAM_LONG(skip) - Z_PARAM_RESOURCE(id); + Z_PARAM_OBJECT_OF_CLASS(id, dba_connection_ce); ZEND_PARSE_PARAMETERS_END_EX(goto standard;); zend_error(E_DEPRECATED, "Calling dba_fetch() with $dba at the 3rd parameter is deprecated"); @@ -975,13 +1036,14 @@ PHP_FUNCTION(dba_fetch) standard: ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_ARRAY_HT_OR_STR(key_ht, key_str) - Z_PARAM_RESOURCE(id); + Z_PARAM_OBJECT_OF_CLASS(id, dba_connection_ce); Z_PARAM_OPTIONAL Z_PARAM_LONG(skip) ZEND_PARSE_PARAMETERS_END(); } - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); if (key_ht) { key_str = php_dba_make_key(key_ht); @@ -1061,11 +1123,12 @@ PHP_FUNCTION(dba_firstkey) zval *id; dba_info *info = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &id, dba_connection_ce) == FAILURE) { RETURN_THROWS(); } - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); zend_string *fkey = info->hnd->firstkey(info); @@ -1083,11 +1146,12 @@ PHP_FUNCTION(dba_nextkey) zval *id; dba_info *info = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &id, dba_connection_ce) == FAILURE) { RETURN_THROWS(); } - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); zend_string *nkey = info->hnd->nextkey(info); @@ -1110,10 +1174,11 @@ PHP_FUNCTION(dba_delete) ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ARRAY_HT_OR_STR(key_ht, key_str) - Z_PARAM_RESOURCE(id); + Z_PARAM_OBJECT_OF_CLASS(id, dba_connection_ce); ZEND_PARSE_PARAMETERS_END(); - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); DBA_WRITE_CHECK(info); if (key_ht) { @@ -1151,11 +1216,12 @@ PHP_FUNCTION(dba_optimize) zval *id; dba_info *info = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &id, dba_connection_ce) == FAILURE) { RETURN_THROWS(); } - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); DBA_WRITE_CHECK(info); if (info->hnd->optimize(info) == SUCCESS) { @@ -1172,11 +1238,12 @@ PHP_FUNCTION(dba_sync) zval *id; dba_info *info = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &id) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &id, dba_connection_ce) == FAILURE) { RETURN_THROWS(); } - DBA_FETCH_RESOURCE(info, id); + info = Z_DBA_INFO_P(id); + CHECK_DBA_CONNECTION(info); if (info->hnd->sync(info) == SUCCESS) { RETURN_TRUE; @@ -1214,26 +1281,19 @@ PHP_FUNCTION(dba_handlers) /* {{{ List opened databases */ PHP_FUNCTION(dba_list) { - zend_ulong numitems, i; - zend_resource *le; - dba_info *info; - if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } array_init(return_value); - numitems = zend_hash_next_free_element(&EG(regular_list)); - for (i=1; ipath)); } - if (le->type == le_db || le->type == le_pdb) { - info = (dba_info *)(le->ptr); - add_index_str(return_value, i, zend_string_copy(info->path)); - } - } + } ZEND_HASH_FOREACH_END(); } /* }}} */ diff --git a/ext/dba/dba.stub.php b/ext/dba/dba.stub.php index 1470f6391088f..fbc0be8cdadad 100644 --- a/ext/dba/dba.stub.php +++ b/ext/dba/dba.stub.php @@ -2,8 +2,18 @@ /** @generate-class-entries */ +namespace Dba { + /** + * @strict-properties + * @not-serializable + */ + final class Connection + { + } +} + namespace { - #ifdef DBA_LMDB +#ifdef DBA_LMDB /** @var int */ const DBA_LMDB_USE_SUB_DIR = 0; /** @@ -11,49 +21,38 @@ * @cvalue MDB_NOSUBDIR */ const DBA_LMDB_NO_SUB_DIR = UNKNOWN; - #endif +#endif - /** @return resource|false */ - function dba_popen(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0, ?int $flags = null) {} + function dba_popen(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0, ?int $flags = null): Dba\Connection|false {} - /** @return resource|false */ - function dba_open(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0, ?int $flags = null) {} + function dba_open(string $path, string $mode, ?string $handler = null, int $permission = 0o644, int $map_size = 0, ?int $flags = null): Dba\Connection|false {} - /** @param resource $dba */ - function dba_close($dba): void {} + function dba_close(Dba\Connection $dba): void {} - /** @param resource $dba */ - function dba_exists(string|array $key, $dba): bool {} + function dba_exists(string|array $key, Dba\Connection $dba): bool {} /** - * @param resource|int $dba overloaded legacy signature has params flipped - * @param resource|int $skip overloaded legacy signature has params flipped + * @param Dba\Connection|int $dba overloaded legacy signature has params flipped + * @param Dba\Connection|int $skip overloaded legacy signature has params flipped */ function dba_fetch(string|array $key, $dba, $skip = 0): string|false {} /** @return array|false */ function dba_key_split(string|false|null $key): array|false {} - /** @param resource $dba */ - function dba_firstkey($dba): string|false {} + function dba_firstkey(Dba\Connection $dba): string|false {} - /** @param resource $dba */ - function dba_nextkey($dba): string|false {} + function dba_nextkey(Dba\Connection $dba): string|false {} - /** @param resource $dba */ - function dba_delete(string|array $key, $dba): bool {} + function dba_delete(string|array $key, Dba\Connection $dba): bool {} - /** @param resource $dba */ - function dba_insert(string|array $key, string $value, $dba): bool {} + function dba_insert(string|array $key, string $value, Dba\Connection $dba): bool {} - /** @param resource $dba */ - function dba_replace(string|array $key, string $value, $dba): bool {} + function dba_replace(string|array $key, string $value, Dba\Connection $dba): bool {} - /** @param resource $dba */ - function dba_optimize($dba): bool {} + function dba_optimize(Dba\Connection $dba): bool {} - /** @param resource $dba */ - function dba_sync($dba): bool {} + function dba_sync(Dba\Connection $dba): bool {} /** * @return array diff --git a/ext/dba/dba_arginfo.h b/ext/dba/dba_arginfo.h index 4fa36f7a3e44b..0d703289de1a8 100644 --- a/ext/dba/dba_arginfo.h +++ b/ext/dba/dba_arginfo.h @@ -1,7 +1,7 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 13541466ecb002ce852f3708deb420029acd0b09 */ + * Stub hash: da00cabc7b6930f1b834af8978b38945df96212f */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_dba_popen, 0, 0, 2) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_dba_popen, 0, 2, Dba\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, mode, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, handler, IS_STRING, 1, "null") @@ -13,12 +13,12 @@ ZEND_END_ARG_INFO() #define arginfo_dba_open arginfo_dba_popen ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dba_close, 0, 1, IS_VOID, 0) - ZEND_ARG_INFO(0, dba) + ZEND_ARG_OBJ_INFO(0, dba, Dba\\Connection, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dba_exists, 0, 2, _IS_BOOL, 0) ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL) - ZEND_ARG_INFO(0, dba) + ZEND_ARG_OBJ_INFO(0, dba, Dba\\Connection, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_dba_fetch, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) @@ -32,7 +32,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_dba_key_split, 0, 1, MAY_BE_ARRA ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_dba_firstkey, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_INFO(0, dba) + ZEND_ARG_OBJ_INFO(0, dba, Dba\\Connection, 0) ZEND_END_ARG_INFO() #define arginfo_dba_nextkey arginfo_dba_firstkey @@ -42,13 +42,13 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dba_insert, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_MASK(0, key, MAY_BE_STRING|MAY_BE_ARRAY, NULL) ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0) - ZEND_ARG_INFO(0, dba) + ZEND_ARG_OBJ_INFO(0, dba, Dba\\Connection, 0) ZEND_END_ARG_INFO() #define arginfo_dba_replace arginfo_dba_insert ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dba_optimize, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, dba) + ZEND_ARG_OBJ_INFO(0, dba, Dba\\Connection, 0) ZEND_END_ARG_INFO() #define arginfo_dba_sync arginfo_dba_optimize @@ -95,6 +95,10 @@ static const zend_function_entry ext_functions[] = { ZEND_FE_END }; +static const zend_function_entry class_Dba_Connection_methods[] = { + ZEND_FE_END +}; + static void register_dba_symbols(int module_number) { #if defined(DBA_LMDB) @@ -104,3 +108,14 @@ static void register_dba_symbols(int module_number) REGISTER_LONG_CONSTANT("DBA_LMDB_NO_SUB_DIR", MDB_NOSUBDIR, CONST_PERSISTENT); #endif } + +static zend_class_entry *register_class_Dba_Connection(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "Dba", "Connection", class_Dba_Connection_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; + + return class_entry; +} diff --git a/ext/dba/php_dba.h b/ext/dba/php_dba.h index 30742661c3bba..033aed59c9eac 100644 --- a/ext/dba/php_dba.h +++ b/ext/dba/php_dba.h @@ -52,6 +52,12 @@ typedef struct dba_info { dba_lock lock; } dba_info; +typedef struct dba_connection { + dba_info *info; + zend_string *hash; + zend_object std; +} dba_connection; + #define DBA_DEFAULT_DRIVER_FLAGS -1 #define DBA_LOCK_READER (0x0001) diff --git a/ext/dba/tests/bug36436.phpt b/ext/dba/tests/bug36436.phpt index 9e7603f5a39f9..23fc9a11653dd 100644 --- a/ext/dba/tests/bug36436.phpt +++ b/ext/dba/tests/bug36436.phpt @@ -29,7 +29,8 @@ $db_name = 'bug36436.db'; cleanup_standard_db($db_name); ?> --EXPECTF-- -resource(%d) of type (dba persistent) +object(Dba\Connection)#%d (%d) { +} string(16) "Content String 1" string(13) "[key10]name10" string(13) "[key30]name30" diff --git a/ext/dba/tests/dba015.phpt b/ext/dba/tests/dba015.phpt index 5712edce59d41..52e280ced1f48 100644 --- a/ext/dba/tests/dba015.phpt +++ b/ext/dba/tests/dba015.phpt @@ -45,7 +45,11 @@ echo dba_fetch("key2", $db_file1), "\n"; echo "Test 5 - close 2nd resource\n"; dba_close($db_file2); var_dump($db_file1); -var_dump($db_file2); +try { + dba_exists("key1", $db_file2); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} echo "Test 6 - query after closing 2nd resource\n"; echo dba_fetch("key1", $db_file1), "\n"; @@ -69,8 +73,9 @@ Test 4 - fetch both rows from first resource This is a test insert 1 This is a test insert 2 Test 5 - close 2nd resource -resource(%d) of type (dba persistent) -resource(%d) of type (Unknown) +object(Dba\Connection)#%d (%d) { +} +DBA connection has already been closed Test 6 - query after closing 2nd resource This is a test insert 1 This is a test insert 2 diff --git a/ext/dba/tests/dba_db4_018.phpt b/ext/dba/tests/dba_db4_018.phpt index dd360a2ec6bba..80d6dc42cc531 100644 --- a/ext/dba/tests/dba_db4_018.phpt +++ b/ext/dba/tests/dba_db4_018.phpt @@ -45,7 +45,11 @@ echo dba_fetch("key2", $db_file1), "\n"; echo "Test 5 - close 2nd resource\n"; dba_close($db_file2); var_dump($db_file1); -var_dump($db_file2); +try { + dba_exists("key1", $db_file2); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} echo "Test 6 - query after closing 2nd resource\n"; echo dba_fetch("key1", $db_file1), "\n"; @@ -69,8 +73,9 @@ Test 4 - fetch both rows from first resource This is a test insert 1 This is a test insert 2 Test 5 - close 2nd resource -resource(%d) of type (dba persistent) -resource(%d) of type (Unknown) +object(Dba\Connection)#%d (%d) { +} +DBA connection has already been closed Test 6 - query after closing 2nd resource This is a test insert 1 This is a test insert 2 diff --git a/ext/dba/tests/default_handler_ini.phpt b/ext/dba/tests/default_handler_ini.phpt index ba115f76e2037..f81169026f4f5 100644 --- a/ext/dba/tests/default_handler_ini.phpt +++ b/ext/dba/tests/default_handler_ini.phpt @@ -39,7 +39,8 @@ database handler: flatfile Test 1 Warning: ini_set(): No such handler: does_not_exist in %s on line %d -resource(%d) of type (dba) +object(Dba\Connection)#%d (%d) { +} Test 2 Warning: dba_open(): No default handler selected in %s on line %d diff --git a/ext/dba/tests/gh9155.phpt b/ext/dba/tests/gh9155.phpt index 19ea67b2ab872..5224e36c1ff24 100644 --- a/ext/dba/tests/gh9155.phpt +++ b/ext/dba/tests/gh9155.phpt @@ -22,4 +22,5 @@ var_dump($db); require_once(__DIR__ .'/clean.inc'); ?> --EXPECTF-- -resource(%d) of type (dba) +object(Dba\Connection)#%d (%d) { +} diff --git a/ext/dba/tests/value_errors_open.phpt b/ext/dba/tests/value_errors_open.phpt index 9b61ec718f83a..9bbb0b00a94d0 100644 --- a/ext/dba/tests/value_errors_open.phpt +++ b/ext/dba/tests/value_errors_open.phpt @@ -115,7 +115,8 @@ require(__DIR__ .'/clean.inc'); ?> --EXPECTF-- database handler: flatfile -resource(%d) of type (dba) +object(Dba\Connection)#%d (%d) { +} === Invalid arguments dba_open() === Warning: dba_open(): Handler "bogus" is not available in %s on line %d From 32433d850105c6dcddfd895b3c2dc66a347b7681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 15 May 2024 09:45:12 +0200 Subject: [PATCH 2/5] Use proc_open instead of dba_open in test --- ...et_external_entity_loader_error_callback_name.phpt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt index 1bdbbfb5b817e..6d6d038388137 100644 --- a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt +++ b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt @@ -2,7 +2,6 @@ libxml_get_external_entity_loader() display correct callable name --EXTENSIONS-- dom -dba --FILE-- getMessage()); } -?> ---CLEAN-- - --EXPECT-- string(73) "DOMDocument::validate(): supplied resource is not a valid stream resource" From 08f3ab8b9ee4cdc65882fb87b3559b17b0f6bd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 15 May 2024 21:54:17 +0200 Subject: [PATCH 3/5] Review + test fix --- ext/dba/dba.c | 14 ++++++++++++++ ...external_entity_loader_error_callback_name.phpt | 2 ++ 2 files changed, 16 insertions(+) diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 5f2daa5d75b43..d6c7979d47410 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -326,6 +326,19 @@ static zend_function *dba_connection_get_constructor(zend_object *object) return NULL; } +static zend_result dba_connection_cast_object(zend_object *obj, zval *result, int type) +{ + if (type == IS_LONG) { + /* For better backward compatibility, make (int) $dba return the object ID, + * similar to how it previously returned the resource ID. */ + ZVAL_LONG(result, obj->handle); + + return SUCCESS; + } + + return zend_std_cast_object_tostring(obj, result, type); +} + static inline dba_connection *dba_connection_from_obj(zend_object *obj) { return (dba_connection *)((char *)(obj) - XtOffsetOf(dba_connection, std)); @@ -404,6 +417,7 @@ PHP_MINIT_FUNCTION(dba) dba_connection_object_handlers.free_obj = dba_connection_free_obj; dba_connection_object_handlers.get_constructor = dba_connection_get_constructor; dba_connection_object_handlers.clone_obj = NULL; + dba_connection_object_handlers.cast_object = dba_connection_cast_object; dba_connection_object_handlers.compare = zend_objects_not_comparable; return SUCCESS; diff --git a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt index 6d6d038388137..cee9b4140996d 100644 --- a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt +++ b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt @@ -2,6 +2,8 @@ libxml_get_external_entity_loader() display correct callable name --EXTENSIONS-- dom +--SKIPIF-- + --FILE-- Date: Wed, 15 May 2024 22:40:37 +0200 Subject: [PATCH 4/5] Really fix test --- .../libxml_get_external_entity_loader_error_callback_name.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt index cee9b4140996d..20e783e279848 100644 --- a/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt +++ b/ext/libxml/tests/libxml_get_external_entity_loader_error_callback_name.phpt @@ -3,7 +3,7 @@ libxml_get_external_entity_loader() display correct callable name --EXTENSIONS-- dom --SKIPIF-- - + --FILE-- Date: Thu, 16 May 2024 23:03:25 +0200 Subject: [PATCH 5/5] Fix review comments --- ext/dba/dba.c | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/ext/dba/dba.c b/ext/dba/dba.c index d6c7979d47410..5cffe3b09f07a 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -239,9 +239,7 @@ static int le_pdb; static zend_class_entry *dba_connection_ce; static zend_object_handlers dba_connection_object_handlers; -/* }}} */ -/* {{{ dba_close */ static void dba_close_info(dba_info *info) { ZEND_ASSERT(info != NULL && "connection has already been closed"); @@ -496,7 +494,7 @@ static dba_info *php_dba_find(const zend_string *path) { zval *zv; - ZEND_HASH_FOREACH_VAL(&DBA_G(connections), zv) { + ZEND_HASH_MAP_FOREACH_VAL(&DBA_G(connections), zv) { dba_info *info = Z_DBA_INFO_P(zv); if (info && zend_string_equals(path, info->path)) { return info; @@ -520,9 +518,6 @@ static zend_always_inline zend_string *php_dba_zend_string_dup_safe(zend_string } } - -#define FREE_RESOURCE_KEY() efree(resource_key); - /* {{{ php_dba_open */ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) { @@ -587,7 +582,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if ((le = zend_hash_str_find_ptr(&EG(persistent_list), resource_key, resource_key_len)) != NULL) { if (le->type != le_pdb) { // TODO This should never happen - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_FALSE; } @@ -604,7 +599,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } zend_hash_add_new(&DBA_G(connections), connection->hash, return_value); - FREE_RESOURCE_KEY(); + efree(resource_key); return; } } @@ -613,7 +608,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) hptr = DBA_G(default_hptr); if (!hptr) { php_error_docref(NULL, E_WARNING, "No default handler selected"); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_FALSE; } ZEND_ASSERT(hptr->name); @@ -623,7 +618,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (!hptr->name) { php_error_docref(NULL, E_WARNING, "Handler \"%s\" is not available", ZSTR_VAL(handler_str)); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_FALSE; } } @@ -647,18 +642,18 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (ZSTR_LEN(mode) == 0) { zend_argument_value_error(2, "cannot be empty"); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_THROWS(); } if (ZSTR_LEN(mode) > 3) { zend_argument_value_error(2, "must be at most 3 characters"); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_THROWS(); } if (ZSTR_LEN(mode) == 3) { if (ZSTR_VAL(mode)[2] != 't') { zend_argument_value_error(2, "third character must be \"t\""); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_THROWS(); } is_test_lock = true; @@ -671,7 +666,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) case '-': if ((hptr->flags & DBA_LOCK_ALL) == 0) { php_error_docref(NULL, E_WARNING, "Locking cannot be disabled for handler %s", hptr->name); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_FALSE; } is_lock_ignored = true; @@ -693,7 +688,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) break; default: zend_argument_value_error(2, "second character must be one of \"d\", \"l\", \"-\", or \"t\""); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_THROWS(); } } else { @@ -762,7 +757,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) break; default: zend_argument_value_error(2, "first character must be one of \"r\", \"w\", \"c\", or \"n\""); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_THROWS(); } if (!lock_file_mode) { @@ -771,17 +766,17 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (is_test_lock) { if (is_lock_ignored) { zend_argument_value_error(2, "cannot combine mode \"-\" (no lock) and \"t\" (test lock)"); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_THROWS(); } if (!lock_mode) { if ((hptr->flags & DBA_LOCK_ALL) == 0) { php_error_docref(NULL, E_WARNING, "Handler %s uses its own locking which doesn't support mode modifier t (test lock)", hptr->name); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_FALSE; } else { php_error_docref(NULL, E_WARNING, "Handler %s doesn't uses locking for this mode which makes modifier t (test lock) obsolete", hptr->name); - FREE_RESOURCE_KEY(); + efree(resource_key); RETURN_FALSE; } } else { @@ -871,7 +866,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } if (!connection->info->lock.fp) { /* stream operation already wrote an error message */ - FREE_RESOURCE_KEY(); + efree(resource_key); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -892,7 +887,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) } if (!connection->info->fp) { /* stream operation already wrote an error message */ - FREE_RESOURCE_KEY(); + efree(resource_key); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -902,7 +897,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) */ if (SUCCESS != php_stream_cast(connection->info->fp, PHP_STREAM_AS_FD, (void*)&connection->info->fd, 1)) { php_error_docref(NULL, E_WARNING, "Could not cast stream"); - FREE_RESOURCE_KEY(); + efree(resource_key); zval_ptr_dtor(return_value); RETURN_FALSE; #ifdef F_SETFL @@ -938,7 +933,7 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) php_error_docref(NULL, E_WARNING, "Driver initialization failed for handler: %s", hptr->name); } } - FREE_RESOURCE_KEY(); + efree(resource_key); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -948,14 +943,14 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) if (persistent) { if (zend_register_persistent_resource(resource_key, resource_key_len, connection->info, le_pdb) == NULL) { php_error_docref(NULL, E_WARNING, "Could not register persistent resource"); - FREE_RESOURCE_KEY(); + efree(resource_key); zval_ptr_dtor(return_value); RETURN_FALSE; } } zend_hash_add_new(&DBA_G(connections), connection->hash, return_value); - FREE_RESOURCE_KEY(); + efree(resource_key); } /* }}} */ @@ -1302,7 +1297,7 @@ PHP_FUNCTION(dba_list) array_init(return_value); zval *zv; - ZEND_HASH_FOREACH_VAL(&DBA_G(connections), zv) { + ZEND_HASH_MAP_FOREACH_VAL(&DBA_G(connections), zv) { dba_info *info = Z_DBA_INFO_P(zv); if (info) { add_next_index_str(return_value, zend_string_copy(info->path));