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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ PHP NEWS
- Intl:
. Fixed malformed ResourceBundle::get() error message when fallback is
disabled. (Weilin Du)
. Fix incorrect argument positions for invalid start/end arguments in
transliterator_transliterate(). (Weilin Du)
. Fixed IntlTimeZone::getDisplayName() to synchronize object error state
for invalid display types. (Weilin Du)
. Added IntlNumberRangeFormatter class to format an interval of two numbers
Expand Down
43 changes: 34 additions & 9 deletions ext/intl/tests/transliterator_transliterate_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,38 @@ intl.use_exceptions=true

$tr = Transliterator::create("latin");

try {
var_dump(transliterator_transliterate($tr, "str", 7));
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
function dump_throwable(callable $callback): void {
try {
$callback();
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
}

try {
//Arguments
dump_throwable(function() use ($tr) {
var_dump(transliterator_transliterate($tr, "str", 7));
});

dump_throwable(function() use ($tr) {
transliterator_transliterate($tr, "str", 7, 6);
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
});

dump_throwable(function() use ($tr) {
transliterator_transliterate($tr, "str", 0, -2);
});

dump_throwable(function() use ($tr) {
transliterator_transliterate($tr, "str", -1);
});

dump_throwable(function() {
transliterator_transliterate("latin", "str", -1);
});

dump_throwable(function() use ($tr) {
$tr->transliterate("str", 7, 6);
});

//bad UTF-8
try {
Expand All @@ -31,5 +52,9 @@ try {
?>
--EXPECT--
IntlException: transliterator_transliterate(): Neither "start" nor the "end" arguments can exceed the number of UTF-16 code units (in this case, 3)
ValueError: transliterator_transliterate(): Argument #2 ($string) must be less than or equal to argument #3 ($end)
ValueError: transliterator_transliterate(): Argument #3 ($start) must be less than or equal to argument #4 ($end)
ValueError: transliterator_transliterate(): Argument #4 ($end) must be greater than or equal to -1
ValueError: transliterator_transliterate(): Argument #3 ($start) must be greater than or equal to 0
ValueError: transliterator_transliterate(): Argument #3 ($start) must be greater than or equal to 0
ValueError: Transliterator::transliterate(): Argument #2 ($start) must be less than or equal to argument #3 ($end)
IntlException: transliterator_transliterate(): String conversion of string to UTF-16 failed
10 changes: 6 additions & 4 deletions ext/intl/transliterator/transliterator_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,16 @@ U_CFUNC PHP_FUNCTION( transliterator_transliterate )
zend_long start = 0,
limit = -1;
int success = 0;
bool is_method;
zval tmp_object;
TRANSLITERATOR_METHOD_INIT_VARS;

object = getThis();
is_method = object != NULL;

ZVAL_UNDEF(&tmp_object);

if (object == nullptr) {
if (!is_method) {
/* in non-OOP version, accept both a transliterator and a string */
zend_string *arg1_str;
zend_object *arg1_obj;
Expand Down Expand Up @@ -320,17 +322,17 @@ U_CFUNC PHP_FUNCTION( transliterator_transliterate )
}

if (limit < -1) {
zend_argument_value_error(object ? 3 : 4, "must be greater than or equal to -1");
zend_argument_value_error(is_method ? 3 : 4, "must be greater than or equal to -1");
goto cleanup_object;
}

if (start < 0) {
zend_argument_value_error(object ? 2 : 3, "must be greater than or equal to 0");
zend_argument_value_error(is_method ? 2 : 3, "must be greater than or equal to 0");
goto cleanup_object;
}

if (limit != -1 && start > limit) {
zend_argument_value_error(object ? 2 : 3, "must be less than or equal to argument #%d ($end)", object ? 3 : 4);
zend_argument_value_error(is_method ? 2 : 3, "must be less than or equal to argument #%d ($end)", is_method ? 3 : 4);
goto cleanup_object;
}

Expand Down
7 changes: 6 additions & 1 deletion ext/openssl/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,12 @@ PHP_METHOD(Openssl_Session, __unserialize)
Z_PARAM_ARRAY_HT(data)
ZEND_PARSE_PARAMETERS_END();

php_openssl_session_object *obj = Z_OPENSSL_SESSION_P(ZEND_THIS);
if (obj->session != NULL) {
zend_throw_error(NULL, "Cannot call Openssl\\Session::__unserialize() on an already-initialized session");
RETURN_THROWS();
}

zval *pem_zv = zend_hash_str_find(data, ZEND_STRL("pem"));
if (!pem_zv || Z_TYPE_P(pem_zv) != IS_STRING) {
zend_throw_exception(php_openssl_exception_ce, "Invalid serialization data", 0);
Expand All @@ -524,7 +530,6 @@ PHP_METHOD(Openssl_Session, __unserialize)
RETURN_THROWS();
}

php_openssl_session_object *obj = Z_OPENSSL_SESSION_P(ZEND_THIS);
obj->session = session;

/* Populate id property */
Expand Down
84 changes: 84 additions & 0 deletions ext/openssl/tests/session_unserialize_repeat.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
--TEST--
Openssl\Session::__unserialize throws on a repeat call
--EXTENSIONS--
openssl
--SKIPIF--
<?php
if (!function_exists("proc_open")) die("skip no proc_open");
?>
--FILE--
<?php
$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'session_unserialize_repeat.pem.tmp';

$serverCode = <<<'CODE'
$serverCtx = stream_context_create(['ssl' => [
'local_cert' => '%s',
]]);

$server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $serverCtx);
phpt_notify_server_start($server);

$client = @stream_socket_accept($server, 10);
if ($client) {
fwrite($client, "ok\n");
fclose($client);
}
CODE;
$serverCode = sprintf($serverCode, $certFile);

$clientCode = <<<'CODE'
$captured = null;
$ctx = stream_context_create(['ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'session_new_cb' => function ($s, $session) use (&$captured) {
$captured = $session;
return true;
},
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
]]);

$c = stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 10,
STREAM_CLIENT_CONNECT, $ctx);
if (!$c) {
echo "connect failed: $errstr\n";
return;
}
fread($c, 8);
fclose($c);

if (!$captured instanceof Openssl\Session) {
echo "no session captured\n";
return;
}

$payload = $captured->__serialize();
$sess = unserialize(serialize($captured));
echo "first: " . (is_object($sess) ? get_class($sess) : "fail") . "\n";

try {
$sess->__unserialize($payload);
echo "second: no throw\n";
} catch (Error $e) {
echo "second: " . $e->getMessage() . "\n";
}

echo "alive\n";
CODE;

include 'CertificateGenerator.inc';
$certificateGenerator = new CertificateGenerator();
$certificateGenerator->saveNewCertAsFileWithKey('session-unserialize-repeat', $certFile);

include 'ServerClientTestCase.inc';
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
?>
--CLEAN--
<?php
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'session_unserialize_repeat.pem.tmp');
?>
--EXPECTF--
first: Openssl\Session
second: Cannot call Openssl\Session::__unserialize() on an already-initialized session
alive
Loading