diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 9910b2b43bbaa..9c60015985c6d 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -2076,6 +2076,7 @@ static void php_pgsql_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, zend_long result_ ZVAL_COPY_VALUE(&dataset, return_value); 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) { diff --git a/ext/tidy/tests/018.phpt b/ext/tidy/tests/018.phpt index b07770eebb2b1..e3934aa6d9fa0 100644 --- a/ext/tidy/tests/018.phpt +++ b/ext/tidy/tests/018.phpt @@ -7,7 +7,7 @@ tidy $x = tidy_repair_string("

abra\0cadabra

", array( 'show-body-only' => true, 'clean' => false, - 'newline' => "\n") + 'newline' => "LF") ); var_dump($x); ?> diff --git a/ext/tidy/tests/gh20374.phpt b/ext/tidy/tests/gh20374.phpt new file mode 100644 index 0000000000000..39c3ba06d315e --- /dev/null +++ b/ext/tidy/tests/gh20374.phpt @@ -0,0 +1,175 @@ +--TEST-- +GH-20374 (PHP with tidy and custom-tags) +--EXTENSIONS-- +tidy +--CREDITS-- +franck-paul +--FILE-- +ret; + } +} + +class MyThrowingStringable { + public function __toString(): string { + throw new Error('no'); + } +} + +$values = [ + 'string blocklevel' => 'blocklevel', + 'int' => 1, + 'double overflow' => (string) (2.0**80.0), + 'numeric string int 1' => '1', + 'numeric string double 1.0' => '1.0', + 'false' => false, + 'true' => true, + 'NAN' => NAN, + 'INF' => INF, + 'object with numeric string int 0' => new MyStringable('0'), + 'object with string blocklevel' => new MyStringable('blocklevel'), + 'object with string empty' => new MyStringable('empty'), + 'object with exception' => new MyThrowingStringable, +]; + +foreach ($values as $key => $value) { + echo "--- $key ---\n"; + $str = 'test'; + + $config = [ + 'custom-tags' => $value, + ]; + + $tidy = new tidy(); + try { + $tidy->parseString($str, $config, 'utf8'); + echo $tidy->value, "\n"; + } catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; + } +} + +?> +--EXPECTF-- +--- string blocklevel --- + + + + + +test + + +--- int --- + + + + + +test + + +--- double overflow --- + +Warning: The float-string "1.2089258196146E+24" is not representable as an int, cast occurred in %s on line %d + + + + + +test + + +--- numeric string int 1 --- + + + + + +test + + +--- numeric string double 1.0 --- + + + + + +test + + +--- false --- + + + + + +test + + +--- true --- + + + + + +test + + +--- NAN --- + +Warning: The float NAN is not representable as an int, cast occurred in %s on line %d + + + + + +test + + +--- INF --- + +Warning: The float INF is not representable as an int, cast occurred in %s on line %d + + + + + +test + + +--- object with numeric string int 0 --- + + + + + +test + + +--- object with string blocklevel --- + + + + + +test + + +--- object with string empty --- + + + + + + +test + + +--- object with exception --- +Error: no diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index cbe12904795e6..63820d1a3075b 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -719,6 +719,7 @@ static bool php_tidy_set_tidy_opt(TidyDoc doc, const char *optname, zval *value, { TidyOption opt = tidyGetOptionByName(doc, optname); zend_long lval; + zend_string *tmp_str; if (!opt) { zend_argument_value_error(arg, "Unknown Tidy configuration option \"%s\"", optname); @@ -736,7 +737,6 @@ static bool php_tidy_set_tidy_opt(TidyDoc doc, const char *optname, zval *value, TidyOptionType type = tidyOptGetType(opt); if (type == TidyString) { - zend_string *tmp_str; const zend_string *str = zval_get_tmp_string(value, &tmp_str); const bool result = tidyOptSetValue(doc, tidyOptGetId(opt), ZSTR_VAL(str)); if (UNEXPECTED(!result)) { @@ -744,9 +744,35 @@ static bool php_tidy_set_tidy_opt(TidyDoc doc, const char *optname, zval *value, } zend_tmp_string_release(tmp_str); return result; - } else if (type == TidyInteger) { - lval = zval_get_long(value); - return tidyOptSetInt(doc, tidyOptGetId(opt), lval); + } else if (type == TidyInteger) { /* integer or enum */ + ZVAL_DEREF(value); + /* Enum will correspond to a non-numeric string or object */ + if (Z_TYPE_P(value) == IS_STRING || Z_TYPE_P(value) == IS_OBJECT) { + double dval; + bool result; + const zend_string *str = zval_try_get_tmp_string(value, &tmp_str); + if (UNEXPECTED(!str)) { + return false; + } + uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &lval, &dval, true); + if (type == IS_DOUBLE) { + lval = zend_dval_to_lval_cap(dval, str); + type = IS_LONG; + } + if (type == IS_LONG) { + result = tidyOptSetInt(doc, tidyOptGetId(opt), lval); + } else { + result = tidyOptSetValue(doc, tidyOptGetId(opt), ZSTR_VAL(str)); + if (UNEXPECTED(!result)) { + zend_argument_type_error(arg, "option \"%s\" does not accept \"%s\" as a value", optname, ZSTR_VAL(str)); + } + } + zend_tmp_string_release(tmp_str); + return result; + } else { + lval = zval_get_long(value); + return tidyOptSetInt(doc, tidyOptGetId(opt), lval); + } } else { ZEND_ASSERT(type == TidyBoolean); lval = zval_get_long(value);