Skip to content

Commit 861caf5

Browse files
committed
ext/gmp: Throw TypeError for unusable types for <<, >>, and ** ops
1 parent 64b2b18 commit 861caf5

6 files changed

+68
-83
lines changed

ext/gmp/gmp.c

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -334,25 +334,70 @@ static zend_object *gmp_clone_obj(zend_object *obj) /* {{{ */
334334
}
335335
/* }}} */
336336

337-
static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2, zend_uchar opcode) {
338-
zend_long shift = zval_get_long(op2);
337+
static zend_result shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2, zend_uchar opcode) {
338+
zend_long shift = 0;
339+
340+
if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
341+
if (UNEXPECTED(!IS_GMP(op2))) {
342+
goto typeof_op_failure;
343+
} else {
344+
// TODO We shouldn't cast the GMP object to int here
345+
shift = zval_get_long(op2);
346+
}
347+
} else {
348+
shift = Z_LVAL_P(op2);
349+
}
339350

340351
if (shift < 0) {
341352
zend_throw_error(
342353
zend_ce_value_error, "%s must be greater than or equal to 0",
343354
opcode == ZEND_POW ? "Exponent" : "Shift"
344355
);
345356
ZVAL_UNDEF(return_value);
346-
return;
357+
return FAILURE;
347358
} else {
348359
mpz_ptr gmpnum_op, gmpnum_result;
349360
gmp_temp_t temp;
350361

351-
FETCH_GMP_ZVAL(gmpnum_op, op1, temp, 1);
362+
/* Inline FETCH_GMP_ZVAL(gmpnum_op, op1, temp, 1); as cannot use RETURN_THROWS() */
363+
if (UNEXPECTED(!IS_GMP(op1))) {
364+
if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
365+
goto typeof_op_failure;
366+
}
367+
mpz_init(temp.num);
368+
mpz_set_si(temp.num, Z_LVAL_P(op1));
369+
temp.is_used = 1;
370+
gmpnum_op = temp.num;
371+
} else {
372+
gmpnum_op = GET_GMP_FROM_ZVAL(op1);
373+
temp.is_used = 0;
374+
}
352375
INIT_GMP_RETVAL(gmpnum_result);
353376
op(gmpnum_result, gmpnum_op, (gmp_ulong) shift);
354377
FREE_GMP_TEMP(temp);
378+
return SUCCESS;
355379
}
380+
381+
typeof_op_failure:
382+
/* Returning FAILURE without throwing an exception would emit the
383+
* Unsupported operand types: GMP OP TypeOfOp2
384+
* However, this leads to the engine trying to interpret the GMP object as an integer
385+
* and doing the operation that way, which is not something we want. */
386+
const char *op_sigil;
387+
switch (opcode) {
388+
case ZEND_POW:
389+
op_sigil = "**";
390+
break;
391+
case ZEND_SL:
392+
op_sigil = "<<";
393+
break;
394+
case ZEND_SR:
395+
op_sigil = ">>";
396+
break;
397+
EMPTY_SWITCH_DEFAULT_CASE();
398+
}
399+
zend_type_error("Unsupported operand types: %s %s %s", zend_zval_type_name(op1), op_sigil, zend_zval_type_name(op2));
400+
return FAILURE;
356401
}
357402

358403
#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
@@ -381,18 +426,15 @@ static zend_result gmp_do_operation_ex(zend_uchar opcode, zval *result, zval *op
381426
case ZEND_MUL:
382427
DO_BINARY_UI_OP(mpz_mul);
383428
case ZEND_POW:
384-
shift_operator_helper(mpz_pow_ui, result, op1, op2, opcode);
385-
return SUCCESS;
429+
return shift_operator_helper(mpz_pow_ui, result, op1, op2, opcode);
386430
case ZEND_DIV:
387431
DO_BINARY_UI_OP_EX(mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1);
388432
case ZEND_MOD:
389433
DO_BINARY_UI_OP_EX(mpz_mod, gmp_mpz_mod_ui, 1);
390434
case ZEND_SL:
391-
shift_operator_helper(mpz_mul_2exp, result, op1, op2, opcode);
392-
return SUCCESS;
435+
return shift_operator_helper(mpz_mul_2exp, result, op1, op2, opcode);
393436
case ZEND_SR:
394-
shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2, opcode);
395-
return SUCCESS;
437+
return shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2, opcode);
396438
case ZEND_BW_OR:
397439
DO_BINARY_OP(mpz_ior);
398440
case ZEND_BW_AND:

ext/gmp/tests/overloading_with_array.phpt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,9 @@ TypeError: Number must be of type GMP|string|int, array given
7676
TypeError: Number must be of type GMP|string|int, array given
7777
TypeError: Number must be of type GMP|string|int, array given
7878
TypeError: Number must be of type GMP|string|int, array given
79-
object(GMP)#3 (1) {
80-
["num"]=>
81-
string(1) "1"
82-
}
79+
TypeError: Unsupported operand types: GMP ** array
8380
TypeError: Number must be of type GMP|string|int, array given
8481
TypeError: Number must be of type GMP|string|int, array given
8582
TypeError: Number must be of type GMP|string|int, array given
86-
object(GMP)#2 (1) {
87-
["num"]=>
88-
string(2) "42"
89-
}
90-
object(GMP)#2 (1) {
91-
["num"]=>
92-
string(2) "42"
93-
}
83+
TypeError: Unsupported operand types: GMP << array
84+
TypeError: Unsupported operand types: GMP >> array

ext/gmp/tests/overloading_with_null.phpt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,9 @@ TypeError: Number must be of type GMP|string|int, null given
7676
TypeError: Number must be of type GMP|string|int, null given
7777
TypeError: Number must be of type GMP|string|int, null given
7878
TypeError: Number must be of type GMP|string|int, null given
79-
object(GMP)#3 (1) {
80-
["num"]=>
81-
string(1) "1"
82-
}
79+
TypeError: Unsupported operand types: GMP ** null
8380
TypeError: Number must be of type GMP|string|int, null given
8481
TypeError: Number must be of type GMP|string|int, null given
8582
TypeError: Number must be of type GMP|string|int, null given
86-
object(GMP)#2 (1) {
87-
["num"]=>
88-
string(2) "42"
89-
}
90-
object(GMP)#2 (1) {
91-
["num"]=>
92-
string(2) "42"
93-
}
83+
TypeError: Unsupported operand types: GMP << null
84+
TypeError: Unsupported operand types: GMP >> null

ext/gmp/tests/overloading_with_object_not_stringable.phpt

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -71,30 +71,15 @@ try {
7171
}
7272

7373
?>
74-
--EXPECTF--
74+
--EXPECT--
7575
TypeError: Number must be of type GMP|string|int, stdClass given
7676
TypeError: Number must be of type GMP|string|int, stdClass given
7777
TypeError: Number must be of type GMP|string|int, stdClass given
7878
TypeError: Number must be of type GMP|string|int, stdClass given
7979
TypeError: Number must be of type GMP|string|int, stdClass given
80-
81-
Warning: Object of class stdClass could not be converted to int in %s on line %d
82-
object(GMP)#4 (1) {
83-
["num"]=>
84-
string(2) "42"
85-
}
80+
TypeError: Unsupported operand types: GMP ** stdClass
8681
TypeError: Number must be of type GMP|string|int, stdClass given
8782
TypeError: Number must be of type GMP|string|int, stdClass given
8883
TypeError: Number must be of type GMP|string|int, stdClass given
89-
90-
Warning: Object of class stdClass could not be converted to int in %s on line %d
91-
object(GMP)#3 (1) {
92-
["num"]=>
93-
string(2) "84"
94-
}
95-
96-
Warning: Object of class stdClass could not be converted to int in %s on line %d
97-
object(GMP)#3 (1) {
98-
["num"]=>
99-
string(2) "21"
100-
}
84+
TypeError: Unsupported operand types: GMP << stdClass
85+
TypeError: Unsupported operand types: GMP >> stdClass

ext/gmp/tests/overloading_with_object_stringable.phpt

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -83,24 +83,9 @@ TypeError: Number must be of type GMP|string|int, T given
8383
TypeError: Number must be of type GMP|string|int, T given
8484
TypeError: Number must be of type GMP|string|int, T given
8585
TypeError: Number must be of type GMP|string|int, T given
86-
87-
Warning: Object of class T could not be converted to int in %s on line %d
88-
object(GMP)#4 (1) {
89-
["num"]=>
90-
string(2) "42"
91-
}
86+
TypeError: Unsupported operand types: GMP ** T
9287
TypeError: Number must be of type GMP|string|int, T given
9388
TypeError: Number must be of type GMP|string|int, T given
9489
TypeError: Number must be of type GMP|string|int, T given
95-
96-
Warning: Object of class T could not be converted to int in %s on line %d
97-
object(GMP)#3 (1) {
98-
["num"]=>
99-
string(2) "84"
100-
}
101-
102-
Warning: Object of class T could not be converted to int in %s on line %d
103-
object(GMP)#3 (1) {
104-
["num"]=>
105-
string(2) "21"
106-
}
90+
TypeError: Unsupported operand types: GMP << T
91+
TypeError: Unsupported operand types: GMP >> T

ext/gmp/tests/overloading_with_resource.phpt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,9 @@ TypeError: Number must be of type GMP|string|int, resource given
7676
TypeError: Number must be of type GMP|string|int, resource given
7777
TypeError: Number must be of type GMP|string|int, resource given
7878
TypeError: Number must be of type GMP|string|int, resource given
79-
object(GMP)#3 (1) {
80-
["num"]=>
81-
string(5) "74088"
82-
}
79+
TypeError: Unsupported operand types: GMP ** resource
8380
TypeError: Number must be of type GMP|string|int, resource given
8481
TypeError: Number must be of type GMP|string|int, resource given
8582
TypeError: Number must be of type GMP|string|int, resource given
86-
object(GMP)#2 (1) {
87-
["num"]=>
88-
string(3) "336"
89-
}
90-
object(GMP)#2 (1) {
91-
["num"]=>
92-
string(1) "5"
93-
}
83+
TypeError: Unsupported operand types: GMP << resource
84+
TypeError: Unsupported operand types: GMP >> resource

0 commit comments

Comments
 (0)