mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Resolve conflict
This commit is contained in:
commit
1e3624290a
42 changed files with 20821 additions and 6764 deletions
|
@ -3,6 +3,17 @@ version: "{branch}.build.{build}"
|
|||
|
||||
image: Visual Studio 2015
|
||||
|
||||
branches:
|
||||
except:
|
||||
- PHP-5.6
|
||||
- PHP-7.0
|
||||
|
||||
skip_commits:
|
||||
files:
|
||||
- NEWS
|
||||
- UPGRADING*
|
||||
- README.*
|
||||
|
||||
clone_depth: 64
|
||||
|
||||
cache:
|
||||
|
|
|
@ -112,6 +112,7 @@ PHP 7.2 UPGRADE NOTES
|
|||
];
|
||||
. count() now raises a warning when an invalid parameter is passed.
|
||||
Only arrays and objects implementing the Countable interface should be passed.
|
||||
. pack() and unpack() now support float and double in both little and big endian.
|
||||
|
||||
- XML:
|
||||
. utf8_encode() and utf8_decode() have been moved to the Standard extension
|
||||
|
|
|
@ -173,7 +173,6 @@ ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_
|
|||
GC_REFCOUNT(ht) = 1;
|
||||
GC_TYPE_INFO(ht) = IS_ARRAY | (persistent ? 0 : (GC_COLLECTABLE << GC_FLAGS_SHIFT));
|
||||
ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
|
||||
ht->nTableSize = zend_hash_check_size(nSize);
|
||||
ht->nTableMask = HT_MIN_MASK;
|
||||
HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
|
||||
ht->nNumUsed = 0;
|
||||
|
@ -181,6 +180,7 @@ ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_
|
|||
ht->nInternalPointer = HT_INVALID_IDX;
|
||||
ht->nNextFreeElement = 0;
|
||||
ht->pDestructor = pDestructor;
|
||||
ht->nTableSize = zend_hash_check_size(nSize);
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_hash_packed_grow(HashTable *ht)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
/* Generated by re2c 0.13.5 */
|
||||
/* Generated by re2c 0.16 */
|
||||
#line 3 "Zend/zend_language_scanner_defs.h"
|
||||
|
||||
enum YYCONDTYPE {
|
||||
|
|
|
@ -480,7 +480,7 @@ static zend_always_inline double _zend_get_nan(void) /* {{{ */
|
|||
#ifdef ZEND_WIN32
|
||||
#define ZEND_SECURE_ZERO(var, size) RtlSecureZeroMemory((var), (size))
|
||||
#else
|
||||
#define ZEND_SECURE_ZERO(var, size) memset((var), 0, (size))
|
||||
#define ZEND_SECURE_ZERO(var, size) explicit_bzero((var), (size))
|
||||
#endif
|
||||
|
||||
/* This check should only be used on network socket, not file descriptors */
|
||||
|
|
|
@ -33,7 +33,7 @@ if "%OPCACHE%" equ "0" set EXT_EXCLUDE_FROM_TEST=%EXT_EXCLUDE_FROM_TEST%,opcache
|
|||
|
||||
call configure.bat ^
|
||||
--enable-snapshot-build ^
|
||||
--enable-debug-pack ^
|
||||
--disable-debug-pack ^
|
||||
--enable-com-dotnet=shared ^
|
||||
--without-analyzer ^
|
||||
--enable-object-out-dir=%PHP_BUILD_OBJ_DIR% ^
|
||||
|
|
|
@ -745,7 +745,7 @@ if test "$ac_cv_func_sync_fetch_and_add" = yes; then
|
|||
AC_DEFINE(HAVE_SYNC_FETCH_AND_ADD,1,[Define if you have the __sync_fetch_and_add function])
|
||||
fi
|
||||
|
||||
AC_REPLACE_FUNCS(strlcat strlcpy getopt)
|
||||
AC_REPLACE_FUNCS(strlcat strlcpy explicit_bzero getopt)
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_ALLOCA
|
||||
dnl PHP_AC_BROKEN_SPRINTF
|
||||
|
@ -1446,7 +1446,7 @@ PHP_ADD_SOURCES(TSRM, TSRM.c tsrm_strtok_r.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=
|
|||
PHP_ADD_SOURCES(main, main.c snprintf.c spprintf.c php_sprintf.c \
|
||||
fopen_wrappers.c alloca.c php_scandir.c \
|
||||
php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \
|
||||
strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \
|
||||
strlcat.c explicit_bzero.c mergesort.c reentrancy.c php_variables.c php_ticks.c \
|
||||
network.c php_open_temporary_file.c \
|
||||
output.c getopt.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
||||
|
||||
|
|
|
@ -1682,7 +1682,7 @@ static size_t exif_convert_any_to_int(void *value, int format, int motorola_inte
|
|||
if (s_den == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return php_ifd_get32s(value, motorola_intel) / s_den;
|
||||
return (size_t)((double)php_ifd_get32s(value, motorola_intel) / s_den);
|
||||
}
|
||||
|
||||
case TAG_FMT_SSHORT: return php_ifd_get16u(value, motorola_intel);
|
||||
|
|
12
ext/exif/tests/bug73737.phpt
Normal file
12
ext/exif/tests/bug73737.phpt
Normal file
|
@ -0,0 +1,12 @@
|
|||
--TEST--
|
||||
Bug #73737 (Crash when parsing a tag format)
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('exif')) print 'skip exif extension not available';?>
|
||||
--FILE--
|
||||
<?php
|
||||
$exif = exif_thumbnail(__DIR__ . '/bug73737.tiff');
|
||||
var_dump($exif);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: exif_thumbnail(bug73737.tiff): Error in TIFF: filesize(x0030) less than start of IFD dir(x10102) in %s line %d
|
||||
bool(false)
|
BIN
ext/exif/tests/bug73737.tiff
Normal file
BIN
ext/exif/tests/bug73737.tiff
Normal file
Binary file not shown.
|
@ -183,6 +183,10 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_real_conne
|
|||
mysqlnd_restart_psession(mysql->mysql);
|
||||
#endif
|
||||
MyG(num_active_persistent)++;
|
||||
|
||||
/* clear error */
|
||||
php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT);
|
||||
|
|
41
ext/mysqli/tests/bug73462.phpt
Normal file
41
ext/mysqli/tests/bug73462.phpt
Normal file
|
@ -0,0 +1,41 @@
|
|||
--TEST--
|
||||
Bug #73462 (Persistent connections don't set $connect_errno)
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('skipifemb.inc');
|
||||
require_once('skipifconnectfailure.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
require_once("connect.inc");
|
||||
|
||||
/* Initial persistent connection */
|
||||
$mysql_1 = new mysqli('p:'.$host, $user, $passwd, $db);
|
||||
$result = $mysql_1->query("SHOW STATUS LIKE 'Connections'");
|
||||
$c1 = $result->fetch_row();
|
||||
$result->free();
|
||||
$mysql_1->close();
|
||||
|
||||
/* Failed connection to invalid host */
|
||||
$mysql_2 = @new mysqli(' !!! invalid !!! ', $user, $passwd, $db);
|
||||
@$mysql_2->close();
|
||||
|
||||
/* Re-use persistent connection */
|
||||
$mysql_3 = new mysqli('p:'.$host, $user, $passwd, $db);
|
||||
$error = mysqli_connect_errno();
|
||||
$result = $mysql_3->query("SHOW STATUS LIKE 'Connections'");
|
||||
$c3 = $result->fetch_row();
|
||||
$result->free();
|
||||
$mysql_3->close();
|
||||
|
||||
if (end($c1) !== end($c3))
|
||||
printf("[001] Expected '%d' got '%d'.\n", end($c1), end($c3));
|
||||
|
||||
if ($error !== 0)
|
||||
printf("[002] Expected '0' got '%d'.\n", $error);
|
||||
|
||||
print "done!";
|
||||
?>
|
||||
--EXPECTF--
|
||||
done!
|
|
@ -1531,7 +1531,7 @@ php_mysqlnd_read_row_ex(MYSQLND_PFC * pfc,
|
|||
pool->free_chunk(pool, *buffer);
|
||||
*buffer = NULL;
|
||||
}
|
||||
*data_size--;
|
||||
(*data_size)--;
|
||||
DBG_RETURN(ret);
|
||||
}
|
||||
/* }}} */
|
||||
|
|
|
@ -7,6 +7,7 @@ outputs the correct logging at the highest log_verbosity_level
|
|||
--INI--
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.file_cache_only=0
|
||||
opcache.log_verbosity_level=4
|
||||
--SKIPIF--
|
||||
<?php require_once('skipif.inc'); ?>
|
||||
|
|
|
@ -32,7 +32,7 @@ $p->setStub($stub);
|
|||
unset($p);
|
||||
|
||||
include "php_cli_server.inc";
|
||||
php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1');
|
||||
php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1 -d extension=phar.'.PHP_SHLIB_SUFFIX);
|
||||
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0115_1.phar.php');
|
||||
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0115_2.phar.php');
|
||||
?>
|
||||
|
|
|
@ -20,7 +20,7 @@ $p->setStub($stub);
|
|||
unset($p);
|
||||
|
||||
include "php_cli_server.inc";
|
||||
php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1');
|
||||
php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1 -d extension=phar.'.PHP_SHLIB_SUFFIX);
|
||||
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0149.phar.php');
|
||||
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0149.phar.php');
|
||||
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/issue0149.phar.php');
|
||||
|
|
|
@ -7,6 +7,7 @@ The process should die regardless of the log_verbosity_level.
|
|||
--INI--
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.file_cache_only=0
|
||||
opcache.memory_consumption=999999999
|
||||
opcache.log_verbosity_level=-1
|
||||
--SKIPIF--
|
||||
|
|
|
@ -983,7 +983,6 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|||
/* if the alias is stored we enforce it (implicit overrides explicit) */
|
||||
if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
|
||||
{
|
||||
buffer[tmp_len] = '\0';
|
||||
php_stream_close(fp);
|
||||
|
||||
if (signature) {
|
||||
|
@ -991,7 +990,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|||
}
|
||||
|
||||
if (error) {
|
||||
spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias);
|
||||
spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%.*s\" under different alias \"%s\"", fname, tmp_len, buffer, alias);
|
||||
}
|
||||
|
||||
efree(savebuf);
|
||||
|
@ -1057,7 +1056,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|||
entry.is_persistent = mydata->is_persistent;
|
||||
|
||||
for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
|
||||
if (buffer + 4 > endbuffer) {
|
||||
if (buffer + 28 > endbuffer) {
|
||||
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
|
||||
}
|
||||
|
||||
|
@ -1071,7 +1070,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
|
|||
entry.manifest_pos = manifest_index;
|
||||
}
|
||||
|
||||
if (entry.filename_len + 20 > (size_t)(endbuffer - buffer)) {
|
||||
if (entry.filename_len > (size_t)(endbuffer - buffer - 24)) {
|
||||
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
|
||||
}
|
||||
|
||||
|
|
BIN
ext/phar/tests/bug73764.phar
Normal file
BIN
ext/phar/tests/bug73764.phar
Normal file
Binary file not shown.
16
ext/phar/tests/bug73764.phpt
Normal file
16
ext/phar/tests/bug73764.phpt
Normal file
|
@ -0,0 +1,16 @@
|
|||
--TEST--
|
||||
Phar: PHP bug #73764: Crash while loading hostile phar archive
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("phar")) die("skip"); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
chdir(__DIR__);
|
||||
try {
|
||||
$p = Phar::LoadPhar('bug73764.phar', 'alias.phar');
|
||||
echo "OK\n";
|
||||
} catch(PharException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
internal corruption of phar "%sbug73764.phar" (truncated manifest entry)
|
BIN
ext/phar/tests/bug73768.phar
Normal file
BIN
ext/phar/tests/bug73768.phar
Normal file
Binary file not shown.
16
ext/phar/tests/bug73768.phpt
Normal file
16
ext/phar/tests/bug73768.phpt
Normal file
|
@ -0,0 +1,16 @@
|
|||
--TEST--
|
||||
Phar: PHP bug #73768: Memory corruption when loading hostile phar
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("phar")) die("skip"); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
chdir(__DIR__);
|
||||
try {
|
||||
$p = Phar::LoadPhar('bug73768.phar', 'alias.phar');
|
||||
echo "OK\n";
|
||||
} catch(PharException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
cannot load phar "%sbug73768.phar" with implicit alias "" under different alias "alias.phar"
|
|
@ -27,10 +27,29 @@
|
|||
#include "zend_ini_scanner.h"
|
||||
#include "zend_globals.h"
|
||||
|
||||
#define BROWSCAP_NUM_CONTAINS 5
|
||||
|
||||
typedef struct {
|
||||
zend_string *key;
|
||||
zend_string *value;
|
||||
} browscap_kv;
|
||||
|
||||
typedef struct {
|
||||
zend_string *pattern;
|
||||
zend_string *parent;
|
||||
uint32_t kv_start;
|
||||
uint32_t kv_end;
|
||||
/* We ensure that the length fits in 16 bits, so this is fine */
|
||||
uint16_t contains_start[BROWSCAP_NUM_CONTAINS];
|
||||
uint8_t contains_len[BROWSCAP_NUM_CONTAINS];
|
||||
uint8_t prefix_len;
|
||||
} browscap_entry;
|
||||
|
||||
typedef struct {
|
||||
HashTable *htab;
|
||||
zval current_section;
|
||||
char *current_section_name;
|
||||
browscap_kv *kv;
|
||||
uint32_t kv_used;
|
||||
uint32_t kv_size;
|
||||
char filename[MAXPATHLEN];
|
||||
} browser_data;
|
||||
|
||||
|
@ -50,43 +69,106 @@ ZEND_DECLARE_MODULE_GLOBALS(browscap)
|
|||
|
||||
/* OBJECTS_FIXME: This whole extension needs going through. The use of objects looks pretty broken here */
|
||||
|
||||
static void browscap_entry_dtor_request(zval *zvalue) /* {{{ */
|
||||
static void browscap_entry_dtor(zval *zvalue)
|
||||
{
|
||||
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
|
||||
zend_hash_destroy(Z_ARRVAL_P(zvalue));
|
||||
efree(Z_ARR_P(zvalue));
|
||||
} else if (Z_TYPE_P(zvalue) == IS_STRING) {
|
||||
zend_string_release(Z_STR_P(zvalue));
|
||||
browscap_entry *entry = Z_PTR_P(zvalue);
|
||||
zend_string_release(entry->pattern);
|
||||
if (entry->parent) {
|
||||
zend_string_release(entry->parent);
|
||||
}
|
||||
efree(entry);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void browscap_entry_dtor_persistent(zval *zvalue) /* {{{ */ {
|
||||
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
|
||||
zend_hash_destroy(Z_ARRVAL_P(zvalue));
|
||||
free(Z_ARR_P(zvalue));
|
||||
} else if (Z_TYPE_P(zvalue) == IS_STRING) {
|
||||
zend_string_release(Z_STR_P(zvalue));
|
||||
static void browscap_entry_dtor_persistent(zval *zvalue)
|
||||
{
|
||||
browscap_entry *entry = Z_PTR_P(zvalue);
|
||||
zend_string_release(entry->pattern);
|
||||
if (entry->parent) {
|
||||
zend_string_release(entry->parent);
|
||||
}
|
||||
pefree(entry, 1);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void convert_browscap_pattern(zval *pattern, int persistent) /* {{{ */
|
||||
static inline zend_bool is_placeholder(char c) {
|
||||
return c == '?' || c == '*';
|
||||
}
|
||||
|
||||
/* Length of prefix not containing any wildcards */
|
||||
static uint8_t browscap_compute_prefix_len(zend_string *pattern) {
|
||||
size_t i;
|
||||
for (i = 0; i < ZSTR_LEN(pattern); i++) {
|
||||
if (is_placeholder(ZSTR_VAL(pattern)[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return MIN(i, UINT8_MAX);
|
||||
}
|
||||
|
||||
static size_t browscap_compute_contains(
|
||||
zend_string *pattern, size_t start_pos,
|
||||
uint16_t *contains_start, uint8_t *contains_len) {
|
||||
size_t i = start_pos;
|
||||
/* Find first non-placeholder character after prefix */
|
||||
for (; i < ZSTR_LEN(pattern); i++) {
|
||||
if (!is_placeholder(ZSTR_VAL(pattern)[i])) {
|
||||
/* Skip the case of a single non-placeholder character.
|
||||
* Let's try to find something longer instead. */
|
||||
if (i + 1 < ZSTR_LEN(pattern) &&
|
||||
!is_placeholder(ZSTR_VAL(pattern)[i + 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*contains_start = i;
|
||||
|
||||
/* Find first placeholder character after that */
|
||||
for (; i < ZSTR_LEN(pattern); i++) {
|
||||
if (is_placeholder(ZSTR_VAL(pattern)[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*contains_len = MIN(i - *contains_start, UINT8_MAX);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Length of regex, including escapes, anchors, etc. */
|
||||
static size_t browscap_compute_regex_len(zend_string *pattern) {
|
||||
size_t i, len = ZSTR_LEN(pattern);
|
||||
for (i = 0; i < ZSTR_LEN(pattern); i++) {
|
||||
switch (ZSTR_VAL(pattern)[i]) {
|
||||
case '*':
|
||||
case '.':
|
||||
case '\\':
|
||||
case '(':
|
||||
case ')':
|
||||
case '~':
|
||||
case '+':
|
||||
len++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return len + sizeof("~^$~")-1;
|
||||
}
|
||||
|
||||
static zend_string *browscap_convert_pattern(zend_string *pattern, int persistent) /* {{{ */
|
||||
{
|
||||
size_t i, j=0;
|
||||
char *t;
|
||||
zend_string *res;
|
||||
char *lc_pattern;
|
||||
ALLOCA_FLAG(use_heap);
|
||||
|
||||
res = zend_string_safe_alloc(Z_STRLEN_P(pattern), 2, 4, persistent);
|
||||
res = zend_string_alloc(browscap_compute_regex_len(pattern), persistent);
|
||||
t = ZSTR_VAL(res);
|
||||
|
||||
lc_pattern = zend_str_tolower_dup(Z_STRVAL_P(pattern), Z_STRLEN_P(pattern));
|
||||
lc_pattern = do_alloca(ZSTR_LEN(pattern) + 1, use_heap);
|
||||
zend_str_tolower_copy(lc_pattern, ZSTR_VAL(pattern), ZSTR_LEN(pattern));
|
||||
|
||||
t[j++] = '~';
|
||||
t[j++] = '^';
|
||||
|
||||
for (i=0; i<Z_STRLEN_P(pattern); i++, j++) {
|
||||
for (i = 0; i < ZSTR_LEN(pattern); i++, j++) {
|
||||
switch (lc_pattern[i]) {
|
||||
case '?':
|
||||
t[j] = '.';
|
||||
|
@ -127,17 +209,100 @@ static void convert_browscap_pattern(zval *pattern, int persistent) /* {{{ */
|
|||
|
||||
t[j++] = '$';
|
||||
t[j++] = '~';
|
||||
|
||||
t[j]=0;
|
||||
|
||||
ZSTR_LEN(res) = j;
|
||||
Z_STR_P(pattern) = res;
|
||||
efree(lc_pattern);
|
||||
free_alloca(lc_pattern, use_heap);
|
||||
return res;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
typedef struct _browscap_parser_ctx {
|
||||
browser_data *bdata;
|
||||
browscap_entry *current_entry;
|
||||
zend_string *current_section_name;
|
||||
zend_string *str_empty;
|
||||
zend_string *str_one;
|
||||
HashTable str_interned;
|
||||
} browscap_parser_ctx;
|
||||
|
||||
static zend_string *browscap_intern_str(
|
||||
browscap_parser_ctx *ctx, zend_string *str) {
|
||||
zend_string *interned = zend_hash_find_ptr(&ctx->str_interned, str);
|
||||
if (interned) {
|
||||
zend_string_addref(interned);
|
||||
} else {
|
||||
interned = zend_string_copy(str);
|
||||
zend_hash_add_new_ptr(&ctx->str_interned, interned, interned);
|
||||
}
|
||||
|
||||
return interned;
|
||||
}
|
||||
|
||||
static zend_string *browscap_intern_str_ci(
|
||||
browscap_parser_ctx *ctx, zend_string *str, zend_bool persistent) {
|
||||
zend_string *lcname;
|
||||
zend_string *interned;
|
||||
ALLOCA_FLAG(use_heap);
|
||||
|
||||
ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(str), use_heap);
|
||||
zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(str), ZSTR_LEN(str));
|
||||
interned = zend_hash_find_ptr(&ctx->str_interned, lcname);
|
||||
|
||||
if (interned) {
|
||||
zend_string_addref(interned);
|
||||
} else {
|
||||
interned = zend_string_dup(lcname, persistent);
|
||||
zend_hash_add_new_ptr(&ctx->str_interned, interned, interned);
|
||||
}
|
||||
|
||||
ZSTR_ALLOCA_FREE(lcname, use_heap);
|
||||
return interned;
|
||||
}
|
||||
|
||||
static void browscap_add_kv(
|
||||
browser_data *bdata, zend_string *key, zend_string *value, zend_bool persistent) {
|
||||
if (bdata->kv_used == bdata->kv_size) {
|
||||
bdata->kv_size *= 2;
|
||||
bdata->kv = safe_perealloc(bdata->kv, sizeof(browscap_kv), bdata->kv_size, 0, persistent);
|
||||
}
|
||||
|
||||
bdata->kv[bdata->kv_used].key = key;
|
||||
bdata->kv[bdata->kv_used].value = value;
|
||||
bdata->kv_used++;
|
||||
}
|
||||
|
||||
static HashTable *browscap_entry_to_array(browser_data *bdata, browscap_entry *entry) {
|
||||
zval tmp;
|
||||
uint32_t i;
|
||||
|
||||
HashTable *ht;
|
||||
ALLOC_HASHTABLE(ht);
|
||||
zend_hash_init(ht, 8, NULL, ZVAL_PTR_DTOR, 0);
|
||||
|
||||
ZVAL_STR(&tmp, browscap_convert_pattern(entry->pattern, 0));
|
||||
zend_hash_str_add(ht, "browser_name_regex", sizeof("browser_name_regex")-1, &tmp);
|
||||
|
||||
ZVAL_STR_COPY(&tmp, entry->pattern);
|
||||
zend_hash_str_add(ht, "browser_name_pattern", sizeof("browser_name_pattern")-1, &tmp);
|
||||
|
||||
if (entry->parent) {
|
||||
ZVAL_STR_COPY(&tmp, entry->parent);
|
||||
zend_hash_str_add(ht, "parent", sizeof("parent")-1, &tmp);
|
||||
}
|
||||
|
||||
for (i = entry->kv_start; i < entry->kv_end; i++) {
|
||||
ZVAL_STR_COPY(&tmp, bdata->kv[i].value);
|
||||
zend_hash_add(ht, bdata->kv[i].key, &tmp);
|
||||
}
|
||||
|
||||
return ht;
|
||||
}
|
||||
|
||||
static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, void *arg) /* {{{ */
|
||||
{
|
||||
browser_data *bdata = arg;
|
||||
browscap_parser_ctx *ctx = arg;
|
||||
browser_data *bdata = ctx->bdata;
|
||||
int persistent = bdata->htab->u.flags & HASH_FLAG_PERSISTENT;
|
||||
|
||||
if (!arg1) {
|
||||
|
@ -146,74 +311,81 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
|
|||
|
||||
switch (callback_type) {
|
||||
case ZEND_INI_PARSER_ENTRY:
|
||||
if (Z_TYPE(bdata->current_section) != IS_UNDEF && arg2) {
|
||||
zval new_property;
|
||||
zend_string *new_key;
|
||||
|
||||
/* parent entry can not be same as current section -> causes infinite loop! */
|
||||
if (!strcasecmp(Z_STRVAL_P(arg1), "parent") &&
|
||||
bdata->current_section_name != NULL &&
|
||||
!strcasecmp(bdata->current_section_name, Z_STRVAL_P(arg2))
|
||||
) {
|
||||
zend_error(E_CORE_ERROR, "Invalid browscap ini file: "
|
||||
"'Parent' value cannot be same as the section name: %s "
|
||||
"(in file %s)", bdata->current_section_name, INI_STR("browscap"));
|
||||
return;
|
||||
}
|
||||
if (ctx->current_entry != NULL && arg2) {
|
||||
zend_string *new_key, *new_value;
|
||||
|
||||
/* Set proper value for true/false settings */
|
||||
if ((Z_STRLEN_P(arg2) == 2 && !strncasecmp(Z_STRVAL_P(arg2), "on", sizeof("on") - 1)) ||
|
||||
(Z_STRLEN_P(arg2) == 3 && !strncasecmp(Z_STRVAL_P(arg2), "yes", sizeof("yes") - 1)) ||
|
||||
(Z_STRLEN_P(arg2) == 4 && !strncasecmp(Z_STRVAL_P(arg2), "true", sizeof("true") - 1))
|
||||
) {
|
||||
ZVAL_NEW_STR(&new_property, zend_string_init("1", sizeof("1")-1, persistent));
|
||||
new_value = zend_string_copy(ctx->str_one);
|
||||
} else if (
|
||||
(Z_STRLEN_P(arg2) == 2 && !strncasecmp(Z_STRVAL_P(arg2), "no", sizeof("no") - 1)) ||
|
||||
(Z_STRLEN_P(arg2) == 3 && !strncasecmp(Z_STRVAL_P(arg2), "off", sizeof("off") - 1)) ||
|
||||
(Z_STRLEN_P(arg2) == 4 && !strncasecmp(Z_STRVAL_P(arg2), "none", sizeof("none") - 1)) ||
|
||||
(Z_STRLEN_P(arg2) == 5 && !strncasecmp(Z_STRVAL_P(arg2), "false", sizeof("false") - 1))
|
||||
) {
|
||||
// TODO: USE ZSTR_EMPTY_ALLOC()?
|
||||
ZVAL_NEW_STR(&new_property, zend_string_init("", sizeof("")-1, persistent));
|
||||
new_value = zend_string_copy(ctx->str_empty);
|
||||
} else { /* Other than true/false setting */
|
||||
ZVAL_STR(&new_property, zend_string_dup(Z_STR_P(arg2), persistent));
|
||||
new_value = browscap_intern_str(ctx, Z_STR_P(arg2));
|
||||
}
|
||||
new_key = zend_string_dup(Z_STR_P(arg1), persistent);
|
||||
zend_str_tolower(ZSTR_VAL(new_key), ZSTR_LEN(new_key));
|
||||
zend_hash_update(Z_ARRVAL(bdata->current_section), new_key, &new_property);
|
||||
zend_string_release(new_key);
|
||||
}
|
||||
break;
|
||||
case ZEND_INI_PARSER_SECTION: {
|
||||
zval processed;
|
||||
zval unprocessed;
|
||||
|
||||
/*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len + 1);*/
|
||||
if (persistent) {
|
||||
ZVAL_NEW_PERSISTENT_ARR(&bdata->current_section);
|
||||
if (!strcasecmp(Z_STRVAL_P(arg1), "parent")) {
|
||||
/* parent entry can not be same as current section -> causes infinite loop! */
|
||||
if (ctx->current_section_name != NULL &&
|
||||
!strcasecmp(ZSTR_VAL(ctx->current_section_name), Z_STRVAL_P(arg2))
|
||||
) {
|
||||
zend_error(E_CORE_ERROR, "Invalid browscap ini file: "
|
||||
"'Parent' value cannot be same as the section name: %s "
|
||||
"(in file %s)", ZSTR_VAL(ctx->current_section_name), INI_STR("browscap"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->current_entry->parent) {
|
||||
zend_string_release(ctx->current_entry->parent);
|
||||
}
|
||||
ctx->current_entry->parent = new_value;
|
||||
} else {
|
||||
ZVAL_NEW_ARR(&bdata->current_section);
|
||||
new_key = browscap_intern_str_ci(ctx, Z_STR_P(arg1), persistent);
|
||||
browscap_add_kv(bdata, new_key, new_value, persistent);
|
||||
ctx->current_entry->kv_end = bdata->kv_used;
|
||||
}
|
||||
zend_hash_init(Z_ARRVAL(bdata->current_section), 0, NULL,
|
||||
(dtor_func_t) (persistent?browscap_entry_dtor_persistent
|
||||
:browscap_entry_dtor_request),
|
||||
persistent);
|
||||
if (bdata->current_section_name) {
|
||||
pefree(bdata->current_section_name, persistent);
|
||||
}
|
||||
bdata->current_section_name = pestrndup(Z_STRVAL_P(arg1),
|
||||
Z_STRLEN_P(arg1), persistent);
|
||||
|
||||
zend_hash_update(bdata->htab, Z_STR_P(arg1), &bdata->current_section);
|
||||
|
||||
ZVAL_STR(&processed, Z_STR_P(arg1));
|
||||
ZVAL_STR(&unprocessed, zend_string_dup(Z_STR_P(arg1), persistent));
|
||||
|
||||
convert_browscap_pattern(&processed, persistent);
|
||||
zend_hash_str_update(Z_ARRVAL(bdata->current_section), "browser_name_regex", sizeof("browser_name_regex")-1, &processed);
|
||||
zend_hash_str_update(Z_ARRVAL(bdata->current_section), "browser_name_pattern", sizeof("browser_name_pattern")-1, &unprocessed);
|
||||
}
|
||||
break;
|
||||
case ZEND_INI_PARSER_SECTION:
|
||||
{
|
||||
browscap_entry *entry;
|
||||
zend_string *pattern = Z_STR_P(arg1);
|
||||
size_t pos;
|
||||
int i;
|
||||
|
||||
if (ZSTR_LEN(pattern) > UINT16_MAX) {
|
||||
php_error_docref(NULL, E_WARNING,
|
||||
"Skipping excessively long pattern of length %zd", ZSTR_LEN(pattern));
|
||||
break;
|
||||
}
|
||||
|
||||
entry = ctx->current_entry
|
||||
= pemalloc(sizeof(browscap_entry), persistent);
|
||||
zend_hash_update_ptr(bdata->htab, pattern, entry);
|
||||
|
||||
if (ctx->current_section_name) {
|
||||
zend_string_release(ctx->current_section_name);
|
||||
}
|
||||
ctx->current_section_name = zend_string_copy(pattern);
|
||||
|
||||
entry->pattern = zend_string_copy(pattern);
|
||||
entry->kv_end = entry->kv_start = bdata->kv_used;
|
||||
entry->parent = NULL;
|
||||
|
||||
pos = entry->prefix_len = browscap_compute_prefix_len(pattern);
|
||||
for (i = 0; i < BROWSCAP_NUM_CONTAINS; i++) {
|
||||
pos = browscap_compute_contains(pattern, pos,
|
||||
&entry->contains_start[i], &entry->contains_len[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -221,41 +393,53 @@ static void php_browscap_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callb
|
|||
static int browscap_read_file(char *filename, browser_data *browdata, int persistent) /* {{{ */
|
||||
{
|
||||
zend_file_handle fh;
|
||||
browscap_parser_ctx ctx = {0};
|
||||
|
||||
if (filename == NULL || filename[0] == '\0') {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
fh.handle.fp = VCWD_FOPEN(filename, "r");
|
||||
fh.opened_path = NULL;
|
||||
fh.free_filename = 0;
|
||||
if (!fh.handle.fp) {
|
||||
zend_error(E_CORE_WARNING, "Cannot open '%s' for reading", filename);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
fh.filename = filename;
|
||||
fh.type = ZEND_HANDLE_FP;
|
||||
|
||||
browdata->htab = pemalloc(sizeof *browdata->htab, persistent);
|
||||
if (browdata->htab == NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
zend_hash_init_ex(browdata->htab, 0, NULL,
|
||||
(dtor_func_t) (persistent?browscap_entry_dtor_persistent
|
||||
:browscap_entry_dtor_request),
|
||||
persistent, 0);
|
||||
persistent ? browscap_entry_dtor_persistent : browscap_entry_dtor, persistent, 0);
|
||||
|
||||
browdata->kv_size = 16 * 1024;
|
||||
browdata->kv_used = 0;
|
||||
browdata->kv = pemalloc(sizeof(browscap_kv) * browdata->kv_size, persistent);
|
||||
|
||||
/* Create parser context */
|
||||
ctx.bdata = browdata;
|
||||
ctx.current_entry = NULL;
|
||||
ctx.current_section_name = NULL;
|
||||
ctx.str_empty = zend_string_init("", sizeof("")-1, persistent);
|
||||
ctx.str_one = zend_string_init("1", sizeof("1")-1, persistent);
|
||||
zend_hash_init(&ctx.str_interned, 8, NULL, NULL, persistent);
|
||||
|
||||
memset(&fh, 0, sizeof(fh));
|
||||
fh.handle.fp = VCWD_FOPEN(filename, "r");
|
||||
fh.opened_path = NULL;
|
||||
fh.free_filename = 0;
|
||||
if (!fh.handle.fp) {
|
||||
zend_hash_destroy(browdata->htab);
|
||||
pefree(browdata->htab, persistent);
|
||||
browdata->htab = NULL;
|
||||
zend_error(E_CORE_WARNING, "Cannot open '%s' for reading", filename);
|
||||
return FAILURE;
|
||||
}
|
||||
fh.filename = filename;
|
||||
fh.type = ZEND_HANDLE_FP;
|
||||
browdata->current_section_name = NULL;
|
||||
zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_RAW,
|
||||
(zend_ini_parser_cb_t) php_browscap_parser_cb, browdata);
|
||||
if (browdata->current_section_name != NULL) {
|
||||
pefree(browdata->current_section_name, persistent);
|
||||
browdata->current_section_name = NULL;
|
||||
(zend_ini_parser_cb_t) php_browscap_parser_cb, &ctx);
|
||||
|
||||
/* Destroy parser context */
|
||||
if (ctx.current_section_name) {
|
||||
zend_string_release(ctx.current_section_name);
|
||||
}
|
||||
zend_string_release(ctx.str_one);
|
||||
zend_string_release(ctx.str_empty);
|
||||
zend_hash_destroy(&ctx.str_interned);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -265,8 +449,7 @@ static int browscap_read_file(char *filename, browser_data *browdata, int persis
|
|||
static void browscap_globals_ctor(zend_browscap_globals *browscap_globals) /* {{{ */
|
||||
{
|
||||
browscap_globals->activation_bdata.htab = NULL;
|
||||
ZVAL_UNDEF(&browscap_globals->activation_bdata.current_section);
|
||||
browscap_globals->activation_bdata.current_section_name = NULL;
|
||||
browscap_globals->activation_bdata.kv = NULL;
|
||||
browscap_globals->activation_bdata.filename[0] = '\0';
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -275,12 +458,20 @@ static void browscap_globals_ctor(zend_browscap_globals *browscap_globals) /* {{
|
|||
static void browscap_bdata_dtor(browser_data *bdata, int persistent) /* {{{ */
|
||||
{
|
||||
if (bdata->htab != NULL) {
|
||||
uint32_t i;
|
||||
|
||||
zend_hash_destroy(bdata->htab);
|
||||
pefree(bdata->htab, persistent);
|
||||
bdata->htab = NULL;
|
||||
|
||||
for (i = 0; i < bdata->kv_used; i++) {
|
||||
zend_string_release(bdata->kv[i].key);
|
||||
zend_string_release(bdata->kv[i].value);
|
||||
}
|
||||
pefree(bdata->kv, persistent);
|
||||
bdata->kv = NULL;
|
||||
}
|
||||
bdata->filename[0] = '\0';
|
||||
/* current_section_* are only used during parsing */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
@ -344,49 +535,89 @@ PHP_MSHUTDOWN_FUNCTION(browscap) /* {{{ */
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
static int browser_reg_compare(zval *browser, int num_args, va_list args, zend_hash_key *key) /* {{{ */
|
||||
static inline size_t browscap_get_minimum_length(browscap_entry *entry) {
|
||||
size_t len = entry->prefix_len;
|
||||
int i;
|
||||
for (i = 0; i < BROWSCAP_NUM_CONTAINS; i++) {
|
||||
len += entry->contains_len[i];
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int browser_reg_compare(
|
||||
zval *entry_zv, int num_args, va_list args, zend_hash_key *key) /* {{{ */
|
||||
{
|
||||
zval *browser_regex, *previous_match;
|
||||
browscap_entry *entry = Z_PTR_P(entry_zv);
|
||||
zend_string *agent_name = va_arg(args, zend_string *);
|
||||
browscap_entry **found_entry_ptr = va_arg(args, browscap_entry **);
|
||||
browscap_entry *found_entry = *found_entry_ptr;
|
||||
ALLOCA_FLAG(use_heap);
|
||||
zend_string *pattern_lc, *regex;
|
||||
const char *cur;
|
||||
int i;
|
||||
|
||||
pcre *re;
|
||||
int re_options;
|
||||
pcre_extra *re_extra;
|
||||
char *lookup_browser_name = va_arg(args, char *);
|
||||
int lookup_browser_length = va_arg(args, int);
|
||||
zval *found_browser_entry = va_arg(args, zval *);
|
||||
|
||||
/* See if we have an exact match, if so, we're done... */
|
||||
if (Z_TYPE_P(found_browser_entry) == IS_ARRAY) {
|
||||
if ((previous_match = zend_hash_str_find(Z_ARRVAL_P(found_browser_entry), "browser_name_pattern", sizeof("browser_name_pattern")-1)) == NULL) {
|
||||
/* Agent name too short */
|
||||
if (ZSTR_LEN(agent_name) < browscap_get_minimum_length(entry)) {
|
||||
return 0;
|
||||
}
|
||||
else if (!strcasecmp(Z_STRVAL_P(previous_match), lookup_browser_name)) {
|
||||
|
||||
/* Quickly discard patterns where the prefix doesn't match. */
|
||||
if (zend_binary_strcasecmp(
|
||||
ZSTR_VAL(agent_name), entry->prefix_len,
|
||||
ZSTR_VAL(entry->pattern), entry->prefix_len) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lowercase the pattern, the agent name is already lowercase */
|
||||
ZSTR_ALLOCA_ALLOC(pattern_lc, ZSTR_LEN(entry->pattern), use_heap);
|
||||
zend_str_tolower_copy(ZSTR_VAL(pattern_lc), ZSTR_VAL(entry->pattern), ZSTR_LEN(entry->pattern));
|
||||
|
||||
/* Check if the agent contains the "contains" portions */
|
||||
cur = ZSTR_VAL(agent_name) + entry->prefix_len;
|
||||
for (i = 0; i < BROWSCAP_NUM_CONTAINS; i++) {
|
||||
if (entry->contains_len[i] != 0) {
|
||||
cur = zend_memnstr(cur,
|
||||
ZSTR_VAL(pattern_lc) + entry->contains_start[i],
|
||||
entry->contains_len[i],
|
||||
ZSTR_VAL(agent_name) + ZSTR_LEN(agent_name));
|
||||
if (!cur) {
|
||||
ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
|
||||
return 0;
|
||||
}
|
||||
cur += entry->contains_len[i];
|
||||
}
|
||||
}
|
||||
|
||||
if ((browser_regex = zend_hash_str_find(Z_ARRVAL_P(browser), "browser_name_regex", sizeof("browser_name_regex")-1)) == NULL) {
|
||||
return 0;
|
||||
/* See if we have an exact match, if so, we're done... */
|
||||
if (zend_string_equals(agent_name, pattern_lc)) {
|
||||
*found_entry_ptr = entry;
|
||||
ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
|
||||
return ZEND_HASH_APPLY_STOP;
|
||||
}
|
||||
|
||||
re = pcre_get_compiled_regex(Z_STR_P(browser_regex), &re_extra, &re_options);
|
||||
regex = browscap_convert_pattern(entry->pattern, 0);
|
||||
re = pcre_get_compiled_regex(regex, &re_extra, &re_options);
|
||||
if (re == NULL) {
|
||||
ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
|
||||
zend_string_release(regex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pcre_exec(re, re_extra, lookup_browser_name, lookup_browser_length, 0, re_options, NULL, 0) == 0) {
|
||||
if (pcre_exec(re, re_extra, ZSTR_VAL(agent_name), ZSTR_LEN(agent_name), 0, re_options, NULL, 0) == 0) {
|
||||
/* If we've found a possible browser, we need to do a comparison of the
|
||||
number of characters changed in the user agent being checked versus
|
||||
the previous match found and the current match. */
|
||||
if (Z_TYPE_P(found_browser_entry) == IS_ARRAY) {
|
||||
if (found_entry) {
|
||||
size_t i, prev_len = 0, curr_len = 0;
|
||||
zval *current_match = zend_hash_str_find(Z_ARRVAL_P(browser), "browser_name_pattern", sizeof("browser_name_pattern")-1);
|
||||
zend_string *previous_match = found_entry->pattern;
|
||||
zend_string *current_match = entry->pattern;
|
||||
|
||||
if (!current_match) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < Z_STRLEN_P(previous_match); i++) {
|
||||
switch (Z_STRVAL_P(previous_match)[i]) {
|
||||
for (i = 0; i < ZSTR_LEN(previous_match); i++) {
|
||||
switch (ZSTR_VAL(previous_match)[i]) {
|
||||
case '?':
|
||||
case '*':
|
||||
/* do nothing, ignore these characters in the count */
|
||||
|
@ -397,8 +628,8 @@ static int browser_reg_compare(zval *browser, int num_args, va_list args, zend_h
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < Z_STRLEN_P(current_match); i++) {
|
||||
switch (Z_STRVAL_P(current_match)[i]) {
|
||||
for (i = 0; i < ZSTR_LEN(current_match); i++) {
|
||||
switch (ZSTR_VAL(current_match)[i]) {
|
||||
case '?':
|
||||
case '*':
|
||||
/* do nothing, ignore these characters in the count */
|
||||
|
@ -412,14 +643,15 @@ static int browser_reg_compare(zval *browser, int num_args, va_list args, zend_h
|
|||
/* Pick which browser pattern replaces the least amount of
|
||||
characters when compared to the original user agent string... */
|
||||
if (prev_len < curr_len) {
|
||||
ZVAL_COPY_VALUE(found_browser_entry, browser);
|
||||
*found_entry_ptr = entry;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZVAL_COPY_VALUE(found_browser_entry, browser);
|
||||
} else {
|
||||
*found_entry_ptr = entry;
|
||||
}
|
||||
}
|
||||
|
||||
ZSTR_ALLOCA_FREE(pattern_lc, use_heap);
|
||||
zend_string_release(regex);
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -434,13 +666,11 @@ static void browscap_zval_copy_ctor(zval *p) /* {{{ */
|
|||
Get information about the capabilities of a browser. If browser_name is omitted or null, HTTP_USER_AGENT is used. Returns an object by default; if return_array is true, returns an array. */
|
||||
PHP_FUNCTION(get_browser)
|
||||
{
|
||||
char *agent_name = NULL;
|
||||
size_t agent_name_len = 0;
|
||||
zend_string *agent_name = NULL, *lookup_browser_name;
|
||||
zend_bool return_array = 0;
|
||||
zval *agent, *z_agent_name, *http_user_agent;
|
||||
zval found_browser_entry;
|
||||
char *lookup_browser_name;
|
||||
browser_data *bdata;
|
||||
browscap_entry *found_entry = NULL;
|
||||
HashTable *agent_ht;
|
||||
|
||||
if (BROWSCAP_G(activation_bdata).filename[0] != '\0') {
|
||||
bdata = &BROWSCAP_G(activation_bdata);
|
||||
|
@ -459,58 +689,66 @@ PHP_FUNCTION(get_browser)
|
|||
|
||||
ZEND_PARSE_PARAMETERS_START(0, 2)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_STRING_EX(agent_name, agent_name_len, 1, 0)
|
||||
Z_PARAM_STR_EX(agent_name, 1, 0)
|
||||
Z_PARAM_BOOL(return_array)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
if (agent_name == NULL) {
|
||||
if ((Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY || zend_is_auto_global_str(ZEND_STRL("_SERVER"))) &&
|
||||
(http_user_agent = zend_hash_str_find(Z_ARRVAL_P(&PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")-1)) == NULL
|
||||
) {
|
||||
zval *http_user_agent = NULL;
|
||||
if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY
|
||||
|| zend_is_auto_global_str(ZEND_STRL("_SERVER"))) {
|
||||
http_user_agent = zend_hash_str_find(
|
||||
Z_ARRVAL_P(&PG(http_globals)[TRACK_VARS_SERVER]),
|
||||
"HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")-1);
|
||||
}
|
||||
if (http_user_agent == NULL) {
|
||||
php_error_docref(NULL, E_WARNING, "HTTP_USER_AGENT variable is not set, cannot determine user agent name");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
agent_name = Z_STRVAL_P(http_user_agent);
|
||||
agent_name_len = Z_STRLEN_P(http_user_agent);
|
||||
agent_name = Z_STR_P(http_user_agent);
|
||||
}
|
||||
|
||||
lookup_browser_name = estrndup(agent_name, agent_name_len);
|
||||
php_strtolower(lookup_browser_name, agent_name_len);
|
||||
lookup_browser_name = zend_string_tolower(agent_name);
|
||||
found_entry = zend_hash_find_ptr(bdata->htab, lookup_browser_name);
|
||||
if (found_entry == NULL) {
|
||||
zend_hash_apply_with_arguments(bdata->htab, browser_reg_compare, 2, lookup_browser_name, &found_entry);
|
||||
|
||||
if ((agent = zend_hash_str_find(bdata->htab, lookup_browser_name, agent_name_len)) == NULL) {
|
||||
ZVAL_UNDEF(&found_browser_entry);
|
||||
zend_hash_apply_with_arguments(bdata->htab, browser_reg_compare, 3, lookup_browser_name, agent_name_len, &found_browser_entry);
|
||||
|
||||
if (Z_TYPE(found_browser_entry) != IS_UNDEF) {
|
||||
agent = &found_browser_entry;
|
||||
} else if ((agent = zend_hash_str_find(bdata->htab, DEFAULT_SECTION_NAME, sizeof(DEFAULT_SECTION_NAME)-1)) == NULL) {
|
||||
if (found_entry == NULL) {
|
||||
found_entry = zend_hash_str_find_ptr(bdata->htab,
|
||||
DEFAULT_SECTION_NAME, sizeof(DEFAULT_SECTION_NAME)-1);
|
||||
if (found_entry == NULL) {
|
||||
efree(lookup_browser_name);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
agent_ht = browscap_entry_to_array(bdata, found_entry);
|
||||
|
||||
if (return_array) {
|
||||
RETVAL_ARR(zend_array_dup(Z_ARRVAL_P(agent)));
|
||||
}
|
||||
else {
|
||||
object_init(return_value);
|
||||
zend_hash_copy(Z_OBJPROP_P(return_value), Z_ARRVAL_P(agent), (copy_ctor_func_t) browscap_zval_copy_ctor);
|
||||
RETVAL_ARR(agent_ht);
|
||||
} else {
|
||||
object_and_properties_init(return_value, zend_standard_class_def, agent_ht);
|
||||
}
|
||||
|
||||
while ((z_agent_name = zend_hash_str_find(Z_ARRVAL_P(agent), "parent", sizeof("parent")-1)) != NULL) {
|
||||
if ((agent = zend_hash_find(bdata->htab, Z_STR_P(z_agent_name))) == NULL) {
|
||||
while (found_entry->parent) {
|
||||
found_entry = zend_hash_find_ptr(bdata->htab, found_entry->parent);
|
||||
if (found_entry == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
agent_ht = browscap_entry_to_array(bdata, found_entry);
|
||||
if (return_array) {
|
||||
zend_hash_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(agent), (copy_ctor_func_t) browscap_zval_copy_ctor, 0);
|
||||
}
|
||||
else {
|
||||
zend_hash_merge(Z_OBJPROP_P(return_value), Z_ARRVAL_P(agent), (copy_ctor_func_t) browscap_zval_copy_ctor, 0);
|
||||
}
|
||||
zend_hash_merge(Z_ARRVAL_P(return_value), agent_ht, (copy_ctor_func_t) browscap_zval_copy_ctor, 0);
|
||||
} else {
|
||||
zend_hash_merge(Z_OBJPROP_P(return_value), agent_ht, (copy_ctor_func_t) browscap_zval_copy_ctor, 0);
|
||||
}
|
||||
|
||||
efree(lookup_browser_name);
|
||||
zend_hash_destroy(agent_ht);
|
||||
efree(agent_ht);
|
||||
}
|
||||
|
||||
zend_string_release(lookup_browser_name);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
|
|
@ -129,12 +129,12 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch
|
|||
|
||||
crypt_res = php_sha512_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
|
||||
if (!crypt_res) {
|
||||
memset(output, 0, PHP_MAX_SALT_LEN);
|
||||
ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
|
||||
efree(output);
|
||||
return NULL;
|
||||
} else {
|
||||
result = zend_string_init(output, strlen(output), 0);
|
||||
memset(output, 0, PHP_MAX_SALT_LEN);
|
||||
ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
|
||||
efree(output);
|
||||
return result;
|
||||
}
|
||||
|
@ -144,12 +144,12 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch
|
|||
|
||||
crypt_res = php_sha256_crypt_r(password, salt, output, PHP_MAX_SALT_LEN);
|
||||
if (!crypt_res) {
|
||||
memset(output, 0, PHP_MAX_SALT_LEN);
|
||||
ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
|
||||
efree(output);
|
||||
return NULL;
|
||||
} else {
|
||||
result = zend_string_init(output, strlen(output), 0);
|
||||
memset(output, 0, PHP_MAX_SALT_LEN);
|
||||
ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN);
|
||||
efree(output);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -97,8 +97,132 @@ static void php_pack(zval *val, size_t size, int *map, char *output)
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pack_reverse_int32
|
||||
*/
|
||||
static inline uint32_t php_pack_reverse_int32(uint32_t arg)
|
||||
{
|
||||
uint32_t result;
|
||||
result = ((arg & 0xFF) << 24) | ((arg & 0xFF00) << 8) | ((arg >> 8) & 0xFF00) | ((arg >> 24) & 0xFF);
|
||||
|
||||
return result;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pack
|
||||
*/
|
||||
static inline uint64_t php_pack_reverse_int64(uint64_t arg)
|
||||
{
|
||||
union Swap64 {
|
||||
uint64_t i;
|
||||
uint32_t ul[2];
|
||||
} tmp, result;
|
||||
tmp.i = arg;
|
||||
result.ul[0] = php_pack_reverse_int32(tmp.ul[1]);
|
||||
result.ul[1] = php_pack_reverse_int32(tmp.ul[0]);
|
||||
|
||||
return result.i;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pack_copy_float
|
||||
*/
|
||||
static void php_pack_copy_float(int is_little_endian, void * dst, float f)
|
||||
{
|
||||
union Copy32 {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} m;
|
||||
m.f = f;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (is_little_endian) {
|
||||
m.i = php_pack_reverse_int32(m.i);
|
||||
}
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
if (!is_little_endian) {
|
||||
m.i = php_pack_reverse_int32(m.i);
|
||||
}
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
|
||||
memcpy(dst, &m.f, sizeof(float));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pack_copy_double
|
||||
*/
|
||||
static void php_pack_copy_double(int is_little_endian, void * dst, double d)
|
||||
{
|
||||
union Copy64 {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} m;
|
||||
m.d = d;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (is_little_endian) {
|
||||
m.i = php_pack_reverse_int64(m.i);
|
||||
}
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
if (!is_little_endian) {
|
||||
m.i = php_pack_reverse_int64(m.i);
|
||||
}
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
|
||||
memcpy(dst, &m.d, sizeof(double));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pack_parse_float
|
||||
*/
|
||||
static float php_pack_parse_float(int is_little_endian, void * src)
|
||||
{
|
||||
union Copy32 {
|
||||
float f;
|
||||
uint32_t i;
|
||||
} m;
|
||||
memcpy(&m.i, src, sizeof(float));
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (is_little_endian) {
|
||||
m.i = php_pack_reverse_int32(m.i);
|
||||
}
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
if (!is_little_endian) {
|
||||
m.i = php_pack_reverse_int32(m.i);
|
||||
}
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
|
||||
return m.f;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_pack_parse_double
|
||||
*/
|
||||
static double php_pack_parse_double(int is_little_endian, void * src)
|
||||
{
|
||||
union Copy64 {
|
||||
double d;
|
||||
uint64_t i;
|
||||
} m;
|
||||
memcpy(&m.i, src, sizeof(double));
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (is_little_endian) {
|
||||
m.i = php_pack_reverse_int64(m.i);
|
||||
}
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
if (!is_little_endian) {
|
||||
m.i = php_pack_reverse_int64(m.i);
|
||||
}
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
|
||||
return m.d;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* pack() idea stolen from Perl (implemented formats behave the same as there except J and P)
|
||||
* Implemented formats are Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, q, Q, J, P, f, d, x, X, @.
|
||||
* Added g, G for little endian float and big endian float, added e, E for little endian double and big endian double.
|
||||
*/
|
||||
/* {{{ proto string pack(string format, mixed arg1 [, mixed arg2 [, mixed ...]])
|
||||
Takes one or more arguments and packs them into a binary string according to the format argument */
|
||||
|
@ -210,8 +334,12 @@ PHP_FUNCTION(pack)
|
|||
case 'N':
|
||||
case 'v':
|
||||
case 'V':
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'f': /* float */
|
||||
case 'g': /* little endian float */
|
||||
case 'G': /* big endian float */
|
||||
case 'd': /* double */
|
||||
case 'e': /* little endian double */
|
||||
case 'E': /* big endian double */
|
||||
if (arg < 0) {
|
||||
arg = num_args - currentarg;
|
||||
}
|
||||
|
@ -289,11 +417,15 @@ PHP_FUNCTION(pack)
|
|||
break;
|
||||
#endif
|
||||
|
||||
case 'f':
|
||||
case 'f': /* float */
|
||||
case 'g': /* little endian float */
|
||||
case 'G': /* big endian float */
|
||||
INC_OUTPUTPOS(arg,sizeof(float))
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'd': /* double */
|
||||
case 'e': /* little endian double */
|
||||
case 'E': /* big endian double */
|
||||
INC_OUTPUTPOS(arg,sizeof(double))
|
||||
break;
|
||||
|
||||
|
@ -469,6 +601,26 @@ PHP_FUNCTION(pack)
|
|||
break;
|
||||
}
|
||||
|
||||
case 'g': {
|
||||
/* pack little endian float */
|
||||
while (arg-- > 0) {
|
||||
float v = (float) zval_get_double(&argv[currentarg++]);
|
||||
php_pack_copy_float(1, &ZSTR_VAL(output)[outputpos], v);
|
||||
outputpos += sizeof(v);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'G': {
|
||||
/* pack big endian float */
|
||||
while (arg-- > 0) {
|
||||
float v = (float) zval_get_double(&argv[currentarg++]);
|
||||
php_pack_copy_float(0, &ZSTR_VAL(output)[outputpos], v);
|
||||
outputpos += sizeof(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': {
|
||||
while (arg-- > 0) {
|
||||
double v = (double) zval_get_double(&argv[currentarg++]);
|
||||
|
@ -478,6 +630,26 @@ PHP_FUNCTION(pack)
|
|||
break;
|
||||
}
|
||||
|
||||
case 'e': {
|
||||
/* pack little endian double */
|
||||
while (arg-- > 0) {
|
||||
double v = (double) zval_get_double(&argv[currentarg++]);
|
||||
php_pack_copy_double(1, &ZSTR_VAL(output)[outputpos], v);
|
||||
outputpos += sizeof(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'E': {
|
||||
/* pack big endian double */
|
||||
while (arg-- > 0) {
|
||||
double v = (double) zval_get_double(&argv[currentarg++]);
|
||||
php_pack_copy_double(0, &ZSTR_VAL(output)[outputpos], v);
|
||||
outputpos += sizeof(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x':
|
||||
memset(&ZSTR_VAL(output)[outputpos], '\0', arg);
|
||||
outputpos += arg;
|
||||
|
@ -537,6 +709,7 @@ static zend_long php_unpack(char *data, size_t size, int issigned, int *map)
|
|||
* Numeric pack types will return numbers, a and A will return strings,
|
||||
* f and d will return doubles.
|
||||
* Implemented formats are Z, A, a, h, H, c, C, s, S, i, I, l, L, n, N, q, Q, J, P, f, d, x, X, @.
|
||||
* Added g, G for little endian float and big endian float, added e, E for little endian double and big endian double.
|
||||
*/
|
||||
/* {{{ proto array unpack(string format, string input)
|
||||
Unpack binary string into named array elements according to format argument */
|
||||
|
@ -679,11 +852,15 @@ PHP_FUNCTION(unpack)
|
|||
|
||||
/* Use sizeof(float) bytes of input */
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
size = sizeof(float);
|
||||
break;
|
||||
|
||||
/* Use sizeof(double) bytes of input */
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'E':
|
||||
size = sizeof(double);
|
||||
break;
|
||||
|
||||
|
@ -939,18 +1116,37 @@ PHP_FUNCTION(unpack)
|
|||
}
|
||||
#endif
|
||||
|
||||
case 'f': {
|
||||
case 'f': /* float */
|
||||
case 'g': /* little endian float*/
|
||||
case 'G': /* big endian float*/
|
||||
{
|
||||
float v;
|
||||
|
||||
if (type == 'g') {
|
||||
v = php_pack_parse_float(1, &input[inputpos]);
|
||||
} else if (type == 'G') {
|
||||
v = php_pack_parse_float(0, &input[inputpos]);
|
||||
} else {
|
||||
memcpy(&v, &input[inputpos], sizeof(float));
|
||||
}
|
||||
|
||||
add_assoc_double(return_value, n, (double)v);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': {
|
||||
double v;
|
||||
|
||||
case 'd': /* double */
|
||||
case 'e': /* little endian float */
|
||||
case 'E': /* big endian float */
|
||||
{
|
||||
double v;
|
||||
if (type == 'e') {
|
||||
v = php_pack_parse_double(1, &input[inputpos]);
|
||||
} else if (type == 'E') {
|
||||
v = php_pack_parse_double(0, &input[inputpos]);
|
||||
} else {
|
||||
memcpy(&v, &input[inputpos], sizeof(double));
|
||||
}
|
||||
add_assoc_double(return_value, n, v);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -364,7 +364,7 @@ char * php_md5_crypt_r(const char *pw, const char *salt, char *out)
|
|||
PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl));
|
||||
|
||||
/* Don't leave anything around in vm they could use. */
|
||||
memset(final, 0, sizeof(final));
|
||||
ZEND_SECURE_ZERO(final, sizeof(final));
|
||||
|
||||
/* Then something really weird... */
|
||||
for (i = pwl; i != 0; i >>= 1)
|
||||
|
|
11018
ext/standard/tests/misc/browscap_lite_2016_12_06.ini
Normal file
11018
ext/standard/tests/misc/browscap_lite_2016_12_06.ini
Normal file
File diff suppressed because it is too large
Load diff
2238
ext/standard/tests/misc/get_browser_variation3.phpt
Normal file
2238
ext/standard/tests/misc/get_browser_variation3.phpt
Normal file
File diff suppressed because it is too large
Load diff
1112
ext/standard/tests/misc/user_agents.txt
Normal file
1112
ext/standard/tests/misc/user_agents.txt
Normal file
File diff suppressed because it is too large
Load diff
12
ext/standard/tests/serialize/bug73825.phpt
Normal file
12
ext/standard/tests/serialize/bug73825.phpt
Normal file
|
@ -0,0 +1,12 @@
|
|||
--TEST--
|
||||
Bug #73825 Heap out of bounds read on unserialize in finish_nested_data()
|
||||
--FILE--
|
||||
<?php
|
||||
$obj = unserialize('O:8:"00000000":');
|
||||
var_dump($obj);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Bad unserialize data in %sbug73825.php on line %d
|
||||
|
||||
Notice: unserialize(): Error at offset 13 of 15 bytes in %sbug73825.php on line %d
|
||||
bool(false)
|
312
ext/standard/tests/strings/pack_float.phpt
Normal file
312
ext/standard/tests/strings/pack_float.phpt
Normal file
|
@ -0,0 +1,312 @@
|
|||
--TEST--
|
||||
pack()/unpack(): float/double tests
|
||||
--FILE--
|
||||
<?php
|
||||
var_dump(
|
||||
'pack e',
|
||||
bin2hex(pack("e", "")),
|
||||
bin2hex(pack("e", "a")),
|
||||
bin2hex(pack("e", " ")),
|
||||
bin2hex(pack("e", NULL)),
|
||||
bin2hex(pack("e", 0)),
|
||||
bin2hex(pack("e", 1)),
|
||||
bin2hex(pack("e", 1.0)),
|
||||
bin2hex(pack("e", 10000000000000000)),
|
||||
bin2hex(pack("e", 0.591234709823149)),
|
||||
bin2hex(pack("e", 12345678901234567890.1234567898765432123456789)),
|
||||
bin2hex(pack("e", -1)),
|
||||
bin2hex(pack("e", -1.0)),
|
||||
bin2hex(pack("e", -10000000000000000)),
|
||||
bin2hex(pack("e", -0.591234709823149)),
|
||||
bin2hex(pack("e", -12345678901234567890.1234567898765432123456789)),
|
||||
|
||||
'pack E',
|
||||
bin2hex(pack("E", "")),
|
||||
bin2hex(pack("E", "a")),
|
||||
bin2hex(pack("E", " ")),
|
||||
bin2hex(pack("E", NULL)),
|
||||
bin2hex(pack("E", 0)),
|
||||
bin2hex(pack("E", 1)),
|
||||
bin2hex(pack("E", 1.0)),
|
||||
bin2hex(pack("E", 10000000000000000)),
|
||||
bin2hex(pack("E", 0.591234709823149)),
|
||||
bin2hex(pack("E", 12345678901234567890.1234567898765432123456789)),
|
||||
bin2hex(pack("E", -1)),
|
||||
bin2hex(pack("E", -1.0)),
|
||||
bin2hex(pack("E", -10000000000000000)),
|
||||
bin2hex(pack("E", -0.591234709823149)),
|
||||
bin2hex(pack("E", -12345678901234567890.1234567898765432123456789)),
|
||||
|
||||
'pack g',
|
||||
bin2hex(pack("g", "")),
|
||||
bin2hex(pack("g", "a")),
|
||||
bin2hex(pack("g", " ")),
|
||||
bin2hex(pack("g", NULL)),
|
||||
bin2hex(pack("g", 0)),
|
||||
bin2hex(pack("g", 1)),
|
||||
bin2hex(pack("g", 1.0)),
|
||||
bin2hex(pack("g", 10000000000000000)),
|
||||
bin2hex(pack("g", 0.591234709823149)),
|
||||
bin2hex(pack("g", 12345678901234567890.1234567898765432123456789)),
|
||||
bin2hex(pack("g", -1)),
|
||||
bin2hex(pack("g", -1.0)),
|
||||
bin2hex(pack("g", -10000000000000000)),
|
||||
bin2hex(pack("g", -0.591234709823149)),
|
||||
bin2hex(pack("g", -12345678901234567890.1234567898765432123456789)),
|
||||
|
||||
'pack G',
|
||||
bin2hex(pack("G", "")),
|
||||
bin2hex(pack("G", "a")),
|
||||
bin2hex(pack("G", " ")),
|
||||
bin2hex(pack("G", NULL)),
|
||||
bin2hex(pack("G", 0)),
|
||||
bin2hex(pack("G", 1)),
|
||||
bin2hex(pack("G", 1.0)),
|
||||
bin2hex(pack("G", 10000000000000000)),
|
||||
bin2hex(pack("G", 0.591234709823149)),
|
||||
bin2hex(pack("G", 12345678901234567890.1234567898765432123456789)),
|
||||
bin2hex(pack("G", -1)),
|
||||
bin2hex(pack("G", -1.0)),
|
||||
bin2hex(pack("G", -10000000000000000)),
|
||||
bin2hex(pack("G", -0.591234709823149)),
|
||||
bin2hex(pack("G", -12345678901234567890.1234567898765432123456789)),
|
||||
|
||||
'unpack e',
|
||||
unpack('e', hex2bin('0000000000000000')),
|
||||
unpack('e', hex2bin('000000000000f03f')),
|
||||
unpack('e', hex2bin('0080e03779c34143')),
|
||||
unpack('e', hex2bin('4a6ade0d65ebe23f')),
|
||||
unpack('e', hex2bin('000000000000f0bf')),
|
||||
unpack('e', hex2bin('0080e03779c341c3')),
|
||||
unpack('e', hex2bin('4a6ade0d65ebe2bf')),
|
||||
unpack('e', hex2bin('e1639d31956ae5c3')),
|
||||
|
||||
'unpack E',
|
||||
unpack('E', hex2bin('3ff0000000000000')),
|
||||
unpack('E', hex2bin('4341c37937e08000')),
|
||||
unpack('E', hex2bin('3fe2eb650dde6a4a')),
|
||||
unpack('E', hex2bin('43e56a95319d63e1')),
|
||||
unpack('E', hex2bin('bff0000000000000')),
|
||||
unpack('E', hex2bin('c341c37937e08000')),
|
||||
unpack('E', hex2bin('bfe2eb650dde6a4a')),
|
||||
unpack('E', hex2bin('c3e56a95319d63e1')),
|
||||
|
||||
'unpack g',
|
||||
unpack('g', hex2bin('0000803f')),
|
||||
unpack('g', hex2bin('ca1b0e5a')),
|
||||
unpack('g', hex2bin('285b173f')),
|
||||
unpack('g', hex2bin('aa542b5f')),
|
||||
unpack('g', hex2bin('000080bf')),
|
||||
unpack('g', hex2bin('ca1b0eda')),
|
||||
unpack('g', hex2bin('285b17bf')),
|
||||
unpack('g', hex2bin('aa542bdf')),
|
||||
|
||||
'unpack G',
|
||||
unpack('G', hex2bin('3f800000')),
|
||||
unpack('G', hex2bin('5a0e1bca')),
|
||||
unpack('G', hex2bin('3f175b28')),
|
||||
unpack('G', hex2bin('5f2b54aa')),
|
||||
unpack('G', hex2bin('bf800000')),
|
||||
unpack('G', hex2bin('da0e1bca')),
|
||||
unpack('G', hex2bin('bf175b28')),
|
||||
unpack('G', hex2bin('df2b54aa'))
|
||||
|
||||
);
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(6) "pack e"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "000000000000f03f"
|
||||
string(16) "000000000000f03f"
|
||||
string(16) "0080e03779c34143"
|
||||
string(16) "4a6ade0d65ebe23f"
|
||||
string(16) "e1639d31956ae543"
|
||||
string(16) "000000000000f0bf"
|
||||
string(16) "000000000000f0bf"
|
||||
string(16) "0080e03779c341c3"
|
||||
string(16) "4a6ade0d65ebe2bf"
|
||||
string(16) "e1639d31956ae5c3"
|
||||
string(6) "pack E"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "0000000000000000"
|
||||
string(16) "3ff0000000000000"
|
||||
string(16) "3ff0000000000000"
|
||||
string(16) "4341c37937e08000"
|
||||
string(16) "3fe2eb650dde6a4a"
|
||||
string(16) "43e56a95319d63e1"
|
||||
string(16) "bff0000000000000"
|
||||
string(16) "bff0000000000000"
|
||||
string(16) "c341c37937e08000"
|
||||
string(16) "bfe2eb650dde6a4a"
|
||||
string(16) "c3e56a95319d63e1"
|
||||
string(6) "pack g"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "0000803f"
|
||||
string(8) "0000803f"
|
||||
string(8) "ca1b0e5a"
|
||||
string(8) "285b173f"
|
||||
string(8) "aa542b5f"
|
||||
string(8) "000080bf"
|
||||
string(8) "000080bf"
|
||||
string(8) "ca1b0eda"
|
||||
string(8) "285b17bf"
|
||||
string(8) "aa542bdf"
|
||||
string(6) "pack G"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "00000000"
|
||||
string(8) "3f800000"
|
||||
string(8) "3f800000"
|
||||
string(8) "5a0e1bca"
|
||||
string(8) "3f175b28"
|
||||
string(8) "5f2b54aa"
|
||||
string(8) "bf800000"
|
||||
string(8) "bf800000"
|
||||
string(8) "da0e1bca"
|
||||
string(8) "bf175b28"
|
||||
string(8) "df2b54aa"
|
||||
string(8) "unpack e"
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(0)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1.0E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(0.59123470982315)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.0E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-0.59123470982315)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.2345678901235E+19)
|
||||
}
|
||||
string(8) "unpack E"
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1.0E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(0.59123470982315)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1.2345678901235E+19)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.0E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-0.59123470982315)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.2345678901235E+19)
|
||||
}
|
||||
string(8) "unpack g"
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1.0000000272564E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(0.59123468399048)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1.2345679395506E+19)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.0000000272564E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-0.59123468399048)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.2345679395506E+19)
|
||||
}
|
||||
string(8) "unpack G"
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1.0000000272564E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(0.59123468399048)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(1.2345679395506E+19)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.0000000272564E+16)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-0.59123468399048)
|
||||
}
|
||||
array(1) {
|
||||
[1]=>
|
||||
float(-1.2345679395506E+19)
|
||||
}
|
|
@ -19,7 +19,7 @@ var_dump(unpack("I", pack("I", 65534), 0, $extra_arg));
|
|||
|
||||
echo "\n-- Testing unpack() function with invalid format character --\n";
|
||||
$extra_arg = 10;
|
||||
var_dump(unpack("G", pack("I", 65534)));
|
||||
var_dump(unpack("B", pack("I", 65534)));
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
|
@ -37,6 +37,6 @@ NULL
|
|||
|
||||
-- Testing unpack() function with invalid format character --
|
||||
|
||||
Warning: unpack(): Invalid format type G in %s on line %d
|
||||
Warning: unpack(): Invalid format type B in %s on line %d
|
||||
bool(false)
|
||||
===DONE===
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -483,6 +483,11 @@ static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *
|
|||
{
|
||||
zend_long elements;
|
||||
|
||||
if( *p >= max - 2) {
|
||||
zend_error(E_WARNING, "Bad unserialize data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
elements = parse_iv2((*p) + 2, p);
|
||||
|
||||
(*p) += 2;
|
||||
|
@ -493,7 +498,7 @@ static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *
|
|||
/* If this class implements Serializable, it should not land here but in object_custom(). The passed string
|
||||
obviously doesn't descend from the regular serializer. */
|
||||
zend_error(E_WARNING, "Erroneous data format for unserializing '%s'", ZSTR_VAL(ce->name));
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return elements;
|
||||
|
@ -800,10 +805,14 @@ use_double:
|
|||
}
|
||||
|
||||
"o:" iv ":" ["] {
|
||||
long elements;
|
||||
if (!var_hash) return 0;
|
||||
|
||||
return object_common2(UNSERIALIZE_PASSTHRU,
|
||||
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
|
||||
elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR);
|
||||
if (elements < 0) {
|
||||
return 0;
|
||||
}
|
||||
return object_common2(UNSERIALIZE_PASSTHRU, elements);
|
||||
}
|
||||
|
||||
object ":" uiv ":" ["] {
|
||||
|
@ -945,6 +954,11 @@ object ":" uiv ":" ["] {
|
|||
|
||||
elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
|
||||
|
||||
if (elements < 0) {
|
||||
zend_string_release(class_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (incomplete_class) {
|
||||
php_store_class_name(rval, ZSTR_VAL(class_name), len2);
|
||||
}
|
||||
|
|
|
@ -67,12 +67,16 @@ if ($pid) {
|
|||
exit;
|
||||
}
|
||||
|
||||
/* Release the child semahpore before releasing
|
||||
the releasing the parent semaphore and letting
|
||||
the child continue execution */
|
||||
sem_release($c_sem_id);
|
||||
|
||||
echo "P: releasing semaphore $p_sem_id.\n";
|
||||
if (!sem_release($p_sem_id)) {
|
||||
echo "P: failed to release semaphore\n";
|
||||
}
|
||||
|
||||
sem_release($c_sem_id);
|
||||
$status = null;
|
||||
pcntl_waitpid($pid, $status);
|
||||
|
||||
|
|
23
ext/wddx/tests/bug73831.phpt
Normal file
23
ext/wddx/tests/bug73831.phpt
Normal file
|
@ -0,0 +1,23 @@
|
|||
--TEST--
|
||||
Bug #73831 (NULL Pointer Dereference while unserialize php object)
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("wddx")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
$xml = <<<EOF
|
||||
<?xml version="1.0" ?>
|
||||
<wddxPacket version="1.0">
|
||||
<struct>
|
||||
<var name="php_class_name">
|
||||
<string>Throwable</string>
|
||||
</var>
|
||||
</struct>
|
||||
</wddxPacket>
|
||||
EOF;
|
||||
try {
|
||||
$wddx = wddx_deserialize($xml);
|
||||
} catch(Error $e) { echo $e->getMessage(); }
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: wddx_deserialize(): Class throwable can not be instantiated in %sbug73831.php on line %d
|
||||
Cannot instantiate interface Throwable
|
|
@ -967,8 +967,11 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name)
|
|||
php_error_docref(NULL, E_WARNING, "Class %s can not be unserialized", Z_STRVAL(ent1->data));
|
||||
} else {
|
||||
/* Initialize target object */
|
||||
object_init_ex(&obj, pce);
|
||||
|
||||
if (object_init_ex(&obj, pce) != SUCCESS || EG(exception)) {
|
||||
zval_ptr_dtor(&ent2->data);
|
||||
ZVAL_UNDEF(&ent2->data);
|
||||
php_error_docref(NULL, E_WARNING, "Class %s can not be instantiated", Z_STRVAL(ent1->data));
|
||||
} else {
|
||||
/* Merge current hashtable with object's default properties */
|
||||
zend_hash_merge(Z_OBJPROP(obj),
|
||||
Z_ARRVAL(ent2->data),
|
||||
|
@ -984,6 +987,7 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name)
|
|||
/* Set stack entry to point to the newly created object */
|
||||
ZVAL_COPY_VALUE(&ent2->data, &obj);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up class name var entry */
|
||||
zval_ptr_dtor(&ent1->data);
|
||||
|
|
43
main/explicit_bzero.c
Normal file
43
main/explicit_bzero.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 7 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2016 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include "php.h"
|
||||
|
||||
#ifndef HAVE_EXPLICIT_BZERO
|
||||
|
||||
/* $OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
|
||||
/*
|
||||
* Public domain.
|
||||
* Written by Matthew Dempsky.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
__attribute__((weak)) void
|
||||
__explicit_bzero_hook(void *dst, size_t siz)
|
||||
{
|
||||
}
|
||||
|
||||
PHPAPI void php_explicit_bzero(void *dst, size_t siz)
|
||||
{
|
||||
memset(dst, 0, siz);
|
||||
__explicit_bzero_hook(dst, siz);
|
||||
}
|
||||
#endif
|
|
@ -176,6 +176,14 @@ END_EXTERN_C()
|
|||
#define strlcat php_strlcat
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_EXPLICIT_BZERO
|
||||
BEGIN_EXTERN_C()
|
||||
PHPAPI void php_explicit_bzero(void *dst, size_t siz);
|
||||
END_EXTERN_C()
|
||||
#undef explicit_bzero
|
||||
#define explicit_bzero php_explicit_bzero
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRTOK_R
|
||||
BEGIN_EXTERN_C()
|
||||
char *strtok_r(char *s, const char *delim, char **last);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#ifndef HAVE_STRLCAT
|
||||
|
||||
/* $OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $ */
|
||||
/* $OpenBSD: strlcat.c,v 1.17 2016/10/14 18:19:04 dtucker Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
|
@ -52,7 +52,7 @@
|
|||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char *rcsid = "$OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $";
|
||||
static char *rcsid = "$OpenBSD: strlcat.c,v 1.17 2016/10/14 18:19:04 dtucker Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -69,29 +69,34 @@ PHPAPI size_t php_strlcat(dst, src, siz)
|
|||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
const char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (*d != '\0' && n-- != 0)
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
while (n-- != 0 && *dst != '\0')
|
||||
dst++;
|
||||
dlen = (uintptr_t)dst - (uintptr_t)d;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
if (n-- == 0)
|
||||
return(dlen + strlen(src));
|
||||
while (*src != '\0') {
|
||||
if (n != 0) {
|
||||
*dst++ = *src;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
src++;
|
||||
}
|
||||
*d = '\0';
|
||||
*dst = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
/*
|
||||
* Cast pointers to unsigned type before calculation, to avoid signed
|
||||
* overflow when the string ends where the MSB has changed.
|
||||
* Return value does not include NUL.
|
||||
*/
|
||||
return(dlen + ((uintptr_t)src - (uintptr_t)s));
|
||||
}
|
||||
|
||||
#endif /* !HAVE_STRLCAT */
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#ifndef HAVE_STRLCPY
|
||||
|
||||
/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
|
||||
/* $OpenBSD: strlcpy.c,v 1.15 2016/10/16 17:37:39 dtucker Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
|
@ -52,7 +52,7 @@
|
|||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
|
||||
static char *rcsid = "$OpenBSD: strlcpy.c,v 1.15 2016/10/16 17:37:39 dtucker Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -68,27 +68,31 @@ PHPAPI size_t php_strlcpy(dst, src, siz)
|
|||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
if (n != 0) {
|
||||
while (--n != 0) {
|
||||
if ((*dst++ = *src++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
*dst = '\0'; /* NUL-terminate dst */
|
||||
while (*src++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
/*
|
||||
* Cast pointers to unsigned type before calculation, to avoid signed
|
||||
* overflow when the string ends where the MSB has changed.
|
||||
* Return value does not include NUL.
|
||||
*/
|
||||
return((uintptr_t)src - (uintptr_t)s - 1);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_STRLCPY */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue