From d741637b126b482fe1c2459f987ea5c807f1cf28 Mon Sep 17 00:00:00 2001
From: George Peter Banyard
Date: Tue, 29 Dec 2020 02:31:15 +0100
Subject: [PATCH] Fix Bug #80560: Strings containing only a base prefix return
0 object
---
ext/gmp/gmp.c | 6 +-
ext/gmp/tests/bug80560.phpt | 222 ++++++++++++++++++++++++++++++++++++
2 files changed, 225 insertions(+), 3 deletions(-)
create mode 100644 ext/gmp/tests/bug80560.phpt
diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c
index 33ed7fd93fb64..5bccdeca5c357 100644
--- a/ext/gmp/gmp.c
+++ b/ext/gmp/gmp.c
@@ -174,7 +174,7 @@ if (IS_GMP(zval)) { \
gmp_create(return_value, &gmpnumber)
static void gmp_strval(zval *result, mpz_t gmpnum, int base);
-static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
+static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg);
/*
@@ -585,7 +585,7 @@ ZEND_MODULE_INFO_D(gmp)
/* {{{ convert_to_gmp
* Convert zval to be gmp number */
-static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
+static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
{
switch (Z_TYPE_P(val)) {
case IS_LONG:
@@ -596,7 +596,7 @@ static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t a
zend_bool skip_lead = 0;
int ret;
- if (Z_STRLEN_P(val) > 2 && numstr[0] == '0') {
+ if (Z_STRLEN_P(val) >= 2 && numstr[0] == '0') {
if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) {
base = 16;
skip_lead = 1;
diff --git a/ext/gmp/tests/bug80560.phpt b/ext/gmp/tests/bug80560.phpt
new file mode 100644
index 0000000000000..f1bf7dc0d7b7a
--- /dev/null
+++ b/ext/gmp/tests/bug80560.phpt
@@ -0,0 +1,222 @@
+--TEST--
+Bug #80560: Strings containing only a base prefix return 0 object
+--SKIPIF--
+
+--FILE--
+getMessage(), \PHP_EOL;
+}
+try {
+ var_dump(gmp_init('0x', 16));
+} catch (\TypeError $e) {
+ echo $e->getMessage(), \PHP_EOL;
+}
+
+echo 'Binary', \PHP_EOL;
+try {
+ var_dump(gmp_init('0B', 2));
+} catch (\TypeError $e) {
+ echo $e->getMessage(), \PHP_EOL;
+}
+try {
+ var_dump(gmp_init('0b', 2));
+} catch (\TypeError $e) {
+ echo $e->getMessage(), \PHP_EOL;
+}
+
+echo 'Fuzzing gmp functions:', \PHP_EOL;
+foreach ($functions1 as $function) {
+ try {
+ $function('0B');
+ echo $function, ' failed with 0B', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0b');
+ echo $function, ' failed with 0b', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0X');
+ echo $function, ' failed with 0X', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0x');
+ echo $function, ' failed with 0x', \PHP_EOL;
+ } catch (\TypeError) { }
+}
+foreach ($functions1_need_int_2 as $function) {
+ try {
+ $function('0B', 1);
+ echo $function, ' failed with 0B', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0b', 1);
+ echo $function, ' failed with 0b', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0X', 1);
+ echo $function, ' failed with 0X', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0x', 1);
+ echo $function, ' failed with 0x', \PHP_EOL;
+ } catch (\TypeError) { }
+}
+foreach ($functions2 as $function) {
+ try {
+ $function('0B', 1);
+ echo $function, ' arg 1 failed with 0B', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0b', 1);
+ echo $function, ' arg 1 failed with 0b', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0X', 1);
+ echo $function, ' arg 1 failed with 0X', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0x', 1);
+ echo $function, ' arg 1 failed with 0x', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0B');
+ echo $function, ' arg 2 failed with 0B', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0b');
+ echo $function, ' arg 2 failed with 0b', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0X');
+ echo $function, ' arg 2 failed with 0X', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0x');
+ echo $function, ' arg 2 failed with 0x', \PHP_EOL;
+ } catch (\TypeError) { }
+}
+foreach ($functions3 as $function) {
+ try {
+ $function('0B', 1, 1);
+ echo $function, ' arg 1 failed with 0B', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0b', 1, 1);
+ echo $function, ' arg 1 failed with 0b', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0X', 1, 1);
+ echo $function, ' arg 1 failed with 0X', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function('0x', 1, 1);
+ echo $function, ' arg 1 failed with 0x', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0B', 1);
+ echo $function, ' arg 2 failed with 0B', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0b', 1);
+ echo $function, ' arg 2 failed with 0b', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0X', 1);
+ echo $function, ' arg 2 failed with 0X', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, '0x', 1);
+ echo $function, ' arg 2 failed with 0x', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, 1, '0B');
+ echo $function, ' arg 3 failed with 0B', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, 1, '0b');
+ echo $function, ' arg 3 failed with 0b', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, 1, '0X');
+ echo $function, ' arg 3 failed with 0X', \PHP_EOL;
+ } catch (\TypeError) { }
+ try {
+ $function(1, 1, '0x');
+ echo $function, ' arg 3 failed with 0x', \PHP_EOL;
+ } catch (\TypeError) { }
+}
+
+echo "Done\n";
+?>
+--EXPECT--
+Explicit base with gmp_init:
+Hexadecimal
+gmp_init(): Argument #1 ($num) is not an integer string
+gmp_init(): Argument #1 ($num) is not an integer string
+Binary
+gmp_init(): Argument #1 ($num) is not an integer string
+gmp_init(): Argument #1 ($num) is not an integer string
+Fuzzing gmp functions:
+Done