Skip to content

Commit b1e0162

Browse files
committed
Fix signum of NAN and int conversion of specials
1 parent 4eaf2c3 commit b1e0162

File tree

4 files changed

+67
-14
lines changed

4 files changed

+67
-14
lines changed

php_decimal.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,22 @@ static void php_decimal_integer_overflow()
211211
zend_throw_exception(spl_ce_OverflowException, "Integer overflow", 0);
212212
}
213213

214+
/**
215+
* Called when NaN or Inf is converted to integer.
216+
*/
217+
void php_decimal_integer_from_special_is_not_defined()
218+
{
219+
zend_throw_exception(spl_ce_RuntimeException, "Converting NaN or Inf to integer is not defined", 0);
220+
}
221+
222+
/**
223+
* Called when attempting to query the signum of NaN.
224+
*/
225+
void php_decimal_sign_of_nan_is_not_defined()
226+
{
227+
zend_throw_exception(spl_ce_RuntimeException, "Sign of NaN is not defined", 0);
228+
}
229+
214230
/**
215231
* Called when __construct is called directly on a decimal object.
216232
*/
@@ -777,8 +793,9 @@ static zend_long php_decimal_to_long(php_decimal_t *obj)
777793
uint32_t status = 0;
778794
zend_long result = 0;
779795

780-
/* This matches PHP's behaviour. */
796+
/* PHP converts to zero but that does not make sense and could hide bugs. */
781797
if (UNEXPECTED(mpd_isspecial(mpd))) {
798+
php_decimal_integer_from_special_is_not_defined();
782799
return 0;
783800
}
784801

@@ -883,6 +900,16 @@ static zend_string *php_decimal_format(php_decimal_t *obj, zend_long places, zen
883900
/* OPERATIONS */
884901
/******************************************************************************/
885902

903+
static int php_decimal_signum(const mpd_t *mpd)
904+
{
905+
if (UNEXPECTED(mpd_isnan(mpd))) {
906+
php_decimal_sign_of_nan_is_not_defined();
907+
return 0;
908+
}
909+
910+
return mpd_iszero(mpd) ? 0 : mpd_arith_sign(mpd);
911+
}
912+
886913
/**
887914
* Sets the result of res to op1 + op2, using the precision of res.
888915
*
@@ -2086,7 +2113,7 @@ PHP_DECIMAL_ARGINFO_END()
20862113
PHP_DECIMAL_METHOD(signum)
20872114
{
20882115
PHP_DECIMAL_PARAMS_PARSE_NONE();
2089-
RETURN_LONG(mpd_iszero(THIS_MPD()) ? 0 : mpd_arith_sign(THIS_MPD()));
2116+
RETURN_LONG(php_decimal_signum(THIS_MPD()));
20902117
}
20912118

20922119
/**

tests/cast.phpt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ $tests = [
5050
[(int) decimal(PHP_INT_MAX), PHP_INT_MAX],
5151
[(int) decimal(PHP_INT_MIN), PHP_INT_MIN],
5252

53-
[(int) decimal( NAN), 0],
54-
[(int) decimal( INF), 0],
55-
[(int) decimal(-INF), 0],
56-
5753
/**
5854
* FLOAT
5955
*/
@@ -92,23 +88,44 @@ foreach ($tests as $test) {
9288
try {
9389
(int) decimal("1E+1000");
9490
} catch (OverflowException $e) {
95-
printf("%s\n", $e->getMessage());
91+
printf("A %s\n", $e->getMessage());
9692
}
9793

9894
try {
9995
(float) decimal("1E-1000");
10096
} catch (UnderflowException $e) {
101-
printf("%s\n", $e->getMessage());
97+
printf("B %s\n", $e->getMessage());
10298
}
10399

104100
try {
105101
(float) decimal("-1E-1000");
106102
} catch (UnderflowException $e) {
107-
printf("%s\n", $e->getMessage());
103+
printf("C %s\n", $e->getMessage());
104+
}
105+
106+
try {
107+
(int) decimal(NAN);
108+
} catch (RuntimeException $e) {
109+
printf("D %s\n", $e->getMessage());
110+
}
111+
112+
try {
113+
(int) decimal(INF);
114+
} catch (RuntimeException $e) {
115+
printf("E %s\n", $e->getMessage());
116+
}
117+
118+
try {
119+
(int) decimal(-INF);
120+
} catch (RuntimeException $e) {
121+
printf("F %s\n", $e->getMessage());
108122
}
109123

110124
?>
111125
--EXPECT--
112-
Integer overflow
113-
Floating point underflow
114-
Floating point underflow
126+
A Integer overflow
127+
B Floating point underflow
128+
C Floating point underflow
129+
D Converting NaN or Inf to integer is not defined
130+
E Converting NaN or Inf to integer is not defined
131+
F Converting NaN or Inf to integer is not defined

tests/methods/signum.phpt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ var_dump(decimal("1234.5678E-9")->signum());
2323
var_dump(decimal("-1234.5678E+9")->signum());
2424
var_dump(decimal("-1234.5678E-9")->signum());
2525

26-
var_dump(decimal( "NAN")->signum());
2726
var_dump(decimal( "INF")->signum());
2827
var_dump(decimal("-INF")->signum());
28+
29+
try {
30+
decimal("NAN")->signum();
31+
} catch (RuntimeException $e) {
32+
printf("%s\n", $e->getMessage());
33+
}
34+
2935
?>
3036
--EXPECT--
3137
int(0)
@@ -36,5 +42,5 @@ int(1)
3642
int(-1)
3743
int(-1)
3844
int(1)
39-
int(1)
4045
int(-1)
46+
Sign of NaN is not defined

tests/methods/toInt.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ if ((string) $number !== "2.5") {
7272

7373
?>
7474
--EXPECT--
75+
RuntimeException: Converting NaN or Inf to integer is not defined
76+
RuntimeException: Converting NaN or Inf to integer is not defined
77+
RuntimeException: Converting NaN or Inf to integer is not defined
7578
OverflowException: Integer overflow
7679
TypeError: Decimal\Decimal::__construct() expected parameter 1 to be a string, integer, or decimal, float given
7780
TypeError: Decimal\Decimal::__construct() expected parameter 1 to be a string, integer, or decimal, float given

0 commit comments

Comments
 (0)