Commit a153011f authored by Ondrej Sury's avatar Ondrej Sury

Imported Upstream version 5.6.29+dfsg

parent e397fbee
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
08 Dec 2016, PHP 5.6.29
- Mysqlnd:
. Fixed bug #64526 (Add missing mysqlnd.* parameters to php.ini-*). (cmb)
- Opcache:
. Fixed bug #73402 (Opcache segfault when using class constant to call a
method). (Laruence)
. Fixed bug #69090 (check cached files permissions)
- OpenSSL
. Fixed bug #72776 (Invalid parameter in memcpy function trough
openssl_pbkdf2). (Jakub Zelenka)
- Postgres:
. Fixed bug #73498 (Incorrect SQL generated for pg_copy_to()). (Craig Duncan)
- SOAP:
. Fixed bug #73452 (Segfault (Regression for #69152)). (Dmitry)
- SQLite3:
. Fixed bug #73530 (Unsetting result set may reset other result set). (cmb)
- Standard:
. Fixed bug #73297 (HTTP stream wrapper should ignore HTTP 100 Continue).
(rowan dot collins at gmail dot com)
- WDDX:
. Fixed bug #73631 (Memory leak due to invalid wddx stack processing).
(bughunter at fosec dot vn).
10 Nov 2016, PHP 5.6.28
- Core:
......@@ -35,6 +66,7 @@ PHP NEWS
- Standard:
. Fixed bug #73203 (passing additional_parameters causes mail to fail). (cmb)
. Fixed bug #73188 (use after free in userspace streams). (Sara)
. Fixed bug #73192 (parse_url return wrong hostname). (Nikita)
- Wddx:
. Fixed bug #73331 (NULL Pointer Dereference in WDDX Packet Deserialization
......
--TEST--
Testing __debugInfo() magic method with bad returns RESOURCE
--INI--
allow_url_fopen=1
--FILE--
<?php
......
......@@ -3672,7 +3672,7 @@ ac_config_headers="$ac_config_headers main/php_config.h"
PHP_MAJOR_VERSION=5
PHP_MINOR_VERSION=6
PHP_RELEASE_VERSION=28
PHP_RELEASE_VERSION=29
PHP_EXTRA_VERSION=""
PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION"
PHP_VERSION_ID=`expr $PHP_MAJOR_VERSION \* 10000 + $PHP_MINOR_VERSION \* 100 + $PHP_RELEASE_VERSION`
......@@ -119,7 +119,7 @@ int zend_sprintf(char *buffer, const char *format, ...);
PHP_MAJOR_VERSION=5
PHP_MINOR_VERSION=6
PHP_RELEASE_VERSION=28
PHP_RELEASE_VERSION=29
PHP_EXTRA_VERSION=""
PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION"
PHP_VERSION_ID=`expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION`
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -157,7 +157,7 @@ static void update_op1_const(zend_op_array *op_array,
opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
Z_STRVAL_P(val) = zend_str_tolower_dup(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val TSRMLS_CC);
op_array->literals[opline->op1.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op1.constant+1].constant), Z_STRLEN(op_array->literals[opline->op1.constant+1].constant) + 1);
break;
......@@ -205,13 +205,13 @@ static void update_op2_const(zend_op_array *op_array,
case ZEND_ADD_INTERFACE:
case ZEND_ADD_TRAIT:
op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot++;
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
Z_STRVAL_P(val) = zend_str_tolower_dup(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val TSRMLS_CC);
op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);
break;
case ZEND_INIT_METHOD_CALL:
case ZEND_INIT_STATIC_METHOD_CALL:
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
Z_STRVAL_P(val) = zend_str_tolower_dup(Z_STRVAL_P(val), Z_STRLEN_P(val));
zend_optimizer_add_literal(op_array, val TSRMLS_CC);
op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);
/* break missing intentionally */
......
......@@ -102,6 +102,16 @@ opcache.validate_timestamps (default "1")
The frequency of the check is controlled by the directive
"opcache.revalidate_freq".
opcache.validate_permission (default "0")
Leads OPcache to check file readability on each access to cached file.
This directive should be enabled in shared hosting environment, when few
users (PHP-FPM pools) reuse the common OPcache shared memory.
opcache.validate_root (default "0")
This directive prevents file name collisions in different "chroot"
environments. It should be enabled for sites that may serve requests in
different "chroot" environments.
opcache.revalidate_freq (default "2")
How often (in seconds) to check file timestamps for changes to the shared
memory storage allocation. ("1" means validate once per second, but only
......
......@@ -1592,6 +1592,28 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type T
persistent_script = NULL;
}
/* Revalidate acessibility of cached file */
if (EXPECTED(persistent_script != NULL) &&
UNEXPECTED(ZCG(accel_directives).validate_permission) &&
file_handle->type == ZEND_HANDLE_FILENAME &&
UNEXPECTED(access(persistent_script->full_path, R_OK) != 0)) {
if (type == ZEND_REQUIRE) {
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
#else
zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
#endif
zend_bailout();
} else {
#if ZEND_EXTENSION_API_NO < PHP_5_3_X_API_NO
zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
#else
zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
#endif
}
return NULL;
}
SHM_UNPROTECT();
/* If script is found then validate_timestamps if option is enabled */
......@@ -2126,6 +2148,27 @@ static void accel_activate(void)
return;
}
#ifndef ZEND_WIN32
if (ZCG(accel_directives).validate_root) {
struct stat buf;
if (stat("/", &buf) != 0) {
ZCG(root_hash) = 0;
} else {
ZCG(root_hash) = buf.st_ino;
if (sizeof(buf.st_ino) > sizeof(ZCG(root_hash))) {
if (ZCG(root_hash) != buf.st_ino) {
zend_alter_ini_entry("opcache.enable", sizeof("opcache.enable"), "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_RUNTIME);
zend_accel_error(ACCEL_LOG_WARNING, "Can't cache files in chroot() directory with too big inode");
return;
}
}
}
} else {
ZCG(root_hash) = 0;
}
#endif
SHM_UNPROTECT();
/* PHP-5.4 and above return "double", but we use 1 sec precision */
ZCG(request_time) = (time_t)sapi_get_request_time(TSRMLS_C);
......
......@@ -230,6 +230,10 @@ typedef struct _zend_accel_directives {
zend_bool file_override_enabled;
zend_bool inherited_hack;
zend_bool enable_cli;
zend_bool validate_permission;
#ifndef ZEND_WIN32
zend_bool validate_root;
#endif
unsigned long revalidate_freq;
unsigned long file_update_protection;
char *error_log;
......@@ -264,6 +268,9 @@ typedef struct _zend_accel_globals {
int include_path_len; /* "include_path" string length */
int include_path_check;
time_t request_time;
#ifndef ZEND_WIN32
unsigned long root_hash;
#endif
/* preallocated shared-memory block to save current script */
void *mem;
/* cache to save hash lookup on the same INCLUDE opcode */
......
--TEST--
Bug #73402 (Opcache segfault when using class constant to call a method)
--INI--
opcache.enable=1
opcache.enable_cli=1
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
class Logger {
public function info($msg) {
echo $msg;
}
}
class B
{
const LOG_LEVEL = 'Info';
public function test()
{
$logger = new \Logger();
$logger->{self::LOG_LEVEL}('test');
}
}
$b = new B;
$b->test();
--EXPECT--
test
......@@ -77,6 +77,9 @@ zend_accel_hash_entry* zend_accel_hash_update(zend_accel_hash *accel_hash, char
zend_ulong index;
zend_accel_hash_entry *entry;
zend_accel_hash_entry *indirect_bucket = NULL;
#ifndef ZEND_WIN32
TSRMLS_FETCH();
#endif
if (indirect) {
indirect_bucket = (zend_accel_hash_entry*)data;
......@@ -86,6 +89,9 @@ zend_accel_hash_entry* zend_accel_hash_update(zend_accel_hash *accel_hash, char
}
hash_value = zend_inline_hash_func(key, key_length);
#ifndef ZEND_WIN32
hash_value ^= ZCG(root_hash);
#endif
index = hash_value % accel_hash->max_num_entries;
/* try to see if the element already exists in the hash */
......@@ -145,8 +151,14 @@ void* zend_accel_hash_find(zend_accel_hash *accel_hash, char *key, zend_uint key
zend_ulong hash_value;
zend_ulong index;
zend_accel_hash_entry *entry;
#ifndef ZEND_WIN32
TSRMLS_FETCH();
#endif
hash_value = zend_inline_hash_func(key, key_length);
#ifndef ZEND_WIN32
hash_value ^= ZCG(root_hash);
#endif
index = hash_value % accel_hash->max_num_entries;
entry = accel_hash->hash_table[index];
......@@ -173,8 +185,14 @@ zend_accel_hash_entry* zend_accel_hash_find_entry(zend_accel_hash *accel_hash, c
zend_ulong hash_value;
zend_ulong index;
zend_accel_hash_entry *entry;
#ifndef ZEND_WIN32
TSRMLS_FETCH();
#endif
hash_value = zend_inline_hash_func(key, key_length);
#ifndef ZEND_WIN32
hash_value ^= ZCG(root_hash);
#endif
index = hash_value % accel_hash->max_num_entries;
entry = accel_hash->hash_table[index];
......@@ -198,8 +216,14 @@ int zend_accel_hash_unlink(zend_accel_hash *accel_hash, char *key, zend_uint key
zend_ulong hash_value;
zend_ulong index;
zend_accel_hash_entry *entry, *last_entry=NULL;
#ifndef ZEND_WIN32
TSRMLS_FETCH();
#endif
hash_value = zend_inline_hash_func(key, key_length);
#ifndef ZEND_WIN32
hash_value ^= ZCG(root_hash);
#endif
index = hash_value % accel_hash->max_num_entries;
entry = accel_hash->hash_table[index];
......
......@@ -255,6 +255,10 @@ ZEND_INI_BEGIN()
STD_PHP_INI_BOOLEAN("opcache.enable" , "1", PHP_INI_ALL, OnEnable, enabled , zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.use_cwd" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.use_cwd , zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.validate_timestamps", "1", PHP_INI_ALL , OnUpdateBool, accel_directives.validate_timestamps, zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.validate_permission", "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_permission, zend_accel_globals, accel_globals)
#ifndef ZEND_WIN32
STD_PHP_INI_BOOLEAN("opcache.validate_root" , "0", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.validate_root , zend_accel_globals, accel_globals)
#endif
STD_PHP_INI_BOOLEAN("opcache.inherited_hack" , "1", PHP_INI_SYSTEM, OnUpdateBool, accel_directives.inherited_hack , zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.dups_fix" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.ignore_dups , zend_accel_globals, accel_globals)
STD_PHP_INI_BOOLEAN("opcache.revalidate_path" , "0", PHP_INI_ALL , OnUpdateBool, accel_directives.revalidate_path , zend_accel_globals, accel_globals)
......@@ -663,6 +667,10 @@ static ZEND_FUNCTION(opcache_get_configuration)
add_assoc_bool(directives, "opcache.enable_cli", ZCG(accel_directives).enable_cli);
add_assoc_bool(directives, "opcache.use_cwd", ZCG(accel_directives).use_cwd);
add_assoc_bool(directives, "opcache.validate_timestamps", ZCG(accel_directives).validate_timestamps);
add_assoc_bool(directives, "opcache.validate_permission", ZCG(accel_directives).validate_permission);
#ifndef ZEND_WIN32
add_assoc_bool(directives, "opcache.validate_root", ZCG(accel_directives).validate_root);
#endif
add_assoc_bool(directives, "opcache.inherited_hack", ZCG(accel_directives).inherited_hack);
add_assoc_bool(directives, "opcache.dups_fix", ZCG(accel_directives).ignore_dups);
add_assoc_bool(directives, "opcache.revalidate_path", ZCG(accel_directives).revalidate_path);
......
......@@ -4059,7 +4059,7 @@ PHP_FUNCTION(openssl_pbkdf2)
return;
}
if (key_length <= 0) {
if (key_length <= 0 || key_length > INT_MAX) {
RETURN_FALSE;
}
......
......@@ -4054,7 +4054,7 @@ PHP_FUNCTION(pg_copy_to)
free_pg_null = 1;
}
spprintf(&query, 0, "COPY %s TO STDOUT DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
spprintf(&query, 0, "COPY %s TO STDOUT DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
while ((pgsql_result = PQgetResult(pgsql))) {
PQclear(pgsql_result);
......@@ -4187,7 +4187,7 @@ PHP_FUNCTION(pg_copy_from)
pg_null_as_free = 1;
}
spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
spprintf(&query, 0, "COPY %s FROM STDIN DELIMITER E'%c' NULL AS E'%s'", table_name, *pg_delim, pg_null_as);
while ((pgsql_result = PQgetResult(pgsql))) {
PQclear(pgsql_result);
}
......
......@@ -29,6 +29,9 @@ else {
echo pg_last_error()."\n";
}
// Create view here
pg_query($db,$view_def);
pg_close($db);
echo "OK";
......
--TEST--
Bug 73498 Incorrect DELIMITER syntax for pg_copy_to()
--SKIPIF--
<?php include("skipif.inc"); ?>
--FILE--
<?php
include('config.inc');
$db = pg_connect($conn_str);
$rows = pg_copy_to($db, "(select * from {$view_name})");
var_dump(gettype($rows));
var_dump(count($rows) > 0);
?>
--EXPECT--
string(5) "array"
bool(true)
......@@ -9,6 +9,7 @@ PostgreSQL drop db
include('config.inc');
$db = pg_connect($conn_str);
pg_query($db, "DROP VIEW {$view_name}");
pg_query($db, "DROP TABLE ".$table_name);
@pg_query($db, "DROP TABLE ".$table_name_92);
......
......@@ -11,6 +11,10 @@ $table_name = "php_pgsql_test"; // test table that will be created
$table_name_92 = "php_pgsql_test_92"; // test table that will be created
$num_test_record = 1000; // Number of records to create
// Test view
$view_name = "php_pgsql_viewtest";
$view_def = "CREATE VIEW {$view_name} AS SELECT * FROM {$table_name};";
// Test table
$table_def = "CREATE TABLE ${table_name} (num int, str text, bin bytea);";
$table_def_92 = "CREATE TABLE ${table_name_92} (textary text[], jsn json);";
......
......@@ -904,6 +904,7 @@ PHP_METHOD(SoapFault, SoapFault)
PHP_METHOD(SoapFault, __toString)
{
zval *faultcode, *faultstring, *file, *line, *trace;
zval *faultcode_cp, *faultstring_cp, *file_cp, *line_cp;
char *str;
int len;
zend_fcall_info fci;
......@@ -932,16 +933,36 @@ PHP_METHOD(SoapFault, __toString)
zend_call_function(&fci, NULL TSRMLS_CC);
convert_to_string(faultcode);
convert_to_string(faultstring);
convert_to_string(file);
convert_to_long(line);
ALLOC_ZVAL(faultcode_cp);
INIT_PZVAL_COPY(faultcode_cp, faultcode);
zval_copy_ctor(faultcode_cp);
ALLOC_ZVAL(faultstring_cp);
INIT_PZVAL_COPY(faultstring_cp, faultstring);
zval_copy_ctor(faultstring_cp);
ALLOC_ZVAL(file_cp);
INIT_PZVAL_COPY(file_cp, file);
zval_copy_ctor(file_cp);
ALLOC_ZVAL(line_cp);
INIT_PZVAL_COPY(line_cp, line);
zval_copy_ctor(line_cp);
convert_to_string(faultcode_cp);
convert_to_string(faultstring_cp);
convert_to_string(file_cp);
convert_to_long(line_cp);
convert_to_string(trace);
len = spprintf(&str, 0, "SoapFault exception: [%s] %s in %s:%ld\nStack trace:\n%s",
Z_STRVAL_P(faultcode), Z_STRVAL_P(faultstring), Z_STRVAL_P(file), Z_LVAL_P(line),
Z_STRVAL_P(faultcode_cp), Z_STRVAL_P(faultstring_cp), Z_STRVAL_P(file_cp), Z_LVAL_P(line_cp),
Z_STRLEN_P(trace) ? Z_STRVAL_P(trace) : "#0 {main}\n");
zval_ptr_dtor(&faultcode_cp);
zval_ptr_dtor(&faultstring_cp);
zval_ptr_dtor(&file_cp);
zval_ptr_dtor(&line_cp);
zval_ptr_dtor(&trace);
RETURN_STRINGL(str, len, 0);
......
--TEST--
Bug #73452 Segfault (Regression for #69152)
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
$data = 'O:9:"SoapFault":4:{s:9:"faultcode";i:4298448493;s:11:"faultstring";i:4298448543;s:7:"'."\0*\0".'file";i:4298447319;s:7:"'."\0*\0".'line";s:4:"ryat";}';
echo unserialize($data);
?>
==DONE==
--EXPECTF--
SoapFault exception: [4298448493] 4298448543 in :0
Stack trace:
#0 %sbug73452.php(4): unserialize('O:9:"SoapFault"...')
#1 {main}==DONE==
......@@ -2184,10 +2184,6 @@ static void php_sqlite3_result_object_free_storage(void *object TSRMLS_DC) /* {{
}
if (intern->stmt_obj_zval) {
if (intern->stmt_obj->initialised) {
sqlite3_reset(intern->stmt_obj->stmt);
}
if (intern->is_prepared_statement == 0) {
zval_dtor(intern->stmt_obj_zval);
FREE_ZVAL(intern->stmt_obj_zval);
......
--TEST--
Bug #73530 (Unsetting result set may reset other result set)
--SKIPIF--
<?php
if (!extension_loaded('sqlite3')) die('skip sqlite3 extension not available');
?>
--FILE--
<?php
$db = new SQLite3(':memory:');
$db->exec("CREATE TABLE foo (num int)");
$db->exec("INSERT INTO foo VALUES (0)");
$db->exec("INSERT INTO foo VALUES (1)");
$stmt = $db->prepare("SELECT * FROM foo WHERE NUM = ?");
$stmt->bindValue(1, 0, SQLITE3_INTEGER);
$res1 = $stmt->execute();
$res1->finalize();
$stmt->clear();
$stmt->reset();
$stmt->bindValue(1, 1, SQLITE3_INTEGER);
$res2 = $stmt->execute();
while ($row = $res2->fetchArray(SQLITE3_ASSOC)) {
var_dump($row);
unset($res1);
}
?>
===DONE===
--EXPECT--
array(1) {
["num"]=>
int(1)
}
===DONE===
......@@ -699,6 +699,24 @@ finish:
if ((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) {
reqok = 1;
}
/* status codes of 1xx are "informational", and will be followed by a real response
* e.g "100 Continue". RFC 7231 states that unexpected 1xx status MUST be parsed,
* and MAY be ignored. As such, we need to skip ahead to the "real" status*/
if (response_code >= 100 && response_code < 200) {
/* consume lines until we find a line starting 'HTTP/1' */
while (
!php_stream_eof(stream)
&& php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL
&& ( tmp_line_len < sizeof("HTTP/1") - 1 || strncasecmp(tmp_line, "HTTP/1", sizeof("HTTP/1") - 1) )
);
if (tmp_line_len > 9) {
response_code = atoi(tmp_line + 9);
} else {
response_code = 0;
}
}
/* all status codes in the 2xx range are defined by the specification as successful;
* all status codes in the 3xx range are for redirection, and so also should never
* fail */
......
......@@ -4,6 +4,8 @@ Bug #43008 (php://filter uris ignore url encoded filternames and can't handle sl
<?php
if (!extension_loaded("iconv")) die("skip iconv extension not available");
?>
--INI--
allow_url_fopen=1
--FILE--
<?php
$url = b""
......
......@@ -73,6 +73,6 @@ bool(true)
Warning: lchown() expects parameter 1 to be a valid path, array given in %s on line %d
bool(true)
Warning: lchown(): Operation not permitted in %s on line %d
Warning: lchown(): %r(Operation not permitted|Invalid argument)%r in %s on line %d
bool(false)
===DONE===
--TEST--
Bug #73297 (Ignore 100 Continue returned by HTTP/1.1 servers)
--INI--
allow_url_fopen=1
--SKIPIF--
<?php require 'server.inc'; http_server_skipif('tcp://127.0.0.1:12342'); ?>
--FILE--
<?php
require 'server.inc';
$options = [
'http' => [
'protocol_version' => '1.1',
'header' => 'Connection: Close'
],
];
$ctx = stream_context_create($options);
$responses = [
"data://text/plain,HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK\r\n\r\n"
. "Hello"
];
$pid = http_server('tcp://127.0.0.1:12342', $responses);
echo file_get_contents('http://127.0.0.1:12342/', false, $ctx);
echo "\n";
http_server_kill($pid);
?>
--EXPECT--
Hello
--TEST--
bug 40459 - Test whether the constructor of the user-space stream wrapper is called when stream functions are called
--INI--
allow_url_fopen=1
--FILE--
<?php
// Test whether the constructor of the user-space stream wrapper is called when stream functions are called
......
--TEST--
Bug #71323: Output of stream_get_meta_data can be falsified by its input
--INI--
allow_url_fopen=1
--FILE--
<?php
$file = 'data:text/plain;z=y;uri=eviluri;mediatype=wut?;mediatype2=hello,somedata';
......
......@@ -104,7 +104,7 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length)
ue = s + length;
/* parse scheme */
if ((e = memchr(s, ':', length)) && (e - s)) {
if ((e = memchr(s, ':', length)) && e != s) {
/* validate scheme */
p = s;
while (p < e) {
......@@ -119,10 +119,10 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length)
p++;
}
if (*(e + 1) == '\0') { /* only scheme is available */
if (e + 1 == ue) { /* only scheme is available */
ret->scheme = estrndup(s, (e - s));
php_replace_controlchars_ex(ret->scheme, (e - s));
goto end;
return ret;
}
/*
......@@ -134,46 +134,39 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length)
* correctly parse things like a.com:80
*/
p = e + 1;
while (isdigit(*p)) {
while (p < ue && isdigit(*p)) {
p++;
}
if ((*p == '\0' || *p == '/') && (p - e) < 7) {
if ((p == ue || *p == '/') && (p - e) < 7) {
goto parse_port;
}
ret->scheme = estrndup(s, (e-s));
php_replace_controlchars_ex(ret->scheme, (e - s));
length -= ++e - s;
s = e;
s = e + 1;
goto just_path;
} else {
ret->scheme = estrndup(s, (e-s));
php_replace_controlchars_ex(ret->scheme, (e - s));
if (*(e+2) == '/') {
if (e + 2 < ue && *(e + 2) == '/') {
s = e + 3;
if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
if (*(e + 3) == '/') {
if (e + 3 < ue && *(e + 3) == '/') {
/* support windows drive letters as in:
file:///c:/somedir/file.txt
*/
if (*(e + 5) == ':') {
if (e + 5 < ue && *(e + 5) == ':') {
s = e + 4;
}
goto nohost;
goto just_path;
}
}
} else {
if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
s = e + 1;
goto nohost;
} else {
length -= ++e - s;
s = e;
goto just_path;
}
s = e + 1;
goto just_path;
}
}
} else if (e) { /* no scheme; starts with colon: look for port */
......@@ -181,18 +174,18 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length)
p = e + 1;
pp = p;
while (pp-p < 6 && isdigit(*pp)) {
while (pp < ue && pp - p < 6 && isdigit(*pp)) {
pp++;
}
if (pp - p > 0 && pp - p < 6 && (*pp == '/' || *pp == '\0')) {
if (pp - p > 0 && pp - p < 6 && (pp == ue || *pp == '/')) {
long port;
memcpy(port_buf, p, (pp - p));
port_buf[pp - p] = '\0';
port = strtol(port_buf, NULL, 10);
if (port > 0 && port <= 65535) {
ret->port = (unsigned short) port;
if (*s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
s += 2;
}
} else {
......@@ -200,24 +193,32 @@ PHPAPI php_url *php_url_parse_ex(char const *str, int length)
efree(ret);
return NULL;
}
} else if (p == pp && *pp == '\0') {
} else if (p == pp && pp == ue) {
STR_FREE(ret->scheme);
efree(ret);
return NULL;
} else if (*s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
} else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
s += 2;
} else {
goto just_path;
}
} else if (*s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
} else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
s += 2;
} else {
just_path:
ue = s + length;
goto nohost;
goto just_path;
}