Resolve conflict

This commit is contained in:
Sammy Kaye Powers 2017-01-03 08:01:05 -06:00
commit 1e3624290a
42 changed files with 20821 additions and 6764 deletions

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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 */

View file

@ -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% ^

View file

@ -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)

View file

@ -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);

View 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)

Binary file not shown.

View file

@ -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);

View 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!

View file

@ -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);
}
/* }}} */

View file

@ -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'); ?>

View file

@ -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');
?>

View file

@ -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');

View file

@ -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--

View file

@ -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)");
}

Binary file not shown.

View 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)

Binary file not shown.

View 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"

View file

@ -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);
}
/* }}} */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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)

View 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)
}

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View 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

View file

@ -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
View 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

View file

@ -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);

View file

@ -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 */

View file

@ -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 */