Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ PHP NEWS
- PGSQL:
. Enabled 64 bits support for pg_lo_truncate()/pg_lo_tell()
if the server supports it. (KentarouTakeda)
. pg_fetch_object() now surfaces non-instantiable class errors
before fetching, resolves the constructor via the get_constructor
handler, and reports the empty-constructor ValueError on the
$constructor_args argument. (David Carlier)

- Phar:
. Support reference values in Phar::mungServer(). (ndossche)
Expand Down
7 changes: 7 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ PHP 8.6 UPGRADE NOTES
. Phar::mungServer() now raises a ValueError when an invalid
argument value is passed instead of being silently ignored.

- PGSQL:
. pg_fetch_object() now reports the ValueError for a non-empty
$constructor_args on a class without a constructor on the
$constructor_args argument instead of $class. Errors raised when
the requested class is not instantiable (abstract, interface, enum)
now surface before the row is fetched.

- Posix:
. posix_access() now raises a ValueError when an invalid $flags
argument value is passed.
Expand Down
2 changes: 1 addition & 1 deletion ext/odbc/odbc_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ PHP_FUNCTION(odbc_connection_string_quote)
Z_PARAM_STR(str)
ZEND_PARSE_PARAMETERS_END();

size_t new_size = php_odbc_connstr_estimate_quote_length(ZSTR_VAL(str));
size_t new_size = php_odbc_connstr_get_quoted_length(ZSTR_VAL(str));
zend_string *new_string = zend_string_alloc(new_size, 0);
php_odbc_connstr_quote(ZSTR_VAL(new_string), ZSTR_VAL(str), new_size);
/* reset length */
Expand Down
12 changes: 6 additions & 6 deletions ext/odbc/php_odbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1951,9 +1951,9 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool
if (use_uid_arg) {
should_quote_uid = !php_odbc_connstr_is_quoted(uid) && php_odbc_connstr_should_quote(uid);
if (should_quote_uid) {
size_t estimated_length = php_odbc_connstr_estimate_quote_length(uid);
uid_quoted = emalloc(estimated_length);
php_odbc_connstr_quote(uid_quoted, uid, estimated_length);
size_t quoted_length = php_odbc_connstr_get_quoted_length(uid);
uid_quoted = emalloc(quoted_length);
php_odbc_connstr_quote(uid_quoted, uid, quoted_length);
} else {
uid_quoted = uid;
}
Expand All @@ -1966,9 +1966,9 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool
if (use_pwd_arg) {
should_quote_pwd = !php_odbc_connstr_is_quoted(pwd) && php_odbc_connstr_should_quote(pwd);
if (should_quote_pwd) {
size_t estimated_length = php_odbc_connstr_estimate_quote_length(pwd);
pwd_quoted = emalloc(estimated_length);
php_odbc_connstr_quote(pwd_quoted, pwd, estimated_length);
size_t quoted_length = php_odbc_connstr_get_quoted_length(pwd);
pwd_quoted = emalloc(quoted_length);
php_odbc_connstr_quote(pwd_quoted, pwd, quoted_length);
} else {
pwd_quoted = pwd;
}
Expand Down
12 changes: 6 additions & 6 deletions ext/pdo_odbc/odbc_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,9 @@ static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{
if (use_uid_arg) {
should_quote_uid = !php_odbc_connstr_is_quoted(dbh->username) && php_odbc_connstr_should_quote(dbh->username);
if (should_quote_uid) {
size_t estimated_length = php_odbc_connstr_estimate_quote_length(dbh->username);
uid = emalloc(estimated_length);
php_odbc_connstr_quote(uid, dbh->username, estimated_length);
size_t quoted_length = php_odbc_connstr_get_quoted_length(dbh->username);
uid = emalloc(quoted_length);
php_odbc_connstr_quote(uid, dbh->username, quoted_length);
} else {
uid = dbh->username;
}
Expand All @@ -565,9 +565,9 @@ static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{
if (use_pwd_arg) {
should_quote_pwd = !php_odbc_connstr_is_quoted(dbh->password) && php_odbc_connstr_should_quote(dbh->password);
if (should_quote_pwd) {
size_t estimated_length = php_odbc_connstr_estimate_quote_length(dbh->password);
pwd = emalloc(estimated_length);
php_odbc_connstr_quote(pwd, dbh->password, estimated_length);
size_t quoted_length = php_odbc_connstr_get_quoted_length(dbh->password);
pwd = emalloc(quoted_length);
php_odbc_connstr_quote(pwd, dbh->password, quoted_length);
} else {
pwd = dbh->password;
}
Expand Down
41 changes: 27 additions & 14 deletions ext/pgsql/pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -2129,37 +2129,50 @@ PHP_FUNCTION(pg_fetch_object)
ce = zend_standard_class_def;
}

if (!ce->constructor && ctor_params && zend_hash_num_elements(ctor_params) > 0) {
zend_argument_value_error(3,
"must be empty when the specified class (%s) does not have a constructor",
ZSTR_VAL(ce->name)
);
if (UNEXPECTED(object_init_ex(return_value, ce) == FAILURE)) {
RETURN_THROWS();
}

zval dataset;
if (UNEXPECTED(!php_pgsql_fetch_hash(&dataset, result, row, row_is_null, PGSQL_ASSOC))) {
/* Either an exception is thrown, or we return false */
zval_ptr_dtor(return_value);
RETURN_FALSE;
}

// TODO: Check CE is an instantiable class earlier?
zend_result obj_initialized = object_init_ex(return_value, ce);
if (UNEXPECTED(obj_initialized == FAILURE)) {
zval_ptr_dtor(&dataset);
RETURN_THROWS();
}
if (!ce->default_properties_count && !ce->__set) {
Z_OBJ_P(return_value)->properties = Z_ARR(dataset);
} else {
zend_merge_properties(return_value, Z_ARRVAL(dataset));
zval_ptr_dtor(&dataset);
}

// TODO: Need to grab constructor via object handler as this allows instantiating internal objects with overridden get_constructor
if (ce->constructor) {
zend_call_known_function(ce->constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value),
zend_object *obj = Z_OBJ_P(return_value);
const zend_class_entry *old = EG(fake_scope);
EG(fake_scope) = ce;
zend_function *constructor = obj->handlers->get_constructor(obj);
EG(fake_scope) = old;

if (UNEXPECTED(EG(exception))) {
/* visibility error or override refused - VM dtors return_value */
return;
}

if (UNEXPECTED(!constructor && ctor_params && zend_hash_num_elements(ctor_params) > 0)) {
zend_argument_value_error(4,
"must be empty when the specified class (%s) does not have a constructor",
ZSTR_VAL(ce->name)
);
RETURN_THROWS();
}

if (constructor) {
zend_call_known_function(constructor, obj, ce,
/* retval */ NULL, /* argc */ 0, /* params */ NULL, ctor_params);
if (EG(exception)) {
zend_object_store_ctor_failed(obj);
RETURN_THROWS();
}
}
}
/* }}} */
Expand Down
69 changes: 69 additions & 0 deletions ext/pgsql/tests/pg_fetch_object_ctor_paths.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
--TEST--
pg_fetch_object() constructor handling: ctor_params validation, throwing constructor, property visibility
--EXTENSIONS--
pgsql
--SKIPIF--
<?php include("inc/skipif.inc"); ?>
--FILE--
<?php
include 'inc/config.inc';

class NoCtor {}

class ThrowingCtor {
public function __construct() {
throw new RuntimeException('boom');
}
public function __destruct() {
echo "ThrowingCtor::__destruct called (BUG)\n";
}
}

class SeesProps {
public function __construct() {
echo "ctor sees: num={$this->num}, str={$this->str}\n";
}
public function __destruct() {
echo "SeesProps::__destruct called\n";
}
}

$table_name = "pg_fetch_object_ctor_paths";
$db = pg_connect($conn_str);
pg_query($db, "CREATE TABLE {$table_name} (num int, str text)");
pg_query($db, "INSERT INTO {$table_name} VALUES(1, 'hello')");

$sql = "SELECT * FROM {$table_name} WHERE num = 1";

// 1) ctor_params on a class with no constructor must throw ValueError
try {
pg_fetch_object(pg_query($db, $sql), null, 'NoCtor', [1, 2]);
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}

// 2) Constructor that throws: __destruct must NOT run on the partially constructed object
try {
pg_fetch_object(pg_query($db, $sql), null, 'ThrowingCtor');
} catch (RuntimeException $e) {
echo "caught: ", $e->getMessage(), "\n";
}

// 3) Constructor sees row properties already merged onto $this
$obj = pg_fetch_object(pg_query($db, $sql), null, 'SeesProps');
unset($obj);

echo "Ok\n";
?>
--CLEAN--
<?php
include('inc/config.inc');
$db = pg_connect($conn_str);
pg_query($db, "DROP TABLE IF EXISTS pg_fetch_object_ctor_paths");
?>
--EXPECT--
pg_fetch_object(): Argument #4 ($constructor_args) must be empty when the specified class (NoCtor) does not have a constructor
caught: boom
ctor sees: num=1, str=hello
SeesProps::__destruct called
Ok
4 changes: 1 addition & 3 deletions ext/phar/dirstream.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
#include "phar_internal.h"
#include "dirstream.h"

void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, bool is_dir);

static const php_stream_ops phar_dir_ops = {
phar_dir_write, /* write */
phar_dir_read, /* read */
Expand Down Expand Up @@ -300,7 +298,7 @@ php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path,

const char *internal_file = ZSTR_VAL(resource->path) + 1; /* strip leading "/" */
size_t internal_file_len = ZSTR_LEN(resource->path) - 1;
phar_entry_info *entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, internal_file_len);
const phar_entry_info *entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, internal_file_len);
php_stream *ret;

if (NULL != entry && !entry->is_dir) {
Expand Down
16 changes: 8 additions & 8 deletions ext/phar/phar.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ ZEND_ATTRIBUTE_NONNULL void phar_entry_remove(phar_entry_data *idata, char **err
/**
* Open an already loaded phar
*/
static zend_result phar_open_parsed_phar(char *fname, size_t fname_len, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
static zend_result phar_open_parsed_phar(char *fname, size_t fname_len, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
{
#ifdef PHP_WIN32
char *save_fname;
Expand Down Expand Up @@ -720,7 +720,7 @@ void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker
* This is used by phar_open_from_filename to process the manifest, but can be called
* directly.
*/
static zend_result phar_parse_pharfile(php_stream *fp, char *fname, size_t fname_len, char *alias, size_t alias_len, zend_long halt_offset, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */
static zend_result phar_parse_pharfile(php_stream *fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, zend_long halt_offset, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */
{
char b32[4], *buffer, *endbuffer, *savebuf;
phar_archive_data *mydata = NULL;
Expand Down Expand Up @@ -1302,7 +1302,7 @@ static zend_result phar_parse_pharfile(php_stream *fp, char *fname, size_t fname
/**
* Create or open a phar for writing
*/
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
{
const char *ext_str, *z;
char *my_error;
Expand Down Expand Up @@ -1366,9 +1366,9 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(ze
}
/* }}} */

static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error);
static zend_result phar_open_from_fp(php_stream* fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error);

ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
{
php_stream *fp;
zend_string *actual = NULL;
Expand Down Expand Up @@ -1507,7 +1507,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(z
* that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS
* or FAILURE is returned and pphar is set to a pointer to the phar's manifest
*/
zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
zend_result phar_open_from_filename(char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
{
php_stream *fp;
zend_string *actual;
Expand Down Expand Up @@ -1564,7 +1564,7 @@ zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias,
* that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS
* or FAILURE is returned and pphar is set to a pointer to the phar's manifest
*/
static zend_result phar_open_from_fp(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
static zend_result phar_open_from_fp(php_stream* fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error) /* {{{ */
{
static const char token[] = "__HALT_COMPILER();";
static const char zip_magic[] = "PK\x03\x04";
Expand Down Expand Up @@ -2252,7 +2252,7 @@ zend_string* phar_split_fname(const char *filename, size_t filename_len, zend_st
* Invoked when a user calls Phar::mapPhar() from within an executing .phar
* to set up its manifest directly
*/
ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **error) /* {{{ */
ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(const char *alias, size_t alias_len, char **error) /* {{{ */
{
*error = NULL;

Expand Down
14 changes: 7 additions & 7 deletions ext/phar/phar_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,10 +406,10 @@ void phar_object_init(void);
void phar_destroy_phar_data(phar_archive_data *phar);

ZEND_ATTRIBUTE_NONNULL zend_result phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip);
zend_result phar_open_from_filename(char *fname, size_t fname_len, char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(char *alias, size_t alias_len, char **error);
zend_result phar_open_from_filename(char *fname, size_t fname_len, const char *alias, size_t alias_len, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_create_or_parse_filename(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(const char *alias, size_t alias_len, char **error);
zend_result phar_free_alias(const phar_archive_data *phar);
phar_archive_data* phar_get_archive(const char *fname, size_t fname_len, const char *alias, size_t alias_len, char **error);
zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, const char *sig, size_t sig_len, const char *fname, char **signature, size_t *signature_len, char **error);
Expand All @@ -423,7 +423,7 @@ const char *phar_compress_filter(const phar_entry_info *entry, bool return_unkno
/* void phar_remove_virtual_dirs(phar_archive_data *phar, char *filename, size_t filename_len); */
void phar_add_virtual_dirs(phar_archive_data *phar, const char *filename, size_t filename_len);
zend_result phar_mount_entry(phar_archive_data *phar, const char *filename, size_t filename_len, char *path, size_t path_len);
zend_string *phar_find_in_include_path(zend_string *file, phar_archive_data **pphar);
zend_string *phar_find_in_include_path(const zend_string *file, phar_archive_data **pphar);
zend_string* phar_fix_filepath(const char *path, size_t path_length, bool use_cwd);
ZEND_ATTRIBUTE_NONNULL phar_entry_info * phar_open_jit(const phar_archive_data *phar, phar_entry_info *entry, char **error);
void phar_parse_metadata_lazy(const char *buffer, phar_metadata_tracker *tracker, uint32_t zip_metadata_len, bool persistent);
Expand All @@ -446,12 +446,12 @@ zend_result phar_copy_on_write(phar_archive_data **pphar);
/* tar functions in tar.c */
bool phar_is_tar(const char *buf, const char *fname);
zend_result phar_parse_tarfile(php_stream* fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, phar_archive_data** pphar, uint32_t compression, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_tar(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_tar(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_default_stub, char **error);

/* zip functions in zip.c */
zend_result phar_parse_zipfile(php_stream *fp, const char *fname, size_t fname_len, const char *alias, size_t alias_len, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_zip(zend_string *fname, char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 6, 7) zend_result phar_open_or_create_zip(zend_string *fname, const char *alias, size_t alias_len, bool is_data, uint32_t options, phar_archive_data** pphar, char **error);
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_zip_flush(phar_archive_data *archive, zend_string *user_stub, bool is_default_stub, char **error);

#ifdef PHAR_MAIN
Expand Down
5 changes: 3 additions & 2 deletions ext/phar/phar_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,10 @@ static void phar_do_404(phar_archive_data *phar, char *fname, size_t fname_len,
/* post-process REQUEST_URI and retrieve the actual request URI. This is for
cases like http://localhost/blah.phar/path/to/file.php/extra/stuff
which calls "blah.phar" file "path/to/file.php" with PATH_INFO "/extra/stuff" */
static void phar_postprocess_ru_web(const char *fname, size_t fname_len, char *entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */
static void phar_postprocess_ru_web(const char *fname, size_t fname_len, const char *entry, size_t *entry_len, char **ru, size_t *ru_len) /* {{{ */
{
char *e = entry + 1, *u1 = NULL, *u = NULL, *saveu = NULL;
const char *e = entry + 1;
char *u1 = NULL, *u = NULL, *saveu = NULL;
size_t e_len = *entry_len - 1, u_len = 0;
phar_archive_data *pphar;

Expand Down
Loading