Skip to content

Commit 336e6e2

Browse files
committed
Add regression test for broken non commutative multiplication
1 parent 50bd8ba commit 336e6e2

File tree

4 files changed

+169
-1
lines changed

4 files changed

+169
-1
lines changed

ext/zend_test/test.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,73 @@ static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic)
611611
zend_forbid_dynamic_call();
612612
}
613613

614+
// TODO HERE
615+
/* ncm refers to non commutative multiplication */
616+
static zend_class_entry *ncm_ce;
617+
static zend_object_handlers ncm_object_handlers;
618+
619+
static zend_object* ncm_object_create_ex(zend_class_entry* ce, zend_long l) {
620+
zend_object *obj = zend_objects_new(ce);
621+
object_properties_init(obj, ce);
622+
obj->handlers = &ncm_object_handlers;
623+
ZVAL_LONG(OBJ_PROP_NUM(obj, 0), l);
624+
return obj;
625+
}
626+
static zend_object *ncm_object_create(zend_class_entry *ce) /* {{{ */
627+
{
628+
return ncm_object_create_ex(ce, 0);
629+
}
630+
/* }}} */
631+
632+
static inline void ncm_create(zval *target, zend_long l) /* {{{ */
633+
{
634+
ZVAL_OBJ(target, ncm_object_create_ex(ncm_ce, l));
635+
}
636+
637+
#define IS_NCM(zval) \
638+
(Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), ncm_ce))
639+
640+
static void ncm_subtraction(zval *result, zval *op1, zval *op2)
641+
{
642+
zend_long val_1;
643+
zend_long val_2;
644+
if (IS_NCM(op1)) {
645+
val_1 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op1), 0));
646+
} else {
647+
val_1 = zval_get_long(op1);
648+
}
649+
if (IS_NCM(op2)) {
650+
val_2 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op2), 0));
651+
} else {
652+
val_2 = zval_get_long(op2);
653+
}
654+
655+
ncm_create(result, val_1 - val_2);
656+
}
657+
658+
static zend_result ncm_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2)
659+
{
660+
switch (opcode) {
661+
case ZEND_MUL:
662+
ncm_subtraction(result, op1, op2);
663+
if (UNEXPECTED(EG(exception))) { return FAILURE; }
664+
return SUCCESS;
665+
default:
666+
return FAILURE;
667+
}
668+
}
669+
670+
PHP_METHOD(NonCommutativeMultiplication, __construct)
671+
{
672+
zend_long l;
673+
674+
ZEND_PARSE_PARAMETERS_START(1, 1)
675+
Z_PARAM_LONG(l)
676+
ZEND_PARSE_PARAMETERS_END();
677+
678+
ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), l);
679+
}
680+
614681
PHP_INI_BEGIN()
615682
STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
616683
STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals)
@@ -713,6 +780,12 @@ PHP_MINIT_FUNCTION(zend_test)
713780
zend_test_string_enum = register_class_ZendTestStringEnum();
714781
zend_test_int_enum = register_class_ZendTestIntEnum();
715782

783+
/* Non commutative multiplication class */
784+
ncm_ce = register_class_NonCommutativeMultiplication();
785+
ncm_ce->create_object = ncm_object_create;
786+
memcpy(&ncm_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
787+
ncm_object_handlers.do_operation = ncm_do_operation;
788+
716789
zend_register_functions(NULL, ext_function_legacy, NULL, EG(current_module)->type);
717790

718791
// Loading via dl() not supported with the observer API

ext/zend_test/test.stub.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ enum ZendTestIntEnum: int {
9898
case Baz = -1;
9999
}
100100

101+
final class NonCommutativeMultiplication {
102+
private int $val;
103+
104+
public function __construct(int $val) {}
105+
}
106+
101107
function zend_test_array_return(): array {}
102108

103109
function zend_test_nullable_array_return(): ?array {}

ext/zend_test/test_arginfo.h

Lines changed: 29 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
--TEST--
2+
Zend: test non commutative multiplication object handler
3+
--EXTENSIONS--
4+
zend_test
5+
--XFAIL--
6+
Broken non commutative multiplication with more than 2 ops
7+
--FILE--
8+
<?php
9+
10+
$ten = new NonCommutativeMultiplication(10);
11+
$fifty = new NonCommutativeMultiplication(50);
12+
$hundred = new NonCommutativeMultiplication(100);
13+
14+
var_dump($ten);
15+
var_dump($fifty);
16+
var_dump($hundred);
17+
18+
/* $hundred * 20 gives a new NCM object, thus final result is 30 = ((100 - 20) - 50) */
19+
var_dump($hundred * 20 * 50);
20+
/* Multiplication corresponds to subtraction for this object */
21+
var_dump(100 - 50 - 10);
22+
var_dump($hundred * $fifty * $ten);
23+
var_dump(10 - 50 - 100);
24+
var_dump($ten * $fifty * $hundred);
25+
var_dump(50 - 100 - 10);
26+
var_dump($fifty * $hundred * $ten);
27+
28+
29+
?>
30+
--EXPECT--
31+
object(NonCommutativeMultiplication)#1 (1) {
32+
["val":"NonCommutativeMultiplication":private]=>
33+
int(10)
34+
}
35+
object(NonCommutativeMultiplication)#2 (1) {
36+
["val":"NonCommutativeMultiplication":private]=>
37+
int(50)
38+
}
39+
object(NonCommutativeMultiplication)#3 (1) {
40+
["val":"NonCommutativeMultiplication":private]=>
41+
int(100)
42+
}
43+
object(NonCommutativeMultiplication)#5 (1) {
44+
["val":"NonCommutativeMultiplication":private]=>
45+
int(30)
46+
}
47+
int(40)
48+
object(NonCommutativeMultiplication)#4 (1) {
49+
["val":"NonCommutativeMultiplication":private]=>
50+
int(40)
51+
}
52+
int(-140)
53+
object(NonCommutativeMultiplication)#5 (1) {
54+
["val":"NonCommutativeMultiplication":private]=>
55+
int(-140)
56+
}
57+
int(-60)
58+
object(NonCommutativeMultiplication)#4 (1) {
59+
["val":"NonCommutativeMultiplication":private]=>
60+
int(-60)
61+
}

0 commit comments

Comments
 (0)