@@ -106,6 +106,69 @@ PHP_GMP_API zend_class_entry *php_gmp_class_entry(void) {
106
106
#define GET_GMP_FROM_ZVAL (zval ) \
107
107
GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num
108
108
109
+ #define GMP_SI_MAX (GMP_NUMB_MAX >> 1)
110
+ #define GMP_SI_MIN (-(1LL << (GMP_NUMB_BITS - 1)))
111
+ #if GMP_NUMB_BITS < SIZEOF_ZEND_LONG * 8
112
+ void gmp_set_zlong (mpz_t z , zend_long zlong ) {
113
+ if (zlong <= GMP_SI_MAX && zlong >= GMP_SI_MIN ) {
114
+ mpz_set_si (z , zlong );
115
+ } else if (zlong >= 0 ) {
116
+ mpz_import (z , 1 , 1 , sizeof (zend_long ), 0 , 0 , & zlong );
117
+ } else {
118
+ mpz_import (z , 1 , 1 , sizeof (zend_long ), 0 , 0 , & zlong );
119
+ mpz_neg (z , z );
120
+ }
121
+ }
122
+
123
+ int gmp_fits_zlong_p (mpz_t z ) {
124
+ int result = 1 ;
125
+ mpz_t z_min_max ;
126
+ zend_long min_max ;
127
+
128
+ if (mpz_cmp_si (z , GMP_SI_MAX ) > 0 ) {
129
+ min_max = ZEND_LONG_MAX ;
130
+ mpz_init (z_min_max );
131
+ mpz_import (z_min_max , 1 , 1 , sizeof (zend_long ), 0 , 0 , & min_max );
132
+ result = mpz_cmp (z , z_min_max ) <= 0 ;
133
+ mpz_clear (z_min_max );
134
+ } else if (mpz_cmp_si (z , GMP_SI_MIN ) < 0 ) {
135
+ min_max = ZEND_LONG_MIN ;
136
+ mpz_init (z_min_max );
137
+ mpz_import (z_min_max , 1 , 1 , sizeof (zend_long ), 0 , 0 , & min_max );
138
+ mpz_neg (z_min_max , z_min_max );
139
+ result = mpz_cmp (z , z_min_max ) >= 0 ;
140
+ mpz_clear (z_min_max );
141
+ }
142
+
143
+ return result ;
144
+ }
145
+
146
+ zend_long gmp_get_zlong (mpz_t z ) {
147
+ zend_long result ;
148
+ zend_long mask = -1 ;
149
+ mpz_t z_tmp ;
150
+ mpz_t z_mask ;
151
+
152
+ if (mpz_cmp_si (z , GMP_SI_MAX ) > 0 || mpz_cmp_si (z , GMP_SI_MIN ) < 0 ) {
153
+ mpz_init (z_tmp );
154
+ mpz_init (z_mask );
155
+ mpz_import (z_mask , 1 , 1 , sizeof (zend_long ), 0 , 0 , & mask );
156
+ mpz_and (z_tmp , z , z_mask );
157
+ mpz_export (& result , NULL , 0 , sizeof (zend_long ), 0 , 0 , z_tmp );
158
+ mpz_clear (z_mask );
159
+ mpz_clear (z_tmp );
160
+ } else {
161
+ result = mpz_get_si (z );
162
+ }
163
+
164
+ return result ;
165
+ }
166
+ #else
167
+ # define gmp_set_zlong (z , l ) mpz_set_si(z, l)
168
+ # define gmp_fits_zlong_p (z ) mpz_fits_si_p(z)
169
+ # define gmp_get_zlong (z ) mpz_get_si(z)
170
+ #endif
171
+
109
172
static void gmp_strval (zval * result , mpz_t gmpnum , int base );
110
173
static zend_result convert_zstr_to_gmp (mpz_t gmp_number , const zend_string * val , zend_long base , uint32_t arg_pos );
111
174
@@ -129,7 +192,7 @@ static bool gmp_zend_parse_arg_into_mpz_ex(
129
192
}
130
193
131
194
if (Z_TYPE_P (arg ) == IS_LONG ) {
132
- mpz_set_si (* destination_mpz_ptr , Z_LVAL_P (arg ));
195
+ gmp_set_zlong (* destination_mpz_ptr , Z_LVAL_P (arg ));
133
196
return true;
134
197
}
135
198
@@ -145,7 +208,7 @@ static bool gmp_zend_parse_arg_into_mpz_ex(
145
208
return false;
146
209
}
147
210
148
- mpz_set_si (* destination_mpz_ptr , lval );
211
+ gmp_set_zlong (* destination_mpz_ptr , lval );
149
212
150
213
return true;
151
214
}
@@ -243,16 +306,16 @@ static zend_result gmp_cast_object(zend_object *readobj, zval *writeobj, int typ
243
306
return SUCCESS ;
244
307
case IS_LONG :
245
308
gmpnum = GET_GMP_OBJECT_FROM_OBJ (readobj )-> num ;
246
- ZVAL_LONG (writeobj , mpz_get_si (gmpnum ));
309
+ ZVAL_LONG (writeobj , gmp_get_zlong (gmpnum ));
247
310
return SUCCESS ;
248
311
case IS_DOUBLE :
249
312
gmpnum = GET_GMP_OBJECT_FROM_OBJ (readobj )-> num ;
250
313
ZVAL_DOUBLE (writeobj , mpz_get_d (gmpnum ));
251
314
return SUCCESS ;
252
315
case _IS_NUMBER :
253
316
gmpnum = GET_GMP_OBJECT_FROM_OBJ (readobj )-> num ;
254
- if (mpz_fits_si_p (gmpnum )) {
255
- ZVAL_LONG (writeobj , mpz_get_si (gmpnum ));
317
+ if (gmp_fits_zlong_p (gmpnum )) {
318
+ ZVAL_LONG (writeobj , gmp_get_zlong (gmpnum ));
256
319
} else {
257
320
ZVAL_DOUBLE (writeobj , mpz_get_d (gmpnum ));
258
321
}
@@ -712,7 +775,7 @@ static zend_result gmp_initialize_number(mpz_ptr gmp_number, const zend_string *
712
775
return convert_zstr_to_gmp (gmp_number , arg_str , base , 1 );
713
776
}
714
777
715
- mpz_set_si (gmp_number , arg_l );
778
+ gmp_set_zlong (gmp_number , arg_l );
716
779
return SUCCESS ;
717
780
}
718
781
@@ -862,7 +925,7 @@ ZEND_FUNCTION(gmp_intval)
862
925
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum )
863
926
ZEND_PARSE_PARAMETERS_END ();
864
927
865
- RETVAL_LONG (mpz_get_si (gmpnum ));
928
+ RETVAL_LONG (gmp_get_zlong (gmpnum ));
866
929
}
867
930
/* }}} */
868
931
@@ -1526,8 +1589,13 @@ ZEND_FUNCTION(gmp_random_range)
1526
1589
}
1527
1590
/* }}} */
1528
1591
1592
+ #if SIZEOF_SIZE_T >= SIZEOF_ZEND_LONG
1593
+ # define GMP_SAFE_BITINDEX_MAX ((mp_bitcnt_t)INT_MAX * GMP_NUMB_BITS)
1594
+ #else
1595
+ # define GMP_SAFE_BITINDEX_MAX ((mp_bitcnt_t)INT_MAX * GMP_NUMB_BITS - 1)
1596
+ #endif
1529
1597
static bool gmp_is_bit_index_valid (zend_long index ) {
1530
- return index >= 0 && (index / GMP_NUMB_BITS < INT_MAX ) ;
1598
+ return index >= 0 && (zend_ulong ) index <= GMP_SAFE_BITINDEX_MAX ;
1531
1599
}
1532
1600
1533
1601
/* {{{ Sets or clear bit in a */
@@ -1543,7 +1611,7 @@ ZEND_FUNCTION(gmp_setbit)
1543
1611
}
1544
1612
1545
1613
if (!gmp_is_bit_index_valid (index )) {
1546
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1614
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1547
1615
RETURN_THROWS ();
1548
1616
}
1549
1617
@@ -1569,7 +1637,7 @@ ZEND_FUNCTION(gmp_clrbit)
1569
1637
}
1570
1638
1571
1639
if (!gmp_is_bit_index_valid (index )) {
1572
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1640
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1573
1641
RETURN_THROWS ();
1574
1642
}
1575
1643
@@ -1590,7 +1658,7 @@ ZEND_FUNCTION(gmp_testbit)
1590
1658
ZEND_PARSE_PARAMETERS_END ();
1591
1659
1592
1660
if (!gmp_is_bit_index_valid (index )) {
1593
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1661
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1594
1662
RETURN_THROWS ();
1595
1663
}
1596
1664
@@ -1602,26 +1670,44 @@ ZEND_FUNCTION(gmp_testbit)
1602
1670
ZEND_FUNCTION (gmp_popcount )
1603
1671
{
1604
1672
mpz_ptr gmpnum_a ;
1673
+ mp_bitcnt_t result ;
1605
1674
1606
1675
ZEND_PARSE_PARAMETERS_START (1 , 1 )
1607
1676
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1608
1677
ZEND_PARSE_PARAMETERS_END ();
1609
1678
1610
- RETURN_LONG (mpz_popcount (gmpnum_a ));
1679
+ result = mpz_popcount (gmpnum_a );
1680
+
1681
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1682
+ if (SIZE_MAX == result ) {
1683
+ RETURN_LONG (-1 );
1684
+ }
1685
+ #endif
1686
+
1687
+ RETURN_LONG (result );
1611
1688
}
1612
1689
/* }}} */
1613
1690
1614
1691
/* {{{ Calculates hamming distance between a and b */
1615
1692
ZEND_FUNCTION (gmp_hamdist )
1616
1693
{
1617
1694
mpz_ptr gmpnum_a , gmpnum_b ;
1695
+ mp_bitcnt_t result ;
1618
1696
1619
1697
ZEND_PARSE_PARAMETERS_START (2 , 2 )
1620
1698
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1621
1699
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_b )
1622
1700
ZEND_PARSE_PARAMETERS_END ();
1623
1701
1624
- RETURN_LONG (mpz_hamdist (gmpnum_a , gmpnum_b ));
1702
+ result = mpz_hamdist (gmpnum_a , gmpnum_b );
1703
+
1704
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1705
+ if (SIZE_MAX == result ) {
1706
+ RETURN_LONG (-1 );
1707
+ }
1708
+ #endif
1709
+
1710
+ RETURN_LONG (result );
1625
1711
}
1626
1712
/* }}} */
1627
1713
@@ -1630,18 +1716,27 @@ ZEND_FUNCTION(gmp_scan0)
1630
1716
{
1631
1717
mpz_ptr gmpnum_a ;
1632
1718
zend_long start ;
1719
+ mp_bitcnt_t result ;
1633
1720
1634
1721
ZEND_PARSE_PARAMETERS_START (2 , 2 )
1635
1722
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1636
1723
Z_PARAM_LONG (start )
1637
1724
ZEND_PARSE_PARAMETERS_END ();
1638
1725
1639
1726
if (!gmp_is_bit_index_valid (start )) {
1640
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1727
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1641
1728
RETURN_THROWS ();
1642
1729
}
1643
1730
1644
- RETURN_LONG (mpz_scan0 (gmpnum_a , start ));
1731
+ result = mpz_scan0 (gmpnum_a , start );
1732
+
1733
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1734
+ if (SIZE_MAX == result ) {
1735
+ RETURN_LONG (-1 );
1736
+ }
1737
+ #endif
1738
+
1739
+ RETURN_LONG (result );
1645
1740
}
1646
1741
/* }}} */
1647
1742
@@ -1650,18 +1745,28 @@ ZEND_FUNCTION(gmp_scan1)
1650
1745
{
1651
1746
mpz_ptr gmpnum_a ;
1652
1747
zend_long start ;
1748
+ mp_bitcnt_t result ;
1749
+
1653
1750
1654
1751
ZEND_PARSE_PARAMETERS_START (2 , 2 )
1655
1752
GMP_Z_PARAM_INTO_MPZ_PTR (gmpnum_a )
1656
1753
Z_PARAM_LONG (start )
1657
1754
ZEND_PARSE_PARAMETERS_END ();
1658
1755
1659
1756
if (!gmp_is_bit_index_valid (start )) {
1660
- zend_argument_value_error (2 , "must be between 0 and %d * %d " , INT_MAX , GMP_NUMB_BITS );
1757
+ zend_argument_value_error (2 , "must be between 0 and %lu " , GMP_SAFE_BITINDEX_MAX );
1661
1758
RETURN_THROWS ();
1662
1759
}
1663
1760
1664
- RETURN_LONG (mpz_scan1 (gmpnum_a , start ));
1761
+ result = mpz_scan1 (gmpnum_a , start );
1762
+
1763
+ #if SIZEOF_SIZE_T <= SIZEOF_ZEND_LONG
1764
+ if (SIZE_MAX == result ) {
1765
+ RETURN_LONG (-1 );
1766
+ }
1767
+ #endif
1768
+
1769
+ RETURN_LONG (result );
1665
1770
}
1666
1771
/* }}} */
1667
1772
0 commit comments