import expect

This commit is contained in:
krakjoe 2014-02-02 12:49:35 +00:00
parent f08e8772a7
commit 3892eba2bf
37 changed files with 526 additions and 39 deletions

View file

@ -0,0 +1,12 @@
--TEST--
test passing assertion
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
assert(true);
var_dump(true);
?>
--EXPECTF--
bool(true)

View file

@ -0,0 +1,16 @@
--TEST--
test failing assertion
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
assert(false);
var_dump(true);
?>
--EXPECTF--
Fatal error: Uncaught exception 'AssertionException' with message 'assert(false)' in %sexpect_002.php:%d
Stack trace:
#0 %sexpect_002.php(%d): assert(false, 'assert(false)')
#1 {main}
thrown in %sexpect_002.php on line %d

View file

@ -0,0 +1,15 @@
--TEST--
test catching failed assertion
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
try {
assert(false);
} catch (AssertionException $ex) {
var_dump($ex->getMessage());
}
?>
--EXPECT--
string(13) "assert(false)"

View file

@ -0,0 +1,15 @@
--TEST--
test providing reason (fail)
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
try {
assert(false, "I require this to succeed");
} catch (AssertionException $ex) {
var_dump($ex->getMessage());
}
?>
--EXPECT--
string(25) "I require this to succeed"

View file

@ -0,0 +1,17 @@
--TEST--
test providing reason (pass)
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
try {
/* by passing we test there are no leaks upon success */
assert(true, "I require this to succeed");
} catch (AssertionException $ex) {
var_dump($ex->getMessage());
}
var_dump(true);
?>
--EXPECT--
bool(true)

View file

@ -0,0 +1,14 @@
--TEST--
test looping assert (pass)
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
for($i=0; $i<100000; $i++) {
assert ($i < 100000, "The universe should make sense");
}
var_dump(true);
?>
--EXPECT--
bool(true)

View file

@ -0,0 +1,22 @@
--TEST--
test compiled reason
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
$next = 1;
$data = array(
"key" => "X-HTTP ",
"value" => "testing"
);
class HeaderMalfunctionException extends AssertionException {}
assert (preg_match("~^([a-zA-Z0-9-]+)$~", $data["key"]), new HeaderMalfunctionException("malformed key found at {$next} \"{$data["key"]}\""));
?>
--EXPECTF--
Fatal error: Uncaught exception 'HeaderMalfunctionException' with message 'malformed key found at 1 "X-HTTP "' in %sexpect_007.php:10
Stack trace:
#0 {main}
thrown in %sexpect_007.php on line 10

View file

@ -0,0 +1,34 @@
--TEST--
test disabled expectations have no ill side effects
--INI--
zend.assertions=0
assert.exception=1
--FILE--
<?php
class One {
public function __construct() {
assert($this || 0);
}
}
class Two extends One {}
class OdEar extends AssertionException {}
function blah(){ return 1; }
$variable = 1;
assert(true, "constant message");
assert(($variable && $variable) || php_sapi_name(), new OdEar("constant message"));
assert(false);
assert(blah(), blah());
new Two();
new Two();
new Two();
assert (blah() || blah() || blah(), blah() || blah() || blah() || blah());
var_dump(true);
?>
--EXPECT--
bool(true)

View file

@ -0,0 +1,26 @@
--TEST--
test stack trace is correct from failed exception in extended class
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
class One {
public function __construct() {
}
}
class Two extends One {
public function __construct() {
assert(false);
}
}
new Two();
?>
--EXPECTF--
Fatal error: Uncaught exception 'AssertionException' with message 'assert(false)' in %sexpect_009.php:%d
Stack trace:
#0 %sexpect_009.php(%d): assert(false, 'assert(false)')
#1 %sexpect_009.php(%d): Two->__construct()
#2 {main}
thrown in %sexpect_009.php on line %d

View file

@ -0,0 +1,23 @@
--TEST--
test stack trace is correct from failed exception in extended class (parent implementing constructor)
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
class One {
public function __construct() {
assert(false);
}
}
class Two extends One {}
new Two();
?>
--EXPECTF--
Fatal error: Uncaught exception 'AssertionException' with message 'assert(false)' in %sexpect_010.php:%d
Stack trace:
#0 %sexpect_010.php(%d): assert(false, 'assert(false)')
#1 %sexpect_010.php(%d): One->__construct()
#2 {main}
thrown in %sexpect_010.php on line %d

View file

@ -0,0 +1,30 @@
--TEST--
test overloaded __toString on custom exception
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
class MyExpectations extends AssertionException {
public function __toString() {
return sprintf(
"[Message]: %s", __CLASS__);
}
}
class One {
public function __construct() {
assert(false, (string) new MyExpectations());
}
}
class Two extends One {}
new Two();
?>
--EXPECTF--
Fatal error: Uncaught exception 'AssertionException' with message '[Message]: MyExpectations' in %sexpect_011.php:%d
Stack trace:
#0 %sexpect_011.php(%d): assert(false, '[Message]: MyEx...')
#1 %sexpect_011.php(%d): One->__construct()
#2 {main}
thrown in %sexpect_011.php on line %d

View file

@ -0,0 +1,21 @@
--TEST--
test enable/disable assertions at runtime
--INI--
zend.assertions=1
assert.exception=1
--FILE--
<?php
var_dump((integer)ini_get("zend.assertions"));
ini_set("zend.assertions", 0);
var_dump((integer)ini_get("zend.assertions"));
assert(false);
ini_set("zend.assertions", 1);
var_dump((integer)ini_get("zend.assertions"));
assert(true);
var_dump(true);
?>
--EXPECT--
int(1)
int(0)
int(1)
bool(true)

View file

@ -0,0 +1,11 @@
--TEST--
test failing assertion when disabled (with return value)
--INI--
zend.assertions=0
assert.exception=1
--FILE--
<?php
var_dump(assert(false));
?>
--EXPECT--
bool(true)

View file

@ -0,0 +1,12 @@
--TEST--
test failing assertion when disabled
--INI--
zend.assertions=0
assert.exception=1
--FILE--
<?php
assert(false);
var_dump(true);
?>
--EXPECT--
bool(true)

View file

@ -101,6 +101,7 @@ static ZEND_INI_MH(OnUpdateScriptEncoding) /* {{{ */
ZEND_INI_BEGIN()
ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting)
STD_ZEND_INI_BOOLEAN("zend.assertions", "1", ZEND_INI_SYSTEM, OnUpdateBool, assertions, zend_executor_globals, executor_globals)
STD_ZEND_INI_BOOLEAN("zend.enable_gc", "1", ZEND_INI_ALL, OnUpdateGCEnabled, gc_enabled, zend_gc_globals, gc_globals)
STD_ZEND_INI_BOOLEAN("zend.multibyte", "0", ZEND_INI_PERDIR, OnUpdateBool, multibyte, zend_compiler_globals, compiler_globals)
ZEND_INI_ENTRY("zend.script_encoding", NULL, ZEND_INI_ALL, OnUpdateScriptEncoding)

View file

@ -1969,6 +1969,22 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
}
lcname = zend_str_tolower_dup(Z_STRVAL(function_name->u.constant), Z_STRLEN(function_name->u.constant));
if (Z_STRLEN(function_name->u.constant) == sizeof("assert")-1 &&
memcmp(lcname, "assert", sizeof("assert")-1) == 0) {
int op_number = get_next_op_number(CG(active_op_array));
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_ASSERT_CHECK;
opline->extended_value = 0;
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
opline->op2.ptr = (void*)LANG_SCNG(yy_text);
function_name->EA = op_number;
}
if ((zend_hash_find(CG(function_table), lcname, Z_STRLEN(function_name->u.constant)+1, (void **) &function)==FAILURE) ||
((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) &&
(function->type == ZEND_INTERNAL_FUNCTION))) {
@ -2538,19 +2554,85 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
}
/* }}} */
static inline void zend_copy_assertion_text(zval *target, const char *start_statement, const char *end_statement TSRMLS_DC) /* {{{ */
{
char *str;
const char *statement = start_statement;
size_t statement_length = end_statement - start_statement;
while (statement && isspace(*statement)) {
statement_length--;
statement++;
}
while (end_statement && isspace(*end_statement)) {
statement_length--;
end_statement--;
}
str = emalloc(sizeof("assert") + statement_length + 1);
memcpy(str, "assert", sizeof("assert") - 1);
memcpy(str + sizeof("assert") - 1, statement, statement_length + 1);
str[sizeof("assert") + statement_length] = 0;
ZVAL_STRINGL(target, str, sizeof("assert") + statement_length, 0);
}
/* }}} */
void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */
{
zend_op *opline;
long arg_num = Z_LVAL(argument_list->u.constant);
if (is_method && function_name && function_name->op_type == IS_UNUSED) {
/* clone */
if (Z_LVAL(argument_list->u.constant) != 0) {
if (arg_num != 0) {
zend_error(E_WARNING, "Clone method does not require arguments");
}
opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)];
} else {
zend_function **function_ptr_ptr;
zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
if (!is_method &&
function_name->op_type==IS_CONST &&
Z_STRLEN(function_name->u.constant) == sizeof("assert")-1 &&
memcmp(Z_STRVAL(function_name->u.constant), "assert", sizeof("assert")-1) == 0) {
int assert_op_number = function_name->EA;
if (arg_num == 1) {
int last_op_number = get_next_op_number(CG(active_op_array));
zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
if (last_op->opcode != ZEND_SEND_VAL ||
last_op->op1_type != IS_CONST ||
Z_TYPE(CONSTANT(last_op->op1.constant)) != IS_STRING) {
zval message;
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_SEND_VAL;
zend_copy_assertion_text(
&message,
(const char*)CG(active_op_array)->opcodes[assert_op_number].op2.ptr,
(const char*)LANG_SCNG(yy_text) TSRMLS_CC);
opline->op1_type = IS_CONST;
opline->op1.constant = zend_add_literal(CG(active_op_array), &message TSRMLS_CC);
CALCULATE_LITERAL_HASH(opline->op1.constant);
opline->op2.opline_num = 2;
opline->extended_value = !is_dynamic_fcall ? ZEND_DO_FCALL : ZEND_DO_FCALL_BY_NAME;
SET_UNUSED(opline->op2);
arg_num = 2;
CG(context).used_stack++;
}
}
CG(active_op_array)->opcodes[assert_op_number].op1.opline_num =
get_next_op_number(CG(active_op_array)) + 1;
CG(active_op_array)->opcodes[assert_op_number].op2.ptr =
NULL;
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
if (*function_ptr_ptr) {
@ -2580,12 +2662,12 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
GET_NODE(result, opline->result);
zend_stack_del_top(&CG(function_call_stack));
opline->extended_value = Z_LVAL(argument_list->u.constant);
opline->extended_value = arg_num;
if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
CG(active_op_array)->used_stack = CG(context).used_stack + 1;
}
CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
CG(context).used_stack -= arg_num;
}
/* }}} */

View file

@ -1299,6 +1299,7 @@ void execute_new_code(TSRMLS_D) /* {{{ */
}
/* break omitted intentionally */
case ZEND_JMP:
case ZEND_ASSERT_CHECK:
opline->op1.jmp_addr = &CG(active_op_array)->opcodes[opline->op1.opline_num];
break;
case ZEND_JMPZ:

View file

@ -256,6 +256,7 @@ struct _zend_executor_globals {
zend_property_info std_property_info;
zend_bool active;
zend_bool assertions;
zend_op *start_op;

View file

@ -699,6 +699,7 @@ ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
}
/* break omitted intentionally */
case ZEND_JMP:
case ZEND_ASSERT_CHECK:
case ZEND_FAST_CALL:
opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
break;

View file

@ -5659,4 +5659,24 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
}
}
ZEND_VM_HANDLER(166, ZEND_ASSERT_CHECK, ANY, ANY)
{
USE_OPLINE
if (!EG(assertions)) {
if (RETURN_VALUE_USED((opline->op1.jmp_addr-1))) {
zval *ret;
MAKE_STD_ZVAL(ret);
Z_SET_REFCOUNT_P(ret, 0);
ZVAL_BOOL(ret, 1);
PZVAL_LOCK(ret);
AI_SET_PTR(&EX_T((opline->op1.jmp_addr-1)->result.var), ret);
}
ZEND_VM_JMP(opline->op1.jmp_addr);
} else {
ZEND_VM_NEXT_OPCODE();
}
}
ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper)

View file

@ -1383,6 +1383,26 @@ static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
}
static int ZEND_FASTCALL ZEND_ASSERT_CHECK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
if (!EG(assertions)) {
if (RETURN_VALUE_USED((opline->op1.jmp_addr-1))) {
zval *ret;
MAKE_STD_ZVAL(ret);
Z_SET_REFCOUNT_P(ret, 0);
ZVAL_BOOL(ret, 1);
PZVAL_LOCK(ret);
AI_SET_PTR(&EX_T((opline->op1.jmp_addr-1)->result.var), ret);
}
ZEND_VM_JMP(opline->op1.jmp_addr);
} else {
ZEND_VM_NEXT_OPCODE();
}
}
static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@ -45078,6 +45098,31 @@ void zend_init_opcodes_handlers(void)
ZEND_SEND_UNPACK_SPEC_HANDLER,
ZEND_SEND_UNPACK_SPEC_HANDLER,
ZEND_SEND_UNPACK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_ASSERT_CHECK_SPEC_HANDLER,
ZEND_NULL_HANDLER
};
zend_opcode_handlers = (opcode_handler_t*)labels;

View file

@ -21,7 +21,7 @@
#include <stdio.h>
#include <zend.h>
const char *zend_vm_opcodes_map[166] = {
const char *zend_vm_opcodes_map[167] = {
"ZEND_NOP",
"ZEND_ADD",
"ZEND_SUB",
@ -188,6 +188,7 @@ const char *zend_vm_opcodes_map[166] = {
"ZEND_FAST_RET",
"ZEND_RECV_VARIADIC",
"ZEND_SEND_UNPACK",
"ZEND_ASSERT_CHECK",
};
ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) {

View file

@ -171,5 +171,6 @@ ZEND_API const char *zend_get_opcode_name(zend_uchar opcode);
#define ZEND_FAST_RET 163
#define ZEND_RECV_VARIADIC 164
#define ZEND_SEND_UNPACK 165
#define ZEND_ASSERT_CHECK 166
#endif

View file

@ -118,6 +118,12 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg)
}
START_BLOCK_OP(opno + 1);
break;
#endif
#ifdef ZEND_ASSERT_CHECK
case ZEND_ASSERT_CHECK:
START_BLOCK_OP(ZEND_OP1(opline).opline_num);
START_BLOCK_OP(opno + 1);
break;
#endif
case ZEND_JMP:
START_BLOCK_OP(ZEND_OP1(opline).opline_num);
@ -268,6 +274,12 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg)
cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
}
break;
#endif
#ifdef ZEND_ASSERT_CHECK
case ZEND_ASSERT_CHECK:
cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];
cur_block->follow_to = &blocks[opno];
break;
#endif
case ZEND_JMP:
cur_block->op1_to = &blocks[ZEND_OP1(opline).opline_num];

View file

@ -57,6 +57,9 @@ static void nop_removal(zend_op_array *op_array)
/* update JMPs */
for (opline = op_array->opcodes; opline<end; opline++) {
switch (opline->opcode) {
#ifdef ZEND_ASSERT_CHECK
case ZEND_ASSERT_CHECK:
#endif
case ZEND_JMP:
#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO
case ZEND_GOTO:

View file

@ -485,6 +485,9 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
case ZEND_FAST_CALL:
case ZEND_FAST_RET:
#endif
#ifdef ZEND_ASSERT_CHECK
case ZEND_ASSERT_CHECK:
#endif
case ZEND_JMP:
case ZEND_JMPZNZ:

View file

@ -474,6 +474,9 @@ static void zend_accel_optimize(zend_op_array *op_array,
}
#endif
switch (opline->opcode) {
#ifdef ZEND_ASSERT_CHECK
case ZEND_ASSERT_CHECK:
#endif
case ZEND_JMP:
#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
case ZEND_GOTO:
@ -515,6 +518,9 @@ static void zend_accel_optimize(zend_op_array *op_array,
}
#endif
switch (opline->opcode) {
#ifdef ZEND_ASSERT_CHECK
case ZEND_ASSERT_CHECK:
#endif
case ZEND_JMP:
#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
case ZEND_GOTO:

View file

@ -345,6 +345,9 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
if (ZEND_DONE_PASS_TWO(op_array)) {
/* fix jumps to point to new array */
switch (opline->opcode) {
#ifdef ZEND_ASSERT_CHECK
case ZEND_ASSERT_CHECK:
#endif
case ZEND_JMP:
case ZEND_GOTO:
#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO

View file

@ -9,12 +9,14 @@ var_dump($standard->getClassNames());
?>
==DONE==
--EXPECTF--
array(3) {
array(4) {
[0]=>
%s(22) "__PHP_Incomplete_Class"
[1]=>
%s(15) "php_user_filter"
[2]=>
%s(9) "Directory"
[3]=>
%s(18) "AssertionException"
}
==DONE==

View file

@ -22,6 +22,7 @@
#include "php.h"
#include "php_assert.h"
#include "php_ini.h"
#include "zend_exceptions.h"
/* }}} */
ZEND_BEGIN_MODULE_GLOBALS(assert)
@ -29,12 +30,15 @@ ZEND_BEGIN_MODULE_GLOBALS(assert)
long bail;
long warning;
long quiet_eval;
long exception;
zval *callback;
char *cb;
ZEND_END_MODULE_GLOBALS(assert)
ZEND_DECLARE_MODULE_GLOBALS(assert)
static zend_class_entry *assertion_exception_ce;
#ifdef ZTS
#define ASSERTG(v) TSRMG(assert_globals_id, zend_assert_globals *, v)
#else
@ -48,7 +52,8 @@ enum {
ASSERT_CALLBACK,
ASSERT_BAIL,
ASSERT_WARNING,
ASSERT_QUIET_EVAL
ASSERT_QUIET_EVAL,
ASSERT_EXCEPTION
};
static PHP_INI_MH(OnChangeCallback) /* {{{ */
@ -84,6 +89,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("assert.warning", "1", PHP_INI_ALL, OnUpdateLong, warning, zend_assert_globals, assert_globals)
PHP_INI_ENTRY("assert.callback", NULL, PHP_INI_ALL, OnChangeCallback)
STD_PHP_INI_ENTRY("assert.quiet_eval", "0", PHP_INI_ALL, OnUpdateLong, quiet_eval, zend_assert_globals, assert_globals)
STD_PHP_INI_ENTRY("assert.exception", "0", PHP_INI_ALL, OnUpdateLong, exception, zend_assert_globals, assert_globals)
PHP_INI_END()
static void php_assert_init_globals(zend_assert_globals *assert_globals_p TSRMLS_DC) /* {{{ */
@ -95,6 +101,8 @@ static void php_assert_init_globals(zend_assert_globals *assert_globals_p TSRMLS
PHP_MINIT_FUNCTION(assert) /* {{{ */
{
zend_class_entry ce;
ZEND_INIT_MODULE_GLOBALS(assert, php_assert_init_globals, NULL);
REGISTER_INI_ENTRIES();
@ -104,6 +112,10 @@ PHP_MINIT_FUNCTION(assert) /* {{{ */
REGISTER_LONG_CONSTANT("ASSERT_BAIL", ASSERT_BAIL, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ASSERT_WARNING", ASSERT_WARNING, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ASSERT_QUIET_EVAL", ASSERT_QUIET_EVAL, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("ASSERT_EXCEPTION", ASSERT_EXCEPTION, CONST_CS|CONST_PERSISTENT);
INIT_CLASS_ENTRY(ce, "AssertionException", NULL);
assertion_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
return SUCCESS;
}
@ -140,24 +152,25 @@ PHP_MINFO_FUNCTION(assert) /* {{{ */
Checks if assertion is false */
PHP_FUNCTION(assert)
{
zval **assertion;
int val, description_len = 0;
zval *assertion;
zval *description = NULL;
int val;
char *myeval = NULL;
char *compiled_string_description, *description = NULL;
char *compiled_string_description;
if (! ASSERTG(active)) {
RETURN_TRUE;
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s", &assertion, &description, &description_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &assertion, &description) == FAILURE) {
return;
}
if (Z_TYPE_PP(assertion) == IS_STRING) {
if (Z_TYPE_P(assertion) == IS_STRING) {
zval retval;
int old_error_reporting = 0; /* shut up gcc! */
myeval = Z_STRVAL_PP(assertion);
myeval = Z_STRVAL_P(assertion);
if (ASSERTG(quiet_eval)) {
old_error_reporting = EG(error_reporting);
@ -165,12 +178,13 @@ PHP_FUNCTION(assert)
}
compiled_string_description = zend_make_compiled_string_description("assert code" TSRMLS_CC);
if (zend_eval_stringl(myeval, Z_STRLEN_PP(assertion), &retval, compiled_string_description TSRMLS_CC) == FAILURE) {
if (zend_eval_stringl(myeval, Z_STRLEN_P(assertion), &retval, compiled_string_description TSRMLS_CC) == FAILURE) {
efree(compiled_string_description);
if (description_len == 0) {
if (!description) {
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Failure evaluating code: %s%s", PHP_EOL, myeval);
} else {
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Failure evaluating code: %s%s:\"%s\"", PHP_EOL, description, myeval);
convert_to_string(description);
php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Failure evaluating code: %s%s:\"%s\"", PHP_EOL, Z_STRVAL_P(description), myeval);
}
if (ASSERTG(bail)) {
zend_bailout();
@ -186,8 +200,11 @@ PHP_FUNCTION(assert)
convert_to_boolean(&retval);
val = Z_LVAL(retval);
} else {
convert_to_boolean_ex(assertion);
val = Z_LVAL_PP(assertion);
#if PHP_VERSION_ID >= 50700
val = zend_is_true(assertion TSRMLS_CC);
#else
val = zend_is_true(assertion);
#endif
}
if (val) {
@ -200,7 +217,7 @@ PHP_FUNCTION(assert)
}
if (ASSERTG(callback)) {
zval **args = safe_emalloc(description_len == 0 ? 3 : 4, sizeof(zval *), 0);
zval **args = safe_emalloc(!description ? 3 : 4, sizeof(zval *), 0);
zval *retval;
int i;
uint lineno = zend_get_executed_lineno(TSRMLS_C);
@ -218,14 +235,15 @@ PHP_FUNCTION(assert)
ZVAL_FALSE(retval);
/* XXX do we want to check for error here? */
if (description_len == 0) {
if (!description) {
call_user_function(CG(function_table), NULL, ASSERTG(callback), retval, 3, args TSRMLS_CC);
for (i = 0; i <= 2; i++) {
zval_ptr_dtor(&(args[i]));
}
} else {
MAKE_STD_ZVAL(args[3]);
ZVAL_STRINGL(args[3], SAFE_STRING(description), description_len, 1);
convert_to_string(description);
Z_ADDREF_P(description);
args[3] = description;
call_user_function(CG(function_table), NULL, ASSERTG(callback), retval, 4, args TSRMLS_CC);
for (i = 0; i <= 3; i++) {
@ -237,18 +255,30 @@ PHP_FUNCTION(assert)
zval_ptr_dtor(&retval);
}
if (ASSERTG(warning)) {
if (description_len == 0) {
if (ASSERTG(exception)) {
if (!description) {
zend_throw_exception(assertion_exception_ce, NULL, E_ERROR TSRMLS_CC);
} else if (Z_TYPE_P(description) == IS_OBJECT &&
instanceof_function(Z_OBJCE_P(description), assertion_exception_ce TSRMLS_CC)) {
Z_ADDREF_P(description);
zend_throw_exception_object(description TSRMLS_CC);
} else {
convert_to_string(description);
zend_throw_exception(assertion_exception_ce, Z_STRVAL_P(description), E_ERROR TSRMLS_CC);
}
} else if (ASSERTG(warning)) {
if (!description) {
if (myeval) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Assertion \"%s\" failed", myeval);
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Assertion failed");
}
} else {
convert_to_string(description);
if (myeval) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: \"%s\" failed", description, myeval);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: \"%s\" failed", Z_STRVAL_P(description), myeval);
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s failed", description);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s failed", Z_STRVAL_P(description));
}
}
}
@ -327,6 +357,15 @@ PHP_FUNCTION(assert_options)
return;
break;
case ASSERT_EXCEPTION:
oldint = ASSERTG(exception);
if (ac == 2) {
convert_to_string_ex(value);
zend_alter_ini_entry_ex("assert.exception", sizeof("assert.exception"), Z_STRVAL_PP(value), Z_STRLEN_PP(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME, 0 TSRMLS_CC);
}
RETURN_LONG(oldint);
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown value %ld", what);
break;

View file

@ -42,7 +42,7 @@ Warning: assert_options() expects at most 2 parameters, 3 given in %s on line %d
Warning: assert_options() expects parameter 1 to be long, %unicode_string_optional% given in %s on line %d
Warning: assert(): Assertion failed in %s on line %d
Warning: assert(): assert(0) failed in %s on line %d
Warning: assert(): Assertion failed in %s on line %d
Warning: assert(): assert(0) failed in %s on line %d

View file

@ -29,9 +29,9 @@ assert(0);
string(2) "f1"
f1 called
Warning: assert(): Assertion failed in %s on line 13
Warning: assert(): assert(0) failed in %s on line 13
string(2) "f1"
string(2) "f2"
f2 called
Warning: assert(): Assertion failed in %s on line 17
Warning: assert(): assert(0) failed in %s on line 17

View file

@ -22,4 +22,4 @@ echo "If this is printed BAIL hasn't worked";
int(0)
f1 called
Warning: assert(): Assertion "0 != 0" failed in %s on line 10
Warning: assert(): assert($sa): "0 != 0" failed in %s on line 10

View file

@ -26,7 +26,7 @@ var_dump($rao=assert_options(ASSERT_WARNING, 0));
int(0)
f1 called
Warning: assert(): Assertion "0 != 0" failed in %s on line 10
Warning: assert(): assert($sa): "0 != 0" failed in %s on line 10
NULL
bool(true)
int(1)

View file

@ -13,4 +13,4 @@ assert(0);
--EXPECTF--
Hello World!
Warning: assert(): Assertion failed in %s on line %d
Warning: assert(): assert(0) failed in %s on line %d

View file

@ -17,8 +17,7 @@ function f1($script, $line, $message, $user_message)
//bail out on error
var_dump($rao = assert_options(ASSERT_BAIL, 1));
$sa = "0 != 0";
var_dump($r2 = assert($sa));
var_dump($r2 = assert("0 != 0"));
echo "If this is printed BAIL hasn't worked";
--EXPECTF--
int(0)
@ -26,5 +25,5 @@ int(0)
Warning: Missing argument 4 for f1() in %s on line 2
f1 called
Warning: assert(): Assertion "0 != 0" failed in %s on line 10
Warning: assert(): Assertion "0 != 0" failed in %s on line 9

View file

@ -10,12 +10,11 @@ error_reporting = -1
display_errors = 1
--FILE--
<?php
$sa = "0 $ 0";
var_dump($r2 = assert($sa));
var_dump($r2 = assert("0 $ 0"));
--EXPECTF--
Parse error: syntax error, unexpected '$' in %s(3) : assert code on line 1
Parse error: syntax error, unexpected '$' in %s(2) : assert code on line 1
Catchable fatal error: assert(): Failure evaluating code:
0 $ 0 in %s on line 3
0 $ 0 in %s on line 2