summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/gmp/bug67917.phpt17
-rw-r--r--ext/gmp/gmp.c22
2 files changed, 38 insertions, 1 deletions
diff --git a/ext/gmp/bug67917.phpt b/ext/gmp/bug67917.phpt
new file mode 100644
index 0000000000..93d46cbb66
--- /dev/null
+++ b/ext/gmp/bug67917.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Bug #67917: Using GMP objects with overloaded operators can cause memory exhaustion
+--FILE--
+<?php
+
+$mem1 = memory_get_usage();
+for ($i = 0; $i < 1000; $i++) {
+ $gmp = gmp_init(42);
+ $gmp <<= 1;
+}
+$mem2 = memory_get_usage();
+
+var_dump($mem2 - $mem1 < 100000);
+
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c
index cd50896cc7..486088bbaf 100644
--- a/ext/gmp/gmp.c
+++ b/ext/gmp/gmp.c
@@ -523,7 +523,7 @@ static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zva
gmp_zval_unary_op(result, op1, op TSRMLS_CC); \
return SUCCESS;
-static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
+static int gmp_do_operation_ex(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
switch (opcode) {
case ZEND_ADD:
@@ -560,6 +560,26 @@ static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op
}
/* }}} */
+static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
+{
+ zval op1_copy;
+ int retval;
+
+ if (result == op1) {
+ ZVAL_COPY_VALUE(&op1_copy, op1);
+ op1 = &op1_copy;
+ }
+
+ retval = gmp_do_operation_ex(opcode, result, op1, op2 TSRMLS_CC);
+
+ if (retval == SUCCESS && op1 == &op1_copy) {
+ zval_dtor(op1);
+ }
+
+ return retval;
+}
+/* }}} */
+
static int gmp_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
{
gmp_cmp(result, op1, op2 TSRMLS_CC);